Commit Graph

3462 Commits

Author SHA1 Message Date
Hagernesh Tadesse
2c16c50701 Merge pull request #840 from Tria-plc/intercity-load-unload
Fix Multiple truck self haul null plates
2026-07-20 15:57:10 +03:00
Hagernesh
7b777792e3 feat(warehouse): expand an inventory row to see which containers ride which truck
The inventory table has one row per inventory item, so on a self-haul booking
with several trucks there was no way to tell which container sat on which
truck without opening a document. The plate column now lists every plate, but
not the mapping.

Each row with a customer truck gets a chevron that opens a per-truck
breakdown: plate, driver, type, the containers it carries, and whether it has
arrived. Bulk trucks show "Bulk" — they haul loose tonnage, not containers.

The breakdown fetches only when opened, so a table nobody expands costs no
extra requests, and it reuses the existing per-booking trucks endpoint rather
than widening the inventory query.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 12:54:10 +00:00
Hagernesh
0c0de284b0 feat(warehouse): show the trucks in the yard, not just a count of them
Multi-truck self-haul had no list anywhere on the warehouse side. The ops
dashboard counted trucks on site and offered no way to open the list, and
the inventory table showed a blank plate on exactly the bookings that have
several trucks: it read booking.customer_truck_plate_number, which
multi-truck self-haul leaves null because plates live in
customer_truck_assignments. Booking BK-2026-000033 has a truck and a driver
on file and displayed neither.

Adds a Trucks on Site page listing every truck that has arrived and not yet
departed, across bookings, with plate, driver, booking, customer, containers
and dwell time. It covers both haulage paths because the gate does — a
customer's own truck and an EDR last-mile truck reach the same barrier — and
flags anything sitting over four hours. It lives under Warehouse Management
rather than Imports or Exports, since the yard is not per-direction.

The inventory queries now read plates and drivers from the assignments and
keep the booking columns as the fallback for single-truck bookings written
before that table existed.

Both new statements were EXPLAIN-validated against the live schema; the
plate fix returns the data that was previously null.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 12:54:10 +00:00
robiman
cd80a29602 Merge pull request #839 from Tria-plc/alpha
Added payment discrepancy report
2026-07-20 15:52:59 +03:00
Roba Boru
6ea2216aeb Merge branch 'dev' of https://github.com/Tria-plc/edr-platform into alpha 2026-07-20 15:50:42 +03:00
Roba Boru
bc4c085d95 Merge branch 'alpha' of https://github.com/Tria-plc/edr-platform into alpha 2026-07-20 15:50:29 +03:00
Roba Boru
1e7324d276 Added payment discrepancy report 2026-07-20 15:50:03 +03:00
Abubeker Yasin
fd55b5c253 Merge pull request #838 from Tria-plc/alpha
fix: (payment ) store fractional payment intent amounts
2026-07-20 15:49:22 +03:00
Abubeker Yasin
800e1e21ed fix: (payment ) store fractional payment intent amounts 2026-07-20 15:47:37 +03:00
marshal
b9b2075207 Merge pull request #837 from Tria-plc/freight_feature/usermanagement
contrat nad booking modification
2026-07-20 15:25:51 +03:00
Marshal
b90afadfba contrat nad booking modification 2026-07-20 12:24:58 +00:00
Nathnael Wondisha
0adaba9ca1 Merge pull request #836 from Tria-plc/freight/feat/fixes-v1
Freight/feat/fixes v1
2026-07-20 15:13:49 +03:00
Nathnael
804c72f14a Merge branch 'dev' into freight/feat/fixes-v1 2026-07-20 12:12:30 +00:00
Nathnael
0549a88d57 feat: otp double sending 2026-07-20 12:10:49 +00:00
Nathnael
aa02700e4c fix: disable global errors 2026-07-20 11:52:08 +00:00
Roba Boru
5e9feab869 Merge branch 'main' of https://github.com/Tria-plc/edr-platform into alpha 2026-07-20 14:45:37 +03:00
Hagernesh Tadesse
1570c8e4bf Merge pull request #835 from Tria-plc/intercity-load-unload
Truck assignment on Bulk and Container
2026-07-20 14:44:10 +03:00
Nathnael
d60f354e9f fix: reuse the locaiton too 2026-07-20 11:44:07 +00:00
Hagernesh
c8a70593cf fix(mile): apply one truck-load rule to customer and EDR haulage alike
A truck holds one 40ft or two 20ft, a container booking takes no more trucks
than it has containers, and a bulk booking takes trucks until its tonnage is
hauled away. The same physics whoever drives, but the rule was written out
four times — addTruck, updateTruck, departTruck and LastMileService — beside
a byte-identical container-size query. Copies drift: that is how the
self-haul guard ended up enforced on one side only.

