Merge branch 'freight/feat/booking-schedule' into freight/develop

This commit is contained in:
ghost2023
2026-06-16 12:39:56 +03:00
35 changed files with 2648 additions and 963 deletions

View File

@@ -1,28 +1,28 @@
import { Inject, Injectable } from '@nestjs/common';
import { In, Not } from 'typeorm';
import { Inject, Injectable } from "@nestjs/common";
import { In, Not } from "typeorm";
import { CargoType } from '../rule-engine/entities/cargo-type.entity';
import { ContainerType } from '../rule-engine/entities/container-type.entity';
import { CargoType } from "../rule-engine/entities/cargo-type.entity";
import { ContainerType } from "../rule-engine/entities/container-type.entity";
import {
CARGO_TYPES_REPOSITORY,
ICargoTypesRepository,
} from '../rule-engine/interfaces/cargo-types.repository.interface';
} from "../rule-engine/interfaces/cargo-types.repository.interface";
import {
CONTAINER_TYPES_REPOSITORY,
IContainerTypesRepository,
} from '../rule-engine/interfaces/container-types.repository.interface';
} from "../rule-engine/interfaces/container-types.repository.interface";
import {
IServiceTypesRepository,
SERVICE_TYPES_REPOSITORY,
} from '../rule-engine/interfaces/service-types.repository.interface';
} from "../rule-engine/interfaces/service-types.repository.interface";
import {
IShippingLinesRepository,
SHIPPING_LINES_REPOSITORY,
} from '../rule-engine/interfaces/shipping-lines.repository.interface';
} from "../rule-engine/interfaces/shipping-lines.repository.interface";
import {
IYardsRepository,
YARDS_REPOSITORY,
} from '../rule-engine/interfaces/yards.repository.interface';
} from "../rule-engine/interfaces/yards.repository.interface";
import {
BookingReferenceCargoTypeChildDto,
BookingReferenceCargoTypeGroupDto,
@@ -32,9 +32,9 @@ import {
BookingReferenceServiceDto,
BookingReferenceShippingLineDto,
BookingReferenceYardDto,
} from './dto/booking-reference-data.dto';
} from "./dto/booking-reference-data.dto";
const LEGACY_YARD_CODES = ['LEGACY_ORIGIN', 'LEGACY_DEST'] as const;
const LEGACY_YARD_CODES = ["LEGACY_ORIGIN", "LEGACY_DEST"] as const;
export function buildCargoTypeTree(
rows: CargoType[],
@@ -42,13 +42,16 @@ export function buildCargoTypeTree(
const active = rows.filter((r) => r.isActive);
const parents = active
.filter((r) => !r.parentGroupId)
.sort((a, b) => a.displayOrder - b.displayOrder || a.code.localeCompare(b.code));
.sort(
(a, b) => a.displayOrder - b.displayOrder || a.code.localeCompare(b.code),
);
return parents.map((parent) => {
const children = active
.filter((r) => r.parentGroupId === parent.id)
.sort(
(a, b) => a.displayOrder - b.displayOrder || a.code.localeCompare(b.code),
(a, b) =>
a.displayOrder - b.displayOrder || a.code.localeCompare(b.code),
)
.map(
(child): BookingReferenceCargoTypeChildDto => ({
@@ -79,14 +82,14 @@ export function groupContainersBySize(
for (const ct of active) {
const sizeKey =
ct.sizeFt != null && ct.sizeFt > 0 ? `${ct.sizeFt}ft` : 'other';
ct.sizeFt != null && ct.sizeFt > 0 ? `${ct.sizeFt}ft` : "other";
const list = bySize.get(sizeKey) ?? [];
list.push(ct);
bySize.set(sizeKey, list);
}
const sortSizeKey = (key: string): number => {
if (key === 'other') return Number.MAX_SAFE_INTEGER;
if (key === "other") return Number.MAX_SAFE_INTEGER;
const n = parseInt(key, 10);
return Number.isNaN(n) ? Number.MAX_SAFE_INTEGER - 1 : n;
};
@@ -126,7 +129,7 @@ export class BookingReferenceDataService {
private readonly shippingLinesRepository: IShippingLinesRepository,
@Inject(CARGO_TYPES_REPOSITORY)
private readonly cargoTypesRepository: ICargoTypesRepository,
) {}
) { }
async getReferenceData(): Promise<BookingReferenceDataDto> {
const [yards, containerTypes, serviceTypes, shippingLines, cargoTypes] =
@@ -136,23 +139,23 @@ export class BookingReferenceDataService {
isActive: true,
code: Not(In([...LEGACY_YARD_CODES])),
},
order: { displayOrder: 'ASC', code: 'ASC' },
order: { displayOrder: "ASC", code: "ASC" },
}),
this.containerTypesRepository.findAll({
where: { isActive: true },
order: { displayOrder: 'ASC', code: 'ASC' },
order: { displayOrder: "ASC", code: "ASC" },
}),
this.serviceTypesRepository.findAll({
where: { isActive: true },
order: { displayOrder: 'ASC', code: 'ASC' },
order: { displayOrder: "ASC", code: "ASC" },
}),
this.shippingLinesRepository.findAll({
where: { isActive: true },
order: { label: 'ASC', code: 'ASC' },
order: { label: "ASC", code: "ASC" },
}),
this.cargoTypesRepository.findAll({
where: { isActive: true },
order: { displayOrder: 'ASC', code: 'ASC' },
order: { displayOrder: "ASC", code: "ASC" },
}),
]);
@@ -168,9 +171,8 @@ export class BookingReferenceDataService {
containers: groupContainersBySize(containerTypes),
service: serviceTypes.map(
(s): BookingReferenceServiceDto => ({
id: s.id,
name: s.serviceName,
code: s.code,
...s,
}),
),
shipping_line: shippingLines.map(

View File

@@ -8,87 +8,98 @@ import {
Patch,
Post,
Query,
} from '@nestjs/common';
import { CurrentUser } from '@edr/api-common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import type { AuthUserPayload } from '../../common/resolve-auth-user-id';
import { resolveAuthUserId } from '../../common/resolve-auth-user-id';
} from "@nestjs/common";
import { CurrentUser } from "@edr/api-common";
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger";
import type { AuthUserPayload } from "../../common/resolve-auth-user-id";
import { resolveAuthUserId } from "../../common/resolve-auth-user-id";
import { TrainSchedulingManage, TrainSchedulingView } from '../../common/booking-guards';
import { AssignBookingsDto } from './dto/assign-bookings.dto';
import { AssignUnassignedBookingDto } from './dto/assign-unassigned-booking.dto';
import { CreateContainerTrainScheduleDto } from './dto/create-container-train-schedule.dto';
import { GetEligibleBookingsDto } from './dto/get-eligible-bookings.dto';
import { GetEligibleBulkBookingsDto } from './dto/get-eligible-bulk-bookings.dto';
import { GetEligibleContainerBookingsDto } from './dto/get-eligible-container-bookings.dto';
import { PinWagonsDto } from './dto/pin-wagons.dto';
import { UpdateContainerItemDto } from './dto/update-container-item.dto';
import { PreviewBulkTrainScheduleDto } from './dto/preview-bulk-train-schedule.dto';
import { PreviewContainerTrainScheduleDto } from './dto/preview-container-train-schedule.dto';
import { PreviewTrainScheduleDto } from './dto/preview-train-schedule.dto';
import { RecordCheckpointDto } from './dto/record-checkpoint.dto';
import { AvailableLocomotivesQueryDto } from './dto/available-locomotives-query.dto';
import { BookableSchedulesQueryDto } from './dto/bookable-schedules-query.dto';
import { UpdateTrainSchedulingGlobalRulesDto } from './dto/update-train-scheduling-global-rules.dto';
import { TrainSchedulingService } from './train-scheduling.service';
import { BookingBatchService } from './booking-batch.service';
import {
TrainSchedulingManage,
TrainSchedulingView,
} from "../../common/booking-guards";
import { AssignBookingsDto } from "./dto/assign-bookings.dto";
import { AssignUnassignedBookingDto } from "./dto/assign-unassigned-booking.dto";
import { CreateContainerTrainScheduleDto } from "./dto/create-container-train-schedule.dto";
import { GetEligibleBookingsDto } from "./dto/get-eligible-bookings.dto";
import { GetEligibleBulkBookingsDto } from "./dto/get-eligible-bulk-bookings.dto";
import { GetEligibleContainerBookingsDto } from "./dto/get-eligible-container-bookings.dto";
import { PinWagonsDto } from "./dto/pin-wagons.dto";
import { UpdateContainerItemDto } from "./dto/update-container-item.dto";
import { PreviewBulkTrainScheduleDto } from "./dto/preview-bulk-train-schedule.dto";
import { PreviewContainerTrainScheduleDto } from "./dto/preview-container-train-schedule.dto";
import { PreviewTrainScheduleDto } from "./dto/preview-train-schedule.dto";
import { RecordCheckpointDto } from "./dto/record-checkpoint.dto";
import { AvailableLocomotivesQueryDto } from "./dto/available-locomotives-query.dto";
import { BookableSchedulesQueryDto } from "./dto/bookable-schedules-query.dto";
import { UpdateTrainSchedulingGlobalRulesDto } from "./dto/update-train-scheduling-global-rules.dto";
import { TrainSchedulingService } from "./train-scheduling.service";
import { BookingBatchService } from "./booking-batch.service";
@ApiTags('train-scheduling')
@ApiTags("train-scheduling")
@ApiBearerAuth()
@Controller('train-scheduling')
@Controller("train-scheduling")
export class TrainSchedulingController {
constructor(
private readonly trainSchedulingService: TrainSchedulingService,
private readonly bookingBatchService: BookingBatchService,
) {}
) { }
@Get('global-rules')
@Get("global-rules")
@TrainSchedulingView()
@ApiOperation({ summary: 'Get global train scheduling rules (singleton)' })
@ApiOperation({ summary: "Get global train scheduling rules (singleton)" })
getGlobalRules() {
return this.trainSchedulingService.getTrainSchedulingGlobalRules();
}
@Patch('global-rules')
@Patch("global-rules")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Update global train scheduling rules (singleton)' })
@ApiOperation({ summary: "Update global train scheduling rules (singleton)" })
updateGlobalRules(@Body() dto: UpdateTrainSchedulingGlobalRulesDto) {
return this.trainSchedulingService.updateTrainSchedulingGlobalRules(dto);
}
@Get('eligible-bookings')
@Get("eligible-bookings")
@TrainSchedulingView()
@ApiOperation({ summary: 'List eligible bookings (container and/or bulk)' })
@ApiOperation({ summary: "List eligible bookings (container and/or bulk)" })
getEligibleBookings(@Query() query: GetEligibleBookingsDto) {
return this.trainSchedulingService.getEligibleBookings(query);
}
@Get('batch-board')
@Get("batch-board")
@TrainSchedulingView()
@ApiOperation({ summary: 'Batch monitoring board: schedules with bookings grouped by state' })
@ApiOperation({
summary: "Batch monitoring board: schedules with bookings grouped by state",
})
getBatchBoard() {
return this.bookingBatchService.getBatchBoard();
}
@Get('batch-board/:scheduleId')
@Get("batch-board/:scheduleId")
@TrainSchedulingView()
@ApiOperation({ summary: 'Batch board detail for one schedule with EAT 3h windows' })
getBatchBoardDetail(@Param('scheduleId', ParseUUIDPipe) scheduleId: string) {
@ApiOperation({
summary: "Batch board detail for one schedule with EAT 3h windows",
})
getBatchBoardDetail(@Param("scheduleId", ParseUUIDPipe) scheduleId: string) {
return this.bookingBatchService.getBatchBoardDetail(scheduleId);
}
@Get('available-locomotives')
@Get("available-locomotives")
@TrainSchedulingView()
@ApiOperation({
summary: 'List AVAILABLE locomotives at the route origin yard',
summary: "List AVAILABLE locomotives at the route origin yard",
})
getAvailableLocomotives(@Query() query: AvailableLocomotivesQueryDto) {
return this.trainSchedulingService.getAvailableLocomotivesForRoute(query.routeId);
return this.trainSchedulingService.getAvailableLocomotivesForRoute(
query.routeId,
);
}
@Get('bookable-schedules')
@TrainSchedulingView()
@ApiOperation({ summary: 'OPEN same-route schedules a new booking can target' })
@Get("bookable-schedules")
// @TrainSchedulingView()
@ApiOperation({
summary: "OPEN same-route schedules a new booking can target",
})
getBookableSchedules(@Query() query: BookableSchedulesQueryDto) {
return this.trainSchedulingService.getBookableSchedules(
query.originYardId,
@@ -96,282 +107,323 @@ export class TrainSchedulingController {
);
}
@Get('container/eligible-bookings')
@Get("container/eligible-bookings")
@TrainSchedulingView()
@ApiOperation({ summary: 'List eligible container bookings' })
getEligibleContainerBookings(@Query() query: GetEligibleContainerBookingsDto) {
@ApiOperation({ summary: "List eligible container bookings" })
getEligibleContainerBookings(
@Query() query: GetEligibleContainerBookingsDto,
) {
return this.trainSchedulingService.getEligibleContainerBookings(query);
}
@Get('bulk/eligible-bookings')
@Get("bulk/eligible-bookings")
@TrainSchedulingView()
@ApiOperation({ summary: 'List eligible bulk bookings' })
@ApiOperation({ summary: "List eligible bulk bookings" })
getEligibleBulkBookings(@Query() query: GetEligibleBulkBookingsDto) {
return this.trainSchedulingService.getEligibleBulkBookings(query);
}
@Post('preview')
@Post("preview")
@TrainSchedulingView()
@ApiOperation({ summary: 'Preview a mixed-capable train schedule' })
@ApiOperation({ summary: "Preview a mixed-capable train schedule" })
previewTrainSchedule(@Body() dto: PreviewTrainScheduleDto) {
return this.trainSchedulingService.previewTrainSchedule(dto);
}
@Post('container/preview')
@Post("container/preview")
@TrainSchedulingView()
@ApiOperation({ summary: 'Preview a container train schedule' })
@ApiOperation({ summary: "Preview a container train schedule" })
previewContainerTrainSchedule(@Body() dto: PreviewContainerTrainScheduleDto) {
return this.trainSchedulingService.previewContainerTrainSchedule(dto);
}
@Post('bulk/preview')
@Post("bulk/preview")
@TrainSchedulingView()
@ApiOperation({ summary: 'Preview a bulk train schedule' })
@ApiOperation({ summary: "Preview a bulk train schedule" })
previewBulkTrainSchedule(@Body() dto: PreviewBulkTrainScheduleDto) {
return this.trainSchedulingService.previewBulkTrainSchedule(dto);
}
@Post('container/schedules')
@Post("container/schedules")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Create a container train schedule' })
@ApiOperation({ summary: "Create a container train schedule" })
createContainerTrainSchedule(@Body() dto: CreateContainerTrainScheduleDto) {
return this.trainSchedulingService.createContainerTrainSchedule(dto);
}
@Post('bulk/schedules')
@Post("bulk/schedules")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Create a bulk train schedule' })
@ApiOperation({ summary: "Create a bulk train schedule" })
createBulkTrainSchedule(@Body() dto: CreateContainerTrainScheduleDto) {
return this.trainSchedulingService.createContainerTrainSchedule(dto);
}
@Post('schedules/:id/assign-bookings')
@Post("schedules/:id/assign-bookings")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Assign bookings to a train schedule (mixed-capable)' })
@ApiOperation({
summary: "Assign bookings to a train schedule (mixed-capable)",
})
assignBookings(
@Param('id', ParseUUIDPipe) id: string,
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: AssignBookingsDto,
) {
return this.trainSchedulingService.assignBookingsToSchedule(id, dto);
}
@Post('container/schedules/:id/assign-bookings')
@Post("container/schedules/:id/assign-bookings")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Assign container bookings to a train schedule' })
@ApiOperation({ summary: "Assign container bookings to a train schedule" })
assignContainerBookings(
@Param('id', ParseUUIDPipe) id: string,
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: AssignBookingsDto,
) {
return this.trainSchedulingService.assignBookingsToSchedule(id, dto, 'CONTAINER');
return this.trainSchedulingService.assignBookingsToSchedule(
id,
dto,
"CONTAINER",
);
}
@Post('bulk/schedules/:id/assign-bookings')
@Post("bulk/schedules/:id/assign-bookings")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Assign bulk bookings to a train schedule' })
@ApiOperation({ summary: "Assign bulk bookings to a train schedule" })
assignBulkBookings(
@Param('id', ParseUUIDPipe) id: string,
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: AssignBookingsDto,
) {
return this.trainSchedulingService.assignBookingsToSchedule(id, dto, 'BULK');
return this.trainSchedulingService.assignBookingsToSchedule(
id,
dto,
"BULK",
);
}
@Delete('schedules/:id/bookings/:bookingId')
@Delete("schedules/:id/bookings/:bookingId")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Unassign a booking from a train schedule' })
@ApiOperation({ summary: "Unassign a booking from a train schedule" })
unassignBooking(
@Param('id', ParseUUIDPipe) id: string,
@Param('bookingId', ParseUUIDPipe) bookingId: string,
@Param("id", ParseUUIDPipe) id: string,
@Param("bookingId", ParseUUIDPipe) bookingId: string,
@CurrentUser() user: AuthUserPayload,
) {
return this.trainSchedulingService.unassignBooking(id, bookingId, resolveAuthUserId(user));
return this.trainSchedulingService.unassignBooking(
id,
bookingId,
resolveAuthUserId(user),
);
}
@Delete('schedules/:id/wagons/:trainSetWagonId')
@Delete("schedules/:id/wagons/:trainSetWagonId")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Remove an empty wagon slot from a train' })
@ApiOperation({ summary: "Remove an empty wagon slot from a train" })
removeWagonSlot(
@Param('id', ParseUUIDPipe) id: string,
@Param('trainSetWagonId', ParseUUIDPipe) trainSetWagonId: string,
@Param("id", ParseUUIDPipe) id: string,
@Param("trainSetWagonId", ParseUUIDPipe) trainSetWagonId: string,
) {
return this.trainSchedulingService.removeTrainSetWagonSlot(id, trainSetWagonId);
return this.trainSchedulingService.removeTrainSetWagonSlot(
id,
trainSetWagonId,
);
}
@Patch('schedules/:id/container-items/:itemId')
@Patch("schedules/:id/container-items/:itemId")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Update a container number on a wagon slot' })
@ApiOperation({ summary: "Update a container number on a wagon slot" })
updateContainerItem(
@Param('id', ParseUUIDPipe) id: string,
@Param('itemId', ParseUUIDPipe) itemId: string,
@Param("id", ParseUUIDPipe) id: string,
@Param("itemId", ParseUUIDPipe) itemId: string,
@Body() dto: UpdateContainerItemDto,
) {
return this.trainSchedulingService.updateContainerItem(id, itemId, dto);
}
@Get('schedules/:id/unassigned-bookings')
@Get("schedules/:id/unassigned-bookings")
@TrainSchedulingView()
@ApiOperation({ summary: 'Get unassigned bookings for a schedule' })
getUnassignedBookings(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Get unassigned bookings for a schedule" })
getUnassignedBookings(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.getUnassignedBookings(id);
}
@Post('schedules/:id/assign-unassigned-booking')
@Post("schedules/:id/assign-unassigned-booking")
@TrainSchedulingManage()
@ApiOperation({
summary: 'Assign one linked unallocated booking to wagons (preserves existing assignments)',
summary:
"Assign one linked unallocated booking to wagons (preserves existing assignments)",
})
assignUnassignedBooking(
@Param('id', ParseUUIDPipe) id: string,
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: AssignUnassignedBookingDto,
) {
return this.trainSchedulingService.assignUnassignedBookingToWagons(id, dto.bookingId);
return this.trainSchedulingService.assignUnassignedBookingToWagons(
id,
dto.bookingId,
);
}
@Get('schedules/:id/composition-removals')
@Get("schedules/:id/composition-removals")
@TrainSchedulingView()
@ApiOperation({ summary: 'Get removal log for a schedule' })
getCompositionRemovals(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Get removal log for a schedule" })
getCompositionRemovals(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.getCompositionRemovals(id);
}
@Post('schedules/:id/pin-wagons')
@Post("schedules/:id/pin-wagons")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Pin physical wagons to train set slots' })
pinWagons(@Param('id', ParseUUIDPipe) id: string, @Body() dto: PinWagonsDto) {
@ApiOperation({ summary: "Pin physical wagons to train set slots" })
pinWagons(@Param("id", ParseUUIDPipe) id: string, @Body() dto: PinWagonsDto) {
return this.trainSchedulingService.pinWagons(id, dto);
}
@Post('schedules/:id/finalize')
@Post("schedules/:id/finalize")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Finalize a draft train schedule' })
finalizeSchedule(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Finalize a draft train schedule" })
finalizeSchedule(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.finalizeSchedule(id);
}
@Post('schedules/:id/dispatch')
@Post("schedules/:id/dispatch")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Dispatch a scheduled train' })
dispatchSchedule(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Dispatch a scheduled train" })
dispatchSchedule(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.dispatchSchedule(id);
}
// ---- batch / booking-window staff actions ----
@Post('schedules/:id/run-batch')
@Post("schedules/:id/run-batch")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Manually run the batch fill for a schedule' })
async runBatch(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Manually run the batch fill for a schedule" })
async runBatch(@Param("id", ParseUUIDPipe) id: string) {
await this.bookingBatchService.fillSchedule(id);
return this.bookingBatchService.getBatchBoardDetail(id);
}
@Post('schedules/:id/run-allocation')
@Post("schedules/:id/run-allocation")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Run wagon-level allocation for all eligible linked bookings' })
async runAllocation(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({
summary: "Run wagon-level allocation for all eligible linked bookings",
})
async runAllocation(@Param("id", ParseUUIDPipe) id: string) {
return this.bookingBatchService.runWagonAllocation(id);
}
@Patch('schedules/:id/booking-window')
@Patch("schedules/:id/booking-window")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Open or close a schedule booking window' })
@ApiOperation({ summary: "Open or close a schedule booking window" })
async setBookingWindow(
@Param('id', ParseUUIDPipe) id: string,
@Body('status') status: 'OPEN' | 'CLOSED',
@Param("id", ParseUUIDPipe) id: string,
@Body("status") status: "OPEN" | "CLOSED",
) {
await this.trainSchedulingService.setBookingWindow(id, status === 'CLOSED' ? 'CLOSED' : 'OPEN');
await this.trainSchedulingService.setBookingWindow(
id,
status === "CLOSED" ? "CLOSED" : "OPEN",
);
return this.trainSchedulingService.getContainerTrainScheduleById(id);
}
@Post('bookings/:bookingId/mark-paid')
@Post("bookings/:bookingId/mark-paid")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Staff: mark a reserved booking paid and allocate it now' })
async markBookingPaid(@Param('bookingId', ParseUUIDPipe) bookingId: string) {
@ApiOperation({
summary: "Staff: mark a reserved booking paid and allocate it now",
})
async markBookingPaid(@Param("bookingId", ParseUUIDPipe) bookingId: string) {
await this.bookingBatchService.markPaid(bookingId);
return { ok: true };
}
@Post('bookings/:bookingId/expire')
@Post("bookings/:bookingId/expire")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Staff: expire a reservation and free its capacity' })
async expireBooking(@Param('bookingId', ParseUUIDPipe) bookingId: string) {
@ApiOperation({
summary: "Staff: expire a reservation and free its capacity",
})
async expireBooking(@Param("bookingId", ParseUUIDPipe) bookingId: string) {
await this.bookingBatchService.expireReservation(bookingId);
return { ok: true };
}
@Post('bookings/:bookingId/move-schedule')
@Post("bookings/:bookingId/move-schedule")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Re-point a booking to another OPEN same-route schedule' })
@ApiOperation({
summary: "Re-point a booking to another OPEN same-route schedule",
})
async moveBookingSchedule(
@Param('bookingId', ParseUUIDPipe) bookingId: string,
@Body('trainScheduleId', ParseUUIDPipe) trainScheduleId: string,
@Param("bookingId", ParseUUIDPipe) bookingId: string,
@Body("trainScheduleId", ParseUUIDPipe) trainScheduleId: string,
) {
await this.bookingBatchService.moveToSchedule(bookingId, trainScheduleId);
return { ok: true };
}
@Get('schedules/:id/checkpoints')
@Get("schedules/:id/checkpoints")
@TrainSchedulingView()
@ApiOperation({ summary: 'Get the tracking corridor + logged checkpoints for a train' })
getScheduleCheckpoints(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({
summary: "Get the tracking corridor + logged checkpoints for a train",
})
getScheduleCheckpoints(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.getScheduleCheckpoints(id);
}
@Post('schedules/:id/checkpoints')
@Post("schedules/:id/checkpoints")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Log the train passing a station (final station triggers arrival)' })
@ApiOperation({
summary: "Log the train passing a station (final station triggers arrival)",
})
recordCheckpoint(
@Param('id', ParseUUIDPipe) id: string,
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: RecordCheckpointDto,
) {
return this.trainSchedulingService.recordCheckpoint(id, dto);
}
@Post('schedules/:id/arrive')
@Post("schedules/:id/arrive")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Mark a dispatched train arrived (move assets to destination yard, free assets)' })
arriveSchedule(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({
summary:
"Mark a dispatched train arrived (move assets to destination yard, free assets)",
})
arriveSchedule(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.arriveSchedule(id);
}
@Get('container/schedules')
@Get("container/schedules")
@TrainSchedulingView()
@ApiOperation({ summary: 'List container train schedules' })
@ApiOperation({ summary: "List container train schedules" })
getContainerTrainSchedules() {
return this.trainSchedulingService.getContainerTrainSchedules();
}
@Get('bulk/schedules')
@Get("bulk/schedules")
@TrainSchedulingView()
@ApiOperation({ summary: 'List bulk train schedules' })
@ApiOperation({ summary: "List bulk train schedules" })
getBulkTrainSchedules() {
return this.trainSchedulingService.getContainerTrainSchedules();
}
@Get('container/schedules/:id')
@Get("container/schedules/:id")
@TrainSchedulingView()
@ApiOperation({ summary: 'Get container train schedule detail' })
getContainerTrainScheduleById(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Get container train schedule detail" })
getContainerTrainScheduleById(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.getContainerTrainScheduleById(id);
}
@Get('bulk/schedules/:id')
@Get("bulk/schedules/:id")
@TrainSchedulingView()
@ApiOperation({ summary: 'Get bulk train schedule detail' })
getBulkTrainScheduleById(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Get bulk train schedule detail" })
getBulkTrainScheduleById(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.getContainerTrainScheduleById(id);
}
@Post('container/schedules/:id/cancel')
@Post("container/schedules/:id/cancel")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Cancel container train schedule' })
cancelTrainSchedule(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Cancel container train schedule" })
cancelTrainSchedule(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.cancelTrainSchedule(id);
}
@Post('bulk/schedules/:id/cancel')
@Post("bulk/schedules/:id/cancel")
@TrainSchedulingManage()
@ApiOperation({ summary: 'Cancel bulk train schedule' })
cancelBulkTrainSchedule(@Param('id', ParseUUIDPipe) id: string) {
@ApiOperation({ summary: "Cancel bulk train schedule" })
cancelBulkTrainSchedule(@Param("id", ParseUUIDPipe) id: string) {
return this.trainSchedulingService.cancelTrainSchedule(id);
}
}