implement update train details feature: add DTO, service method, and UI modal for editing train name and run numbers

This commit is contained in:
Marshal
2026-07-15 20:14:39 +00:00
parent d7d9db9c3a
commit fc44eee25e
44 changed files with 970 additions and 14 deletions

View File

@@ -1,5 +1,6 @@
import {
BadRequestException,
ConflictException,
forwardRef,
Inject,
Injectable,
@@ -714,6 +715,11 @@ export class BookingTransitionService {
files: Express.Multer.File[],
): Promise<Booking> {
const booking = await this.bookingsService.findById(bookingId);
if (booking.status === "AWAITING_CLEARANCE_PAYMENT") {
throw new ConflictException(
"The customs clearance service fee for this shipment has not been paid yet — pay it from the portal to unlock document upload.",
);
}
assertBookingStatus(booking, [
"AWAITING_DOCUMENTS",
"DOCUMENTS_UNDER_REVIEW",

View File

@@ -46,6 +46,7 @@ export const BOOKING_STATUSES = [
'CONTRACT_ACTIVE',
'CONTRACT_CLOSED',
// Post counter-sign document-clearance gate (GL workflow).
'AWAITING_CLEARANCE_PAYMENT', // clearance fee invoiced, unpaid — docs locked
'AWAITING_DOCUMENTS',
'DOCUMENTS_UNDER_REVIEW',
'CLEARANCE_READY',
@@ -521,6 +522,10 @@ export class Booking extends BaseEntity {
@Column({ name: 'clearance_current_phase', type: 'varchar', length: 40, nullable: true })
clearanceCurrentPhase?: string | null;
/** When the prepaid customs clearance service fee settled (GENERAL + customs). */
@Column({ name: 'clearance_fee_paid_at', type: 'timestamptz', nullable: true })
clearanceFeePaidAt?: Date | null;
@Column({ name: 'duty_required', type: 'boolean', nullable: true })
dutyRequired?: boolean | null;