Commit Graph

825 Commits

Author SHA1 Message Date
hager
3fb5cdf29f feat: empty container Import 2026-09-04 22:43:20 +00:00
ghost2023
aa96bb4086 Merge branch 'dev' into dj-franc 2026-09-04 16:31:21 +03:00
ghost2023
ba90ce7a0f style: publication 2026-09-04 15:41:11 +03:00
ghost2023
0dd0e8d992 feat: add publication 2026-09-04 14:43:17 +03:00
ghost2023
f451d0106d feat(freight-portal): support DJF as a billing and payment currency
lib/currency.ts re-exports the shared @edr/ui-common formatter (was a
local implementation always forcing 2 decimals, wrong for DJF).
Currency pickers (new-booking-form, new-contract-form, new-shipment
Currency selector and schemas) offer DJF wherever USD is offered.

The bigger piece: offline-payment.ts's isUsdCurrency/isUsdOfflineBooking
assumed exactly two payment rails (ETB online, USD offline) and picked
one. DJF supports BOTH, so it's replaced with independent
canPayOnline/canPayOffline predicates, updated across the 5 call sites
that gated the Pay button vs. the bank-transfer badge. PaymentMethodModal's
WAAFI/CAC Bank entries (Djibouti gateways mislabeled USD-only) now list
DJF, and a currency that matches no provider returns no providers
instead of silently offering all of them (was returning every provider,
including the ETB-only one, on any unmatched currency).

Claude-Session: https://claude.ai/code/session_01CZy77vCWhka3pnmVF9NDkL
2026-09-04 11:53:19 +03:00
marshal
3fd94c9314 feat(transit-agent): timed document uploads and a real-data overview 2026-09-02 23:36:35 +00:00
marshal
42ca020a1f Merge branch 'dev' of github.com:Tria-plc/edr-platform into origin/freight_feature/transit 2026-09-02 22:38:15 +00:00
marshal
13ac3144e2 merge conflict resolved 2026-09-02 22:35:18 +00:00
marshal
6efa9dab93 feat(freight): GL rebook of cancelled wagons, seal+train required on completion, train/voyage in SMS 2026-09-02 21:23:24 +00:00
marshal
3e274cc2a2 fix(freight): gate loading on booking paymentStatus only; default schedule voyage no. to train's voyage number 2026-09-02 21:15:48 +00:00
hager
29c1a21b68 feat(bookings): make customer self-haul assignment work end to end
The customer truck card on the booking's Logistics tab is now usable for
every cargo type, with an Excel template and bulk upload that match what
the API enforces.

Excel template and bulk upload
- The template is built per booking. Container bookings get the booking's
  own containers with their sizes on a reference sheet and sample rows
  paired 20ft+20ft; bulk (PER_TON) bookings get a Planned Tons column;
  counted cargo (PER_ITEM: machinery, RoRo vehicles) gets Planned Quantity.
- Parsing validates the whole file before anything is posted: plate,
  driver, truck type, ISO container numbers, containers on the booking,
  duplicates across rows, containers already on a truck, and the capacity
  rule (one 40ft alone, or two 20ft). Errors quote the Excel row number.
- The bulk DTO reuses AddCustomerTruckDto instead of a drifted copy that
  lacked plannedTons/plannedQuantity, so bulk cargo can be uploaded at all.
- A partial failure is reported per row in the modal instead of closing it
  as if every truck had been created.

Capacity rule in the form
- The container picker shows sizes and stops offering a second container
  once a 40ft is picked, or a 40ft once a 20ft is picked.
- PER_ITEM cargo commits by item count; tonnage becomes optional.

Shared vocabulary
- CUSTOMER_TRUCK_TYPES and ISO_CONTAINER_NUMBER move to @edr/types so the
  API validators, the dropdown and the template read one list.

When assignment is open
- The card always renders and states why assignment is closed (EDR
  haulage, unpaid, train not arrived, cargo already loaded) rather than
  vanishing.