The bulk cap was the real gap. EDR summed net_weight_tons of departed trucks
and refused another once the booking was drawn down. The customer side had
no cap at all: for bulk it skipped straight past every check, so a self-haul
bulk booking could take unlimited trucks.

It could not simply reuse the EDR sum. customer_truck_assignments had no net
and no tare, only a gross_weight_kg that holds tonnes despite its name and
that nothing in the live flow ever wrote — release() recorded exit weights
against the EDR table alone, which is why all five customer trucks on dev
have neither weight nor departure. Any drawdown keyed on it would have
summed zero forever and never fired.

So the customer table now carries tare_weight_tons and net_weight_tons to
match the EDR one, release() records the customer truck's exit as it already
did for EDR, and the drawdown counts both sources — a booking hauls by one
path or the other and "until no tonnage is left" means the same either way.

Also locks a load once its truck has arrived on the EDR side, which the
customer side has always done, and fills the arrival form from the customer
truck on file: the prefill read booking.customer_truck_*, which multi-truck
self-haul leaves null, so a booking with a truck assigned opened blank.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 11:41:57 +00:00
Marshal
540f4a1ff6 changes 2026-07-20 11:41:57 +00:00
Marshal
0727de0f4d Refactor clearance terminology to document approval across services and UI components 2026-07-20 11:41:57 +00:00
Nathnael
b67aa813f9 fix: type error in portal 2026-07-20 11:41:57 +00:00
Nathnael
38bccaccf9 fix: normalized the region and logged the otp properly 2026-07-20 11:41:57 +00:00
Nathnael
6cb921e617 fix: 194 and 183 plane takss 2026-07-20 11:41:57 +00:00
Nathnael
ccd9afacb1 feat: setup forget password to the backoffice 2026-07-20 11:41:57 +00:00
Nathnael
149548a9b1 chore: packages 2026-07-20 11:41:57 +00:00
Nathnael
4b4a4ce788 feat: setup the attachment to the passenger clients 2026-07-20 11:41:57 +00:00
Nathnael
779af4c348 feat: setup the attachment to the passenger api 2026-07-20 11:41:57 +00:00
Nathnael
59cecd44e7 chore: chat types update 2026-07-20 11:41:57 +00:00
Nathnael
9fbe1c5236 feat: setup attachment to the freight chat 2026-07-20 11:41:57 +00:00
Nathnael
5bf82bf531 fix: notify the backoffice of new booking 2026-07-20 11:28:18 +00:00
Nathnael
6420c72e89 feat(auth): implement staff-triggered password-reset links 2026-07-20 11:20:50 +00:00
marshal
bb068d38d1 Merge pull request #834 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-07-20 13:52:55 +03:00
Marshal
eb532399d9 changes 2026-07-20 10:52:20 +00:00
Nathnael Wondisha
bed1208dee Merge pull request #833 from Tria-plc/freight/feat/fixes-v1
Freight/feat/fixes v1
2026-07-20 11:26:30 +03:00
Nathnael
03e21d104c fix: type error in portal 2026-07-20 08:25:54 +00:00
Nathnael Wondisha
f41463748d Merge pull request #788 from Tria-plc/freight/feat/chat-app
Freight/feat/chat app added attachment
2026-07-20 11:23:16 +03:00
Nathnael
2c7a4b7112 Merge branch 'dev' into freight/feat/fixes-v1 2026-07-20 08:20:34 +00:00
Nathnael
a45e1008fa fix: normalized the region and logged the otp properly 2026-07-20 08:19:59 +00:00
Hagernesh
c1c362ab9d fix(mile): only send bookings that bought EDR haulage to the mile queues
The rule that a customer's own truck and an EDR road leg are alternatives
existed on the truck side only (CustomerTruckService.assertSelfHaulPaid).
LastMileService had no counterpart: create checked payment and nothing else,
so any paid booking could be accepted into the queue. A booking took a
customer truck at 06:42 and an EDR last-mile leg with a real EDR truck at
06:47, neither side aware of the other, on a contract that had chosen no
road legs at all.

