Commit Graph

948 Commits

Author SHA1 Message Date
Nathnael
ef74bc442a fix: prevent the backoffice from approve the user before he submits 2026-07-17 08:54:24 +00:00
Hagernesh
fc636fbe4f fix(warehouse): scope the arrival GRN stamp to EXPORT only
The previous commit made autoUnloadArrived and unloadBooking raise a GRN for any
direction, which changed import behaviour. Import keeps its own GRN handling
(autoUnloadArrivedBookings) and is left exactly as it was. Both paths now stamp a
GRN only when the booking is EXPORT — the direction whose cargo needs one to be
loaded onto a train. Import and domestic behave as before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 08:01:58 +00:00
Hagernesh
a95667fde4 fix(warehouse): raise a GRN on every warehouse receipt
Requiring a GRN before loading only works if every path into the warehouse
issues one. Two did not: autoUnloadArrived and unloadBooking created RECEIVED
inventory with a null grn_number, so cargo that genuinely arrived — by first
mile or self haul — would have been stuck un-loadable behind the new gate.

Both now stamp a GRN, derived from the booking's trade direction, matching
receive/bulkReceive/autoUnloadArrivedBookings. unloadBooking keeps an
already-issued GRN when it re-unloads an existing row rather than reissuing one.

Every path that creates warehouse inventory now issues a GRN, so the chain is
seamless: booking arrives (first mile or self haul) -> received -> GRN -> loadable
onto its allocated wagon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 08:01:58 +00:00
Hagernesh
a26fa61d66 feat(warehouse): require a GRN before export cargo can be loaded onto a train
The export chain is: paid -> received into the warehouse -> GRN raised on arrival
-> loaded onto the allocated wagon. Receipt was already structural (the inventory
row only exists once receive() runs) and the wagon was already required, but the
GRN was merely displayed, never enforced — so cargo could be loaded and
dispatched without one.

- loadable now also requires a GRN, so the queue won't offer un-GRN'd cargo.
- loadItemsOntoTrain skips items with no GRN, so the rule holds server-side and
  a hand-made API call can't bypass it.
- Read the GRN from inv.grn_number (what receive() stamps) and fall back to the
  note only for legacy/seeded rows; it previously read the note alone, which the
  real receive path merely mirrors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 08:01:57 +00:00
Hagernesh
d9db4cbc0c fix(train-scheduling): scope the not-loaded dispatch guard to EXPORT only
The guard fired on every dispatch. Loading out of an origin warehouse is an
export concept — import cargo isn't loaded from a warehouse, so its warehouse
inventory says nothing about what's aboard and the check would have blocked
legitimate import dispatches. Derive the route direction (reusing
deriveTradeDirection, as the warehouse loading queue does) and return early for
anything that isn't EXPORT. Import and domestic behave exactly as before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 08:01:57 +00:00
Hagernesh
2798fed6d8 fix(train-scheduling): block dispatch when allocated cargo is not loaded
dispatchSchedule guarded status, Djibouti departure rules, locomotives and
wagons — but never checked the cargo. A train could be dispatched while the
bookings allocated to it sat received in the warehouse, silently leaving them
behind. Dispatch now refuses when an allocated booking has warehouse inventory
in RECEIVED/STORED/READY_FOR_LOADING, naming the bookings and pointing at the
two ways out: load them, or drop the wagon allocation so they ride a later
train. Bookings with no inventory at all are not blocked — allocating a wagon
before the goods arrive is normal planning.

Also drops RESERVED from the Load-to-Train filters: reserved stock is not
awaiting loading.

The sched_bookings CTE moves to common/schedule-bookings.sql so the warehouse
loading queue and this dispatch guard resolve a train's bookings identically —
if they drift, a train departs leaving cargo the warehouse still expects to load.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 08:01:57 +00:00
Hagernesh
e115b9b753 fix(warehouse): resolve Load-to-Train bookings from wagon allocation
The Load-to-Train queue was permanently empty for real traffic. loadableTrains()
and trainLoadableItems() gated on freight.train_schedule_bookings, but nothing in
the application writes that table — only the demo seeders do. Real wagon
allocation writes wagon_booking_allocations, reached via
train_schedules -> train_sets -> train_set_wagons, so an allocated export booking
never satisfied the EXISTS gate and no train ever appeared.

