103 lines
4.0 KiB
TypeScript
103 lines
4.0 KiB
TypeScript
import { Controller, Get, Post, Param, Query, Request, HttpCode, HttpStatus } from "@nestjs/common";
|
|
import { InvoiceRetrievalService } from "./services/invoice-retrieval.service.js";
|
|
import { WhmcsPaymentService } from "@bff/integrations/whmcs/services/whmcs-payment.service.js";
|
|
import { WhmcsSsoService } from "@bff/integrations/whmcs/services/whmcs-sso.service.js";
|
|
import { MappingsService } from "@bff/modules/id-mappings/mappings.service.js";
|
|
import { createZodDto, ZodResponse } from "nestjs-zod";
|
|
import type { RequestWithUser } from "@bff/modules/auth/auth.types.js";
|
|
|
|
import type { Invoice, InvoiceList, InvoiceSsoLink } from "@customer-portal/domain/billing";
|
|
import {
|
|
invoiceIdParamSchema,
|
|
invoiceListQuerySchema,
|
|
invoiceListSchema,
|
|
invoiceSchema,
|
|
invoiceSsoLinkSchema,
|
|
invoiceSsoQuerySchema,
|
|
} from "@customer-portal/domain/billing";
|
|
import type { PaymentMethodList } from "@customer-portal/domain/payments";
|
|
import { paymentMethodListSchema } from "@customer-portal/domain/payments";
|
|
|
|
class InvoiceListQueryDto extends createZodDto(invoiceListQuerySchema) {}
|
|
class InvoiceIdParamDto extends createZodDto(invoiceIdParamSchema) {}
|
|
class InvoiceListDto extends createZodDto(invoiceListSchema) {}
|
|
class InvoiceDto extends createZodDto(invoiceSchema) {}
|
|
class InvoiceSsoLinkDto extends createZodDto(invoiceSsoLinkSchema) {}
|
|
class InvoiceSsoQueryDto extends createZodDto(invoiceSsoQuerySchema) {}
|
|
class PaymentMethodListDto extends createZodDto(paymentMethodListSchema) {}
|
|
|
|
/**
|
|
* Billing Controller
|
|
*
|
|
* All request validation is handled by Zod schemas via global ZodValidationPipe.
|
|
* Business logic is delegated to service layer.
|
|
*/
|
|
@Controller("invoices")
|
|
export class BillingController {
|
|
constructor(
|
|
private readonly invoicesService: InvoiceRetrievalService,
|
|
private readonly whmcsPaymentService: WhmcsPaymentService,
|
|
private readonly whmcsSsoService: WhmcsSsoService,
|
|
private readonly mappingsService: MappingsService
|
|
) {}
|
|
|
|
@Get()
|
|
@ZodResponse({ description: "List invoices", type: InvoiceListDto })
|
|
async getInvoices(
|
|
@Request() req: RequestWithUser,
|
|
@Query() query: InvoiceListQueryDto
|
|
): Promise<InvoiceList> {
|
|
return this.invoicesService.getInvoices(req.user.id, query);
|
|
}
|
|
|
|
@Get("payment-methods")
|
|
@ZodResponse({ description: "List payment methods", type: PaymentMethodListDto })
|
|
async getPaymentMethods(@Request() req: RequestWithUser): Promise<PaymentMethodList> {
|
|
const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(req.user.id);
|
|
return this.whmcsPaymentService.getPaymentMethods(whmcsClientId, req.user.id);
|
|
}
|
|
|
|
@Post("payment-methods/refresh")
|
|
@HttpCode(HttpStatus.OK)
|
|
@ZodResponse({ description: "Refresh payment methods", type: PaymentMethodListDto })
|
|
async refreshPaymentMethods(@Request() req: RequestWithUser): Promise<PaymentMethodList> {
|
|
// Invalidate cache first
|
|
await this.whmcsPaymentService.invalidatePaymentMethodsCache(req.user.id);
|
|
|
|
// Return fresh payment methods
|
|
const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(req.user.id);
|
|
return this.whmcsPaymentService.getPaymentMethods(whmcsClientId, req.user.id);
|
|
}
|
|
|
|
@Get(":id")
|
|
@ZodResponse({ description: "Get invoice by id", type: InvoiceDto })
|
|
async getInvoiceById(
|
|
@Request() req: RequestWithUser,
|
|
@Param() params: InvoiceIdParamDto
|
|
): Promise<Invoice> {
|
|
return this.invoicesService.getInvoiceById(req.user.id, params.id);
|
|
}
|
|
|
|
@Post(":id/sso-link")
|
|
@HttpCode(HttpStatus.OK)
|
|
@ZodResponse({ description: "Create invoice SSO link", type: InvoiceSsoLinkDto })
|
|
async createSsoLink(
|
|
@Request() req: RequestWithUser,
|
|
@Param() params: InvoiceIdParamDto,
|
|
@Query() query: InvoiceSsoQueryDto
|
|
): Promise<InvoiceSsoLink> {
|
|
const whmcsClientId = await this.mappingsService.getWhmcsClientIdOrThrow(req.user.id);
|
|
|
|
const ssoUrl = await this.whmcsSsoService.whmcsSsoForInvoice(
|
|
whmcsClientId,
|
|
params.id,
|
|
query.target
|
|
);
|
|
|
|
return {
|
|
url: ssoUrl,
|
|
expiresAt: new Date(Date.now() + 60000).toISOString(), // 60 seconds per WHMCS spec
|
|
};
|
|
}
|
|
}
|