Skip to content

Commit

Permalink
Orv2 2874 be dates validation (#1631)
Browse files Browse the repository at this point in the history
  • Loading branch information
gchauhan-aot authored Oct 9, 2024
1 parent a2d5b14 commit 82180c0
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 28 deletions.
2 changes: 2 additions & 0 deletions vehicles/src/common/constants/api.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ export const CRYPTO_ALGORITHM_MD5 = 'md5';
export const CRYPTO_ALGORITHM_SHA256 = 'sha256';
export const TOKEN_EXPIRY_BUFFER = 15;
export const PERMISSIONS_KEY = 'permissions';
export const TIMEZONE_PACIFIC = "America/Vancouver";
export const GL_PROJ_CODE_PLACEHOLDER = 'PROJECT';

7 changes: 7 additions & 0 deletions vehicles/src/common/helper/common.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Cache } from 'cache-manager';
import { CacheKey } from '../enum/cache-key.enum';
import { getFromCache } from './cache.helper';
import { FeatureFlagValue } from '../enum/feature-flag-value.enum';
import { IDP } from '../enum/idp.enum';

/**
* Evaluates the given predicate and returns the value if the predicate is true or the value is not null, otherwise returns undefined.
Expand Down Expand Up @@ -48,3 +49,9 @@ export const isFeatureEnabled = async (

return true;
};

export const isCVClient = (identityProvider: IDP): boolean => {
return (
identityProvider !== IDP.IDIR && identityProvider !== IDP.SERVICE_ACCOUNT
);
};
8 changes: 8 additions & 0 deletions vehicles/src/common/helper/permit-application.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { User } from '../../modules/company-user-management/users/entities/user.
import { ApplicationStatus } from '../enum/application-status.enum';
import { PermitType } from '../enum/permit-type.enum';
import { PERMIT_TYPES_FOR_QUEUE } from '../constants/permit.constant';
import * as dayjs from 'dayjs';

/**
* Fetches and resolves various types of names associated with a permit using cache.
Expand Down Expand Up @@ -266,3 +267,10 @@ export const isPermitTypeEligibleForQueue = (
): boolean => {
return PERMIT_TYPES_FOR_QUEUE.includes(permitType);
};

export const validApplicationDates = (application: Permit, timezone: string): boolean => {
const todayUTC = dayjs(new Date());
const todayPacific = todayUTC.tz(timezone).format("YYYY-MM-DD");
const { startDate, expiryDate } = application.permitData;
return startDate >= todayPacific && startDate <= expiryDate;
}
19 changes: 19 additions & 0 deletions vehicles/src/common/helper/permit-fee.helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,22 @@ export const calculatePermitAmount = (

return amount;
};

export const validAmount = (
calculatedAmount: number,
receivedAmount: number,
transactionType: TransactionType,
): boolean =>{
const isAmountValid =
receivedAmount.toFixed(2) === Math.abs(calculatedAmount).toFixed(2);

// For refund transactions, ensure the calculated amount is negative.
const isRefundValid =
calculatedAmount < 0 && transactionType === TransactionType.REFUND;

// Return true if the amounts are valid or if it's a valid refund transaction
return (
isAmountValid &&
(isRefundValid || transactionType !== TransactionType.REFUND)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
InternalServerErrorException,
Logger,
NotFoundException,
UnprocessableEntityException,
} from '@nestjs/common';
import { CreateTransactionDto } from './dto/request/create-transaction.dto';
import { ReadTransactionDto } from './dto/response/read-transaction.dto';
Expand Down Expand Up @@ -46,10 +47,11 @@ import { PermitHistoryDto } from '../permit/dto/response/permit-history.dto';
import {
calculatePermitAmount,
permitFee,
validAmount,
} from 'src/common/helper/permit-fee.helper';
import { CfsTransactionDetail } from './entities/cfs-transaction.entity';
import { CfsFileStatus } from 'src/common/enum/cfs-file-status.enum';
import { isAmendmentApplication } from '../../../common/helper/permit-application.helper';
import { isAmendmentApplication, validApplicationDates } from '../../../common/helper/permit-application.helper';
import { isCfsPaymentMethodType } from 'src/common/helper/payment.helper';
import { PgApprovesStatus } from 'src/common/enum/pg-approved-status-type.enum';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
Expand All @@ -62,8 +64,12 @@ import {
throwBadRequestException,
throwUnprocessableEntityException,
} from '../../../common/helper/exception.helper';
import { isFeatureEnabled } from '../../../common/helper/common.helper';
import {
isCVClient,
isFeatureEnabled,
} from '../../../common/helper/common.helper';
import { SpecialAuth } from 'src/modules/special-auth/entities/special-auth.entity';
import { TIMEZONE_PACIFIC } from 'src/common/constants/api.constant';

@Injectable()
export class PaymentService {
Expand Down Expand Up @@ -323,12 +329,12 @@ export class PaymentService {
'Application in its current status cannot be processed for payment.',
);
}
const totalTransactionAmount =
await this.validatePaymentAndCalculateAmount(
createTransactionDto,
existingApplications,
queryRunner,
);
const totalTransactionAmount = await this.validateApplicationAndPayment(
createTransactionDto,
existingApplications,
currentUser,
queryRunner,
);
const transactionOrderNumber =
await this.generateTransactionOrderNumber();

Expand Down Expand Up @@ -496,40 +502,41 @@ export class PaymentService {
* @throws {BadRequestException} When the transaction amount in the request doesn't match with the calculated amount,
* or if there's a transaction type and amount mismatch in case of refunds.
*/
private async validatePaymentAndCalculateAmount(
private async validateApplicationAndPayment(
createTransactionDto: CreateTransactionDto,
applications: Permit[],
currentUser: IUserJWT,
queryRunner: QueryRunner,
) {
let totalTransactionAmountCalculated = 0;
const isCVClientUser: boolean = isCVClient(currentUser.identity_provider);
// Calculate and add amount for each requested application, as per the available backend data.
for (const application of applications) {
totalTransactionAmountCalculated =
totalTransactionAmountCalculated +
(await this.permitFeeCalculator(application, queryRunner));
//Check if each application has a valid start date and valid expiry date.
if (isCVClientUser && !validApplicationDates(application, TIMEZONE_PACIFIC))
{
throw new UnprocessableEntityException(
`Atleast one of the application has invalid startDate or expiryDate.`,
);
}
totalTransactionAmountCalculated += await this.permitFeeCalculator(
application,
queryRunner,
);
}
const totalTransactionAmount =
createTransactionDto.applicationDetails?.reduce(
(accumulator, item) => accumulator + item.transactionAmount,
0,
);
if (
totalTransactionAmount.toFixed(2) !=
Math.abs(totalTransactionAmountCalculated).toFixed(2)
) {
throw new BadRequestException(
`Transaction Amount Mismatch. Amount received is $${totalTransactionAmount.toFixed(2)} but amount calculated is $${Math.abs(totalTransactionAmountCalculated).toFixed(2)}`,
);
}

//For transaction type refund, total transaction amount in backend should be less than zero and vice a versa.
//This extra check to compare transaction type and amount is only needed in case of refund, for other trasaction types, comparing amount is sufficient.
if (
totalTransactionAmountCalculated < 0 &&
createTransactionDto.transactionTypeId != TransactionType.REFUND
) {
throw new BadRequestException('Transaction Type Mismatch');
}
!validAmount(
totalTransactionAmountCalculated,
totalTransactionAmount,
createTransactionDto.transactionTypeId,
)
)
throw new BadRequestException('Transaction amount mismatch.');
return totalTransactionAmount;
}

Expand Down

0 comments on commit 82180c0

Please sign in to comment.