Both queries now resolve a schedule's bookings through a shared sched_bookings
CTE that unions the wagon-allocation chain with train_schedule_bookings, so real
allocations show up and the seeded demo scenarios keep working. The panel already
groups the returned rows by booking with their containers, so the queue now lists
the train, its bookings and their containers for selection.

Export flow this serves: booked -> paid -> received at the warehouse (first-mile
or self-haul) -> GRN -> loaded onto the wagons allocated to the booking.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 08:01:57 +00:00
marshal
2def8f9b0e Merge pull request #753 from Tria-plc/freight_feature/usermanagement
Comment out payment event handling for local demos in BillingService
2026-07-17 10:49:46 +03:00
Marshal
5a1e0dba4d Comment out payment event handling for local demos in BillingService 2026-07-17 07:43:17 +00:00
Nathnael Wondisha
f769d97135 Merge pull request #752 from Tria-plc/freight/feat/fixes-v1
Freight/feat/fixes v1
2026-07-17 10:01:44 +03:00
Marshal
71507b27fd changes 2026-07-16 20:09:59 +00:00
Marshal
35c53e3f36 changes 2026-07-16 20:03:35 +00:00
Nathnael
e626e1db63 Merge branch 'dev' into freight/feat/fixes-v1 2026-07-16 13:23:40 +00:00
marshal
1a3fa4bc5a Merge pull request #738 from Tria-plc/freight_feature/usermanagement
fix issue
2026-07-16 16:00:07 +03:00
Marshal
b50adc4666 fix issue 2026-07-16 12:59:28 +00:00
Nathnael Wondisha
8ee3f13bdb Merge pull request #735 from Tria-plc/freight/feat/payment-revert
fix: revert the testing
2026-07-16 15:13:30 +03:00
Nathnael
f71bbbf782 feat: setup account page for customer and centeralize the otps and phone usages to use the iam user 2026-07-16 12:08:45 +00:00
Nathnael
c19e4260c1 fix: revert the testing 2026-07-16 12:04:58 +00:00
marshal
35a9d25aaa Merge pull request #734 from Tria-plc/freight_feature/usermanagement
fix u=issue
2026-07-16 15:02:40 +03:00
Marshal
e8e12c1363 fix u=issue 2026-07-16 12:02:11 +00:00
Hagernesh
d5182c5d85 feat(last-mile): wire multi-container assignment, bulk drawdown + EDR exit papers
Frontend for the per-truck EDR backend:

- Assign modal takes a container LOAD per truck (MultiSelect, max 2) instead of a
  single container, so a truck can carry one 40ft or two 20ft. Sends
  containerNumbers[]; the API enforces the size rule.
- requiredVehicles is now size-aware: a 40ft fills a truck (1 each), two 20ft
  share one. It previously assumed ceil(containers / 2) regardless of size, so a
  2x40ft booking under-counted the trucks needed.
- Bulk bookings show the drawdown in the assign modal — remaining vs total
  tonnage, what's been hauled, and a "fully hauled" state when it reaches 0.
- New "Truck exit papers" row action opens a per-truck list (plate, containers,
  arrival, exit, net weight) with a per-truck exit-paper download.
- last-mile findAll/findById now load each assignment's containers so the UI can
  hydrate a truck's load.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:24:22 +00:00
Hagernesh
ff49554cc2 feat(last-mile): per-truck EDR arrival/exit, exit paper, bulk drawdown, departure notify
EDR last-mile is multi-truck but was modelled as one: setVehicles accepted any
number of trucks with no validation, arrival/delivery were stamped once per
last_mile record (N trucks shared one timestamp), EDR trucks got no exit paper,
and the per-truck EDR handover never happened because deliver() resolved the
plate via last_mile_container_allocations — a table nothing writes.

