refactor: the invoice and subscription flow of user
This commit is contained in:
@@ -11,6 +11,8 @@ import { DiscountRepository } from "../../discounts/repositories/discount.reposi
|
||||
import { UsageDiscountRepository } from "../../discounts/repositories/usage-discount.repository";
|
||||
import { NotificationsService } from "../../notifications/providers/notifications.service";
|
||||
import { SubscriptionPlan } from "../../subscriptions/entities/subscription.entity";
|
||||
import { UserSubscription } from "../../subscriptions/entities/user-subscription.entity";
|
||||
import { SubscriptionStatus } from "../../subscriptions/enums/subscription-status.enum";
|
||||
import { UsersService } from "../../users/providers/users.service";
|
||||
import { OTPService } from "../../utils/providers/otp.service";
|
||||
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||
@@ -110,9 +112,13 @@ export class InvoicesService {
|
||||
const invoice = await this.invoiceRepository.findOne({ where: { id: invoiceId, user: { id: userId } }, relations: { items: true } });
|
||||
if (!invoice) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID);
|
||||
|
||||
if (invoice.status === InvoiceStatus.APPROVED) throw new BadRequestException(InvoiceMessage.ALREADY_APPROVED);
|
||||
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(invoice.dueDate)) {
|
||||
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);
|
||||
|
||||
@@ -149,14 +155,13 @@ export class InvoicesService {
|
||||
const isValid = await this.otpService.verifyOtp(user.phone, code, "INVOICE_VERIFY");
|
||||
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
||||
|
||||
if (invoice.status === InvoiceStatus.REJECTED) throw new BadRequestException(InvoiceMessage.INVOICE_IS_REJECTED);
|
||||
if (invoice.status === InvoiceStatus.APPROVED) throw new BadRequestException(InvoiceMessage.ALREADY_APPROVED);
|
||||
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 (invoice.status !== InvoiceStatus.PENDING) throw new BadRequestException(InvoiceMessage.INVOICE_CAN_NOT_APPROVED);
|
||||
|
||||
invoice.status = InvoiceStatus.APPROVED;
|
||||
invoice.status = InvoiceStatus.WAIT_PAYMENT;
|
||||
|
||||
await this.invoiceRepository.save(invoice);
|
||||
|
||||
@@ -167,14 +172,27 @@ export class InvoicesService {
|
||||
}
|
||||
///********************************** */
|
||||
|
||||
async createInvoiceForSubscription(userId: string, plan: SubscriptionPlan, dueDate: Date, queryRunner: QueryRunner) {
|
||||
async createInvoiceForSubscription(
|
||||
userId: string,
|
||||
plan: SubscriptionPlan,
|
||||
userSub: UserSubscription,
|
||||
dueDate: Date,
|
||||
queryRunner: QueryRunner,
|
||||
) {
|
||||
const invoiceItems = [
|
||||
{ name: plan.service.name, count: 1, unitPrice: plan.price, discount: 0, subscriptionPlan: plan, totalPrice: plan.price },
|
||||
{
|
||||
name: plan.service.name,
|
||||
count: 1,
|
||||
unitPrice: plan.price,
|
||||
discount: 0,
|
||||
subscriptionPlan: userSub,
|
||||
totalPrice: plan.price,
|
||||
},
|
||||
];
|
||||
const invoice = queryRunner.manager.create(Invoice, {
|
||||
totalPrice: plan.price,
|
||||
user: { id: userId },
|
||||
status: InvoiceStatus.PAID,
|
||||
status: InvoiceStatus.PENDING,
|
||||
paidAt: new Date(),
|
||||
dueDate,
|
||||
items: invoiceItems,
|
||||
@@ -238,7 +256,9 @@ export class InvoicesService {
|
||||
.andWhere("invoice.user.id = :userId", { userId: userId })
|
||||
.leftJoinAndSelect("invoice.items", "items")
|
||||
.leftJoinAndSelect("items.subscriptionPlan", "subscriptionPlan", "subscriptionPlan.id IS NOT NULL")
|
||||
.leftJoinAndSelect("subscriptionPlan.service", "service", "subscriptionPlan.id IS NOT NULL");
|
||||
.leftJoinAndSelect("subscriptionPlan.plan", "plan", "subscriptionPlan.id IS NOT NULL")
|
||||
.leftJoin("plan.service", "service", "subscriptionPlan.id IS NOT NULL")
|
||||
.addSelect(["service.name", "service.id"]);
|
||||
|
||||
if (queryDto.status) {
|
||||
queryBuilder.andWhere("invoice.status = :status", { status: queryDto.status });
|
||||
@@ -265,27 +285,33 @@ export class InvoicesService {
|
||||
const user = await this.usersService.findOneByIdWithQueryRunner(userId, queryRunner);
|
||||
|
||||
const invoice = await this.getPendingInvoiceByIdWithQueryRunner(invoiceId, user.id, queryRunner);
|
||||
console.log(invoice);
|
||||
|
||||
if (invoice.status === InvoiceStatus.REJECTED) throw new BadRequestException(InvoiceMessage.INVOICE_IS_REJECTED);
|
||||
if (invoice.status === InvoiceStatus.EXPIRED) throw new BadRequestException(InvoiceMessage.INVOICE_IS_OVERDUE);
|
||||
if (invoice.status === InvoiceStatus.PAID) throw new BadRequestException(InvoiceMessage.INVOICE_ALREADY_PAID);
|
||||
if (invoice.status !== InvoiceStatus.APPROVED) throw new BadRequestException(InvoiceMessage.INVOICE_CAN_NOT_PAID);
|
||||
if (invoice.status !== InvoiceStatus.WAIT_PAYMENT) throw new BadRequestException(InvoiceMessage.INVOICE_CAN_NOT_PAID);
|
||||
|
||||
const userWallet = await this.walletsService.getWalletByUserId(user.id, queryRunner);
|
||||
|
||||
if (new Decimal(userWallet.balance).lessThan(invoice.totalPrice)) throw new BadRequestException(WalletMessage.INSUFFICIENT_BALANCE);
|
||||
if (userWallet.balance < invoice.totalPrice) throw new BadRequestException(WalletMessage.INSUFFICIENT_BALANCE);
|
||||
|
||||
userWallet.balance = new Decimal(userWallet.balance).sub(invoice.totalPrice);
|
||||
|
||||
await queryRunner.manager.save(Wallet, userWallet);
|
||||
|
||||
await this.walletsService.createInvoiceTransaction(invoice.totalPrice, userWallet.id, queryRunner);
|
||||
if (invoice.items[0]?.subscriptionPlan) {
|
||||
const userSubscription = invoice.items[0].subscriptionPlan;
|
||||
userSubscription.status = SubscriptionStatus.ACTIVE;
|
||||
|
||||
//
|
||||
await queryRunner.manager.save(UserSubscription, userSubscription);
|
||||
await this.walletsService.createSubscriptionTransaction(invoice.totalPrice, userWallet.id, queryRunner);
|
||||
//
|
||||
} else {
|
||||
await this.walletsService.createInvoiceTransaction(invoice.totalPrice, userWallet.id, queryRunner);
|
||||
}
|
||||
invoice.status = InvoiceStatus.PAID;
|
||||
invoice.paidAt = new Date();
|
||||
invoice.paidAt = dayjs().toDate();
|
||||
|
||||
await queryRunner.manager.save(Invoice, invoice);
|
||||
console.log(invoice);
|
||||
await queryRunner.commitTransaction();
|
||||
return {
|
||||
message: InvoiceMessage.INVOICE_PAID,
|
||||
@@ -302,7 +328,20 @@ export class InvoicesService {
|
||||
//*********************************** */
|
||||
|
||||
async getPendingInvoiceByIdWithQueryRunner(invoiceId: string, userId: string, queryRunner: QueryRunner) {
|
||||
const invoice = await queryRunner.manager.findOneBy(Invoice, { user: { id: userId }, status: InvoiceStatus.PENDING, id: invoiceId });
|
||||
const invoice = await queryRunner.manager.findOne(Invoice, {
|
||||
where: {
|
||||
user: { id: userId },
|
||||
status: InvoiceStatus.WAIT_PAYMENT,
|
||||
id: invoiceId,
|
||||
},
|
||||
relations: {
|
||||
items: {
|
||||
subscriptionPlan: {
|
||||
plan: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!invoice) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID);
|
||||
return invoice;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user