import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, ParseUUIDPipe, Patch, Post, Query, } from '@nestjs/common'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { CurrentUser } from '@edr/api-common'; import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type'; import { BookingStaff, FleetManage, StaffReference, } from '../../common/booking-guards'; import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry'; import { CreateWagonDto } from './dto/create-wagon.dto'; import { ListWagonsQueryDto } from './dto/list-wagons-query.dto'; import { UpdateWagonDto } from './dto/update-wagon.dto'; import { AssignWagonToTrainDto } from './dto/assign-wagon-to-train.dto'; import { BulkTransferWagonsDto } from './dto/bulk-transfer-wagons.dto'; import { BulkSetWagonStatusDto } from './dto/bulk-set-wagon-status.dto'; import { WagonsService } from './wagons.service'; @ApiTags('wagons') // No class-level guard: reads (list, by-id, movements) are login-only reference // data — any staff can fetch wagon data for a cross-flow view without the // fleet:view that drives the Fleet sidebar. Every mutation has its @FleetManage(). @Controller('wagons') export class WagonsController { constructor(private readonly wagonsService: WagonsService) {} @Post() @FleetManage(FREIGHT_PERMS.wagons.create) @ApiOperation({ summary: 'Create a new wagon' }) create(@Body() dto: CreateWagonDto) { return this.wagonsService.create(dto); } @Get() @StaffReference() @ApiOperation({ summary: 'List wagons, paginated ({items, meta}) — 10 per page by default', }) findAll(@Query() query: ListWagonsQueryDto) { return this.wagonsService.findAll(query); } @Get(':id') @StaffReference() @ApiOperation({ summary: 'Get a wagon by ID' }) findOne(@Param('id', ParseUUIDPipe) id: string) { return this.wagonsService.findById(id); } @Get(':id/movements') @StaffReference() @ApiOperation({ summary: "Wagon movement ledger (loaded legs, empty repositions, manual moves), newest first", }) listMovements(@Param('id', ParseUUIDPipe) id: string) { return this.wagonsService.listMovements(id); } @Patch(':id') @FleetManage(FREIGHT_PERMS.wagons.update) @ApiOperation({ summary: 'Update a wagon' }) update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateWagonDto) { return this.wagonsService.update(id, dto); } // Declared before @Delete(':id') so "permanent" is never captured as an id. // BookingStaff, not FleetManage: the latter also accepts the coarse // fleet:manage key, which would hand an irreversible purge to everyone who // can edit the fleet. This action requires its own grant, nothing else. @Delete(':id/permanent') @BookingStaff(FREIGHT_PERMS.wagons.hardDelete) @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Permanently delete a wagon (irreversible; refused if it has movements, containers or train-set slots)', }) purge(@Param('id', ParseUUIDPipe) id: string) { return this.wagonsService.purge(id); } @Delete(':id') @FleetManage(FREIGHT_PERMS.wagons.delete) @ApiOperation({ summary: 'Delete a wagon' }) remove(@Param('id', ParseUUIDPipe) id: string) { return this.wagonsService.remove(id); } @Post(':id/assign-train') @FleetManage(FREIGHT_PERMS.trains.assignWagons) @ApiOperation({ summary: 'Assign wagon to a train' }) assignToTrain(@Param('id', ParseUUIDPipe) id: string, @Body() dto: AssignWagonToTrainDto) { return this.wagonsService.assignToTrain(id, dto); } @Post(':id/unassign-train') @FleetManage(FREIGHT_PERMS.trains.assignWagons) @ApiOperation({ summary: 'Unassign wagon from train' }) unassignFromTrain(@Param('id', ParseUUIDPipe) id: string) { return this.wagonsService.unassignFromTrain(id); } @Post('bulk-transfer') @FleetManage(FREIGHT_PERMS.wagons.update) @ApiOperation({ summary: 'Transfer multiple wagons to a destination yard' }) bulkTransfer(@Body() dto: BulkTransferWagonsDto, @CurrentUser() user: TCurrentUser) { return this.wagonsService.bulkTransfer(dto, user?.id); } @Post('bulk-status') @FleetManage(FREIGHT_PERMS.wagons.update) @ApiOperation({ summary: 'Set the status of multiple wagons' }) bulkSetStatus(@Body() dto: BulkSetWagonStatusDto) { return this.wagonsService.bulkSetStatus(dto); } }