- Migration 2260000000000: per-truck arrived_at/departed_at/gross_weight_tons/
  net_weight_tons on last_mile_vehicle_assignments, plus a
  last_mile_vehicle_containers child table (a truck holds 1x40ft OR 2x20ft, so
  the single container_number scalar could not express a load). Weights are
  TONNES and named accordingly — the older gross_weight_kg lies about its unit.
- setVehicles: enforce the size rule (one 40ft, or two 20ft), container
  membership, one-container-one-truck, and never more trucks than containers.
  Bulk carries no containers and is instead gated on tonnage remaining.
- Bulk drawdown: remainingTonsForBooking = booking VGM minus the net weighed off
  every departed truck (both tonnes, no conversion), exposed as
  GET /last-mile/booking/:bookingId/remaining-tons.
- release() now stamps the EDR truck's own arrival and exit (matched by plate, so
  it works for bulk too) alongside the existing customer-truck stamp. The exit
  weighing itself is untouched.
- New GET /warehouse-inventory/edr-truck-exit-paper/:assignmentId — per-truck
  exit paper for EDR trucks. Deliberately not signature-gated: EDR handovers are
  generated at delivery, after the truck has left.
- deliver(): resolve the handover plate from the truck's own containers instead
  of the dead allocations table, so EDR handovers are genuinely per-truck.
- Notify the customer (portal inbox + SMS/email) when a truck leaves — one hook
  in release() covers both self-haul and EDR, since it is the single exit path.

Self-haul is intentionally unchanged (one booking-level handover signed once).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 09:24:22 +00:00
Nathnael Wondisha
68f6a393a9 Merge pull request #730 from Tria-plc/freight/feat/fixes-v1
Freight/feat/fixes v1
2026-07-16 11:59:01 +03:00
Nathnael
6dde17fa4d fix: premature payable invoice 2026-07-16 08:38:49 +00:00
natib21
af57ffdda4 Merge branch 'dev' of github.com:Tria-plc/edr-platform into freight/feature/user_management_UI 2026-07-16 08:13:57 +00:00
natib21
4a04aa7e97 fic 2026-07-16 08:13:22 +00:00
Nathnael Wondisha
2db321b37a Merge pull request #724 from Tria-plc/freight/feat/fixes-v1
Freight/feat/fixes v1
2026-07-16 10:59:36 +03:00
yaschalew10
b6d71ccc57 Merge pull request #723 from Tria-plc/freight/feature/user_management_UI
Freight/feature/user management UI
2026-07-16 10:50:34 +03:00
natib21
9d53552f95 Merge branch 'dev' of github.com:Tria-plc/edr-platform into freight/feature/user_management_UI 2026-07-16 07:48:27 +00:00
natib21
a4b3309412 add seed 2026-07-16 07:43:54 +00:00
Nathnael
08faf56c4f fix: payment autopay on the payment init added for testing 2026-07-16 06:43:30 +00:00
marshal
50d5ce5ad9 Merge pull request #721 from Tria-plc/freight_feature/usermanagement
fix issue
2026-07-16 04:06:52 +03:00
Marshal
fe29b38377 fix issue 2026-07-16 01:05:57 +00:00
marshal
ea22f38adf Merge pull request #720 from Tria-plc/freight_feature/usermanagement
fix issue
2026-07-16 03:34:14 +03:00
Marshal
41fe04652f fix issue 2026-07-16 00:33:31 +00:00
marshal
67bc835458 Merge pull request #719 from Tria-plc/freight_feature/usermanagement
implement empty-container return service: add return quantity handlin…
2026-07-16 02:06:08 +03:00
Marshal
234a74e812 implement empty-container return service: add return quantity handling, update related DTOs, services, and UI components 2026-07-15 22:48:04 +00:00
marshal
e3fccbd24d Merge pull request #717 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-07-15 23:18:55 +03:00
Marshal
fc44eee25e implement update train details feature: add DTO, service method, and UI modal for editing train name and run numbers 2026-07-15 20:14:39 +00:00
Hagernesh
2647776d19 feat(warehouse): stamp actor as display name instead of UUID
Add actorLabel(user) — resolves the authenticated user to a readable name
(name → username → email → id) — and use it for the performed_by audit stamp on
every warehouse action, so the activity log shows a person, not a UUID. The
freight DB has no users table to join, so the name is stamped at write time.
approve-delivery keeps the raw user id (it is an id argument, not the audit
label). Existing rows keep their prior value; this applies going forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:24:05 +00:00
Hagernesh
2044312d93 feat(warehouse): stamp authenticated user as action actor (performedBy)
Warehouse mutation endpoints now record the JWT-authenticated user as the actor
(user.id) instead of trusting a client-supplied performedBy string, unlocking
per-operator productivity metrics and a trustworthy audit trail. Covers receive,
receive-bulk, reserve, store, ready-for-loading, ready-for-pickup, load-onto-
train, bulk-dispatch, dispatch, deliver, gate-clearance, approve-delivery, the
Djibouti/import auto-unload actions, and fee-invoice generation. The prior
client value is kept only as a fallback for unauthenticated/internal calls.

