import { Injectable, UnprocessableEntityException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { RescheduleVerificationModel } from '../../../data/models/reschedule-verification.model'; import { RescheduleRequest, RescheduleVerification, } from '../../entities/reschedule-verification.entity'; import { generateOtp } from 'src/modules/booking-online/helpers/generate-otp'; import { TransactionReadService } from 'src/modules/transaction/transaction/data/services/transaction-read.service'; import { TransactionEntity } from 'src/modules/transaction/transaction/domain/entities/transaction.entity'; import { WhatsappService } from 'src/services/whatsapp/whatsapp.service'; @Injectable() export class RescheduleVerificationManager { constructor( @InjectRepository(RescheduleVerificationModel) private readonly rescheduleVerificationRepository: Repository, private readonly transactionService: TransactionReadService, ) {} async saveVerification( request: RescheduleRequest, ): Promise { try { const otp = generateOtp(); const transaction = await this.findDetailByBookingId(request.booking_id); if (!transaction) { throw new Error('Transaction not found for the provided booking id'); } const data: Partial = { code: otp, booking_id: transaction.id, name: transaction.customer_name, phone_number: transaction.customer_phone, reschedule_date: request.reschedule_date, }; const existTransaction = await this.rescheduleVerificationRepository.findOne({ where: { booking_id: transaction.id, }, }); const verification = existTransaction ?? this.rescheduleVerificationRepository.create(data); const result = await this.rescheduleVerificationRepository.save({ ...verification, code: otp, }); const whatsapp = new WhatsappService(); whatsapp.sendOtpNotification({ phone: transaction.customer_phone, code: otp.toString(), }); return result; } catch (error) { // You can customize the error handling as needed, e.g., throw HttpException for NestJS throw new UnprocessableEntityException( `Failed to save reschedule verification: ${error.message}`, ); } } async verifyOtp( booking_id: string, code: number, ): Promise<{ success: boolean; message: string }> { const verification = await this.rescheduleVerificationRepository.findOne({ where: { booking_id, code }, order: { created_at: 'DESC' }, }); if (!verification) { return { success: false, message: 'No verification code found for this booking.', }; } // Optionally, you can implement OTP expiration logic here if (verification.code !== code) { // Increment tried count verification.tried = (verification.tried || 0) + 1; await this.rescheduleVerificationRepository.save(verification); return { success: false, message: 'Invalid verification code.' }; } // Optionally, you can mark the verification as used or verified here return { success: true, message: 'Verification successful.' }; } async findDetailByBookingId(bookingId: string): Promise { const transaction = await this.transactionService.getOneByOptions({ where: { id: bookingId }, }); return transaction; } }