"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BillingService = void 0; const common_1 = require("@nestjs/common"); const typeorm_1 = require("@nestjs/typeorm"); const typeorm_2 = require("typeorm"); const subscription_entity_1 = require("../entities/subscription.entity"); const invoice_entity_1 = require("../entities/invoice.entity"); const payment_method_entity_1 = require("../entities/payment-method.entity"); let BillingService = class BillingService { constructor(subscriptionRepo, invoiceRepo, paymentMethodRepo) { this.subscriptionRepo = subscriptionRepo; this.invoiceRepo = invoiceRepo; this.paymentMethodRepo = paymentMethodRepo; } async createSubscription(dto) { const now = new Date(); const periodEnd = new Date(now); periodEnd.setMonth(periodEnd.getMonth() + 1); const subscription = this.subscriptionRepo.create({ tenant_id: dto.tenant_id, plan_id: dto.plan_id, status: dto.trial_end ? subscription_entity_1.SubscriptionStatus.TRIAL : subscription_entity_1.SubscriptionStatus.ACTIVE, current_period_start: now, current_period_end: periodEnd, trial_end: dto.trial_end ? new Date(dto.trial_end) : null, payment_provider: dto.payment_provider, }); return this.subscriptionRepo.save(subscription); } async getSubscription(tenantId) { return this.subscriptionRepo.findOne({ where: { tenant_id: tenantId }, order: { created_at: 'DESC' }, }); } async updateSubscription(tenantId, dto) { const subscription = await this.getSubscription(tenantId); if (!subscription) { throw new common_1.NotFoundException('Subscription not found'); } Object.assign(subscription, dto); return this.subscriptionRepo.save(subscription); } async cancelSubscription(tenantId, dto) { const subscription = await this.getSubscription(tenantId); if (!subscription) { throw new common_1.NotFoundException('Subscription not found'); } subscription.cancelled_at = new Date(); if (dto.immediately) { subscription.status = subscription_entity_1.SubscriptionStatus.CANCELLED; } if (dto.reason) { subscription.metadata = { ...subscription.metadata, cancellation_reason: dto.reason, }; } return this.subscriptionRepo.save(subscription); } async changePlan(tenantId, newPlanId) { const subscription = await this.getSubscription(tenantId); if (!subscription) { throw new common_1.NotFoundException('Subscription not found'); } subscription.plan_id = newPlanId; subscription.metadata = { ...subscription.metadata, plan_changed_at: new Date().toISOString(), }; return this.subscriptionRepo.save(subscription); } async renewSubscription(tenantId) { const subscription = await this.getSubscription(tenantId); if (!subscription) { throw new common_1.NotFoundException('Subscription not found'); } const now = new Date(); const newPeriodEnd = new Date(subscription.current_period_end); newPeriodEnd.setMonth(newPeriodEnd.getMonth() + 1); subscription.current_period_start = subscription.current_period_end; subscription.current_period_end = newPeriodEnd; subscription.status = subscription_entity_1.SubscriptionStatus.ACTIVE; return this.subscriptionRepo.save(subscription); } async createInvoice(tenantId, subscriptionId, lineItems) { const invoiceNumber = await this.generateInvoiceNumber(); const items = lineItems.map((item) => ({ ...item, amount: item.quantity * item.unit_price, })); const subtotal = items.reduce((sum, item) => sum + item.amount, 0); const tax = subtotal * 0.16; const total = subtotal + tax; const dueDate = new Date(); dueDate.setDate(dueDate.getDate() + 15); const invoice = this.invoiceRepo.create({ tenant_id: tenantId, subscription_id: subscriptionId, invoice_number: invoiceNumber, status: invoice_entity_1.InvoiceStatus.OPEN, subtotal, tax, total, due_date: dueDate, line_items: items, }); return this.invoiceRepo.save(invoice); } async getInvoices(tenantId, options) { const page = options?.page || 1; const limit = options?.limit || 10; const [data, total] = await this.invoiceRepo.findAndCount({ where: { tenant_id: tenantId }, order: { created_at: 'DESC' }, skip: (page - 1) * limit, take: limit, }); return { data, total, page, limit }; } async getInvoice(invoiceId, tenantId) { const invoice = await this.invoiceRepo.findOne({ where: { id: invoiceId, tenant_id: tenantId }, }); if (!invoice) { throw new common_1.NotFoundException('Invoice not found'); } return invoice; } async markInvoicePaid(invoiceId, tenantId) { const invoice = await this.getInvoice(invoiceId, tenantId); invoice.status = invoice_entity_1.InvoiceStatus.PAID; invoice.paid_at = new Date(); return this.invoiceRepo.save(invoice); } async voidInvoice(invoiceId, tenantId) { const invoice = await this.getInvoice(invoiceId, tenantId); if (invoice.status === invoice_entity_1.InvoiceStatus.PAID) { throw new common_1.BadRequestException('Cannot void a paid invoice'); } invoice.status = invoice_entity_1.InvoiceStatus.VOID; return this.invoiceRepo.save(invoice); } async generateInvoiceNumber() { const year = new Date().getFullYear(); const month = String(new Date().getMonth() + 1).padStart(2, '0'); const count = await this.invoiceRepo.count(); const sequence = String(count + 1).padStart(6, '0'); return `INV-${year}${month}-${sequence}`; } async addPaymentMethod(tenantId, dto) { if (dto.is_default) { await this.paymentMethodRepo.update({ tenant_id: tenantId, is_default: true }, { is_default: false }); } const paymentMethod = this.paymentMethodRepo.create({ tenant_id: tenantId, ...dto, }); return this.paymentMethodRepo.save(paymentMethod); } async getPaymentMethods(tenantId) { return this.paymentMethodRepo.find({ where: { tenant_id: tenantId, is_active: true }, order: { is_default: 'DESC', created_at: 'DESC' }, }); } async getDefaultPaymentMethod(tenantId) { return this.paymentMethodRepo.findOne({ where: { tenant_id: tenantId, is_default: true, is_active: true }, }); } async setDefaultPaymentMethod(paymentMethodId, tenantId) { const paymentMethod = await this.paymentMethodRepo.findOne({ where: { id: paymentMethodId, tenant_id: tenantId }, }); if (!paymentMethod) { throw new common_1.NotFoundException('Payment method not found'); } await this.paymentMethodRepo.update({ tenant_id: tenantId, is_default: true }, { is_default: false }); paymentMethod.is_default = true; return this.paymentMethodRepo.save(paymentMethod); } async removePaymentMethod(paymentMethodId, tenantId) { const paymentMethod = await this.paymentMethodRepo.findOne({ where: { id: paymentMethodId, tenant_id: tenantId }, }); if (!paymentMethod) { throw new common_1.NotFoundException('Payment method not found'); } if (paymentMethod.is_default) { throw new common_1.BadRequestException('Cannot remove default payment method'); } paymentMethod.is_active = false; await this.paymentMethodRepo.save(paymentMethod); } async getBillingSummary(tenantId) { const subscription = await this.getSubscription(tenantId); const defaultPaymentMethod = await this.getDefaultPaymentMethod(tenantId); const pendingInvoices = await this.invoiceRepo.find({ where: { tenant_id: tenantId, status: invoice_entity_1.InvoiceStatus.OPEN }, }); const totalDue = pendingInvoices.reduce((sum, inv) => sum + Number(inv.total), 0); return { subscription, defaultPaymentMethod, pendingInvoices: pendingInvoices.length, totalDue, }; } async checkSubscriptionStatus(tenantId) { const subscription = await this.getSubscription(tenantId); if (!subscription) { return { isActive: false, daysRemaining: 0, status: subscription_entity_1.SubscriptionStatus.EXPIRED }; } const now = new Date(); const periodEnd = new Date(subscription.current_period_end); const daysRemaining = Math.ceil((periodEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); const isActive = [ subscription_entity_1.SubscriptionStatus.ACTIVE, subscription_entity_1.SubscriptionStatus.TRIAL, ].includes(subscription.status); return { isActive, daysRemaining: Math.max(0, daysRemaining), status: subscription.status, }; } }; exports.BillingService = BillingService; exports.BillingService = BillingService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, typeorm_1.InjectRepository)(subscription_entity_1.Subscription)), __param(1, (0, typeorm_1.InjectRepository)(invoice_entity_1.Invoice)), __param(2, (0, typeorm_1.InjectRepository)(payment_method_entity_1.PaymentMethod)), __metadata("design:paramtypes", [typeorm_2.Repository, typeorm_2.Repository, typeorm_2.Repository]) ], BillingService); //# sourceMappingURL=billing.service.js.map