move/load do not yet carry an actor (their DTOs have no performedBy) — separate
follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:51:21 +00:00
Marshal
d7d9db9c3a changes 2026-07-15 14:27:00 +00:00
Hagernesh
ac90b04be0 feat(warehouse): P2 dashboard — gate/dock throughput + live auto-refresh
- gateStats(): items cleared through the gate today, average arrival→gate
  turnaround (hours, 30d), and clearances per hour over the last 24h → new
  GateThroughputCard in the dashboard Performance section.
- Live board: every dashboard query (dashboard, ops, throughput, dwell, cycle,
  on-time, zone occupancy, accrual, gate) now auto-refreshes on a 60s interval,
  with a "Live" indicator in the header.

New endpoint GET /warehouse-inventory/gate-stats (guarded). Deferred (need
upstream data): capacity forecast, labour productivity, WebSocket push, yard map.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:26:02 +00:00
Hagernesh
fc4aadbc57 feat(warehouse): P1 dashboard analytics — dwell/aging, cycle-time + on-time, live deltas
Adds the operational-performance layer to the warehouse cockpit:

- Dwell time & aging: dwellStats() (avg + 0-3/4-7/8-14/15+ buckets over
  in-warehouse items) → DwellAgingCard histogram.
- Cycle time & on-time: cycleStats() (arrived→ready→loaded→dispatched stage
  averages + dock-to-dispatch) and onTimeDispatchStats() (share of items that
  left before their storage free-days expired, resolved via the fee engine's
  own rule matching) → CycleTimeCard.
- Live tiles: opsStats() now returns receivedYesterday; KpiStrip renders an
  optional ▲/▼ delta, and the ops strip shows received-today vs yesterday.

New endpoints: GET /warehouse-inventory/{dwell-stats,cycle-stats} and
/warehouse-fees/on-time-dispatch (all guarded). New "Performance" section on
WarehouseDashboardPage. On-time reads N/A when there is no sample / no active
storage rule.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 13:55:39 +00:00
marshal
6391ba837a Merge pull request #707 from Tria-plc/freight_feature/usermanagement
changes
2026-07-15 16:30:28 +03:00
Marshal
19c9da28ae changes 2026-07-15 13:29:01 +00:00
Hagernesh
2e22b72e27 feat(warehouse): assemble dashboard cockpit + server-side throughput series
- WarehouseDashboardPage now composes the ops KPI strip, lifecycle cards, flow
  charts, zone-occupancy heatmap and demurrage/accrual exceptions into one
  control-tower view; drop the redundant lifecycle donut.
- New GET /warehouse-inventory/throughput (date_trunc time series) replaces the
  client-side buildTrend that downloaded the entire inventory list to bucket it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 12:27:53 +00:00
SennayT
f9706c9fb0 refactor: separate base image configuration into Dockerfile.base for improved build management 2026-07-15 10:51:35 +00:00
SennayT
3416585a01 add puppeteer support 2026-07-15 13:42:42 +03:00
marshal
7700aa6358 Merge pull request #701 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-07-15 13:32:37 +03:00