update: invoice processor and fix bug

This commit is contained in:
mahyargdz
2025-03-09 23:16:00 +03:30
parent 0d16a670e4
commit dff944ef90
5 changed files with 44 additions and 19 deletions
+4 -3
View File
@@ -9,9 +9,10 @@ export function bullMqConfig(): SharedBullAsyncConfiguration {
url: configService.getOrThrow<string>("REDIS_URI"),
},
defaultJobOptions: {
removeOnComplete: 1000,
removeOnFail: 5000,
attempts: 3,
removeOnComplete: 2000, // Consider lower values in high-volume production
removeOnFail: 5000, // Consider lower values to reduce Redis memory usage
attempts: 3, // Reasonable default, adjust based on job criticality
backoff: { type: "exponential", delay: 2000 }, // Consider adding for better retry behavior
},
}),
};
+1 -1
View File
@@ -11,5 +11,5 @@ export const INVOICE = Object.freeze({
FINE_PERCENTAGE: 0.01, // 1% of the total price
MAX_DAYS_AFTER_OVERDUE: 10,
DUEDATE: 7,
DAYS_BEFORE_OVERDUE: 6,
DAYS_BEFORE_OVERDUE: 3,
});
@@ -62,7 +62,8 @@ export class InvoicesService {
const totalPrice = invoiceItems.reduce((sum, item) => new Decimal(item.totalPrice).add(sum), new Decimal(0));
const tax = totalPrice.mul(0.1);
const dueDate = dayjs().add(INVOICE.DUEDATE, "day").toDate();
// const dueDate = dayjs().add(INVOICE.DUEDATE, "day").toDate();
const dueDate = dayjs().add(1, "minute").toDate();
const invoice = queryRunner.manager.create(Invoice, {
user: { id: createDto.userId },
@@ -90,13 +91,12 @@ export class InvoicesService {
},
queryRunner,
);
//TODO:remove the test delay
await this.invoiceQueue.add(
INVOICE.INVOICE_REMINDER_JOB_NAME,
{ invoiceId: invoice.id },
{
// delay: dayjs(invoice.dueDate).subtract(INVOICE.DAYS_BEFORE_OVERDUE, "day").diff(dayjs()),
delay: 900000, // 15 minutes in milliseconds
delay: dayjs(invoice.dueDate).subtract(INVOICE.DAYS_BEFORE_OVERDUE, "day").diff(dayjs()),
// delay: 1.5 * 60 * 1000, // 5 minutes in milliseconds
attempts: INVOICE.INVOICE_REMINDER_JOB_ATTEMPTS,
backoff: INVOICE.INVOICE_REMINDER_JOB_BACKOFF,
},
@@ -126,7 +126,7 @@ export class InvoicesService {
if (invoice.status === InvoiceStatus.WAIT_PAYMENT) throw new BadRequestException(InvoiceMessage.ALREADY_APPROVED);
if (invoice.status === InvoiceStatus.PAID) throw new BadRequestException(InvoiceMessage.INVOICE_ALREADY_PAID);
if (dayjs().isAfter(invoice.dueDate)) {
if (dayjs().isAfter(dayjs(invoice.dueDate).add(INVOICE.MAX_DAYS_AFTER_OVERDUE, "day"))) {
invoice.status = InvoiceStatus.EXPIRED;
await this.invoiceRepository.save(invoice);
throw new BadRequestException(InvoiceMessage.INVOICE_IS_OVERDUE);
@@ -177,7 +177,13 @@ export class InvoicesService {
if (invoice.status === InvoiceStatus.WAIT_PAYMENT) throw new BadRequestException(InvoiceMessage.ALREADY_APPROVED);
if (invoice.status === InvoiceStatus.PAID) throw new BadRequestException(InvoiceMessage.INVOICE_ALREADY_PAID);
if (dayjs().isAfter(invoice.dueDate)) throw new BadRequestException(InvoiceMessage.INVOICE_IS_OVERDUE);
//
if (dayjs().isAfter(dayjs(invoice.dueDate).add(INVOICE.MAX_DAYS_AFTER_OVERDUE, "day"))) {
invoice.status = InvoiceStatus.EXPIRED;
await this.invoiceRepository.save(invoice);
throw new BadRequestException(InvoiceMessage.INVOICE_IS_OVERDUE);
}
//
if (invoice.status !== InvoiceStatus.PENDING) throw new BadRequestException(InvoiceMessage.INVOICE_CAN_NOT_APPROVED);
invoice.status = InvoiceStatus.WAIT_PAYMENT;
@@ -256,8 +262,7 @@ export class InvoicesService {
INVOICE.INVOICE_REMINDER_JOB_NAME,
{ invoiceId: invoice.id },
{
// delay: dayjs(invoice.dueDate).subtract(INVOICE.DAYS_BEFORE_OVERDUE, "day").diff(dayjs()),
delay: 900000, // 15 minutes in milliseconds
delay: dayjs(invoice.dueDate).subtract(INVOICE.DAYS_BEFORE_OVERDUE, "day").diff(dayjs()),
attempts: INVOICE.INVOICE_REMINDER_JOB_ATTEMPTS,
backoff: INVOICE.INVOICE_REMINDER_JOB_BACKOFF,
repeat: { every: 300000 },
@@ -8,6 +8,7 @@ import { DataSource, QueryRunner } from "typeorm";
import { WorkerProcessor } from "../../../common/queues/worker.processor";
import { NotificationsService } from "../../notifications/providers/notifications.service";
import { SubscriptionStatus } from "../../subscriptions/enums/subscription-status.enum";
import { INVOICE } from "../constants";
import { Invoice } from "../entities/invoice.entity";
import { InvoiceStatus } from "../enums/invoice-status.enum";
@@ -77,7 +78,7 @@ export class InvoiceProcessor extends WorkerProcessor {
private async fetchInvoice(invoiceId: string, queryRunner: QueryRunner) {
const invoice = await queryRunner.manager.findOne(Invoice, {
where: { id: invoiceId },
relations: { user: true },
relations: { user: true, items: { subscriptionPlan: true } },
});
if (!invoice) throw new Error(`Invoice not found: ${invoiceId}`);
@@ -86,15 +87,34 @@ export class InvoiceProcessor extends WorkerProcessor {
//********************************** */
private isInvoiceOverdueForCancellation(invoice: Invoice): boolean {
const fiveDaysAfterDueDate = dayjs(invoice.dueDate).add(INVOICE.MAX_DAYS_AFTER_OVERDUE, "day");
return dayjs().isAfter(fiveDaysAfterDueDate);
const tenDaysAfterDueDate = dayjs(invoice.dueDate).add(INVOICE.MAX_DAYS_AFTER_OVERDUE, "day");
return dayjs().isAfter(tenDaysAfterDueDate);
}
//********************************** */
private async cancelOverdueInvoice(invoice: Invoice, queryRunner: QueryRunner) {
invoice.status = InvoiceStatus.CANCELLED;
await queryRunner.manager.save(Invoice, invoice);
this.logger.log(`Invoice ${invoice.id} has been cancelled as it is more than 7 days overdue.`);
if (invoice.items[0]?.subscriptionPlan) {
this.logger.log(
`Invoice ${invoice.id} has been cancelled as it is more than 10 days overdue. Subscription Plan ${invoice.items[0].subscriptionPlan.id} has been cancelled.`,
);
const userSubscription = invoice.items[0].subscriptionPlan;
userSubscription.status = SubscriptionStatus.INACTIVE;
await queryRunner.manager.save(userSubscription);
// await this.notificationService.createSubscriptionPlanCancelledNotification(
// invoice.user.id,
// {
// userPhone: invoice.user.phone,
// userEmail: invoice.user.email,
// subscriptionPlanId: invoice.items[0].subscriptionPlan.id,
// },
// queryRunner,
// );
}
this.logger.log(`Invoice ${invoice.id} has been cancelled as it is more than 10 days overdue.`);
}
//********************************** */
@@ -1,7 +1,6 @@
export enum SubscriptionStatus {
ACTIVE = "ACTIVE",
INACTIVE = "INACTIVE",
// PENDING = "PENDING",
CANCELED = "CANCELED",
EXPIRED = "EXPIRED",
// CANCELED = "CANCELED",
// EXPIRED = "EXPIRED",
}