From fefa4e299550426c5679facb5bbfbd5155e47280 Mon Sep 17 00:00:00 2001 From: jos3duardo Date: Sat, 9 Aug 2025 22:36:26 -0400 Subject: [PATCH] Add payment processors for handling payment processing logic --- .../processor/payment-default.processor.ts | 56 +++++++++++++++++++ .../processor/payment-fallback.processor.ts | 51 +++++++++++++++++ .../payments/processor/payment.processor.ts | 37 ++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 src/modules/payments/processor/payment-default.processor.ts create mode 100644 src/modules/payments/processor/payment-fallback.processor.ts create mode 100644 src/modules/payments/processor/payment.processor.ts diff --git a/src/modules/payments/processor/payment-default.processor.ts b/src/modules/payments/processor/payment-default.processor.ts new file mode 100644 index 0000000..ebf9383 --- /dev/null +++ b/src/modules/payments/processor/payment-default.processor.ts @@ -0,0 +1,56 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { HttpService } from '@nestjs/axios'; +import { ConfigService } from '@nestjs/config'; +import { Payment } from '../entities/payment.entity'; +import { firstValueFrom } from 'rxjs'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ProcessorTypeEnum } from '../enumns/processor-type.enum'; +import { PaymentStatusEnum } from '../enumns/payment-status.enum'; + +@Injectable() +export class PaymentDefaultProcessor { + private readonly logger = new Logger(PaymentDefaultProcessor.name); + + constructor( + private readonly httpService: HttpService, + private readonly configService: ConfigService, + @InjectRepository(Payment) private readonly repository: Repository, + ) {} + + async execute(payment: Payment): Promise { + const url = this.configService.get('paymentProcessors.defaultUrl'); + + this.logger.log( + `Processando Pagamento ${payment.id} com default processor`, + ); + + const paymentData = { + amount: payment.amount, + correlationId: payment.correlationId, + }; + + const response = await firstValueFrom( + this.httpService.post(`${url}/payments`, paymentData, { + timeout: 2000, // 30 segundos + }), + ); + this.logger.log(response.status === 200); + if (response.status === 200) { + this.logger.log( + `Payment ${payment.id} processed successfully via default processor`, + ); + + await this.repository.update(payment.id, { + ...payment, + paymentProcessor: ProcessorTypeEnum.DEFAULT, + status: PaymentStatusEnum.SUCCESS, + }); + return true; + } + this.logger.log( + `Payment ${payment.id} not processed successfully via default processor: ${response.data.message || 'Unknown error'}`, + ); + return false; + } +} diff --git a/src/modules/payments/processor/payment-fallback.processor.ts b/src/modules/payments/processor/payment-fallback.processor.ts new file mode 100644 index 0000000..409e52b --- /dev/null +++ b/src/modules/payments/processor/payment-fallback.processor.ts @@ -0,0 +1,51 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { HttpService } from '@nestjs/axios'; +import { ConfigService } from '@nestjs/config'; +import { Payment } from '../entities/payment.entity'; +import { firstValueFrom } from 'rxjs'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ProcessorTypeEnum } from '../enumns/processor-type.enum'; +import { PaymentStatusEnum } from '../enumns/payment-status.enum'; + +@Injectable() +export class PaymentFallbackProcessor { + private readonly logger = new Logger(PaymentFallbackProcessor.name); + + constructor( + private readonly httpService: HttpService, + private readonly configService: ConfigService, + @InjectRepository(Payment) private readonly repository: Repository, + ) {} + + async execute(payment: Payment): Promise { + const url = this.configService.get('paymentProcessors.fallbackUrl'); + + this.logger.log(`Processing payment ${payment.id} via fallback processor`); + + const paymentData = { + amount: payment.amount, + correlationId: payment.correlationId, + }; + + const response = await firstValueFrom( + this.httpService.post(`${url}/payments`, paymentData, { + timeout: 2000, // 30 segundos + }), + ); + + if (response.status === 200 && response.data.success) { + this.logger.log( + `Payment ${payment.id} processed successfully via fallback processor`, + ); + + await this.repository.update(payment.id, { + ...payment, + paymentProcessor: ProcessorTypeEnum.FALLBACK, + status: PaymentStatusEnum.SUCCESS, + }); + return true; + } + return false; + } +} diff --git a/src/modules/payments/processor/payment.processor.ts b/src/modules/payments/processor/payment.processor.ts new file mode 100644 index 0000000..ff7d775 --- /dev/null +++ b/src/modules/payments/processor/payment.processor.ts @@ -0,0 +1,37 @@ +import { Job } from 'bullmq'; +import { PaymentJobData } from '../../queue/queue.service'; +import { Processor, WorkerHost } from '@nestjs/bullmq'; +import { Injectable, Logger } from '@nestjs/common'; +import { ProcessPaymentService } from '../services/process-payment.service'; +import { PAYMENT_QUEUE } from '../../queue/constants/queue.constants'; + +@Processor(PAYMENT_QUEUE) +@Injectable() +export class PaymentProcessor extends WorkerHost { + private readonly logger = new Logger(PaymentProcessor.name); + + constructor(private processPaymentService: ProcessPaymentService) { + super(); + } + + async process(job: Job) { + const { paymentId, retryCount = 0 } = job.data; + + this.logger.log( + `Processing payment ${paymentId}, attempt ${retryCount + 1}`, + ); + + try { + await this.processPaymentService.execute(paymentId); + this.logger.log(`Pagamento ${paymentId} processado com sucesso`); + + return { success: true, paymentId }; + } catch (error) { + this.logger.error( + `Failed to process payment ${paymentId}:`, + error.message, + ); + throw error; + } + } +}