mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 05:30:55 +00:00
Gates the previously open support-agent, procurement, compliance, facilities, list-users and trade-access controllers, separates customer from staff routes across bookings, contracts, companies, billing, warehouses, files and train scheduling, and moves billing, overview, reports and the settings controllers onto their own keys instead of the blanket admin key. Drops the demo-permissions module and the untested notification test route.
78 lines
2.6 KiB
TypeScript
78 lines
2.6 KiB
TypeScript
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);
|
|
}
|