mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
- Removed maxWagonsPerTrain from WagonType entity and related DTOs. - Updated containerWagonsForLines function to calculate required wagons based on container lines more accurately. - Added unit tests for containerWagonsForLines to ensure correct calculations. - Adjusted related services and scripts to reflect the removal of maxWagonsPerTrain. - Enhanced booking and contract components to use new status labels for better user experience. - Implemented validation for unique container numbers in shipment forms.
75 lines
4.0 KiB
Markdown
75 lines
4.0 KiB
Markdown
# Priority & Batch Window Flow (Import, Freight)
|
|
|
|
Export = no batch, no priority. Pure first-come-first-served (`booking-batch.service.ts:462-467, 625-628`). Everything below is import only.
|
|
|
|
## Step by step
|
|
|
|
**1. Booking submitted → priority score computed**
|
|
`booking-transition.service.ts:110-111,196-197` → `booking-pricing.service.ts:403-407` `computeSubmitPriorityScore()` → `rule-engine.service.ts:118`.
|
|
- Government booking: `+50,000` (`government-priority.constants.ts:2`, applied `rule-engine.service.ts:201`)
|
|
- Plus cargo/weight modifiers
|
|
- Stored on `booking.priorityScore`
|
|
|
|
**2. Window opens (PRE_WINDOW → OPEN)**
|
|
Cron tick every 10s: `booking-window.service.ts:63` → `advanceImport` → `booking-window.service.ts:232-251`.
|
|
Times computed by `computeImportWindowTimes` (`batch-window.util.ts:248-283`).
|
|
|
|
**3. Customers book during OPEN**
|
|
Booking lands as:
|
|
- Commercial → `FULLY_EXECUTED`
|
|
- Government → `APPROVED/PAID` (skips contract flow)
|
|
|
|
**4. Window closes (OPEN → DOC_REVIEW)**
|
|
`booking-window.service.ts:254-268`. Staff review docs for `docReviewMinutes`.
|
|
|
|
**5. Doc review ends**
|
|
Staff `completeDocReview()` (`booking-window.service.ts:124-159`) or timeout → `booking-window.service.ts:270-295`.
|
|
Before batch runs: `expireUnacceptedForRouteDay` (`booking-batch.service.ts:1853-1883`) kills never-accepted bookings so they can't compete.
|
|
|
|
**6. Batch fill runs**
|
|
`processRouteDay` → `fillRouteDay` (`booking-batch.service.ts:1138-1319`), or single-schedule `fillSchedule` (`:1018-1128`).
|
|
|
|
- Pool pulled pre-sorted: `findBatchPool`/`findBatchPoolByCorridorDay` (`bookings.repository.ts:991-1008, 1055-1083`)
|
|
`ORDER BY is_government DESC, priority_score DESC, fully_executed_at ASC, created_at ASC`
|
|
- Consolidated pairs grouped as one atomic unit: `groupConsolidatedPool` (`:1962-1987`) — never split.
|
|
- Greedy placement, earliest-departing fitting train first: loop at `:1218-1306`.
|
|
- No fit + government booking → `preemptForGovernment` (`:1891-1910`): bumps lowest-`priorityScore` commercial victim first, only if legs overlap (`:1920`).
|
|
- No fit + commercial import (GENERAL/ONE_TIME) → maybe partial "split" offer: `maybeOfferPartial`/`isSplitEligible` (`:1326-1370`).
|
|
- Still no fit → stays pooled, `notifier.unplaced` (`:1278-1280`).
|
|
|
|
**7. Placed bookings get reserved/allocated**
|
|
- Commercial: `reserve()` (`:1673-1703`) → `SELECTED_FOR_BATCH`, payment deadline set, DOC_REVIEW→PAYMENT (`booking-window.service.ts:275-294`).
|
|
- Government: `allocate()` directly (`:1706-1746`), no payment step.
|
|
|
|
**8. Payment phase ends**
|
|
`booking-window.service.ts:297-309` → `settleDueReservations` → `settleReserved` (`:1437-1491`):
|
|
- paid → allocated
|
|
- unpaid → expired, capacity freed
|
|
|
|
Then `concludeCycle` (`:315-373`):
|
|
- Train full → `DONE` + auto-finalize (`:320-329`)
|
|
- Not full → reopen same/next day (`nextCycleOpensAt` / office hours, `:331-372`, `batch-window.util.ts:217-224`) or `DONE` if no cycle fits before departure.
|
|
|
|
**9. Backstop**
|
|
`settleOverdueReservations` (`booking-window.service.ts:388-406`) catches any reservation whose deadline passed outside the normal tick.
|
|
|
|
## Phase enum
|
|
|
|
`PRE_WINDOW → OPEN → DOC_REVIEW → PAYMENT → (reopen PRE_WINDOW | DONE)`
|
|
(`booking-window.config.ts:27-34`)
|
|
|
|
## What decides priority
|
|
|
|
1. `is_government` — always first, both in SQL sort and `compareSchedulingPriority` util (`compare-scheduling-priority.util.ts:9-23`)
|
|
2. `priority_score` DESC (rule engine: government bonus + cargo/weight modifiers)
|
|
3. `fully_executed_at` ASC (earlier wins)
|
|
4. `created_at` ASC
|
|
|
|
## Edge cases
|
|
|
|
- Government preemption only bumps if legs overlap; picks lowest-priority victim first.
|
|
- Consolidated pairs are both-or-neither, never split (`:1326-1334, 1793`).
|
|
- Only GENERAL/ONE_TIME import bookings are eligible for partial "split" offers.
|
|
- Per-unit try/catch around reserve — one failure can't cause silent trickle/stagger allocation (comment at `:1283-1288`).
|
|
- Each train freezes its own rule snapshot at window-open time, not live config (`booking-window.service.ts:85-93`).
|