import { Body, Controller, Get, Param, ParseUUIDPipe, Patch, Post, Query, Res } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger'; import type { Response } from 'express'; import { BookingStaff } from '../../common/booking-guards'; import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry'; import { PayInvoiceDto as GatewayPayInvoiceDto } from '../billing/dto/pay-invoice.dto'; import { GenerateInvoiceDto, PayInvoiceBodyDto } from './dto/invoice.dto'; import { WarehouseInvoiceService } from './warehouse-invoice.service'; @ApiTags('warehouse-fee-invoices') @ApiBearerAuth() @Controller() export class WarehouseInvoiceController { constructor(private readonly invoiceService: WarehouseInvoiceService) {} @Post('warehouse-inventory/:id/generate-fee-invoice') @BookingStaff(FREIGHT_PERMS.warehouseFeeInvoices.generate) @ApiOperation({ summary: 'Generate a warehouse fee invoice from Batch 5 fee calculation' }) generate(@Param('id', ParseUUIDPipe) id: string, @Body() dto: GenerateInvoiceDto) { return this.invoiceService.generateForInventory(id, dto); } @Post('last-mile/:id/generate-truck-detention-invoice') @BookingStaff(FREIGHT_PERMS.warehouseFeeInvoices.generate) @ApiOperation({ summary: 'Generate a truck-detention invoice for a last-mile leg (per truck per day)' }) generateTruckDetention( @Param('id', ParseUUIDPipe) id: string, @Body() dto: GenerateInvoiceDto, ) { return this.invoiceService.generateTruckDetentionInvoice(id, dto); } @Get('warehouse-inventory/:id/fee-invoices') @BookingStaff(FREIGHT_PERMS.warehouseFeeInvoices.view) @ApiOperation({ summary: 'List fee invoices for an inventory item' }) listForInventory(@Param('id', ParseUUIDPipe) id: string) { return this.invoiceService.listForInventory(id); } @Get('bookings/:id/warehouse-fee-invoices') @ApiOperation({ summary: 'List warehouse fee invoices for a booking' }) listForBooking(@Param('id', ParseUUIDPipe) id: string) { return this.invoiceService.listForBooking(id); } @Get('warehouse-fee-invoices') @BookingStaff(FREIGHT_PERMS.warehouseFeeInvoices.view) @ApiOperation({ summary: 'List / filter warehouse fee invoices' }) findAll( @Query('status') status?: string, @Query('invoiceType') invoiceType?: string, @Query('warehouseId') warehouseId?: string, @Query('facilityId') facilityId?: string, @Query('customerId') customerId?: string, @Query('bookingId') bookingId?: string, ) { return this.invoiceService.findAll({ status: status as never, invoiceType: invoiceType as never, warehouseId, facilityId, customerId, bookingId, }); } @Get('warehouse-fee-invoices/:id') @ApiOperation({ summary: 'Get a warehouse fee invoice with items + payment history' }) findOne(@Param('id', ParseUUIDPipe) id: string) { return this.invoiceService.findById(id); } @Get('warehouse-fee-invoices/:id/document') @ApiOperation({ summary: 'Download sealed warehouse fee invoice PDF' }) async document(@Param('id', ParseUUIDPipe) id: string, @Res() res: Response) { const { filename, buffer } = await this.invoiceService.document(id); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); res.setHeader('Content-Length', buffer.length); return res.send(buffer); } @Get('warehouse-fee-invoices/:id/receipt') @ApiOperation({ summary: 'Download sealed warehouse fee payment receipt PDF' }) async receipt(@Param('id', ParseUUIDPipe) id: string, @Res() res: Response) { const { filename, buffer } = await this.invoiceService.receipt(id); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); res.setHeader('Content-Length', buffer.length); return res.send(buffer); } @Patch('warehouse-fee-invoices/:id/cancel') @BookingStaff(FREIGHT_PERMS.warehouseFeeInvoices.cancel) @ApiOperation({ summary: 'Cancel a warehouse fee invoice' }) cancel(@Param('id', ParseUUIDPipe) id: string) { return this.invoiceService.cancel(id); } @Post('warehouse-fee-invoices/:id/pay') @BookingStaff(FREIGHT_PERMS.warehouseFeeInvoices.pay) @ApiOperation({ summary: 'Record a payment against a warehouse fee invoice' }) pay(@Param('id', ParseUUIDPipe) id: string, @Body() dto: PayInvoiceBodyDto) { return this.invoiceService.pay(id, dto); } @Post('warehouse-fee-invoices/:id/pay-online') @ApiOperation({ summary: 'Initiate Telebirr/Waafi payment for a warehouse fee invoice' }) payOnline(@Param('id', ParseUUIDPipe) id: string, @Body() dto: GatewayPayInvoiceDto) { return this.invoiceService.initiatePayment(id, dto); } }