feat: implement support plan upgrade functionality with invoice creation
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import dayjs from "dayjs";
|
||||
import { Decimal } from "decimal.js";
|
||||
import { DataSource } from "typeorm";
|
||||
|
||||
import { SupportPlanMessage } from "../../../common/enums/message.enum";
|
||||
@@ -26,7 +27,7 @@ export class SupportPlansService {
|
||||
|
||||
async createSupportPlan(createSupportPlanDto: CreateSupportPlanDto) {
|
||||
const supportPlan = this.supportPlanRepo.create(createSupportPlanDto);
|
||||
await this.supportPlanRepo.save(supportPlan);
|
||||
await this.supportPlanRepo.save({ ...supportPlan, isFree: createSupportPlanDto.price === 0 });
|
||||
return {
|
||||
message: SupportPlanMessage.SUPPORT_PLAN_CREATED,
|
||||
supportPlan,
|
||||
@@ -123,13 +124,13 @@ export class SupportPlansService {
|
||||
where: { user: { id: userId }, supportPlan: { id } },
|
||||
});
|
||||
|
||||
if (existingUserSupportPlan) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_ALREADY_SUBSCRIBED_OR_INVOICE_EXIST);
|
||||
if (existingUserSupportPlan) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_ALREADY_SUBSCRIBED);
|
||||
|
||||
const existingUserSupport = await queryRunner.manager.findOne(this.userSupportPlanRepo.target, {
|
||||
where: { user: { id: userId } },
|
||||
});
|
||||
|
||||
if (existingUserSupport) throw new BadRequestException(SupportPlanMessage.USER_ALREADY_HAS_SUPPORT_PLAN);
|
||||
if (existingUserSupport) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_ALREADY_SUBSCRIBED_OR_INVOICE_EXIST);
|
||||
|
||||
const startDate = dayjs().toDate();
|
||||
const endDate = dayjs().add(supportPlan.duration, "day").toDate();
|
||||
@@ -163,4 +164,94 @@ export class SupportPlansService {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
//***************************************** */
|
||||
async getUserSupportPlanOfUser(userId: string) {
|
||||
const userSupportPlan = await this.userSupportPlanRepo.findOne({
|
||||
where: { user: { id: userId }, status: UserSupportPlanStatus.ACTIVE },
|
||||
relations: { supportPlan: { features: true } },
|
||||
});
|
||||
|
||||
return { userSupportPlan };
|
||||
}
|
||||
//***************************************** */
|
||||
async upgradeSupportPlan(newPlanId: string, userId: string) {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
try {
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
const user = await this.usersService.findOneByIdWithQueryRunner(userId, queryRunner);
|
||||
|
||||
const currentUserSupportPlan = await queryRunner.manager.findOne(this.userSupportPlanRepo.target, {
|
||||
where: { user: { id: userId } },
|
||||
relations: { supportPlan: true },
|
||||
});
|
||||
|
||||
if (!currentUserSupportPlan) throw new BadRequestException(SupportPlanMessage.USER_HAS_NO_SUPPORT_PLAN);
|
||||
|
||||
const newSupportPlan = await queryRunner.manager.findOne(this.supportPlanRepo.target, {
|
||||
where: { id: newPlanId },
|
||||
});
|
||||
|
||||
if (!newSupportPlan) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_NOT_FOUND);
|
||||
|
||||
const newSupportPlanPrice = new Decimal(newSupportPlan.price);
|
||||
|
||||
const currentUserSupportPlanPrice = new Decimal(currentUserSupportPlan.supportPlan.price);
|
||||
// check if new plan is actually an upgrade
|
||||
if (newSupportPlanPrice.lessThanOrEqualTo(currentUserSupportPlanPrice)) {
|
||||
throw new BadRequestException(SupportPlanMessage.DOWN_GRADE_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
// calculate remaining days and price
|
||||
const remainingDays = dayjs(currentUserSupportPlan.endDate).diff(dayjs(), "day");
|
||||
const dailyPrice = currentUserSupportPlanPrice.div(currentUserSupportPlan.supportPlan.duration);
|
||||
const remainingPrice = dailyPrice.mul(remainingDays);
|
||||
|
||||
// calculate upgrade price
|
||||
const upgradePrice = newSupportPlanPrice.sub(remainingPrice).round();
|
||||
|
||||
// create new user support plan
|
||||
const startDate = dayjs().toDate();
|
||||
const endDate = dayjs().add(newSupportPlan.duration, "day").toDate();
|
||||
|
||||
const newUserSupportPlan = queryRunner.manager.create(this.userSupportPlanRepo.target, {
|
||||
user,
|
||||
supportPlan: newSupportPlan,
|
||||
startDate,
|
||||
endDate,
|
||||
status: UserSupportPlanStatus.INACTIVE,
|
||||
});
|
||||
|
||||
await queryRunner.manager.save(this.userSupportPlanRepo.target, newUserSupportPlan);
|
||||
|
||||
// create invoice for upgrade
|
||||
const invoiceDueDate = dayjs(startDate).add(INVOICE.DUEDATE, "day").toDate();
|
||||
const invoice = await this.invoicesService.createInvoiceForSupportPlan(
|
||||
user,
|
||||
newSupportPlan,
|
||||
newUserSupportPlan,
|
||||
invoiceDueDate,
|
||||
queryRunner,
|
||||
upgradePrice.toNumber(),
|
||||
);
|
||||
|
||||
// cancel old support plan
|
||||
currentUserSupportPlan.status = UserSupportPlanStatus.CANCELLED;
|
||||
await queryRunner.manager.save(this.userSupportPlanRepo.target, currentUserSupportPlan);
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return {
|
||||
message: SupportPlanMessage.SUPPORT_PLAN_UPGRADE_INITIATED_SUCCESSFULLY,
|
||||
invoice,
|
||||
upgradePrice: upgradePrice.toNumber(),
|
||||
};
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user