|
|
|
@@ -505,22 +505,22 @@ export class InvoicesService {
|
|
|
|
|
let delayMs: number;
|
|
|
|
|
switch (recurringPeriod) {
|
|
|
|
|
case RecurringPeriodEnum.WEEKLY:
|
|
|
|
|
delayMs = dayjs().add(1, "week").subtract(INVOICE.DAYS_BEFORE_OVERDUE, "days").diff(dayjs());
|
|
|
|
|
delayMs = dayjs().add(1, "week").subtract(INVOICE.DAYS_BEFORE_OVERDUE, "day").diff(dayjs());
|
|
|
|
|
break;
|
|
|
|
|
case RecurringPeriodEnum.MONTHLY:
|
|
|
|
|
delayMs = dayjs().add(1, "month").subtract(7, "days").diff(dayjs());
|
|
|
|
|
delayMs = dayjs().add(1, "month").subtract(7, "day").diff(dayjs());
|
|
|
|
|
break;
|
|
|
|
|
case RecurringPeriodEnum.QUARTERLY:
|
|
|
|
|
delayMs = dayjs().add(3, "month").subtract(7, "days").diff(dayjs());
|
|
|
|
|
delayMs = dayjs().add(3, "month").subtract(7, "day").diff(dayjs());
|
|
|
|
|
break;
|
|
|
|
|
case RecurringPeriodEnum.BIANNUALLY:
|
|
|
|
|
delayMs = dayjs().add(6, "month").subtract(7, "days").diff(dayjs());
|
|
|
|
|
delayMs = dayjs().add(6, "month").subtract(7, "day").diff(dayjs());
|
|
|
|
|
break;
|
|
|
|
|
case RecurringPeriodEnum.ANNUALLY:
|
|
|
|
|
delayMs = dayjs().add(1, "year").subtract(7, "days").diff(dayjs());
|
|
|
|
|
delayMs = dayjs().add(1, "year").subtract(7, "day").diff(dayjs());
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
delayMs = dayjs().add(1, "month").subtract(7, "days").diff(dayjs());
|
|
|
|
|
delayMs = dayjs().add(1, "month").subtract(7, "day").diff(dayjs());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.logger.log(`Calculated recurring delay: ${delayMs}ms for period: ${recurringPeriod}`);
|
|
|
|
@@ -558,116 +558,4 @@ export class InvoicesService {
|
|
|
|
|
this.logger.log(`Scheduled recurring invoice for user ${createDto.userId} with interval ${createDto.recurringPeriod}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// async applyDiscount(invoiceId: string, applyDiscountDto: ApplyDiscountDto, userId: string) {
|
|
|
|
|
// const invoice = await this.invoiceRepository.findOneBy({ id: invoiceId, status: InvoiceStatus.PENDING });
|
|
|
|
|
// if (!invoice) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID);
|
|
|
|
|
|
|
|
|
|
// const discount = await this.discountRepository.findOne({
|
|
|
|
|
// where: { code: applyDiscountDto.discountCode, isActive: true },
|
|
|
|
|
// relations: ["subscriptionPlans", "users"],
|
|
|
|
|
// });
|
|
|
|
|
// if (!discount) {
|
|
|
|
|
// throw new BadRequestException(DiscountMessage.NOT_FOUND);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const hasUsedDiscount = await this.hasUserUsedDiscount(userId, discount.id);
|
|
|
|
|
// if (hasUsedDiscount) throw new BadRequestException(DiscountMessage.ALREADY_USED);
|
|
|
|
|
|
|
|
|
|
// if (discount.subscriptionPlans && discount.subscriptionPlans.length > 0) {
|
|
|
|
|
// const isApplicable = invoice.items.some((item) => {
|
|
|
|
|
// const subscriptionPlan = item.subscriptionPlan;
|
|
|
|
|
// if (!subscriptionPlan) return false;
|
|
|
|
|
// return discount.subscriptionPlans.some((plan) => plan.id === subscriptionPlan.id);
|
|
|
|
|
// });
|
|
|
|
|
// if (!isApplicable) {
|
|
|
|
|
// throw new BadRequestException(DiscountMessage.CAN_NOT_APPLICABLE);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (discount.users && discount.users.length > 0) {
|
|
|
|
|
// if (!discount.users.some((user) => user.id === userId)) {
|
|
|
|
|
// throw new BadRequestException(DiscountMessage.CAN_NOT_APPLICABLE);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// const discountAmount =
|
|
|
|
|
// discount.calculationType === "PERCENTAGE"
|
|
|
|
|
// ? new Decimal(invoice.totalPrice).mul(discount.amount).div(100)
|
|
|
|
|
// : new Decimal(discount.amount);
|
|
|
|
|
|
|
|
|
|
// invoice.totalPrice = new Decimal(invoice.totalPrice).minus(discountAmount);
|
|
|
|
|
// await this.invoiceRepository.save(invoice);
|
|
|
|
|
|
|
|
|
|
// const usageDiscount = this.usageDiscountRepository.create({
|
|
|
|
|
// discount,
|
|
|
|
|
// users: [{ id: userId }],
|
|
|
|
|
// usageDate: new Date(),
|
|
|
|
|
// });
|
|
|
|
|
|
|
|
|
|
// await this.usageDiscountRepository.save(usageDiscount);
|
|
|
|
|
|
|
|
|
|
// return {
|
|
|
|
|
// message: InvoiceMessage.DISCOUNT_APPLIED,
|
|
|
|
|
// invoice,
|
|
|
|
|
// };
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
//*********************************** */
|
|
|
|
|
|
|
|
|
|
// async cancelDiscount(invoiceId: string, userId: string) {
|
|
|
|
|
// // Find the invoice by ID and ensure it is in a PENDING status
|
|
|
|
|
// const invoice = await this.invoiceRepository.findOneBy({ id: invoiceId, status: InvoiceStatus.PENDING });
|
|
|
|
|
// if (!invoice) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID);
|
|
|
|
|
|
|
|
|
|
// // Find the usage discount associated with the user and invoice
|
|
|
|
|
// const usage = await this.usageDiscountRepository.findOne({
|
|
|
|
|
// where: {
|
|
|
|
|
// users: { id: userId },
|
|
|
|
|
// discount: { invoice: { id: invoice.id } },
|
|
|
|
|
// },
|
|
|
|
|
// relations: {
|
|
|
|
|
// discount: true,
|
|
|
|
|
// users: true,
|
|
|
|
|
// },
|
|
|
|
|
// });
|
|
|
|
|
// console.log(usage);
|
|
|
|
|
// if (!usage) throw new BadRequestException(DiscountMessage.NOT_FOUND);
|
|
|
|
|
|
|
|
|
|
// // Find the discount associated with the usage
|
|
|
|
|
// const discount = await this.discountRepository.findOneBy({ id: usage.discount.id });
|
|
|
|
|
// if (!discount) throw new BadRequestException(DiscountMessage.NOT_FOUND);
|
|
|
|
|
|
|
|
|
|
// // Calculate the discount amount to be removed from the invoice
|
|
|
|
|
// const discountAmount =
|
|
|
|
|
// discount.calculationType === "PERCENTAGE"
|
|
|
|
|
// ? new Decimal(invoice.totalPrice).mul(discount.amount).div(100)
|
|
|
|
|
// : new Decimal(discount.amount);
|
|
|
|
|
|
|
|
|
|
// // Update the invoice's total price by adding the discount amount (effectively removing the discount)
|
|
|
|
|
// invoice.totalPrice = new Decimal(invoice.totalPrice).add(discountAmount);
|
|
|
|
|
// await this.invoiceRepository.save(invoice);
|
|
|
|
|
|
|
|
|
|
// // Delete the usage discount record
|
|
|
|
|
// await this.usageDiscountRepository.delete(usage.id);
|
|
|
|
|
|
|
|
|
|
// return {
|
|
|
|
|
// message: InvoiceMessage.DISCOUNT_CANCELLED,
|
|
|
|
|
// invoice,
|
|
|
|
|
// };
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// private async hasUserUsedDiscount(userId: string, discountId: string): Promise<boolean> {
|
|
|
|
|
// const usage = await this.usageDiscountRepository.findOne({
|
|
|
|
|
// where: {
|
|
|
|
|
// users: {
|
|
|
|
|
// id: userId,
|
|
|
|
|
// },
|
|
|
|
|
// discount: {
|
|
|
|
|
// id: discountId,
|
|
|
|
|
// },
|
|
|
|
|
// },
|
|
|
|
|
// });
|
|
|
|
|
// return !!usage;
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|