- Self-haul is blocked only once EDR has committed to the road leg: an
  approved last-mile request or an existing last-mile leg. A delivery
  address whose request is still awaiting confirmation, submitted or
  rejected no longer blocks the customer from bringing their own truck.
  Collection on exports has no approval step and still blocks as before.
  Both the multi-truck service and the legacy single-truck path read the
  same SQL fragment (edrHaulsThisBooking), and the portal applies the same
  rule with a notice that assigning a truck makes the pending request
  unapprovable. The last-mile side already refuses to approve a booking
  carrying a customer truck, so the two paths stay mutually exclusive.

Verified: EXPLAIN on the new SQL against edr_dev, type-check clean for
freight-api and portal, 12 util specs pass (5 new). Backoffice type-check
fails only in pre-existing user-management files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 20:47:18 +00:00
hager
de55d809c7 fix(empty-return-requests): pick the containers off the booking
Typing container numbers let a customer request a return for a box that
never came in on that booking — and gave them a blank field to guess at
when they did not have the numbers to hand.

The portal now lists the booking's own containers, minus any already
spoken for by a live request, as a tick list; the count follows the
ticks. The API backs that up: every submitted number must be one of the
booking's containers, and a booking with no container numbers recorded
says so instead of offering an empty form.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 11:24:43 +00:00
hager
3f7b744987 feat(empty-return-requests): customer-requested empty return, priced and paid
A booking sold WITHOUT the return service had no way to send its empties
back: the containers were the customer's problem and nothing in the
system priced, billed or planned the movement.

Adds the request flow end to end. The customer opens the booking, says
how many containers are coming back and types each number; the request
lands in a new backoffice queue (Empty Return Requests). Approval prices
it off the same live WITH_RETURN route rate the rule engine bills when
the service IS bought up front — per container, converted to birr, and
overridable by the reviewer — and issues the invoice there and then.
Payment settles through the normal invoice path, whose
`empty_return_request.invoice.paid` event moves the request to PAID; the
customer then books the return date and the truck.

Scheduled requests surface on Container Returns as Planned Empty
Returns, where confirming the arrival records the containers through the
existing empty-container-return flow — which in turn closes the request
once its last container is in.

Container freight only, never a booking that already ships WITH_RETURN,
and only from IN_TRANSIT onward: the empty comes back after delivery, so
the option has to outlive ARRIVED.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 11:05:03 +00:00
hagiye
031efce92b Truck assiggnment and per truc 2026-09-02 07:17:19 +03:00
marshal
ec5df4b328 Merge pull request #1472 from Tria-plc/freight_feature/usermanagement
feat: Implement handling for partially loaded bookings in train sched…
2026-09-01 23:56:07 +03:00
marshalyordanos
d51bed5630 feat: Implement handling for partially loaded bookings in train scheduling
- Added  to manage decisions on partially loaded bookings during log-pass and dispatch actions.
- Enhanced  to track and manage bookings left behind when a train departs a yard.
- Updated  and  to pass necessary station data for handling partially loaded bookings.
- Modified  and  to account for customer-fault fees and ensure proper handling of credits.
- Introduced fault tracking in  interface to differentiate between customer and EDR faults.
2026-09-01 23:53:58 +03:00
Marshal
b5ad46f317 feat: add Transit Clearance Action Panel for managing delivery and release orders
- Implemented TransitClearanceActionPanel component for transit agents to handle DO/RO uploads and amendments.
- Added file picker for uploading documents with validation for vessel arrival and collection dates.
- Introduced modals for uploading T1 documents and requesting RO amendments.
- Enhanced transit assignments service with new API endpoints for clearance history, GL exchange documents, and incident reports.
- Updated types to include new document upload sources and statuses.
- Created CSS styles for transit bookings table to improve layout and responsiveness.
- Exported new TransitAgentBookingDetailPage for detailed booking views.
2026-08-31 13:56:39 +00:00
Hagernesh
fd6f0d03b6 feat(loading): notify loaded and left-behind containers, surface the CAS
A booking is routinely loaded in parts, and nothing told the customer which
containers boarded and which stayed behind. The carriage acceptance sheet was
the only record, and it both totalled up cargo still sitting in the yard and
lived inside a Warehouse documents bundle that direct truck-to-train cargo
has no business in.

