refactor: the invoice queue logic
This commit is contained in:
@@ -18,8 +18,6 @@ import { InvoicesService } from "../providers/invoices.service";
|
||||
|
||||
@Processor(INVOICE.INVOICE_QUEUE_NAME, { concurrency: 5 })
|
||||
export class InvoiceProcessor extends WorkerProcessor {
|
||||
// protected readonly logger = new Logger(InvoiceProcessor.name);
|
||||
|
||||
constructor(
|
||||
@InjectQueue(INVOICE.INVOICE_QUEUE_NAME) private readonly invoiceQueue: Queue,
|
||||
private readonly invoicesService: InvoicesService,
|
||||
@@ -94,9 +92,7 @@ export class InvoiceProcessor extends WorkerProcessor {
|
||||
this.logger.verbose(`Creating subscription-based recurring invoice`);
|
||||
|
||||
const userSubscriptionPlan = invoice.items[0]?.subscriptionPlan;
|
||||
if (!userSubscriptionPlan) {
|
||||
throw new Error(`No subscription plan found for invoice ${invoice.id}`);
|
||||
}
|
||||
if (!userSubscriptionPlan) throw new Error(`No subscription plan found for invoice ${invoice.id}`);
|
||||
|
||||
const { plan } = userSubscriptionPlan;
|
||||
const dueDate = dayjs().add(INVOICE.DUEDATE, "day").toDate();
|
||||
@@ -192,18 +188,49 @@ export class InvoiceProcessor extends WorkerProcessor {
|
||||
const dueDate = dayjs(invoice.dueDate);
|
||||
|
||||
if (today.isAfter(dueDate)) {
|
||||
// Mark invoice as overdue in status if not already paid
|
||||
if (invoice.status === InvoiceStatus.PENDING || invoice.status === InvoiceStatus.WAIT_PAYMENT) {
|
||||
this.logger.log(`Marking invoice ${invoice.id} as overdue`);
|
||||
invoice.status = InvoiceStatus.OVERDUE;
|
||||
}
|
||||
|
||||
const daysOverdue = Math.min(today.diff(dueDate, "day"), INVOICE.MAX_DAYS_AFTER_OVERDUE);
|
||||
|
||||
// Get the original price without late fees to calculate the fine correctly
|
||||
const originalPrice = invoice.originalPrice || invoice.totalPrice;
|
||||
const currentFine = invoice.lateFee || new Decimal(0);
|
||||
const totalDaysFineShouldBeApplied = daysOverdue;
|
||||
const finePerDay = new Decimal(invoice.totalPrice).mul(INVOICE.FINE_PERCENTAGE);
|
||||
const newTotalFine = finePerDay.mul(totalDaysFineShouldBeApplied);
|
||||
const finePerDay = new Decimal(originalPrice).mul(INVOICE.FINE_PERCENTAGE);
|
||||
const newTotalFine = finePerDay.mul(daysOverdue);
|
||||
|
||||
if (newTotalFine.gt(currentFine)) {
|
||||
this.logger.log(`Applying late fee for invoice ${invoice.id}: ${newTotalFine} (${daysOverdue} days overdue)`);
|
||||
|
||||
// Calculate the difference between new and current fine
|
||||
const additionalFine = newTotalFine.minus(currentFine);
|
||||
|
||||
// Update the late fee
|
||||
invoice.lateFee = newTotalFine;
|
||||
invoice.totalPrice = new Decimal(invoice.totalPrice).plus(newTotalFine.minus(currentFine));
|
||||
|
||||
// Add only the additional fine to total price to avoid compounding
|
||||
invoice.totalPrice = new Decimal(invoice.totalPrice).plus(additionalFine);
|
||||
|
||||
await queryRunner.manager.save(Invoice, invoice);
|
||||
|
||||
// Send overdue notification to the user
|
||||
await this.notificationService.createInvoiceOverdueNotification(
|
||||
invoice.user.id,
|
||||
{
|
||||
userPhone: invoice.user.phone,
|
||||
userEmail: invoice.user.email,
|
||||
invoiceId: invoice.numericId.toString(),
|
||||
price: new Decimal(invoice.totalPrice).toNumber(),
|
||||
lateFee: new Decimal(newTotalFine).toNumber(),
|
||||
dueDate: invoice.dueDate,
|
||||
createDate: invoice.createdAt,
|
||||
items: invoice.items.map((item) => item.name).join(", "),
|
||||
},
|
||||
queryRunner,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,7 +247,7 @@ export class InvoiceProcessor extends WorkerProcessor {
|
||||
price: new Decimal(invoice.totalPrice).toNumber(),
|
||||
dueDate: invoice.dueDate,
|
||||
createDate: invoice.createdAt,
|
||||
items: invoice.items.join(", "),
|
||||
items: invoice.items.map((item) => item.name).join(", "),
|
||||
},
|
||||
queryRunner,
|
||||
);
|
||||
@@ -258,7 +285,7 @@ export class InvoiceProcessor extends WorkerProcessor {
|
||||
price: new Decimal(invoice.totalPrice).toNumber(),
|
||||
dueDate: invoice.dueDate,
|
||||
createDate: invoice.createdAt,
|
||||
items: invoice.items.join(", "),
|
||||
items: invoice.items.map((item) => item.name).join(", "),
|
||||
};
|
||||
|
||||
await Promise.all(
|
||||
|
||||
Reference in New Issue
Block a user