diff --git a/src/core/helpers/otp/otp-service.ts b/src/core/helpers/otp/otp-service.ts index 9b0e33e..0b4e3e1 100644 --- a/src/core/helpers/otp/otp-service.ts +++ b/src/core/helpers/otp/otp-service.ts @@ -38,6 +38,14 @@ export class OtpService { return Object.values(counts).some((count) => count > 2); } + private hasNoMatchLength(str: string) { + return str.length !== this.otpLength; + } + + private hasStartWithZero(str: string) { + return str.split('')[0] === '0'; + } + public generateSecureOTP(): string { let otp: string; @@ -46,11 +54,12 @@ export class OtpService { Math.floor(Math.random() * 10).toString(), ).join(''); } while ( + this.hasNoMatchLength(otp) || this.hasSequentialDigits(otp) || this.hasRepeatedDigits(otp) || this.isPalindrome(otp) || this.hasPartiallyRepeatedDigits(otp) || - otp?.length < this.otpLength + this.hasStartWithZero(otp) ); return otp; } diff --git a/src/modules/configuration/otp-verification/data/services/otp-verification.service.ts b/src/modules/configuration/otp-verification/data/services/otp-verification.service.ts index 11420d2..148325e 100644 --- a/src/modules/configuration/otp-verification/data/services/otp-verification.service.ts +++ b/src/modules/configuration/otp-verification/data/services/otp-verification.service.ts @@ -74,7 +74,9 @@ export class OtpVerificationService { const createdAtMoment = moment(Number(activeOTP.created_at)); const nowMoment = moment(Number(dateNow)); const diffSeconds = nowMoment.diff(createdAtMoment, 'seconds'); - if (diffSeconds < 60) { + const isProduction = process.env.NODE_ENV === 'true'; + + if (diffSeconds < 60 && isProduction) { throw new BadRequestException( 'An active OTP request was made recently. Please try again later.', ); @@ -116,10 +118,13 @@ export class OtpVerificationService { ); } + let otp: any; + // Build a where condition with OR between target_id and reference - const otp = await this.otpVerificationRepo.findOne({ - where: [ - { + + if (target_id) { + otp = await this.otpVerificationRepo.findOne({ + where: { otp_code, action_type, target_id, @@ -127,7 +132,10 @@ export class OtpVerificationService { is_used: false, is_replaced: false, }, - { + }); + } else if (reference) { + otp = await this.otpVerificationRepo.findOne({ + where: { otp_code, action_type, reference, @@ -135,8 +143,8 @@ export class OtpVerificationService { is_used: false, is_replaced: false, }, - ], - }); + }); + } if (!otp) { throw new BadRequestException('Invalid or expired OTP.'); diff --git a/src/modules/transaction/reconciliation/domain/usecases/managers/cancel-reconciliation.manager.ts b/src/modules/transaction/reconciliation/domain/usecases/managers/cancel-reconciliation.manager.ts index 0782fa6..71a71be 100644 --- a/src/modules/transaction/reconciliation/domain/usecases/managers/cancel-reconciliation.manager.ts +++ b/src/modules/transaction/reconciliation/domain/usecases/managers/cancel-reconciliation.manager.ts @@ -15,6 +15,12 @@ import { TransactionEntity } from 'src/modules/transaction/transaction/domain/en @Injectable() export class CancelReconciliationManager extends BaseUpdateStatusManager { + protected payloadBody: any; + + setCustomBodyRequest(body) { + this.payloadBody = body; + } + getResult(): string { return `Success active data ${this.result.id}`; } @@ -50,6 +56,7 @@ export class CancelReconciliationManager extends BaseUpdateStatusManager { if (this.data.is_recap_transaction) { Object.assign(this.data, { + otp_code: this.payloadBody?.otp_code, reconciliation_confirm_by: null, reconciliation_confirm_date: null, reconciliation_status: STATUS.PENDING, @@ -58,6 +65,7 @@ export class CancelReconciliationManager extends BaseUpdateStatusManager { + async cancel(dataId, body): Promise { this.cancelManager.setData(dataId, STATUS.REJECTED); this.cancelManager.setService(this.serviceData, TABLE_NAME.TRANSACTION); + this.cancelManager.setCustomBodyRequest(body); await this.cancelManager.execute(); return this.cancelManager.getResult(); } diff --git a/src/modules/transaction/reconciliation/infrastructure/dto/cancel-top-dto.ts b/src/modules/transaction/reconciliation/infrastructure/dto/cancel-top-dto.ts new file mode 100644 index 0000000..042a863 --- /dev/null +++ b/src/modules/transaction/reconciliation/infrastructure/dto/cancel-top-dto.ts @@ -0,0 +1,14 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export class OtpVerifyDto { + @ApiProperty({ + name: 'otp_code', + type: String, + required: true, + example: '2345', + }) + @IsString() + @IsNotEmpty() + otp_code: string; +} diff --git a/src/modules/transaction/reconciliation/infrastructure/reconciliation-data.controller.ts b/src/modules/transaction/reconciliation/infrastructure/reconciliation-data.controller.ts index c983d2f..4f76225 100644 --- a/src/modules/transaction/reconciliation/infrastructure/reconciliation-data.controller.ts +++ b/src/modules/transaction/reconciliation/infrastructure/reconciliation-data.controller.ts @@ -16,6 +16,7 @@ import { Public } from 'src/core/guards'; import { TransactionEntity } from '../../transaction/domain/entities/transaction.entity'; import { UpdateReconciliationDto } from './dto/reconciliation.dto'; import { RecapReconciliationDto } from './dto/recap.dto'; +import { OtpVerifyDto } from './dto/cancel-top-dto'; @ApiTags(`${MODULE_NAME.RECONCILIATION.split('-').join(' ')} - data`) @Controller(`v1/${MODULE_NAME.RECONCILIATION}`) @@ -40,8 +41,11 @@ export class ReconciliationDataController { } @Patch(':id/cancel') - async cancel(@Param('id') dataId: string): Promise { - return await this.orchestrator.cancel(dataId); + async cancel( + @Param('id') dataId: string, + @Body() body: OtpVerifyDto, + ): Promise { + return await this.orchestrator.cancel(dataId, body); } @Put('/batch-cancel')