import { Controller, Get, HttpStatus, Param, ParseUUIDPipe, Query, Res, } from "@nestjs/common"; import { ApiTags, ApiOperation, ApiQuery, ApiOkResponse, ApiProduces, } from "@nestjs/swagger"; import { Response } from "express"; import { CurrentUser, Public } from "@edr/api-common"; import type { TCurrentUser } from "@tria-plc/api-common/modules/auth/types/current-user.type"; import { BookingStaff, BookingView } from "../../common/booking-guards"; import { UserTradeAccessService } from "../user-trade-access/user-trade-access.service"; import { FREIGHT_PERMS } from "../../seed/freight-permissions.registry"; import { PaymentService } from "./payment.service"; import { IntentStatusDto } from "./payments.dto"; @ApiTags("Payment") @Controller("payments") export class PaymentController { constructor( private readonly paymentService: PaymentService, private readonly userTradeAccessService: UserTradeAccessService, ) { } // Customer-detail payments tab — same one-of rule as the bookings tab. @Get("by-company/:companyId/customer-view") @BookingStaff([FREIGHT_PERMS.customers.view, FREIGHT_PERMS.payments.view]) @ApiOperation({ summary: "List payments for a company (customer-view shape, backoffice)" }) findByCompanyCustomerView( @Param("companyId", ParseUUIDPipe) companyId: string, ) { return this.paymentService.findByCompanyId(companyId); } @Get("summary") @BookingView() @ApiOperation({ summary: "Payment count/amount summary for dashboard cards" }) getSummary() { return this.paymentService.getSummary(); } @Get("all") @BookingView() @ApiOperation({ summary: "Get all payments with filters (view-only, any staff)" }) @ApiQuery({ name: "search", required: false }) @ApiQuery({ name: "status", required: false }) @ApiQuery({ name: "method", required: false }) @ApiQuery({ name: "page", required: false }) @ApiQuery({ name: "pageSize", required: false }) async getAll( @CurrentUser() user: TCurrentUser, @Query("search") search?: string, @Query("status") status?: string, @Query("method") method?: string, @Query("page") page?: string, @Query("pageSize") pageSize?: string, ) { // Per-user trade-direction scope, applied via the booking in ref_id. const allowed = await this.userTradeAccessService.resolveAllowedDirections(user); return this.paymentService.getAll({ search, status, method, page: page ? parseInt(page) : 1, pageSize: pageSize ? parseInt(pageSize) : 10, tradeDirections: allowed ?? undefined, }); } @Get("intents/:bookingId") @ApiOperation({ summary: "Get payment intent status for a booking" }) @ApiOkResponse({ type: IntentStatusDto }) getIntent(@Param("bookingId") bookingId: string) { return this.paymentService.getIntentByBookingId(bookingId); } @Get("receipt/:orderId") @Public() @ApiOperation({ summary: "Generate a payment receipt HTML page" }) @ApiProduces("text/html") async receipt(@Param("orderId") orderId: string, @Res() res: Response) { const html = await this.paymentService.genReceiptHtml(orderId); return res.status(HttpStatus.OK).type("html").send(html); } }