The sheet now marks each wagon Loaded or Not loaded and totals only the loaded
ones. On load, the customer gets an in-app, SMS and email notice carrying the
train number, route, departure time and both container lists — capped to a
summary on SMS and email, complete in the inbox. Anything left behind also
raises a warehouse-desk notice so somebody owns finding it space.

That desk is addressed by a new warehouse_inventory:get_notification
permission: a recipient selector, not a route guard, so ops can assign who
gets pinged without granting access to anything.

The GRN notice went out over SMS alone, to whatever phone number the gate
clerk typed. Where the receive carries a booking it now resolves the company
and delivers in-app, SMS and email, skipping the typed phone so the customer
is not texted twice; manual and backlog receives keep the old path.
2026-08-29 08:47:39 +00:00
marshal
abf856547a Merge pull request #1453 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-08-29 10:40:53 +03:00
Marshal
978f1889c6 feat(transit-agents): give transit agents a portal login
Optional IAM account per agent — nullable, nothing backfilled, so
roster-only rows keep working. Staff invite existing ones; new ones get
an account when an email is supplied. Activation reuses the shipping-line
link path. SMS reachability widens to Djibouti.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 07:40:07 +00:00
Hagernesh
312c1f1da3 feat(warehouses): backoffice UI for container stack positions
Surfaces the physical stack/slot model in the staff app.

- ZoneLayoutModal: stacks drawn level by level with occupancy colours,
  configured-vs-built-vs-occupied counts, and stack create/delete plus
  block/reserve/free on empty levels
- SlotPicker in the store and move modals, offering only the next
  fillable level of each stack so the form cannot suggest a position
  the API will refuse
- move modal warns when a container is buried, lists the blockers, and
  disables the action instead of firing a 409
- fix: move() now asserts accessibility server-side, matching release —
  both are exits from a stack
2026-08-29 06:39:29 +00:00
Marshal
7e163088d9 fix issue, add transit flow, fix cancellation 2026-08-28 22:13:49 +00:00
marshal
081f66fb82 Merge pull request #1434 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-08-28 10:34:31 +03:00
Marshal
8b8870e85e fix issue 2026-08-27 20:58:44 +00:00
Nathnael
604710bd25 feat(companies): attach an eTrade business to each company profile
A TIN holds many business licences split by activity — export of coffee,
freight forwarding, import of vehicles — but the company picked one for
its whole record, so every operational role shared it. Each profile now
names the business it actually operates as.

Stored on `company_profiles.etrade_business` as a snapshot (licence
number, trade name, activity, renewal) rather than a bare licence number,
so the portal and backoffice can show it without an eTrade round-trip —
that API is slow, serves a broken TLS chain and is regularly down. Not
unique: one business may legitimately back several roles.

The licence number is a client input, so it is never stored as sent —
`ETradeService.findBusinessOption` looks it up under the company's own
TIN and persists eTrade's record, which makes another company's licence
simply unfindable.

Choosing one is required wherever the customer adds a role with a TIN
already on file. The onboarding wizard is the exception by necessity: it
picks roles on its first step, before a TIN exists, so there is nothing
to choose from yet. There it is enforced through
`getOnboardingRequirements` instead — an unattached role is reported
outstanding and blocks submission — and the picker sits on the documents
step beside that role's licence upload.

Lifted entirely for a co-operative or investment-licence company: eTrade
holds no record for its TIN, so the requirement would be unsatisfiable.
2026-08-27 09:29:15 +00:00
Marshal
b926a3116e 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.
2026-08-25 21:44:21 +00:00
Marshal
d5a5085d6d feat: enhance booking and audit log functionalities
- Implemented read-only locking for customer-requested container sizes and billing currency in the GlCreateBookingForm component.
- Added functionality to lock partner quantities based on shipment requests in the ConsolidationPartnerPanel.
- Introduced a new Leave action in the LogPassYardWorkModal to unassign bookings from trains.
- Enhanced the AuditLogsPage to support filtering by action and added a Go button for direct navigation to entity detail pages.
- Updated WagonCancellationsPage to handle odd-20ft credits requiring partner selection during rebooking.
- Improved TrainScheduleV2DetailPage to allow manual loading of cargo and display warnings for unassigned bookings.
- Added a new reference field to the audit logs for better searchability and tracking of actions.
- Created a migration to add the reference column to the audit logs table and established an index for efficient querying.
- Defined a registry for audit reference sources to streamline the retrieval of human identifiers for various entities.
2026-08-24 23:49:20 +00:00
Marshal
2a107e8ba3 fix issue -> consolidation 2026-08-24 12:24:23 +00:00
Marshal
31fa313c66 add draft declaration 2026-08-23 19:02:33 +00:00
marshal
105879b531 Merge pull request #1399 from Tria-plc/freight_feature/usermanagement
feat(train-scheduling): mid-route consist changes, audit history, saf…
2026-08-23 06:59:27 +03:00
Marshal
8e6fc09aac feat(train-scheduling): mid-route consist changes, audit history, safer workspace
- planned couples: loose wagons join the train at a route stop, added
  from the schedule yards tab; capacity credits them per corridor edge
  and coupling validates locomotive weight/length caps per leg
