import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Put, } from "@nestjs/common"; import { ApiOperation, ApiTags } from "@nestjs/swagger"; import { BookingStaff } from "../../common/booking-guards"; import { FREIGHT_PERMS } from "../../seed/freight-permissions.registry"; import { ContractTemplatesService } from "./contract-templates.service"; import { CreateArticleDto, CreateContractTemplateDto, PreviewContractTemplateDto, ReplaceArticlesDto, UpdateArticleDto, UpdateContractTemplateDto, } from "./dto/contract-template.dto"; // `view` opens the Templates page; `read` is API-read-only for other pages // that show template data; create/update/delete gate each write. `manage` is // the legacy write key and keeps working for roles that already hold it. const TEMPLATE_READ = [ FREIGHT_PERMS.settings.contractTemplates.view, FREIGHT_PERMS.settings.contractTemplates.read, FREIGHT_PERMS.settings.contractTemplates.update, FREIGHT_PERMS.settings.contractTemplates.manage, FREIGHT_PERMS.admin, ]; const TEMPLATE_UPDATE = [ FREIGHT_PERMS.settings.contractTemplates.update, FREIGHT_PERMS.settings.contractTemplates.manage, FREIGHT_PERMS.admin, ]; @ApiTags("contract-templates") @Controller("contract-templates") export class ContractTemplatesController { constructor(private readonly service: ContractTemplatesService) {} @Get() @BookingStaff(TEMPLATE_READ) @ApiOperation({ summary: "List contract templates (system container + staff-created bulk)" }) list() { return this.service.list(); } @Post() @BookingStaff([ FREIGHT_PERMS.settings.contractTemplates.create, FREIGHT_PERMS.settings.contractTemplates.manage, FREIGHT_PERMS.admin, ]) @ApiOperation({ summary: "Create a bulk contract template for a (cargo type, trade direction, customs option) combination", }) create(@Body() dto: CreateContractTemplateDto) { return this.service.create(dto); } @Get(":code") @BookingStaff(TEMPLATE_READ) @ApiOperation({ summary: "Get one contract template by code" }) getByCode(@Param("code") code: string) { return this.service.getByCode(code); } @Patch(":code") @BookingStaff(TEMPLATE_UPDATE) @ApiOperation({ summary: "Update template metadata (name, title, recitals, active flag)" }) update(@Param("code") code: string, @Body() dto: UpdateContractTemplateDto) { return this.service.update(code, dto); } @Delete(":code") @BookingStaff([ FREIGHT_PERMS.settings.contractTemplates.delete, FREIGHT_PERMS.admin, ]) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: "Delete a staff-created bulk template (system templates refuse)", }) remove(@Param("code") code: string) { return this.service.remove(code); } @Post(":code/preview") @BookingStaff(TEMPLATE_READ) @ApiOperation({ summary: "Render an HTML preview of the template against mock contract data", }) preview( @Param("code") code: string, @Body() dto: PreviewContractTemplateDto, ) { return this.service.preview(code, dto); } /* ------------------------- article routes ------------------------- */ @Put(":code/articles") @BookingStaff(TEMPLATE_UPDATE) @ApiOperation({ summary: "Replace the full ordered article list (used for reorder)" }) replaceArticles(@Param("code") code: string, @Body() dto: ReplaceArticlesDto) { return this.service.replaceArticles(code, dto.articles); } @Post(":code/articles") @BookingStaff(TEMPLATE_UPDATE) @ApiOperation({ summary: "Add an article to the template" }) addArticle(@Param("code") code: string, @Body() dto: CreateArticleDto) { return this.service.addArticle(code, dto); } @Patch(":code/articles/:articleId") @BookingStaff(TEMPLATE_UPDATE) @ApiOperation({ summary: "Update an article's title or body" }) updateArticle( @Param("code") code: string, @Param("articleId") articleId: string, @Body() dto: UpdateArticleDto, ) { return this.service.updateArticle(code, articleId, dto); } @Delete(":code/articles/:articleId") @BookingStaff(TEMPLATE_UPDATE) @ApiOperation({ summary: "Remove an article from the template" }) removeArticle( @Param("code") code: string, @Param("articleId") articleId: string, ) { return this.service.removeArticle(code, articleId); } }