Add PaymentsService, ProcessPaymentService, and RetryPaymentService for payment processing logic
This commit is contained in:
parent
04b874a3a2
commit
8d6a8f75ea
34
src/modules/payments/services/payments.service.ts
Normal file
34
src/modules/payments/services/payments.service.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { CreatePaymentDto } from '../dto/create-payment.dto';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Payment } from '../entities/payment.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { QueueService } from '../../queue/queue.service';
|
||||||
|
import { PaymentStatusEnum } from '../enumns/payment-status.enum';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class PaymentsService {
|
||||||
|
private readonly logger = new Logger(PaymentsService.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(Payment) private readonly repository: Repository<Payment>,
|
||||||
|
private queueService: QueueService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async store(createPaymentDto: CreatePaymentDto) {
|
||||||
|
const payment = await this.repository.save({
|
||||||
|
...createPaymentDto,
|
||||||
|
status: PaymentStatusEnum.PENDING,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.queueService.addPaymentJob({
|
||||||
|
paymentId: payment.id,
|
||||||
|
paymentData: createPaymentDto,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'Payment created successfully and added to processing queue',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/modules/payments/services/process-payment.service.ts
Normal file
73
src/modules/payments/services/process-payment.service.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Payment } from '../entities/payment.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { HealthService } from '../../health/services/health.service';
|
||||||
|
import { ProcessorTypeEnum } from '../enumns/processor-type.enum';
|
||||||
|
import { PaymentStatusEnum } from '../enumns/payment-status.enum';
|
||||||
|
import { PaymentDefaultProcessor } from '../processor/payment-default.processor';
|
||||||
|
import { PaymentFallbackProcessor } from '../processor/payment-fallback.processor';
|
||||||
|
import { RetryPaymentService } from './retry-payment.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ProcessPaymentService {
|
||||||
|
private readonly logger = new Logger(ProcessPaymentService.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(Payment) private readonly repository: Repository<Payment>,
|
||||||
|
private healthService: HealthService,
|
||||||
|
private paymentDefaultProcessor: PaymentDefaultProcessor,
|
||||||
|
private paymentFallbackProcessor: PaymentFallbackProcessor,
|
||||||
|
private retryPaymentService: RetryPaymentService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(paymentId: string): Promise<void> {
|
||||||
|
const payment = await this.repository.findOne({
|
||||||
|
where: { id: paymentId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!payment) {
|
||||||
|
throw new Error(`Payment ${paymentId} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.repository.update(paymentId, {
|
||||||
|
status: PaymentStatusEnum.PROCESSING,
|
||||||
|
});
|
||||||
|
|
||||||
|
const preferredProcessor = this.healthService.getPreferredProcessor();
|
||||||
|
|
||||||
|
if (!preferredProcessor) {
|
||||||
|
throw new Error('No payment processor available');
|
||||||
|
}
|
||||||
|
|
||||||
|
let result;
|
||||||
|
|
||||||
|
let processorUsed: ProcessorTypeEnum =
|
||||||
|
preferredProcessor === ProcessorTypeEnum.DEFAULT
|
||||||
|
? ProcessorTypeEnum.DEFAULT
|
||||||
|
: ProcessorTypeEnum.FALLBACK;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (preferredProcessor === ProcessorTypeEnum.DEFAULT) {
|
||||||
|
result = await this.paymentDefaultProcessor.execute(payment);
|
||||||
|
processorUsed = ProcessorTypeEnum.DEFAULT;
|
||||||
|
} else {
|
||||||
|
result = await this.paymentFallbackProcessor.execute(payment);
|
||||||
|
processorUsed = ProcessorTypeEnum.FALLBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
await this.retryPaymentService.execute(payment.id, processorUsed);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
`Error processing payment ${paymentId}:`,
|
||||||
|
error.message,
|
||||||
|
);
|
||||||
|
await this.repository.update(payment.id, {
|
||||||
|
status: PaymentStatusEnum.RETRY,
|
||||||
|
});
|
||||||
|
await this.retryPaymentService.execute(payment.id, processorUsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/modules/payments/services/retry-payment.service.ts
Normal file
84
src/modules/payments/services/retry-payment.service.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Payment } from '../entities/payment.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { ProcessorTypeEnum } from '../enumns/processor-type.enum';
|
||||||
|
import { HealthService } from '../../health/services/health.service';
|
||||||
|
import { PaymentStatusEnum } from '../enumns/payment-status.enum';
|
||||||
|
import { PaymentDefaultProcessor } from '../processor/payment-default.processor';
|
||||||
|
import { PaymentFallbackProcessor } from '../processor/payment-fallback.processor';
|
||||||
|
import { QueueService } from '../../queue/queue.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RetryPaymentService {
|
||||||
|
private readonly logger = new Logger(RetryPaymentService.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(Payment) private readonly repository: Repository<Payment>,
|
||||||
|
private healthService: HealthService,
|
||||||
|
private paymentDefaultProcessor: PaymentDefaultProcessor,
|
||||||
|
private paymentFallbackProcessor: PaymentFallbackProcessor,
|
||||||
|
private queueService: QueueService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(paymentId: string, failedProcessor: ProcessorTypeEnum) {
|
||||||
|
const alternativeProcessor =
|
||||||
|
failedProcessor === ProcessorTypeEnum.DEFAULT
|
||||||
|
? ProcessorTypeEnum.FALLBACK
|
||||||
|
: ProcessorTypeEnum.DEFAULT;
|
||||||
|
|
||||||
|
const payment = await this.repository.findOne({
|
||||||
|
where: { id: paymentId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!payment) {
|
||||||
|
throw new Error(`Payment ${paymentId} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isAlternativeAvailable =
|
||||||
|
alternativeProcessor === ProcessorTypeEnum.DEFAULT
|
||||||
|
? this.healthService.shouldUseDefaultProcessor()
|
||||||
|
: this.healthService.shouldUseFallbackProcessor();
|
||||||
|
|
||||||
|
if (!isAlternativeAvailable) {
|
||||||
|
await this.repository.update(payment.id, {
|
||||||
|
status: PaymentStatusEnum.RETRY,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result;
|
||||||
|
|
||||||
|
if (failedProcessor === ProcessorTypeEnum.DEFAULT) {
|
||||||
|
result = await this.paymentDefaultProcessor.execute(payment);
|
||||||
|
} else {
|
||||||
|
result = await this.paymentFallbackProcessor.execute(payment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
this.logger.log(
|
||||||
|
`Nova Tentativa do Payment ${payment?.id} processed successfully via ${alternativeProcessor}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await this.queueService.addRetryPaymentJob({
|
||||||
|
paymentId: payment.id,
|
||||||
|
paymentData: {
|
||||||
|
amount: payment.amount,
|
||||||
|
correlationId: payment.correlationId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.repository.update(payment.id, {
|
||||||
|
status: PaymentStatusEnum.RETRY,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Error processing payment:', error.message);
|
||||||
|
|
||||||
|
await this.repository.update(payment.id, {
|
||||||
|
status: PaymentStatusEnum.FAILED,
|
||||||
|
errorMessage: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user