feat: add Container Returns page with EDR/Customer filter

Separate page for tracking empty container returns by type: EDR returns
(empty containers from EDR first-mile) or Customer returns (customer
self-haul). Segmented control filter, expandable booking rows showing
containers, modal to record return with warehouse selection. Accessible
via sidebar menu under Import Operations.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Hagernesh
2026-07-30 13:58:30 +00:00
parent 154b7d11d5
commit c0d6b1a1c5
3 changed files with 513 additions and 3 deletions

View File

@@ -415,15 +415,22 @@ export function planWagonsWithStock(params: {
* sequenceNos, the snapshot re-sorts by them, and the board/allocation views all
* read them — so the stored train order and the schedule order stay identical,
* just reversed. A false/absent flag returns the plan unchanged.
*
* Only the NUMBERS flip — the array itself stays in packing order. Container
* placements are generated by walking the container units in booking order
* against getContainerSlotSequenceNos(plan) in array order, then matched back to
* their allocation by `sequenceNo:bookingId`. Reordering the array here broke
* that pairing on every reversed schedule: unit 1 was handed the number of the
* slot holding the LAST booking, the match missed, and persistAllocationsAndLoads
* silently dropped every container item — which is why a reversed export train
* printed a marshalling doc with no container numbers and 0/0 container counts.
*/
export function applyWagonOrderReversal(
plan: WagonPlanSlot[],
reverse: boolean | null | undefined,
): WagonPlanSlot[] {
if (!reverse) return plan;
return [...plan]
.reverse()
.map((slot, index) => ({ ...slot, sequenceNo: index + 1 }));
return plan.map((slot, index) => ({ ...slot, sequenceNo: plan.length - index }));
}
/** Unbounded stock — used to compute pure demand for availability reporting. */