import { BadRequestException, Injectable } from "@nestjs/common"; import dayjs from "dayjs"; import Decimal from "decimal.js"; import { SubscriptionMessage } from "../../../common/enums/message.enum"; import { InvoicesService } from "../../invoices/providers/invoices.service"; import { UserSubscription } from "../../subscriptions/entities/user-subscription.entity"; import { UserSubscriptionsRepository } from "../../subscriptions/repositories/user-subscriptions.repository"; import { BuyPremiumPlanDto } from "../DTO/buy-premium-plan.dto"; @Injectable() export class PremiumService { constructor( private readonly userSubscriptionsRepository: UserSubscriptionsRepository, private readonly invoicesService: InvoicesService, ) {} async buyPremiumPlan(dto: BuyPremiumPlanDto, userId: string) { // Find the user's current subscription const userSubscription = await this.userSubscriptionsRepository.findOne({ where: { id: dto.userSubscriptionId, user: { id: userId } }, relations: { user: true, plan: { service: true }, }, }); if (!userSubscription) { throw new BadRequestException(SubscriptionMessage.NOT_FOUND); } // Calculate remaining days const remainingDays = this.calculateRemainingDays(userSubscription); // Extract duration from current plan and convert to months const planDurationInMonths = Math.round(userSubscription.plan.duration / 30); // Get premium pricing based on extracted duration const premiumPrice = this.getPremiumPrice(planDurationInMonths); // Create invoice items for premium purchase const invoiceItems = [{ name: `Premium Plan - ${planDurationInMonths} Months`, count: 1, unitPrice: premiumPrice.toNumber(), discount: 0, }]; // Create invoice directly const createInvoiceDto = { userId: userSubscription.user.id, items: invoiceItems, isRecurring: false, }; const invoice = await this.invoicesService.createInvoiceAdmin(createInvoiceDto, { ip: '', headers: {}, userId: userSubscription.user.id }); return { message: "Premium plan purchased successfully", userSubscription, invoice, remainingDays, premiumPrice: premiumPrice.toNumber(), }; } //************************************ */ private calculateRemainingDays(userSubscription: UserSubscription): number { const now = dayjs(); const endDate = dayjs(userSubscription.endDate); if (endDate.isBefore(now)) { return 0; } return endDate.diff(now, 'day'); } //************************************ */ private getPremiumPrice(durationInMonths: number): Decimal { switch (durationInMonths) { case 6: return new Decimal(5000000); case 12: return new Decimal(10000000); default: throw new BadRequestException("Invalid premium plan duration. Only 6 and 12 month plans are supported."); } } }