mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 21:15:41 +00:00
feat: enhance train scheduling and contract management features
- Added StationWorkControls to manage loading/unloading phases in TrainScheduleV2DetailPage. - Implemented API endpoints for recording station work and managing wagon detach requests. - Updated contract templates to include Ethiopian customs handling options. - Enhanced shipment forms to collect customs clearing agent details for without-customs bookings. - Introduced NUMBER_OF_WAGONS as a unit of measure for bulk cargo, allowing customers to specify wagon counts. - Improved validation for customs clearing agent information in shipment forms. - Updated various components and services to accommodate new features and ensure data integrity.
This commit is contained in:
@@ -591,6 +591,24 @@ export class BookingWagonCancellationService {
|
||||
this.logger.error(
|
||||
`Consolidation-lapse cancellation failed for paid booking ${payload.paidBookingId}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
);
|
||||
// A silent failure here leaves a PAID half-wagon booking boarding alone
|
||||
// (BK-2026-000201: no LIVE IMPORT 20ft CANCELLATION_FEE rate — the fee
|
||||
// pricing threw and the booking stayed PAID). Scream to staff so it is
|
||||
// fixed and the booking cancelled by hand instead of shipping.
|
||||
try {
|
||||
const failed = await this.bookingsRepository.findById(
|
||||
payload.paidBookingId,
|
||||
);
|
||||
if (failed) {
|
||||
this.notifyStaff(
|
||||
failed,
|
||||
'Consolidation-lapse cancellation FAILED — action needed',
|
||||
`${failed.reference}: its consolidation partner lapsed unpaid, but the automatic cancellation failed: ${err instanceof Error ? err.message : String(err)}. Fix the cause (usually a missing LIVE per-wagon CANCELLATION_FEE rate for this trade direction + container size), then cancel the whole booking manually so the fee is invoiced and its wagons are freed.`,
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
// Notification is best-effort — the error log above already fired.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -359,6 +359,12 @@ export class Booking extends BaseEntity {
|
||||
@Column({ name: 'customs_clearing_agent', type: 'varchar', length: 200, nullable: true })
|
||||
customsClearingAgent?: string | null;
|
||||
|
||||
@Column({ name: 'customs_clearing_agent_email', type: 'varchar', length: 200, nullable: true })
|
||||
customsClearingAgentEmail?: string | null;
|
||||
|
||||
@Column({ name: 'customs_clearing_agent_phone', type: 'varchar', length: 50, nullable: true })
|
||||
customsClearingAgentPhone?: string | null;
|
||||
|
||||
@Column({ name: 'equipment_return', type: 'varchar', length: 20 })
|
||||
equipmentReturn!: string;
|
||||
|
||||
@@ -411,6 +417,23 @@ export class Booking extends BaseEntity {
|
||||
@Column({ name: 'bulk_total_weight_tons', type: 'numeric', precision: 12, scale: 3, nullable: true })
|
||||
bulkTotalWeightTons?: number | null;
|
||||
|
||||
/**
|
||||
* NUMBER_OF_WAGONS bulk only: the wagon count the customer asked for at
|
||||
* booking. Allocation and PER_WAGON pricing use this count verbatim, and the
|
||||
* cargo weight spreads evenly across it (weight ÷ count per wagon — validated
|
||||
* against wagon capacity at creation). Null for every other cargo unit.
|
||||
*/
|
||||
@Column({ name: 'bulk_requested_wagons', type: 'int', nullable: true })
|
||||
bulkRequestedWagons?: number | null;
|
||||
|
||||
/**
|
||||
* NUMBER_OF_WAGONS bulk only: optional informational item count entered with
|
||||
* the weight. Never prices or sizes anything (unlike PER_ITEM, where the
|
||||
* count lives in cargoTotalWeightVgm).
|
||||
*/
|
||||
@Column({ name: 'bulk_item_count', type: 'int', nullable: true })
|
||||
bulkItemCount?: number | null;
|
||||
|
||||
@Column({ name: 'is_hazardous', type: 'boolean', default: false })
|
||||
isHazardous!: boolean;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user