mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
221 lines
7.4 KiB
TypeScript
221 lines
7.4 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
HttpCode,
|
|
HttpStatus,
|
|
Param,
|
|
ParseUUIDPipe,
|
|
Patch,
|
|
Post,
|
|
Put,
|
|
Query,
|
|
} from '@nestjs/common';
|
|
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
|
import { CurrentUser } from '@edr/api-common';
|
|
|
|
import { FleetManage, FleetView } from '../../common/booking-guards';
|
|
import type { AuthUserPayload } from '../../common/resolve-auth-user-id';
|
|
import { resolveAuthUserId } from '../../common/resolve-auth-user-id';
|
|
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
|
|
import { AssignTrainWagonsDto } from './dto/assign-train-wagons.dto';
|
|
import { BuildTrainDto } from './dto/build-train.dto';
|
|
import { ListBuiltTrainsQueryDto } from './dto/list-built-trains-query.dto';
|
|
import { ReorderTrainWagonsDto } from './dto/reorder-train-wagons.dto';
|
|
import { SendWagonToMaintenanceDto } from './dto/send-wagon-to-maintenance.dto';
|
|
import { UpdateTrainDetailsDto } from './dto/update-train-details.dto';
|
|
import { UpdateTrainLocomotivesDto } from './dto/update-train-locomotives.dto';
|
|
import { UpdateTrainYardDto } from './dto/update-train-yard.dto';
|
|
import { SetTrainWagonsYardDto } from './dto/set-train-wagons-yard.dto';
|
|
import { TrainBuilderService } from './train-builder.service';
|
|
|
|
@ApiTags('train-builder')
|
|
@ApiBearerAuth()
|
|
@Controller('train-builder')
|
|
// Class gate lists every key its routes use: Nest runs class AND method
|
|
// guards, so a key missing here would deny before the route's own key runs.
|
|
@FleetView([
|
|
FREIGHT_PERMS.trains.view,
|
|
FREIGHT_PERMS.trains.create,
|
|
FREIGHT_PERMS.trains.update,
|
|
FREIGHT_PERMS.trains.assignWagons,
|
|
FREIGHT_PERMS.trains.delete,
|
|
FREIGHT_PERMS.trains.changeLocomotives,
|
|
FREIGHT_PERMS.trains.changeYard,
|
|
FREIGHT_PERMS.trains.changeWagonYard,
|
|
FREIGHT_PERMS.trains.toggleActive,
|
|
FREIGHT_PERMS.trains.disband,
|
|
])
|
|
export class TrainBuilderController {
|
|
constructor(private readonly trainBuilderService: TrainBuilderService) {}
|
|
|
|
@Post()
|
|
@FleetManage(FREIGHT_PERMS.trains.create)
|
|
@ApiOperation({ summary: 'Build a train: code + yard + 2+ locomotives (+ optional wagons)' })
|
|
build(@Body() dto: BuildTrainDto) {
|
|
return this.trainBuilderService.buildTrain(dto);
|
|
}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'Paginated built trains with composition summary' })
|
|
list(@Query() query: ListBuiltTrainsQueryDto) {
|
|
return this.trainBuilderService.listBuilt(query);
|
|
}
|
|
|
|
// Must be declared before @Get(':id') so the path isn't captured as an id.
|
|
@Get('used-train-numbers')
|
|
@ApiOperation({
|
|
summary: 'Import/export run numbers already claimed by existing trains',
|
|
})
|
|
usedTrainNumbers() {
|
|
return this.trainBuilderService.usedTrainNumbers();
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Full train composition: locomotives, ordered wagons, totals vs. limits' })
|
|
composition(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.trainBuilderService.getComposition(id);
|
|
}
|
|
|
|
@Put(':id/locomotives')
|
|
@FleetManage(FREIGHT_PERMS.trains.changeLocomotives)
|
|
@ApiOperation({ summary: 'Replace the locomotive set (minimum 1, same yard)' })
|
|
setLocomotives(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Body() dto: UpdateTrainLocomotivesDto,
|
|
) {
|
|
return this.trainBuilderService.setLocomotives(id, dto);
|
|
}
|
|
|
|
@Patch(':id/details')
|
|
@FleetManage(FREIGHT_PERMS.trains.update)
|
|
@ApiOperation({
|
|
summary: "Edit the train's name and fixed import/export run numbers",
|
|
})
|
|
updateDetails(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Body() dto: UpdateTrainDetailsDto,
|
|
) {
|
|
return this.trainBuilderService.updateDetails(id, dto);
|
|
}
|
|
|
|
@Patch(':id/yard')
|
|
@FleetManage(FREIGHT_PERMS.trains.changeYard)
|
|
@ApiOperation({
|
|
summary: 'Relocate the train — its locomotives and wagons move to the new yard with it',
|
|
})
|
|
setYard(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateTrainYardDto) {
|
|
return this.trainBuilderService.setYard(id, dto.currentYardId);
|
|
}
|
|
|
|
@Patch(':id/wagons/:wagonId/yard')
|
|
@FleetManage(FREIGHT_PERMS.trains.changeWagonYard)
|
|
@ApiOperation({
|
|
summary:
|
|
'Move one coupled wagon to another yard — refused while any live schedule has the wagon allocated',
|
|
})
|
|
setWagonYard(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Param('wagonId', ParseUUIDPipe) wagonId: string,
|
|
@Body() dto: UpdateTrainYardDto,
|
|
@CurrentUser() user: AuthUserPayload,
|
|
) {
|
|
return this.trainBuilderService.setWagonYard(
|
|
id,
|
|
wagonId,
|
|
dto.currentYardId,
|
|
resolveAuthUserId(user),
|
|
);
|
|
}
|
|
|
|
@Patch(':id/wagons/yard')
|
|
@FleetManage(FREIGHT_PERMS.trains.changeWagonYard)
|
|
@ApiOperation({
|
|
summary:
|
|
'Move several coupled wagons to another yard in one transaction — refused outright if any is allocated to a live schedule',
|
|
})
|
|
setWagonsYard(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Body() dto: SetTrainWagonsYardDto,
|
|
@CurrentUser() user: AuthUserPayload,
|
|
) {
|
|
return this.trainBuilderService.setWagonsYard(
|
|
id,
|
|
dto.wagonIds,
|
|
dto.currentYardId,
|
|
resolveAuthUserId(user),
|
|
);
|
|
}
|
|
|
|
@Post(':id/wagons')
|
|
@FleetManage(FREIGHT_PERMS.trains.assignWagons)
|
|
@ApiOperation({ summary: "Append AVAILABLE wagons from the train's yard to the consist" })
|
|
assignWagons(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Body() dto: AssignTrainWagonsDto,
|
|
@CurrentUser() user: AuthUserPayload,
|
|
) {
|
|
return this.trainBuilderService.assignWagons(id, dto, resolveAuthUserId(user));
|
|
}
|
|
|
|
@Delete(':id/wagons/:wagonId')
|
|
@FleetManage(FREIGHT_PERMS.trains.assignWagons)
|
|
@ApiOperation({ summary: 'Detach one wagon from the consist' })
|
|
removeWagon(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Param('wagonId', ParseUUIDPipe) wagonId: string,
|
|
@CurrentUser() user: AuthUserPayload,
|
|
) {
|
|
return this.trainBuilderService.removeWagon(id, wagonId, resolveAuthUserId(user));
|
|
}
|
|
|
|
@Post(':id/wagons/:wagonId/maintenance')
|
|
@FleetManage(FREIGHT_PERMS.trains.assignWagons)
|
|
@ApiOperation({ summary: 'Detach one wagon and move it to MAINTENANCE status' })
|
|
sendWagonToMaintenance(
|
|
@Param('id', ParseUUIDPipe) id: string,
|
|
@Param('wagonId', ParseUUIDPipe) wagonId: string,
|
|
@CurrentUser() user: AuthUserPayload,
|
|
@Body() dto?: SendWagonToMaintenanceDto,
|
|
) {
|
|
return this.trainBuilderService.sendWagonToMaintenance(
|
|
id,
|
|
wagonId,
|
|
resolveAuthUserId(user),
|
|
dto?.note,
|
|
);
|
|
}
|
|
|
|
@Post(':id/reorder-wagons')
|
|
@FleetManage(FREIGHT_PERMS.trains.assignWagons)
|
|
@ApiOperation({ summary: 'Persist a drag-reorder of the full consist' })
|
|
reorderWagons(@Param('id', ParseUUIDPipe) id: string, @Body() dto: ReorderTrainWagonsDto) {
|
|
return this.trainBuilderService.reorderWagons(id, dto);
|
|
}
|
|
|
|
@Post(':id/deactivate')
|
|
@FleetManage(FREIGHT_PERMS.trains.toggleActive)
|
|
@ApiOperation({
|
|
summary: 'Deactivate the train (park it) — only allowed with no active schedule',
|
|
})
|
|
deactivate(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.trainBuilderService.deactivate(id);
|
|
}
|
|
|
|
@Post(':id/activate')
|
|
@FleetManage(FREIGHT_PERMS.trains.toggleActive)
|
|
@ApiOperation({ summary: 'Reactivate a deactivated train back to AVAILABLE' })
|
|
activate(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.trainBuilderService.activate(id);
|
|
}
|
|
|
|
@Delete(':id')
|
|
@FleetManage(FREIGHT_PERMS.trains.disband)
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Disband the train (release wagons and locomotives)' })
|
|
disband(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.trainBuilderService.disband(id);
|
|
}
|
|
}
|