upgrade plan
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { InjectQueue } from "@nestjs/bullmq";
|
||||
import { BadRequestException, ForbiddenException, Injectable, Logger } from "@nestjs/common";
|
||||
import { ModuleRef } from "@nestjs/core";
|
||||
import { Queue } from "bullmq";
|
||||
import dayjs from "dayjs";
|
||||
import Decimal from "decimal.js";
|
||||
@@ -35,11 +36,15 @@ export class SubscriptionsService {
|
||||
@InjectQueue(SUBSCRIPTIONS.PROVISIONING_QUEUE_NAME) private readonly provisioningQueue: Queue,
|
||||
private readonly subscriptionsPlanRepository: SubscriptionsPlanRepository,
|
||||
private readonly userSubscriptionsRepository: UserSubscriptionsRepository,
|
||||
private readonly invoicesService: InvoicesService,
|
||||
private readonly moduleRef: ModuleRef,
|
||||
private readonly usersService: UsersService,
|
||||
private readonly danakServices: DanakServicesService,
|
||||
private readonly dataSource: DataSource,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
private get invoicesService(): InvoicesService {
|
||||
return this.moduleRef.get(InvoicesService, { strict: false });
|
||||
}
|
||||
|
||||
//************************************ */
|
||||
async createSubscriptionsPlan(createDto: AddSubscriptionsToServiceDto) {
|
||||
@@ -361,6 +366,98 @@ export class SubscriptionsService {
|
||||
}
|
||||
}
|
||||
|
||||
//************************************ */
|
||||
async upgradeSubscription(userSubscriptionId: string, planId: string, userId: string) {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
|
||||
try {
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
|
||||
const userSubscription = await queryRunner.manager.findOne(UserSubscription, {
|
||||
where: { id: userSubscriptionId, user: { id: userId } },
|
||||
relations: { plan: true }
|
||||
});
|
||||
if (!userSubscription) throw new BadRequestException(SubscriptionMessage.USER_SUBS_NOT_FOUND);
|
||||
|
||||
const newPlan = await this.subscriptionsPlanRepository.findOneBy({ id: planId });
|
||||
if (!newPlan) throw new BadRequestException(SubscriptionMessage.PLAN_NOT_FOUND);
|
||||
|
||||
if (userSubscription.plan.service.id !== newPlan.service.id) {
|
||||
throw new BadRequestException(SubscriptionMessage.SERVICE_MISMATCH);
|
||||
}
|
||||
|
||||
// Validate that new plan is more expensive than current plan
|
||||
if (new Decimal(newPlan.price).lessThanOrEqualTo(userSubscription.plan.price)) {
|
||||
throw new BadRequestException(SubscriptionMessage.UPGRADE_TO_LOWER_OR_EQUAL_PLAN_NOT_ALLOWED);
|
||||
}
|
||||
|
||||
// Calculate remaining days in current subscription
|
||||
const today = dayjs();
|
||||
const endDate = dayjs(userSubscription.endDate);
|
||||
const remainingDays = Math.max(0, endDate.diff(today, 'day'));
|
||||
|
||||
if (remainingDays <= 0) {
|
||||
throw new BadRequestException(SubscriptionMessage.SUBSCRIPTION_EXPIRED_CANNOT_UPGRADE);
|
||||
}
|
||||
|
||||
// Calculate daily rates
|
||||
const currentPlanDuration = userSubscription.plan.duration;
|
||||
const newPlanDuration = newPlan.duration;
|
||||
|
||||
const currentDailyRate = new Decimal(userSubscription.plan.price).div(currentPlanDuration);
|
||||
const newDailyRate = new Decimal(newPlan.price).div(newPlanDuration);
|
||||
|
||||
// Calculate price difference per day
|
||||
const dailyPriceDifference = newDailyRate.sub(currentDailyRate);
|
||||
|
||||
// Calculate prorated upgrade cost for remaining days
|
||||
const proratedUpgradeCost = dailyPriceDifference.mul(remainingDays);
|
||||
|
||||
// Ensure minimum charge amount
|
||||
const minimumCharge = new Decimal(1000); // 1000 IRR minimum
|
||||
const finalUpgradeCost = Decimal.max(proratedUpgradeCost, minimumCharge);
|
||||
|
||||
const user = await this.usersService.findOneByIdWithQueryRunner(userSubscription.user.id, queryRunner);
|
||||
|
||||
const invoiceDueDate = dayjs().add(INVOICE.DUEDATE, "day").toDate();
|
||||
|
||||
const invoice = await this.invoicesService.createInvoiceForSubscriptionUpgrade(
|
||||
user,
|
||||
newPlan,
|
||||
userSubscription,
|
||||
invoiceDueDate,
|
||||
queryRunner,
|
||||
finalUpgradeCost
|
||||
);
|
||||
|
||||
// Update the subscription to the new plan
|
||||
userSubscription.plan = newPlan;
|
||||
await queryRunner.manager.save(UserSubscription, userSubscription);
|
||||
|
||||
// Add provisioning job for the new plan
|
||||
await this.addProvisioningJob(userSubscription, newPlan, user);
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
return {
|
||||
message: SubscriptionMessage.INVOICE_CREATED_SUCCESSFULLY,
|
||||
userSubscription,
|
||||
invoice,
|
||||
upgradeDetails: {
|
||||
remainingDays,
|
||||
currentPlanPrice: userSubscription.plan.price,
|
||||
newPlanPrice: newPlan.price,
|
||||
proratedUpgradeCost: finalUpgradeCost.toNumber(),
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
//************************************ */
|
||||
async getServiceSubscriptions(serviceId: string, queryDto: ServiceSubsQueryDto) {
|
||||
const service = await this.danakServices.findServiceById(serviceId);
|
||||
|
||||
Reference in New Issue
Block a user