chore: add discount logic to apply to the plan price and ...
This commit is contained in:
@@ -9,6 +9,8 @@ import { Between, DataSource, QueryRunner } from "typeorm";
|
||||
|
||||
import { AuthMessage, InvoiceMessage, WalletMessage } from "../../../common/enums/message.enum";
|
||||
import { VerifyOtpWithUserId } from "../../auth/DTO/verify-otp.dto";
|
||||
import { Discount } from "../../discounts/entities/discount.entity";
|
||||
import { DiscountType } from "../../discounts/enums/discount-type.enum";
|
||||
import { NotificationsService } from "../../notifications/providers/notifications.service";
|
||||
import { SubscriptionPlan } from "../../subscriptions/entities/subscription.entity";
|
||||
import { UserSubscription } from "../../subscriptions/entities/user-subscription.entity";
|
||||
@@ -267,26 +269,31 @@ export class InvoicesService {
|
||||
}
|
||||
///********************************** */
|
||||
async createInvoiceForSubscription(user: User, plan: SubscriptionPlan, userSub: UserSubscription, dueDate: Date, qryRnr: QueryRunner) {
|
||||
const discount = plan.directDiscount;
|
||||
const originalPrice = plan.originalPrice || plan.price;
|
||||
const finalPrice = plan.price;
|
||||
|
||||
const invoiceItem = {
|
||||
name: plan.service.name,
|
||||
count: 1,
|
||||
unitPrice: plan.price,
|
||||
discount: 0,
|
||||
unitPrice: originalPrice,
|
||||
discount: discount ? new Decimal(originalPrice).sub(finalPrice).toNumber() : 0,
|
||||
subscriptionPlan: userSub,
|
||||
totalPrice: plan.price,
|
||||
totalPrice: finalPrice,
|
||||
};
|
||||
|
||||
const basePrice = plan.price;
|
||||
const taxAmount = new Decimal(basePrice).mul(0.1);
|
||||
const totalPrice = new Decimal(basePrice).add(taxAmount);
|
||||
const taxAmount = new Decimal(finalPrice).mul(0.1);
|
||||
const totalPrice = new Decimal(finalPrice).add(taxAmount);
|
||||
|
||||
const invoice = qryRnr.manager.create(Invoice, {
|
||||
user,
|
||||
totalPrice: totalPrice,
|
||||
originalPrice: new Decimal(originalPrice).add(new Decimal(originalPrice).mul(0.1)),
|
||||
tax: taxAmount.toNumber(),
|
||||
status: InvoiceStatus.WAIT_PAYMENT,
|
||||
dueDate,
|
||||
items: [invoiceItem],
|
||||
discount: discount || undefined,
|
||||
});
|
||||
|
||||
await qryRnr.manager.save(Invoice, invoice);
|
||||
@@ -345,12 +352,12 @@ export class InvoicesService {
|
||||
if (isAdmin) {
|
||||
invoice = await this.invoiceRepository.findOne({
|
||||
where: { id: invoiceId },
|
||||
relations: { items: { subscriptionPlan: true }, user: true },
|
||||
relations: { items: { subscriptionPlan: true }, user: true, discount: true },
|
||||
});
|
||||
} else {
|
||||
invoice = await this.invoiceRepository.findOne({
|
||||
where: { id: invoiceId, user: { id: userId } },
|
||||
relations: { items: { subscriptionPlan: true } },
|
||||
relations: { items: { subscriptionPlan: true }, discount: true },
|
||||
});
|
||||
}
|
||||
|
||||
@@ -487,6 +494,7 @@ export class InvoicesService {
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
//*********************************** */
|
||||
|
||||
async countUserInvoices(userId: string) {
|
||||
@@ -558,4 +566,87 @@ export class InvoicesService {
|
||||
this.logger.log(`Scheduled recurring invoice for user ${createDto.userId} with interval ${createDto.recurringPeriod}`);
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************** */
|
||||
async applyDiscount(invoiceId: string, discountCode: string, userId: string) {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
|
||||
try {
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
const invoice = await this.getInvoiceByIdWithQueryRunner(invoiceId, userId, queryRunner);
|
||||
|
||||
if (invoice.discount) throw new BadRequestException(InvoiceMessage.DISCOUNT_ALREADY_APPLIED);
|
||||
|
||||
const discount = await queryRunner.manager.findOne(Discount, {
|
||||
where: { code: discountCode, isActive: true },
|
||||
});
|
||||
|
||||
if (!discount) throw new BadRequestException(InvoiceMessage.INVALID_DISCOUNT_CODE);
|
||||
|
||||
if (!invoice.originalPrice) invoice.originalPrice = new Decimal(invoice.totalPrice);
|
||||
|
||||
let discountAmount: Decimal;
|
||||
if (discount.type === DiscountType.PERCENTAGE) {
|
||||
discountAmount = invoice.originalPrice.mul(discount.value).div(100);
|
||||
} else {
|
||||
discountAmount = new Decimal(discount.value);
|
||||
}
|
||||
|
||||
invoice.totalPrice = invoice.originalPrice.sub(discountAmount);
|
||||
invoice.discount = discount;
|
||||
|
||||
await queryRunner.manager.save(invoice);
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return {
|
||||
message: InvoiceMessage.DISCOUNT_APPLIED,
|
||||
invoice,
|
||||
};
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
//*********************************** */
|
||||
async cancelDiscount(invoiceId: string, userId: string) {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
try {
|
||||
const invoice = await this.getInvoiceByIdWithQueryRunner(invoiceId, userId, queryRunner);
|
||||
|
||||
if (!invoice.discount) throw new BadRequestException(InvoiceMessage.NO_DISCOUNT);
|
||||
|
||||
if (!invoice.originalPrice) throw new BadRequestException(InvoiceMessage.ORIGINAL_PRICE_NOT_FOUND);
|
||||
|
||||
invoice.totalPrice = invoice.originalPrice;
|
||||
invoice.discount = undefined;
|
||||
|
||||
await queryRunner.manager.save(invoice);
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return {
|
||||
message: InvoiceMessage.DISCOUNT_CANCELED,
|
||||
invoice,
|
||||
};
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
//*********************************** */
|
||||
private async getInvoiceByIdWithQueryRunner(invoiceId: string, userId: string, queryRunner: QueryRunner) {
|
||||
const invoice = await queryRunner.manager.findOne(Invoice, {
|
||||
where: { id: invoiceId, user: { id: userId } },
|
||||
relations: { user: true, discount: true },
|
||||
});
|
||||
if (!invoice) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID_OR_NOT_BELONG_TO_USER);
|
||||
return invoice;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user