- real-cut toggle: a cut wagon permanently leaves the train build at
  its cut yard (soft cut still sits out one trip only)
- fix heaviest-leg display counting a shared slot's full cargo on
  every spanned edge (phantom pull-weight overload on S-2026-00045)
- confirmation dialogs for workspace add/load/unload/remove actions
- train-builder History and Detached-wagons tabs, backed by paginated
  endpoints; builder detaches now always write adjustment-log rows

Migrations 3660 (planned_wagon_couples, planned_wagon_real_cuts) and
3670 (adjustment log train_schedule_id nullable) — both applied to the
dev DB by hand; watch mode does not run migrations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 03:55:54 +00:00
marshal
12b537ef90 Merge pull request #1392 from Tria-plc/freight_feature/usermanagement
fix issue
2026-08-22 09:17:41 +03:00
Marshal
722874203b fix issue 2026-08-22 06:09:36 +00:00
marshal
e2dd761203 Merge pull request #1387 from Tria-plc/freight_feature/usermanagement
fix issue
2026-08-22 03:50:34 +03:00
Marshal
b6c1efa043 fix issue 2026-08-22 00:49:53 +00:00
marshal
ed57490575 Merge pull request #1382 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-08-22 02:17:34 +03:00
Marshal
09deecd04c fix issue and add consolidation 2026-08-21 23:16:06 +00:00
Hagernesh Tadesse
4eb840c090 Merge branch 'dev' into eims-bulk-register 2026-08-21 16:03:03 +03:00
Hagernesh
8181834037 Ticket
Empty container returns now generate a downloadable Equipment Interchange Receipt: container number & size, exact return timestamp, depot/location, condition, and the carrier/booking reference. Customers can download it from their booking's Documents tab (own-booking returns only); staff can pull any via the same endpoint.
2026-08-21 08:59:06 +00:00
Marshal
fbb169469f feat(clearance): preview charge documents before and after upload 2026-08-21 08:59:06 +00:00
Marshal
a9c6b85c08 feat(clearance): preview charge documents before and after upload 2026-08-21 08:59:06 +00:00
Marshal
b3823a4f32 fix issue 2026-08-21 08:59:06 +00:00
Marshal
3a4eeee61b feat: enhance ClearanceChargesSection with file viewing and downloading capabilities 2026-08-21 08:47:47 +00:00
Marshal
c5909b8ec7 [200~feat: add CustomsPaymentsCard and PaymentsTab components for handling customs payments and payment summaries 2026-08-21 08:47:47 +00:00
Marshal
24f5d94709 feat(clearance): preview charge documents before and after upload 2026-08-21 07:10:50 +00:00
Marshal
4c549029fe feat(clearance): preview charge documents before and after upload 2026-08-21 07:04:22 +00:00
Marshal
0e8e6acb04 fix issue 2026-08-20 18:28:40 +00:00
Marshal
d99b294c21 fix issue 2026-08-20 18:10:29 +00:00
Marshal
0d34b9f5e3 feat: enhance ClearanceChargesSection with file viewing and downloading capabilities 2026-08-20 16:07:16 +00:00
Marshal
9e1d5ee9f2 [200~feat: add CustomsPaymentsCard and PaymentsTab components for handling customs payments and payment summaries 2026-08-20 15:45:42 +00:00