import { Controller, Get, Param, ParseUUIDPipe, Query, Res, } from "@nestjs/common"; import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger"; import type { Response } from "express"; import { CurrentUser } from "@edr/api-common"; import type { TCurrentUser } from "@tria-plc/api-common/modules/auth/types/current-user.type"; import { BookingStaff } from "../../common/booking-guards"; import { FREIGHT_PERMS } from "../../seed/freight-permissions.registry"; import { UserTradeAccessService } from "../user-trade-access/user-trade-access.service"; import { BillingService } from "./billing.service"; import { FilterInvoiceDto } from "./dto/filter-invoice.dto"; @ApiTags("billing") @Controller("billing") @BookingStaff(FREIGHT_PERMS.invoices.view) @ApiBearerAuth() export class BillingController { constructor( private readonly billingService: BillingService, private readonly userTradeAccessService: UserTradeAccessService, ) {} @Get("invoices") @ApiOperation({ summary: "List invoices (paginated, filterable by company/status/search)", }) async findAll( @Query() query: FilterInvoiceDto, @CurrentUser() user: TCurrentUser, ) { // Per-user trade-direction scope, applied via each invoice's source booking. const allowed = await this.userTradeAccessService.resolveAllowedDirections(user); return this.billingService.findAllPaginated({ ...query, tradeDirections: allowed ?? undefined, }); } @Get("invoices/:id") @ApiOperation({ summary: "Get an invoice with its line items" }) findById(@Param("id", ParseUUIDPipe) id: string) { return this.billingService.findById(id); } @Get("invoices/:id/document") @BookingStaff(FREIGHT_PERMS.invoices.export) @ApiOperation({ summary: "Download the sealed invoice PDF" }) async document(@Param("id", ParseUUIDPipe) id: string, @Res() res: Response) { const { filename, buffer } = await this.billingService.document(id); sendPdf(res, filename, buffer); } @Get("invoices/:id/receipt") @BookingStaff(FREIGHT_PERMS.invoices.export) @ApiOperation({ summary: "Download the sealed payment receipt PDF" }) async receipt(@Param("id", ParseUUIDPipe) id: string, @Res() res: Response) { const { filename, buffer } = await this.billingService.receipt(id); sendPdf(res, filename, buffer); } } /** Stream a generated PDF as a file download. */ export function sendPdf(res: Response, filename: string, buffer: Buffer): void { res.setHeader("Content-Type", "application/pdf"); res.setHeader("Content-Disposition", `attachment; filename="${filename}"`); res.setHeader("Content-Length", buffer.length); res.send(buffer); }