upgrade plan
This commit is contained in:
@@ -11,6 +11,7 @@ import { OperationType } from "../../access-logs/enums/operation-type.enum";
|
||||
import { UserType } from "../../access-logs/enums/user-type.enum";
|
||||
import { AccessLogService } from "../../access-logs/providers/access-log.service";
|
||||
import { VerifyOtpWithUserId } from "../../auth/DTO/verify-otp.dto";
|
||||
import { RestaurantService } from "../../dmenu/providers/restaurant.service";
|
||||
import { Discount } from "../../discounts/entities/discount.entity";
|
||||
import { DiscountType } from "../../discounts/enums/discount-type.enum";
|
||||
import { NotificationQueue } from "../../notifications/queue/notification.queue";
|
||||
@@ -53,6 +54,7 @@ export class InvoicesService {
|
||||
private readonly smsService: SmsService,
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly accessLogService: AccessLogService,
|
||||
private readonly restaurantService: RestaurantService,
|
||||
) {}
|
||||
|
||||
///********************************** */
|
||||
@@ -498,6 +500,7 @@ export class InvoicesService {
|
||||
unitPrice: originalPrice,
|
||||
discount: discount ? new Decimal(originalPrice).sub(finalPrice).toNumber() : 0,
|
||||
subscriptionPlan: userSub,
|
||||
plan: plan,
|
||||
totalPrice: finalPrice,
|
||||
};
|
||||
|
||||
@@ -540,6 +543,63 @@ export class InvoicesService {
|
||||
|
||||
return invoice;
|
||||
}
|
||||
|
||||
//********************************** */
|
||||
async createInvoiceForSubscriptionUpgrade(user: User, plan: SubscriptionPlan, userSub: UserSubscription, dueDate: Date, qryRnr: QueryRunner, upgradeCost?: Decimal) {
|
||||
const discount = plan.directDiscount;
|
||||
const originalPrice = upgradeCost || (plan.originalPrice || plan.price);
|
||||
const finalPrice = upgradeCost || plan.price;
|
||||
|
||||
const invoiceItem = {
|
||||
name: `${plan.service.name} - Upgrade`,
|
||||
count: 1,
|
||||
unitPrice: originalPrice,
|
||||
discount: discount ? new Decimal(originalPrice).sub(finalPrice).toNumber() : 0,
|
||||
subscriptionPlan: userSub,
|
||||
plan: plan,
|
||||
totalPrice: finalPrice,
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
await this.notificationQueue.addInvoiceCreationNotification(user.id, {
|
||||
invoiceId: invoice.numericId.toString(),
|
||||
dueDate: invoice.dueDate,
|
||||
createDate: invoice.createdAt,
|
||||
price: totalPrice.toNumber(),
|
||||
userPhone: user.phone,
|
||||
userEmail: user.email,
|
||||
items: plan.service.name,
|
||||
});
|
||||
|
||||
await this.invoiceQueue.add(
|
||||
INVOICE.REMINDER_JOB_NAME,
|
||||
{ invoiceId: invoice.id },
|
||||
{
|
||||
delay: dayjs(invoice.dueDate).subtract(INVOICE.DAYS_BEFORE_OVERDUE, "day").diff(dayjs()),
|
||||
attempts: INVOICE.REMINDER_JOB_ATTEMPTS,
|
||||
backoff: { type: "exponential", delay: INVOICE.REMINDER_JOB_BACKOFF },
|
||||
priority: INVOICE.REMINDER_JOB_PRIORITY,
|
||||
},
|
||||
);
|
||||
|
||||
return invoice;
|
||||
}
|
||||
|
||||
//********************************** */
|
||||
async createInvoiceForSupportPlan(
|
||||
user: User,
|
||||
@@ -735,18 +795,51 @@ export class InvoicesService {
|
||||
|
||||
if (invoice.items[0]?.subscriptionPlan && !invoice.isExternal) {
|
||||
const userSubscription = invoice.items[0].subscriptionPlan;
|
||||
const invoiceItem = invoice.items[0];
|
||||
|
||||
const isRenewal = userSubscription.status === SubscriptionStatus.ACTIVE;
|
||||
// Check if this is an upgrade (subscription is ACTIVE and plan in invoice differs from current plan)
|
||||
const isUpgrade = userSubscription.status === SubscriptionStatus.ACTIVE &&
|
||||
invoiceItem.plan &&
|
||||
invoiceItem.plan.id !== userSubscription.plan.id;
|
||||
|
||||
if (isRenewal) {
|
||||
const newEndDate = dayjs(userSubscription.endDate).add(userSubscription.plan.duration, "day").toDate();
|
||||
userSubscription.endDate = newEndDate;
|
||||
if (isUpgrade) {
|
||||
// This is an upgrade - update subscription with the new plan
|
||||
const upgradePlan = invoiceItem.plan!;
|
||||
|
||||
this.logger.log(`Subscription ${userSubscription.id} renewed until ${newEndDate}`);
|
||||
userSubscription.plan = upgradePlan;
|
||||
this.logger.log(`Subscription ${userSubscription.id} upgraded to plan ${upgradePlan.name}`);
|
||||
await this.scheduleNextRenewalJob(userSubscription);
|
||||
|
||||
// Call external API for dmenu service upgrades
|
||||
if (upgradePlan.service.name.toLowerCase().includes('dmenu') || upgradePlan.service.slug?.toLowerCase().includes('dmenu')) {
|
||||
try {
|
||||
this.logger.log(`Calling external API for dmenu upgrade: subscription ${userSubscription.id}`);
|
||||
const dmenuPlan = upgradePlan.name.includes("دلیوری") ? "premium" : "base";
|
||||
await this.restaurantService.upgradeSubscription(
|
||||
userSubscription.id,
|
||||
dmenuPlan,
|
||||
userSubscription.endDate.toISOString()
|
||||
);
|
||||
this.logger.log(`External API call completed for dmenu upgrade: subscription ${userSubscription.id}`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to call external API for dmenu upgrade: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
// Don't fail the transaction if external API call fails
|
||||
}
|
||||
}
|
||||
} else {
|
||||
userSubscription.status = SubscriptionStatus.ACTIVE;
|
||||
await this.scheduleNextRenewalJob(userSubscription);
|
||||
// Regular subscription logic (renewal or activation)
|
||||
const isRenewal = userSubscription.status === SubscriptionStatus.ACTIVE;
|
||||
|
||||
if (isRenewal) {
|
||||
const newEndDate = dayjs(userSubscription.endDate).add(userSubscription.plan.duration, "day").toDate();
|
||||
userSubscription.endDate = newEndDate;
|
||||
|
||||
this.logger.log(`Subscription ${userSubscription.id} renewed until ${newEndDate}`);
|
||||
await this.scheduleNextRenewalJob(userSubscription);
|
||||
} else {
|
||||
userSubscription.status = SubscriptionStatus.ACTIVE;
|
||||
await this.scheduleNextRenewalJob(userSubscription);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -849,6 +942,7 @@ export class InvoicesService {
|
||||
subscriptionPlan: {
|
||||
plan: true,
|
||||
},
|
||||
plan: true,
|
||||
supportPlan: {
|
||||
supportPlan: true,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user