diff --git a/database/mssql/scripts/versions/revert/v_36_ddl_revert.sql b/database/mssql/scripts/versions/revert/v_36_ddl_revert.sql new file mode 100644 index 000000000..9fb6a7e98 --- /dev/null +++ b/database/mssql/scripts/versions/revert/v_36_ddl_revert.sql @@ -0,0 +1,26 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +SET NOCOUNT ON +GO + +SET XACT_ABORT ON + +BEGIN TRY + BEGIN TRANSACTION + + DELETE FROM [access].[ORBC_GROUP_ROLE] WHERE ROLE_TYPE = 'ORBC-READ-CREDIT-ACCOUNT' AND USER_AUTH_GROUP_TYPE='PAPPLICANT' + COMMIT +END TRY + +BEGIN CATCH + IF @@TRANCOUNT > 0 + ROLLBACK; + THROW +END CATCH + +DECLARE @VersionDescription VARCHAR(255) +SET @VersionDescription = 'Reverting ORBC-READ-CREDIT-ACCOUNT role for PAPPLICANT.' + +INSERT [dbo].[ORBC_SYS_VERSION] ([VERSION_ID], [DESCRIPTION], [RELEASE_DATE]) VALUES (35, @VersionDescription, getutcdate()) diff --git a/database/mssql/scripts/versions/v_36_ddl.sql b/database/mssql/scripts/versions/v_36_ddl.sql new file mode 100644 index 000000000..62379444e --- /dev/null +++ b/database/mssql/scripts/versions/v_36_ddl.sql @@ -0,0 +1,43 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +SET NOCOUNT ON +GO + +SET XACT_ABORT ON +GO +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE +GO +BEGIN TRANSACTION +GO +IF @@ERROR <> 0 SET NOEXEC ON +GO + +INSERT [access].[ORBC_GROUP_ROLE] ([USER_AUTH_GROUP_TYPE], [ROLE_TYPE]) VALUES (N'PAPPLICANT', N'ORBC-READ-CREDIT-ACCOUNT') +GO + +IF @@ERROR <> 0 SET NOEXEC ON +GO + +DECLARE @VersionDescription VARCHAR(255) +SET @VersionDescription = 'Credit Account roles for PAPPLICANT' + +INSERT [dbo].[ORBC_SYS_VERSION] ([VERSION_ID], [DESCRIPTION], [UPDATE_SCRIPT], [REVERT_SCRIPT], [RELEASE_DATE]) VALUES (36, @VersionDescription, '$(UPDATE_SCRIPT)', '$(REVERT_SCRIPT)', getutcdate()) +IF @@ERROR <> 0 SET NOEXEC ON +GO + +COMMIT TRANSACTION +GO +IF @@ERROR <> 0 SET NOEXEC ON +GO +DECLARE @Success AS BIT +SET @Success = 1 +SET NOEXEC OFF +IF (@Success = 1) PRINT 'The database update succeeded' +ELSE BEGIN + IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION + PRINT 'The database update failed' +END +GO + diff --git a/database/mssql/test/versions/v_36_1_test.sql b/database/mssql/test/versions/v_36_1_test.sql new file mode 100644 index 000000000..b7df1e6a8 --- /dev/null +++ b/database/mssql/test/versions/v_36_1_test.sql @@ -0,0 +1,5 @@ +-- Test that the role types have been inserted correctly against user auth groups +SET NOCOUNT ON + +SELECT COUNT(*) FROM $(DB_NAME).[access].[ORBC_GROUP_ROLE] +WHERE ROLE_TYPE = 'ORBC-READ-CREDIT-ACCOUNT' AND USER_AUTH_GROUP_TYPE='PAPPLICANT' \ No newline at end of file diff --git a/database/mssql/test/versions/v_36_test.sh b/database/mssql/test/versions/v_36_test.sh new file mode 100644 index 000000000..01bcb788b --- /dev/null +++ b/database/mssql/test/versions/v_36_test.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Retrieve arguments +source ${SCRIPT_DIR}/utility/getopt.sh +USAGE="-u USER -p PASS -s SERVER -d DATABASE" +parse_options "${USAGE}" ${@} + +# All database tests for database version 36 are run from this shell script. +# TESTS_DIR variable set by the calling test-runner script. + +TEST_36_1_RESULT=$(/opt/mssql-tools/bin/sqlcmd -U ${USER} -P "${PASS}" -S ${SERVER} -v DB_NAME=${DATABASE} -h -1 -i ${TESTS_DIR}/v_36_1_test.sql | xargs) +if [[ $TEST_36_1_RESULT -eq 1 ]]; then + echo "Test 36.1 passed: Role types inserted correctly" +else + echo "******** Test 36.1 failed: Role types not inserted correctly" +fi \ No newline at end of file diff --git a/vehicles/src/modules/credit-account/credit-account-user.controller.ts b/vehicles/src/modules/credit-account/credit-account-user.controller.ts index 9dd9bb464..1480d5d22 100644 --- a/vehicles/src/modules/credit-account/credit-account-user.controller.ts +++ b/vehicles/src/modules/credit-account/credit-account-user.controller.ts @@ -32,6 +32,10 @@ import { CreditAccountIdPathParamDto } from './dto/request/pathParam/creditAccou import { GetCreditAccountUserQueryParamsDto } from './dto/request/queryParam/getCreditAccountUser.query-params.dto'; import { ReadCreditAccountUserDto } from './dto/response/read-credit-account-user.dto'; import { IsFeatureFlagEnabled } from '../../common/decorator/is-feature-flag-enabled.decorator'; +import { + ClientUserAuthGroup, + IDIR_USER_AUTH_GROUP_LIST, +} from '../../common/enum/user-auth-group.enum'; @ApiBearerAuth() @ApiTags('Credit Account Users') @@ -53,7 +57,7 @@ import { IsFeatureFlagEnabled } from '../../common/decorator/is-feature-flag-ena }) @IsFeatureFlagEnabled('CREDIT-ACCOUNT') @Controller( - 'companies/:companyId/credit-account/:creditAccountId/credit-account-user', + 'companies/:companyId/credit-accounts/:creditAccountId/credit-account-users', ) export class CreditAccountUserController { constructor(private readonly creditAccountService: CreditAccountService) {} @@ -141,7 +145,13 @@ export class CreditAccountUserController { type: [ReadCreditAccountUserDto], }) @Get() - @Roles(Role.READ_CREDIT_ACCOUNT) + @Roles({ + userAuthGroup: [ + ...IDIR_USER_AUTH_GROUP_LIST, + ClientUserAuthGroup.COMPANY_ADMINISTRATOR, + ], + oneOf: [Role.READ_CREDIT_ACCOUNT], + }) async getCreditAccountUsers( @Req() request: Request, @Param() { companyId, creditAccountId }: CreditAccountIdPathParamDto, diff --git a/vehicles/src/modules/credit-account/credit-account.controller.ts b/vehicles/src/modules/credit-account/credit-account.controller.ts index 2d61c6eec..6e904db2a 100644 --- a/vehicles/src/modules/credit-account/credit-account.controller.ts +++ b/vehicles/src/modules/credit-account/credit-account.controller.ts @@ -24,6 +24,14 @@ import { ReadCreditAccountUserDto } from './dto/response/read-credit-account-use import { ReadCreditAccountDto } from './dto/response/read-credit-account.dto'; import { CreditAccountIdPathParamDto } from './dto/request/pathParam/creditAccountUsers.path-params.dto'; import { UpdateCreditAccountStatusDto } from './dto/request/update-credit-account-status.dto'; +import { ReadCreditAccountActivityDto } from './dto/response/read-credit-account-activity.dto'; +import { + ClientUserAuthGroup, + IDIR_USER_AUTH_GROUP_LIST, + IDIRUserAuthGroup, +} from '../../common/enum/user-auth-group.enum'; +import { ReadCreditAccountMetadataDto } from './dto/response/read-credit-account-metadata.dto'; +import { ReadCreditAccountLimitDto } from './dto/response/read-credit-account-limit.dto'; @ApiBearerAuth() @ApiTags('Credit Accounts') @@ -44,7 +52,7 @@ import { UpdateCreditAccountStatusDto } from './dto/request/update-credit-accoun type: ExceptionDto, }) @IsFeatureFlagEnabled('CREDIT-ACCOUNT') -@Controller('companies/:companyId/credit-account') +@Controller('companies/:companyId/credit-accounts') export class CreditAccountController { constructor(private readonly creditAccountService: CreditAccountService) {} @@ -60,7 +68,7 @@ export class CreditAccountController { }) @ApiCreatedResponse({ description: 'The created credit account.', - type: ReadCreditAccountUserDto, + type: ReadCreditAccountDto, }) @ApiBadRequestResponse({ description: 'The response containing a message of why a request failed.', @@ -80,11 +88,45 @@ export class CreditAccountController { } /** - * Retrieves a credit account. + * Retrieves a credit account metadata. * * @param { companyId } - The companyId path parameter. * @returns The result of the creation operation. */ + @ApiOperation({ + summary: + 'Retrieves a credit account (if available) metadata associated with a company.', + description: + 'Retrieves a credit account (if available) metadata associated with a company, enforcing authentication.', + }) + @ApiOkResponse({ + description: 'The retrieved credit account.', + type: ReadCreditAccountMetadataDto, + }) + @Get('meta-data') + @Roles(Role.READ_CREDIT_ACCOUNT) + async getCreditAccountMetadata( + @Req() request: Request, + @Param() { companyId }: CompanyIdPathParamDto, + ): Promise { + const readCreditAccounMetadataDto = + await this.creditAccountService.getCreditAccountMetadata({ + companyId, + currentUser: request.user as IUserJWT, + }); + if (!readCreditAccounMetadataDto) { + throw new DataNotFoundException(); + } + return readCreditAccounMetadataDto; + } + + /** + * Retrieves a credit account. + * + * @param { companyId } - The companyId path parameter. + * @param { creditAccountId } - The creditAccountId path parameter. + * @returns The result of the retrieval operation OR a relevant exception. + */ @ApiOperation({ summary: 'Retrieves a credit account (if available) associated with a company.', @@ -95,23 +137,106 @@ export class CreditAccountController { description: 'The retrieved credit account.', type: ReadCreditAccountDto, }) - @Get() - @Roles(Role.READ_CREDIT_ACCOUNT) + @Get(':creditAccountId') + @Roles({ + userAuthGroup: [ + ...IDIR_USER_AUTH_GROUP_LIST, + ClientUserAuthGroup.COMPANY_ADMINISTRATOR, + ], + oneOf: [Role.READ_CREDIT_ACCOUNT], + }) async getCreditAccount( @Req() request: Request, - @Param() { companyId }: CompanyIdPathParamDto, + @Param() { companyId, creditAccountId }: CreditAccountIdPathParamDto, ): Promise { const readCreditAccountDto = - await this.creditAccountService.getCreditAccount( - request.user as IUserJWT, + await this.creditAccountService.getCreditAccount({ companyId, - ); + creditAccountId, + currentUser: request.user as IUserJWT, + }); if (!readCreditAccountDto) { throw new DataNotFoundException(); } return readCreditAccountDto; } + /** + * Retrieves a credit account (if available) limits. + * + * @param {Object} params - The path parameters. + * @param {string} params.companyId - The companyId path parameter. + * @param {string} params.creditAccountId - The creditAccountId path parameter. + * @returns {Promise} The retrieved credit account limits. + */ + @ApiOperation({ + summary: 'Retrieves a credit account (if available) limits.', + description: + 'Retrieves a credit account (if available) limits, enforcing authentication.', + }) + @ApiOkResponse({ + description: 'The retrieved credit account limits.', + type: ReadCreditAccountLimitDto, + }) + @Get(':creditAccountId/limits') + @Roles({ + userAuthGroup: [ + IDIRUserAuthGroup.FINANCE, + IDIRUserAuthGroup.HQ_ADMINISTRATOR, + IDIRUserAuthGroup.SYSTEM_ADMINISTRATOR, + ClientUserAuthGroup.COMPANY_ADMINISTRATOR, + ], + oneOf: [Role.READ_CREDIT_ACCOUNT], + }) + async getCreditAccountLimit( + @Req() request: Request, + @Param() { companyId, creditAccountId }: CreditAccountIdPathParamDto, + ): Promise { + const readCreditAccountLimitDto = + await this.creditAccountService.getCreditAccountLimit({ + companyId, + creditAccountId, + currentUser: request.user as IUserJWT, + }); + return readCreditAccountLimitDto; + } + + /** + * Retrieves a credit account History. + * + * @param {Object} params - The path parameters. + * @param {string} params.companyId - The companyId path parameter. + * @param {string} params.creditAccountId - The creditAccountId path parameter. + * @returns {Promise} The retrieved credit account history. + */ + @ApiOperation({ + summary: 'Retrieves a credit account (if available) history.', + description: + 'Retrieves a credit account (if available) history, enforcing authentication.', + }) + @ApiOkResponse({ + description: 'The retrieved credit account history.', + isArray: true, + type: ReadCreditAccountActivityDto, + }) + @Get(':creditAccountId/history') + @Roles({ + userAuthGroup: [IDIRUserAuthGroup.FINANCE], + oneOf: [Role.READ_CREDIT_ACCOUNT], + }) + async getCreditAccountHistory( + @Req() request: Request, + @Param() { companyId, creditAccountId }: CreditAccountIdPathParamDto, + ): Promise { + const readCreditAccountActivityDto = + await this.creditAccountService.getCreditAccountActivity({ + companyId, + creditAccountId, + currentUser: request.user as IUserJWT, + }); + return readCreditAccountActivityDto; + } + /** * Updates the status of a credit account user. * @@ -127,7 +252,7 @@ export class CreditAccountController { }) @ApiOkResponse({ description: 'The updated credit account status details.', - type: ReadCreditAccountUserDto, + type: ReadCreditAccountDto, }) @Put(':creditAccountId/status') @Roles(Role.WRITE_CREDIT_ACCOUNT) diff --git a/vehicles/src/modules/credit-account/credit-account.service.ts b/vehicles/src/modules/credit-account/credit-account.service.ts index 7fff891eb..95b47b132 100644 --- a/vehicles/src/modules/credit-account/credit-account.service.ts +++ b/vehicles/src/modules/credit-account/credit-account.service.ts @@ -1,6 +1,7 @@ import { Mapper } from '@automapper/core'; import { InjectMapper } from '@automapper/nestjs'; import { + ForbiddenException, Injectable, InternalServerErrorException, Logger, @@ -42,13 +43,18 @@ import { CreditAccountActivity } from './entities/credit-account-activity.entity import { CreditAccountActivityType } from '../../common/enum/credit-account-activity-type.enum'; import { User } from '../company-user-management/users/entities/user.entity'; import { DataNotFoundException } from '../../common/exception/data-not-found.exception'; -import { ReadCreditAccountMetadataDto } from './dto/response/read-credit-account-metadata.dto'; + import { throwUnprocessableEntityException } from '../../common/helper/exception.helper'; import { ClientUserAuthGroup, IDIRUserAuthGroup, UserAuthGroup, } from '../../common/enum/user-auth-group.enum'; +import { ReadCreditAccountActivityDto } from './dto/response/read-credit-account-activity.dto'; +import { ReadCreditAccountMetadataDto } from './dto/response/read-credit-account-metadata.dto'; +import { ReadCreditAccountUserDetailsDto } from './dto/response/read-credit-account-user-details.dto'; +import { ReadCreditAccountLimitDto } from './dto/response/read-credit-account-limit.dto'; +import { doesUserHaveAuthGroup } from '../../common/helper/auth.helper'; /** * Service functions for credit account operations. @@ -223,72 +229,115 @@ export class CreditAccountService { } } - const creditAccountHolder = await this.classMapper.mapAsync( - companyInfo, - Company, - ReadCreditAccountUserDto, - ); - const createdCreditAccountDto = await this.classMapper.mapAsync( savedCreditAccount, CreditAccount, ReadCreditAccountDto, - { - extraArgs: () => ({ - userAuthGroup: currentUser.orbcUserAuthGroup, - creditBalance: 0, - availableCredit: creditLimit, - creditLimit, - }), - }, ); - createdCreditAccountDto.creditAccountUsers = [creditAccountHolder]; + return createdCreditAccountDto; } + /** + * Retrieves detailed information about a credit account for a given company and user. + * + * This method fetches the credit account details based on company ID and optionally credit account ID. + * If the credit account does not exist, it throws a DataNotFoundException. It then maps the credit account + * details to a ReadCreditAccountDto with additional parameters derived from the user context. + * + * @param {number} companyId - The ID of the company. + * @param {Nullable} creditAccountId - The optional ID of the credit account. + * @param {IUserJWT} currentUser - The current authenticated user. + * @returns {Promise} - The data transfer object containing credit account details. + * @throws {DataNotFoundException} - If the specified credit account is not found. + */ @LogAsyncMethodExecution() - async getCreditAccount(currentUser: IUserJWT, companyId: number) { + async getCreditAccount({ + companyId, + creditAccountId, + currentUser, + }: { + companyId: number; + creditAccountId?: Nullable; + currentUser: IUserJWT; + }): Promise { const creditAccount = await this.findCreditAccountDetails( companyId, currentUser, + creditAccountId, ); if (!creditAccount) { throw new DataNotFoundException(); + } else if ( + doesUserHaveAuthGroup(currentUser.orbcUserAuthGroup, [ + ClientUserAuthGroup.COMPANY_ADMINISTRATOR, + ]) && + creditAccount?.company.companyId !== companyId + ) { + // Throw exception if companyId is a Credit Account User and user is Company Admin. + throw new ForbiddenException(); } - creditAccount.creditAccountUsers = - creditAccount?.creditAccountUsers?.filter( - (creditAccountUser) => creditAccountUser.isActive, - ); const readCreditAccountDto = await this.classMapper.mapAsync( creditAccount, CreditAccount, ReadCreditAccountDto, - { - extraArgs: () => ({ - userAuthGroup: currentUser.orbcUserAuthGroup, - creditBalance: 0, - availableCredit: 0, - creditLimit: 0, - }), - }, ); - const mappedCreditAccountHolderInfo = await this.classMapper.mapAsync( - creditAccount?.company, - Company, - ReadCreditAccountUserDto, + return readCreditAccountDto; + } + + /** + * Retrieves detailed information about a credit account for a given company and user. + * + * This method fetches the credit account details based on company ID and optionally credit account ID. + * If the credit account does not exist, it throws a DataNotFoundException. It then maps the credit account + * details to a ReadCreditAccountDto with additional parameters derived from the user context. + * + * @param {number} companyId - The ID of the company. + * @param {Nullable} creditAccountId - The optional ID of the credit account. + * @param {IUserJWT} currentUser - The current authenticated user. + * @returns {Promise} - The data transfer object containing credit account details. + * @throws {DataNotFoundException} - If the specified credit account is not found. + */ + @LogAsyncMethodExecution() + async getCreditAccountMetadata({ + companyId, + creditAccountId, + currentUser, + }: { + companyId: number; + creditAccountId?: Nullable; + currentUser: IUserJWT; + }): Promise { + const creditAccount = await this.findCreditAccountDetails( + companyId, + currentUser, + creditAccountId, ); - if (readCreditAccountDto?.creditAccountUsers?.length) { - readCreditAccountDto?.creditAccountUsers?.unshift( - mappedCreditAccountHolderInfo, + if (!creditAccount) { + throw new DataNotFoundException(); + } + + creditAccount.creditAccountUsers = + creditAccount?.creditAccountUsers?.filter( + (creditAccountUser) => creditAccountUser.isActive, ); - } else { - readCreditAccountDto.creditAccountUsers = [mappedCreditAccountHolderInfo]; + + const readCreditAccountMetadataDto = new ReadCreditAccountMetadataDto(); + readCreditAccountMetadataDto.creditAccountId = + creditAccount.creditAccountId; + + if (creditAccount?.company?.companyId === companyId) + readCreditAccountMetadataDto.userType = + CreditAccountUserType.ACCOUNT_HOLDER; + else { + readCreditAccountMetadataDto.userType = + CreditAccountUserType.ACCOUNT_USER; } - return readCreditAccountDto; + return readCreditAccountMetadataDto; } /** @@ -438,7 +487,10 @@ export class CreditAccountService { } finally { await queryRunner.release(); } - return await this.getCreditAccount(currentUser, creditAccountHolderId); + return await this.getCreditAccount({ + currentUser, + companyId: creditAccountHolderId, + }); } /** @@ -540,14 +592,14 @@ export class CreditAccountService { // Check if there is an active credit account or if there are any active credit account users if (existingActiveAccount) { - const existingAccountMetadata = await this.classMapper.mapAsync( + const existingAccountUserDetails = await this.classMapper.mapAsync( existingActiveAccount, CreditAccount, - ReadCreditAccountMetadataDto, + ReadCreditAccountUserDetailsDto, ); throwUnprocessableEntityException( 'Client already associated with an active Credit Account', - existingAccountMetadata, + existingAccountUserDetails, ); } @@ -924,8 +976,21 @@ export class CreditAccountService { if (!creditAccount) { throw new DataNotFoundException(); + } else if ( + doesUserHaveAuthGroup(currentUser.orbcUserAuthGroup, [ + ClientUserAuthGroup.COMPANY_ADMINISTRATOR, + ]) && + creditAccount?.company.companyId !== companyId + ) { + // Throw exception if companyId is a Credit Account User and user is Company Admin. + throw new ForbiddenException(); } + creditAccount.creditAccountUsers = + creditAccount?.creditAccountUsers?.filter( + (creditAccountUser) => creditAccountUser.isActive, + ); + let readCreditAccountUserDtoList: ReadCreditAccountUserDto[] = []; if (creditAccount?.creditAccountUsers?.length) { readCreditAccountUserDtoList = await this.classMapper.mapArrayAsync( @@ -951,6 +1016,93 @@ export class CreditAccountService { return readCreditAccountUserDtoList; } + /** + * Retrieves credit account limit information based on account holder and credit account ID. + * + * @param companyId - The ID of the company. + * @param creditAccountId - The ID of the credit account. + * @param currentUser - The current authenticated user. + * @returns {Promise} - The details of the credit account limit. + * @throws {DataNotFoundException} - If the credit account is not found. + * @throws {ForbiddenException} - If the user is a Company Admin but the company is a Credit Account User. + */ + @LogAsyncMethodExecution() + public async getCreditAccountLimit({ + companyId, + creditAccountId, + currentUser, + }: { + companyId: number; + creditAccountId: number; + currentUser: IUserJWT; + }): Promise { + const creditAccount = await this.findCreditAccountDetails( + companyId, + currentUser, + creditAccountId, + ); + + if (!creditAccount) { + throw new DataNotFoundException(); + } else if ( + doesUserHaveAuthGroup(currentUser.orbcUserAuthGroup, [ + ClientUserAuthGroup.COMPANY_ADMINISTRATOR, + ]) && + creditAccount?.company.companyId !== companyId + ) { + // Throw exception if companyId is a Credit Account User and user is Company Admin. + throw new ForbiddenException(); + } + + // TODO Limit calculation is currently blocked and needs to be implemented + return await this.classMapper.mapAsync( + creditAccount, + CreditAccount, + ReadCreditAccountLimitDto, + ); + } + + /** + * Retrieves credit account activity based on account holder and credit account ID. + * + * @param companyId - The ID of the company. + * @param creditAccountId - The ID of the credit account. + * @param currentUser - The current user. + * @returns {Promise} - The list of credit account activities. + */ + @LogAsyncMethodExecution() + public async getCreditAccountActivity({ + companyId, + creditAccountId, + currentUser, + }: { + companyId: number; + creditAccountId: number; + currentUser: IUserJWT; + }): Promise { + const creditAccount = await this.findCreditAccountDetails( + companyId, + currentUser, + creditAccountId, + ); + + if (!creditAccount) { + throw new DataNotFoundException(); + } else if (creditAccount?.company.companyId !== companyId) { + // Throw exception if companyId is a Credit Account User. + // History is only available to Credit Account Holders + throw new ForbiddenException(); + } + + if (creditAccount?.creditAccountActivities?.length) { + return await this.classMapper.mapArrayAsync( + creditAccount?.creditAccountActivities, + CreditAccountActivity, + ReadCreditAccountActivityDto, + ); + } + } + private async findCreditAccountDetails( companyId: number, currentUser: IUserJWT, @@ -1039,6 +1191,8 @@ export class CreditAccountService { company: true, creditAccountUsers: { company: true }, }; + case ClientUserAuthGroup.PERMIT_APPLICANT: + return { company: true }; } break; // Check if the user is an ACCOUNT_USER @@ -1049,13 +1203,14 @@ export class CreditAccountService { return { company: true, creditAccountUsers: { company: true }, - creditAccountActivities: { idirUser: true }, }; - // Grant partial access to SYSTEM_ADMINISTRATOR, HQ_ADMINISTRATOR, PPC_CLERK, and PPC_SUPERVISOR groups + // Grant partial access to SYSTEM_ADMINISTRATOR, HQ_ADMINISTRATOR, PPC_CLERK, PPC_SUPERVISOR, COMPANY_ADMINISTRATOR, and PERMIT_APPLICANT groups case IDIRUserAuthGroup.SYSTEM_ADMINISTRATOR: case IDIRUserAuthGroup.HQ_ADMINISTRATOR: case IDIRUserAuthGroup.PPC_CLERK: case IDIRUserAuthGroup.PPC_SUPERVISOR: + case ClientUserAuthGroup.COMPANY_ADMINISTRATOR: + case ClientUserAuthGroup.PERMIT_APPLICANT: return { company: true }; } break; diff --git a/vehicles/src/modules/credit-account/dto/response/read-credit-account-limit.dto.ts b/vehicles/src/modules/credit-account/dto/response/read-credit-account-limit.dto.ts new file mode 100644 index 000000000..be5e4652f --- /dev/null +++ b/vehicles/src/modules/credit-account/dto/response/read-credit-account-limit.dto.ts @@ -0,0 +1,29 @@ +import { AutoMap } from '@automapper/classes'; +import { ApiProperty } from '@nestjs/swagger'; +import { + CreditAccountLimit, + CreditAccountLimitType, +} from '../../../../common/enum/credit-account-limit.enum'; + +export class ReadCreditAccountLimitDto { + @AutoMap() + @ApiProperty({ + description: 'The credit limit of the account.', + example: CreditAccountLimit[10000], + }) + creditLimit: CreditAccountLimitType; + + @AutoMap() + @ApiProperty({ + description: 'The credit balance of the account.', + example: 1200, + }) + creditBalance: number; + + @AutoMap() + @ApiProperty({ + description: 'The available credit of the account.', + example: 800, + }) + availableCredit: number; +} diff --git a/vehicles/src/modules/credit-account/dto/response/read-credit-account-metadata.dto.ts b/vehicles/src/modules/credit-account/dto/response/read-credit-account-metadata.dto.ts index b39abd8b4..46540465c 100644 --- a/vehicles/src/modules/credit-account/dto/response/read-credit-account-metadata.dto.ts +++ b/vehicles/src/modules/credit-account/dto/response/read-credit-account-metadata.dto.ts @@ -1,12 +1,19 @@ import { AutoMap } from '@automapper/classes'; import { ApiProperty } from '@nestjs/swagger'; -import { ReadCompanyMetadataDto } from '../../../company-user-management/company/dto/response/read-company-metadata.dto'; +import { CreditAccountUserType } from '../../../../common/enum/credit-accounts.enum'; -export class ReadCreditAccountMetadataDto extends ReadCompanyMetadataDto { +export class ReadCreditAccountMetadataDto { @AutoMap() @ApiProperty({ - description: 'The credit account number.', - example: 'WS5667', + description: 'The credit account id.', + example: 62, }) - creditAccountNumber: string; + creditAccountId: number; + + @AutoMap() + @ApiProperty({ + description: 'The credit account user type.', + example: CreditAccountUserType.ACCOUNT_HOLDER, + }) + userType: CreditAccountUserType; } diff --git a/vehicles/src/modules/credit-account/dto/response/read-credit-account-user-details.dto.ts b/vehicles/src/modules/credit-account/dto/response/read-credit-account-user-details.dto.ts new file mode 100644 index 000000000..d213c9249 --- /dev/null +++ b/vehicles/src/modules/credit-account/dto/response/read-credit-account-user-details.dto.ts @@ -0,0 +1,12 @@ +import { AutoMap } from '@automapper/classes'; +import { ApiProperty } from '@nestjs/swagger'; +import { ReadCreditAccountUserDto } from './read-credit-account-user.dto'; + +export class ReadCreditAccountUserDetailsDto extends ReadCreditAccountUserDto { + @AutoMap() + @ApiProperty({ + description: 'The credit account number.', + example: 'WS5667', + }) + creditAccountNumber: string; +} diff --git a/vehicles/src/modules/credit-account/dto/response/read-credit-account-user.dto.ts b/vehicles/src/modules/credit-account/dto/response/read-credit-account-user.dto.ts index 2e0fef263..4693c925c 100644 --- a/vehicles/src/modules/credit-account/dto/response/read-credit-account-user.dto.ts +++ b/vehicles/src/modules/credit-account/dto/response/read-credit-account-user.dto.ts @@ -1,9 +1,36 @@ import { AutoMap } from '@automapper/classes'; import { ApiProperty } from '@nestjs/swagger'; import { CreditAccountUserType } from '../../../../common/enum/credit-accounts.enum'; -import { ReadCompanyMetadataDto } from '../../../company-user-management/company/dto/response/read-company-metadata.dto'; -export class ReadCreditAccountUserDto extends ReadCompanyMetadataDto { +export class ReadCreditAccountUserDto { + @AutoMap() + @ApiProperty({ + description: 'The company ID.', + example: 1, + }) + companyId: number; + + @AutoMap() + @ApiProperty({ + description: 'The ORBC client number.', + example: '1234', + }) + clientNumber: string; + + @AutoMap() + @ApiProperty({ + description: 'The legal name of the company.', + example: 'ABC Carriers Inc.', + }) + legalName: string; + + @AutoMap() + @ApiProperty({ + description: 'The Alternate name of the company/Doing Business As (DBA).', + example: 'ABC Carriers Inc.', + }) + alternateName?: string; + @AutoMap() @ApiProperty({ description: 'The credit account user type.', diff --git a/vehicles/src/modules/credit-account/dto/response/read-credit-account.dto.ts b/vehicles/src/modules/credit-account/dto/response/read-credit-account.dto.ts index 589a4aab8..84228d568 100644 --- a/vehicles/src/modules/credit-account/dto/response/read-credit-account.dto.ts +++ b/vehicles/src/modules/credit-account/dto/response/read-credit-account.dto.ts @@ -1,16 +1,12 @@ import { AutoMap } from '@automapper/classes'; import { ApiProperty } from '@nestjs/swagger'; -import { - CreditAccountLimit, - CreditAccountLimitType, -} from '../../../../common/enum/credit-account-limit.enum'; + import { CreditAccountStatus, CreditAccountStatusType, } from '../../../../common/enum/credit-account-status-type.enum'; -import { ReadCreditAccountUserDto } from './read-credit-account-user.dto'; + import { CreditAccountType } from '../../../../common/enum/credit-account-type.enum'; -import { ReadCreditAccountActivityDto } from './read-credit-account-activity.dto'; export class ReadCreditAccountDto { @AutoMap() @@ -35,48 +31,10 @@ export class ReadCreditAccountDto { }) creditAccountNumber: string; - @AutoMap() - @ApiProperty({ - description: 'The collection of companies using this credit account.', - required: false, - }) - creditAccountUsers: ReadCreditAccountUserDto[]; - @AutoMap() @ApiProperty({ description: 'The status of the credit account.', example: CreditAccountStatus.ACCOUNT_ACTIVE, }) creditAccountStatusType: CreditAccountStatusType; - - @AutoMap() - @ApiProperty({ - description: 'The credit account status update activity details .', - required: false, - }) - creditAccountActivities?: ReadCreditAccountActivityDto[]; - - @AutoMap() - @ApiProperty({ - description: 'The credit limit of the account.', - example: CreditAccountLimit[10000], - required: false, - }) - creditLimit?: CreditAccountLimitType; - - @AutoMap() - @ApiProperty({ - description: 'The credit balance of the account.', - example: 1200, - required: false, - }) - creditBalance?: number; - - @AutoMap() - @ApiProperty({ - description: 'The available credit of the account.', - example: 800, - required: false, - }) - availableCredit?: number; } diff --git a/vehicles/src/modules/credit-account/profiles/credit-account.profile.ts b/vehicles/src/modules/credit-account/profiles/credit-account.profile.ts index 06f33f0c2..31892e3f7 100644 --- a/vehicles/src/modules/credit-account/profiles/credit-account.profile.ts +++ b/vehicles/src/modules/credit-account/profiles/credit-account.profile.ts @@ -6,7 +6,6 @@ import { forSelf, fromValue, mapFrom, - mapWith, mapWithArguments, } from '@automapper/core'; import { Injectable } from '@nestjs/common'; @@ -17,12 +16,10 @@ import { Company } from '../../company-user-management/company/entities/company. import { CreditAccountUserType } from '../../../common/enum/credit-accounts.enum'; import { CreditAccount } from '../entities/credit-account.entity'; import { ReadCreditAccountDto } from '../dto/response/read-credit-account.dto'; -import { CreditAccountLimitType } from '../../../common/enum/credit-account-limit.enum'; import { CreditAccountActivity } from '../entities/credit-account-activity.entity'; import { ReadCreditAccountActivityDto } from '../dto/response/read-credit-account-activity.dto'; -import { ReadCreditAccountMetadataDto } from '../dto/response/read-credit-account-metadata.dto'; -import { IDIRUserAuthGroup } from '../../../common/enum/user-auth-group.enum'; -import { undefinedSubstitution } from '../../../common/helper/common.helper'; +import { ReadCreditAccountUserDetailsDto } from '../dto/response/read-credit-account-user-details.dto'; +import { ReadCreditAccountLimitDto } from '../dto/response/read-credit-account-limit.dto'; @Injectable() export class CreditAccountProfile extends AutomapperProfile { @@ -97,89 +94,14 @@ export class CreditAccountProfile extends AutomapperProfile { ), ); - createMap( - mapper, - CreditAccount, - ReadCreditAccountDto, - forMember( - (d) => d.creditAccountActivities, - mapWith( - ReadCreditAccountActivityDto, - CreditAccountActivity, - (s) => s.creditAccountActivities, - ), - ), - forMember( - (d) => d.creditAccountUsers, - mapWith( - ReadCreditAccountUserDto, - CreditAccountUser, - (s) => s.creditAccountUsers, - ), - ), - forMember( - (d) => d.availableCredit, - mapWithArguments( - ( - _s, - { - userAuthGroup, - availableCredit, - }: { userAuthGroup: IDIRUserAuthGroup; availableCredit: number }, - ) => - undefinedSubstitution( - availableCredit, - () => - userAuthGroup !== IDIRUserAuthGroup.PPC_CLERK && - userAuthGroup !== IDIRUserAuthGroup.PPC_SUPERVISOR, - ), - ), - ), - forMember( - (d) => d.creditLimit, - mapWithArguments( - ( - _s, - { - userAuthGroup, - creditLimit, - }: { - userAuthGroup: IDIRUserAuthGroup; - creditLimit: CreditAccountLimitType; - }, - ) => - undefinedSubstitution( - creditLimit, - () => - userAuthGroup !== IDIRUserAuthGroup.PPC_CLERK && - userAuthGroup !== IDIRUserAuthGroup.PPC_SUPERVISOR, - ), - ), - ), - forMember( - (d) => d.creditBalance, - mapWithArguments( - ( - _s, - { - userAuthGroup, - creditBalance, - }: { userAuthGroup: IDIRUserAuthGroup; creditBalance: number }, - ) => - undefinedSubstitution( - creditBalance, - () => - userAuthGroup !== IDIRUserAuthGroup.PPC_CLERK && - userAuthGroup !== IDIRUserAuthGroup.PPC_SUPERVISOR, - ), - ), - ), - ); + createMap(mapper, CreditAccount, ReadCreditAccountDto); + + createMap(mapper, CreditAccount, ReadCreditAccountLimitDto); createMap( mapper, CreditAccount, - ReadCreditAccountMetadataDto, + ReadCreditAccountUserDetailsDto, forSelf(Company, (source) => source?.company), );