import { getErrorMessage } from "@bff/core/utils/error.util"; import { Injectable, Inject } from "@nestjs/common"; import type { Invoice, InvoiceList } from "@customer-portal/domain/billing"; import type { Subscription, SubscriptionList } from "@customer-portal/domain/subscriptions"; import type { PaymentMethodList, PaymentGatewayList } from "@customer-portal/domain/payments"; import type { Address } from "@customer-portal/domain/common"; import { WhmcsConnectionOrchestratorService } from "./connection/services/whmcs-connection-orchestrator.service"; import { WhmcsInvoiceService, InvoiceFilters } from "./services/whmcs-invoice.service"; import { WhmcsSubscriptionService, SubscriptionFilters, } from "./services/whmcs-subscription.service"; import { WhmcsClientService } from "./services/whmcs-client.service"; import { WhmcsPaymentService } from "./services/whmcs-payment.service"; import { WhmcsSsoService } from "./services/whmcs-sso.service"; import { WhmcsOrderService } from "./services/whmcs-order.service"; import { WhmcsAddClientParams, WhmcsClientResponse, WhmcsCatalogProductsResponse, WhmcsGetClientsProductsParams, WhmcsProductsResponse, } from "./types/whmcs-api.types"; import { Logger } from "nestjs-pino"; @Injectable() export class WhmcsService { constructor( private readonly connectionService: WhmcsConnectionOrchestratorService, private readonly invoiceService: WhmcsInvoiceService, private readonly subscriptionService: WhmcsSubscriptionService, private readonly clientService: WhmcsClientService, private readonly paymentService: WhmcsPaymentService, private readonly ssoService: WhmcsSsoService, private readonly orderService: WhmcsOrderService, @Inject(Logger) private readonly logger: Logger ) {} // ========================================== // INVOICE OPERATIONS (delegate to InvoiceService) // ========================================== /** * Get paginated invoices for a client with caching */ async getInvoices( clientId: number, userId: string, filters: InvoiceFilters = {} ): Promise { return this.invoiceService.getInvoices(clientId, userId, filters); } /** * Get invoices with items (for subscription linking) */ async getInvoicesWithItems( clientId: number, userId: string, filters: InvoiceFilters = {} ): Promise { return this.invoiceService.getInvoicesWithItems(clientId, userId, filters); } /** * Get individual invoice by ID with caching */ async getInvoiceById(clientId: number, userId: string, invoiceId: number): Promise { return this.invoiceService.getInvoiceById(clientId, userId, invoiceId); } /** * Invalidate cache for a specific invoice */ async invalidateInvoiceCache(userId: string, invoiceId: number): Promise { return this.invoiceService.invalidateInvoiceCache(userId, invoiceId); } // ========================================== // SUBSCRIPTION OPERATIONS (delegate to SubscriptionService) // ========================================== /** * Get client subscriptions/services with caching */ async getSubscriptions( clientId: number, userId: string, filters: SubscriptionFilters = {} ): Promise { return this.subscriptionService.getSubscriptions(clientId, userId, filters); } /** * Get individual subscription by ID */ async getSubscriptionById( clientId: number, userId: string, subscriptionId: number ): Promise { return this.subscriptionService.getSubscriptionById(clientId, userId, subscriptionId); } /** * Invalidate cache for a specific subscription */ async invalidateSubscriptionCache(userId: string, subscriptionId: number): Promise { return this.subscriptionService.invalidateSubscriptionCache(userId, subscriptionId); } // ========================================== // CLIENT OPERATIONS (delegate to ClientService) // ========================================== /** * Validate client login credentials */ async validateLogin( email: string, password: string ): Promise<{ userId: number; passwordHash: string }> { return this.clientService.validateLogin(email, password); } /** * Get client details by ID */ async getClientDetails(clientId: number): Promise { return this.clientService.getClientDetails(clientId); } /** * Get client details by email */ async getClientDetailsByEmail(email: string): Promise { return this.clientService.getClientDetailsByEmail(email); } /** * Update client details in WHMCS */ async updateClient( clientId: number, updateData: Partial ): Promise { return this.clientService.updateClient(clientId, updateData); } /** * Convenience helpers for address get/update on WHMCS client */ async getClientAddress(clientId: number): Promise
{ const client = await this.clientService.getClientDetails(clientId); return { street: client.address1 || null, streetLine2: client.address2 || null, city: client.city || null, state: client.state || null, postalCode: client.postcode || null, country: client.country || null, }; } async updateClientAddress(clientId: number, address: Partial
): Promise { const updateData: Partial = {}; if (address.street !== undefined) updateData.address1 = address.street ?? undefined; if (address.streetLine2 !== undefined) updateData.address2 = address.streetLine2 ?? undefined; if (address.city !== undefined) updateData.city = address.city ?? undefined; if (address.state !== undefined) updateData.state = address.state ?? undefined; if (address.postalCode !== undefined) updateData.postcode = address.postalCode ?? undefined; if (address.country !== undefined) updateData.country = address.country ?? undefined; if (Object.keys(updateData).length === 0) return; await this.clientService.updateClient(clientId, updateData); } /** * Add new client */ async addClient(clientData: WhmcsAddClientParams): Promise<{ clientId: number }> { return this.clientService.addClient(clientData); } /** * Invalidate cache for a user */ async invalidateUserCache(userId: string): Promise { return this.clientService.invalidateUserCache(userId); } // ========================================== // PAYMENT OPERATIONS (delegate to PaymentService) // ========================================== /** * Get payment methods for a client */ async getPaymentMethods(clientId: number, userId: string): Promise { return this.paymentService.getPaymentMethods(clientId, userId); } /** * Get available payment gateways */ async getPaymentGateways(): Promise { return this.paymentService.getPaymentGateways(); } /** * Invalidate payment methods cache for a user */ async invalidatePaymentMethodsCache(userId: string): Promise { return this.paymentService.invalidatePaymentMethodsCache(userId); } /** * Create SSO token with payment method for invoice payment */ async createPaymentSsoToken( clientId: number, invoiceId: number, paymentMethodId?: number, gatewayName?: string ): Promise<{ url: string; expiresAt: string }> { return this.paymentService.createPaymentSsoToken( clientId, invoiceId, paymentMethodId, gatewayName ); } /** * Get products catalog */ async getProducts(): Promise { return this.paymentService.getProducts() as Promise; } // ========================================== // SSO OPERATIONS (delegate to SsoService) // ========================================== /** * Create SSO token for WHMCS access */ async createSsoToken( clientId: number, destination?: string, ssoRedirectPath?: string ): Promise<{ url: string; expiresAt: string }> { return this.ssoService.createSsoToken(clientId, destination, ssoRedirectPath); } /** * Helper function to create SSO links for invoices */ async whmcsSsoForInvoice( clientId: number, invoiceId: number, target: "view" | "download" | "pay" ): Promise { return this.ssoService.whmcsSsoForInvoice(clientId, invoiceId, target); } // ========================================== // CONNECTION & HEALTH (delegate to ConnectionService) // ========================================== /** * Health check for WHMCS API */ async healthCheck(): Promise { return this.connectionService.healthCheck(); } /** * Check if WHMCS service is available */ async isAvailable(): Promise { return this.connectionService.isAvailable(); } /** * Get WHMCS system information */ async getSystemInfo(): Promise { return this.connectionService.getSystemInfo(); } async getClientsProducts(params: WhmcsGetClientsProductsParams): Promise { return this.connectionService.getClientsProducts(params); } // ========================================== // ORDER OPERATIONS (delegate to OrderService) // ========================================== /** * Get order service for direct access to order operations * Used by OrderProvisioningService for complex order workflows */ getOrderService(): WhmcsOrderService { return this.orderService; } // ========================================== // INVOICE CREATION AND PAYMENT OPERATIONS (Used by SIM/Order services) // ========================================== /** * Create a new invoice for a client */ async createInvoice(params: { clientId: number; description: string; amount: number; currency?: string; dueDate?: Date; notes?: string; }): Promise<{ id: number; number: string; total: number; status: string }> { return this.invoiceService.createInvoice(params); } /** * Update an existing invoice */ async updateInvoice(params: { invoiceId: number; status?: | "Draft" | "Unpaid" | "Paid" | "Cancelled" | "Refunded" | "Collections" | "Payment Pending"; dueDate?: Date; notes?: string; }): Promise<{ success: boolean; message?: string }> { return this.invoiceService.updateInvoice(params); } /** * Capture payment for an invoice */ async capturePayment(params: { invoiceId: number; amount: number; currency?: string; }): Promise<{ success: boolean; transactionId?: string; error?: string }> { return this.invoiceService.capturePayment(params); } }