The road legs are chosen on the contract and copied onto the booking, and
the pickup/delivery address is the only per-booking record of that choice.
service_types cannot serve: every type ships with includes_first_mile and
includes_last_mile set to true, so reading them would mean no booking could
ever self-haul. That same always-true flag had already killed the first-mile
guard, whose `address || serviceType.includesFirstMile` admitted every paid
export booking.

One shared rule now answers it for both sides, so the two halves cannot
drift apart again: last-mile create rejects a booking that chose no road
legs and one already carrying a customer truck; first-mile no longer honours
the service-type flag; the customer-truck guard reads the same helper.

Existing legs are untouched — the guards are on creation, so the one booking
already carrying both needs a human to reconcile it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 08:03:16 +00:00
Marshal
e22b336e8c Refactor clearance terminology to document approval across services and UI components 2026-07-20 07:46:38 +00:00
Nathnael
c7195f077a fix: 194 and 183 plane takss 2026-07-20 07:41:25 +00:00
Hagernesh Tadesse
d51e2e4042 Merge pull request #832 from Tria-plc/intercity-load-unload
feat(clearance): keep an audit trail of customs risk reassignments
2026-07-20 10:18:03 +03:00
Hagernesh
2906c6bb45 test(train-scheduling): cover the checkpoint backdating guard on the DTO
The IsNotBackdated validator was covered in isolation, but not on the DTO
that actually carries it. Asserts a backdated occurredAt is rejected, that
"now" passes, and that omitting the field still validates so the service can
stamp it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 07:13:52 +00:00
Hagernesh
536d6043c2 fix(clearance): allow customs risk to be corrected and keep the trail
RiskStep returned early to a badge as soon as a risk level existed, so the
control was unreachable and a mis-assigned level could never be corrected.
Both the server and the sibling AssignRiskCard treat risk as correctable
until duty is advised off it — completeWithMetadata has no already-completed
guard and overwrites metadata.riskLevel. RiskStep was stricter than either.

It now keeps the control mounted alongside the assigned badge, offers
"Reassign risk", and locks to badge-only once DUTY_TAXES_ADVISED completes.
The control also reads the persisted level (it was hardcoded to GREEN, so
unhiding it alone would have misreported the assignment), and the T1 gate is
skipped once a level exists, since risk cannot be assigned without a closed
T1 and stale T1 data must not hide the badge.

Correcting a level previously left no record of the old value, who changed
it, or when — thin ground for a customer-visible level that may be disputed.
assignRisk now appends each decision to metadata.riskHistory: the level, the
level it replaced, the timestamp, the user id, and a display name resolved
at assignment time so the trail shows a person rather than a UUID. riskLevel
still carries the current value and always equals the last entry, so
existing consumers are unchanged.

History lives on the existing metadata JSONB column, so no migration is
needed, and the logic sits in assignRisk rather than the shared
completeWithMetadata that adviseDuty and others also use. Re-picking the
level already in force is not recorded — it changed nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 07:13:52 +00:00
Hagernesh
21df861979 back date validator 2026-07-20 07:13:52 +00:00
Hagernesh
c0fdffa7ef Marshalling document empty wagon rendering 2026-07-20 07:13:52 +00:00
Hagernesh
eb998bfddd Facility 2026-07-20 07:13:51 +00:00
Hagernesh
ee6ad7da8b Auto arrival train 2026-07-20 07:13:51 +00:00
Hagernesh
a5973de6e1 feat(intercity): a facility only handles the cargo its equipment can lift
Containers need a reach stacker or gantry, so only Indode, Modjo and Dire Dawa
take them. Bulk needs far less and is handled at all five facilities. Having a
facility was previously enough to load anything, so a container booking through
Sebeta or Adama would have been accepted and then had nothing to lift it.

- yard_facilities gains handles_container / handles_bulk, both defaulting true so
  a facility handles everything unless told otherwise; the seeder states the real
  capability.
- The intercity gate now refuses cargo a facility cannot lift, saying which type,
  not just "no facility". canHandleFreight keeps that rule in the resolver so
  callers cannot get it subtly wrong.
- The intercity list resolves each end against the booking's own freight type, so
  the view flags a container booking routed through a bulk-only yard while the
  train is still coming rather than when the load is refused.

Import/export untouched — the gate is still DOMESTIC-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 07:13:51 +00:00