1434 Commits

Author SHA1 Message Date
marshal
081f66fb82 Merge pull request #1434 from Tria-plc/freight_feature/usermanagement
Freight feature/usermanagement
2026-08-28 10:34:31 +03:00
Marshal
ba56974e32 feat(train): enhance train history and scheduling features
- Added a reason field to train history entries for detach/maintenance actions.
- Updated TrainHistoryPanel to display the reason for wagon detachments.
- Introduced per-wagon load/unload functionality in ScheduleWorkspacePanel with a modal for managing individual wagons.
- Implemented API endpoints for loading and unloading specific wagons, including the ability to cancel remaining wagons with a reason.
- Refactored detach request handling in TrainBuilderDetailPage to streamline the process and remove the approval flow, requiring a reason for detachments.
- Updated types and services to support new wagon loading/unloading features and booking wagon retrieval.
2026-08-28 07:33:28 +00:00
Marshal
8b8870e85e fix issue 2026-08-27 20:58:44 +00:00
Nathnael Wondisha
649a3c226c Merge pull request #1433 from Tria-plc/freight/nati-2
Freight/nati 2
2026-08-27 15:59:22 +03:00
Nathnael
7d9d1fb518 fix: invoice filter 2026-08-27 12:40:03 +00:00
marshal
041c165d6c Merge pull request #1430 from Tria-plc/freight_feature/usermanagement
feat: simplify dispatch logic by removing manual loading checks and u…
2026-08-27 14:17:27 +03:00
Marshal
1626903192 feat: simplify dispatch logic by removing manual loading checks and updating related comments 2026-08-27 11:16:43 +00:00
Nathnael Wondisha
81334258d3 Merge pull request #1429 from Tria-plc/freight/nati-2
Freight/nati 2
2026-08-27 12:40:16 +03:00
Nathnael
3af3017b86 feat(backoffice): add an Account tab with the customer's portal logins
The detail page showed the company's business contact details but not the
credentials anyone actually signs in with, and the two drift apart
routinely — so "the customer says they can't log in" was unanswerable
from this screen.

Adds `GET /backoffice/customers/:companyId/accounts`, joining each
external profile to its IAM account, primary contact first. Deliberately
not filtered to active accounts: a suspended or never-activated login is
exactly the case being looked into. The user query selects columns
explicitly — the entity's relations include credentials and sessions, and
this response reaches a browser.

Rendered as cards rather than a table: it is a handful of rows of
mostly-optional fields, which a table renders as a field of dashes.
"Password never set" is called out on its own, being the usual answer to
"they never got in", and a profile whose IAM user is gone reads as a red
fault rather than an inactive status.
2026-08-27 09:30:24 +00:00
Nathnael
f8e8897f5c feat(backoffice): search customers by trade name and licence, filter by role
Staff search with whatever is in front of them. Company name, TIN, email
and profile reference already matched; a TIN's licence number and the
trade name of the business a role operates as did not, which is most of
what appears on a customer's own paperwork.

Adds a Role filter alongside it. Distinct from the existing Type pill:
that is the company's own kind, this asks "who does X?" — one `customer`
company routinely holds importer and exporter at once.

Both are EXISTS subqueries rather than constraints on the joined
`companyProfiles` alias. Filtering the join would drop the company's
other profiles from the loaded entity, so an importer-and-exporter would
render as importer-only.
2026-08-27 09:30:12 +00:00
Nathnael
a48d77aff8 feat(backoffice): show each role's eTrade business on the customer detail page
The reviewer approving a role had no way to see which business it claims
to operate as, so there was nothing to check the uploaded licence
document against. The Role profiles table now carries a column with the
trade name, the licensed activity (does it actually cover this role?),
the licence number (the only unambiguous handle — trade names repeat
across a TIN's licences) and the renewal date.

A role with nothing attached reads as a yellow "Not attached" rather than
a blank: it is a review finding. Yellow, not red, because a co-operative
or investment-licence company legitimately has none.

Two fixes alongside it:

- The profile reference was already rendered but is minted only on
  approval, so every pending role drew an empty line. It now says so.
- `TableCard` gained an optional header section, so padding sits per
  section and the table runs edge to edge. The header stays outside the
  scroll region — inside, a title slides away from its own table.
2026-08-27 09:29:41 +00:00
Marshal
065bdd0189 tracking ui 2026-08-27 07:45:32 +00:00
Marshal
d9017df730 feat: refine loading window validation and improve error messaging for dispatching 2026-08-27 03:26:44 +00:00
Marshal
6ec3c8c5e0 feat: enhance station work logging with user display names and improve loading/unloading logic 2026-08-27 02:29:50 +00:00
marshal
bcc5daa137 Merge pull request #1415 from Tria-plc/freight_feature/usermanagement
feat: implement MANUAL_ONLY status for bookings and update related logic
2026-08-26 01:02:18 +03:00
Marshal
29371b0b39 feat: implement MANUAL_ONLY status for bookings and update related logic 2026-08-25 22:01:03 +00:00
marshal
1459e646f6 Merge pull request #1414 from Tria-plc/freight_feature/usermanagement
feat: enhance train scheduling and contract management features
2026-08-26 00:46:17 +03: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
Nathnael
8adbb05479 Merge branch 'dev' into freight/nati-2 2026-08-25 13:07:09 +00:00
Nathnael
08aba3fb4d fix 2026-08-25 13:05:55 +00:00
Nathnael
6d1e4a630e feat(reports): publish per-stop times when loading & unloading groups by train
Grouped by Train, a row was a period average over the train's stops, which
threw away the one thing that grain is for: when the work actually happened.
The row is now the stop itself — logged arrival, departure, unloading and
loading times, and that stop's own durations. Grouped by Station it still
averages over every train that called there.

The two shapes need different columns, so `ReportColumn.hideWhen` names the
filter values that hide a column, and the runner resolves sort against the
visible set — sorting by an average and then switching to Train falls back to
the default sort instead of a 42703 on a column the query no longer selects.
`ReportFilterDef.defaultValue` pins the unset grain to `train`, so "no value"
is never a third shape. The table, the export field list and the chart toggle
all follow the visible set; the chart is station-grain only, since per-stop
rows have nothing to bar-chart.

Both grains EXPLAIN-validated and run against the dev database.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 13:01:47 +00:00
marshal
a4e9466915 Merge pull request #1412 from Tria-plc/freight_feature/usermanagement
feat: enhance booking and audit log functionalities
2026-08-25 02:50:34 +03: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
Nathnael
0a85dbe60d Merge branch 'dev' into freight/nati-2 2026-08-24 14:02:03 +00:00
Nathnael
562c8b48ba feat: updateing the loading and unloading 2026-08-24 14:01:19 +00:00
marshal
6da8adc6e9 Merge pull request #1409 from Tria-plc/freight_feature/usermanagement
fix issue -> consolidation
2026-08-24 15:51:12 +03:00
Marshal
2a107e8ba3 fix issue -> consolidation 2026-08-24 12:24:23 +00:00
Nathnael
17c2dca3cc feat(reports): record loading and unloading time per stop
The OCC report publishes total loading and unloading time and the other
activity left over from a station stay, but nothing recorded when handling
started or ended — the July 2026 seed had to write the figure into a
checkpoint note. Four nullable stamps now ride the stop's arrival row, which
is the row the staying-time report builds a stay from (a turnaround's
departure belongs to a different schedule).

Handling is unloading start to loading end, so a container stop reads as one
window and a bulk station that only loads or only unloads still reports its
half; other activity is the rest of the stay. Both stay NULL where nothing
was logged rather than collapsing to zero.

- station-staying-time: + loading/unloading and other activity per stop
- turnaround-cycle: + the same, summed over the cycle's stops
- loading-unloading (new): per train per station per period, so a week or
  month view is that train's average over its stops
- the stop/stay query moves to operations-classification, shared by both
2026-08-24 12:09:04 +00:00
Nathnael
ee2caa332c Merge branch 'dev' into freight/nati-2 2026-08-24 08:38:37 +00:00
Nathnael
de407c0014 feat(reports): clamp report descriptions with a show more toggle
Report descriptions run to a paragraph. ReportDescription wraps Mantine's
Spoiler to clamp them to two lines, and the toggle only renders when the
text actually overflows.

PageHeader kept its subtitle on a hard truncate class, which would have
pinned the spoiler to one line, so a ReactNode subtitle now renders as-is
and owns its own layout. A string subtitle still truncates as before.
2026-08-24 07:54:36 +00:00
Nathnael
2be1876460 feat(reports): carry time of day on report date columns
Eleven report columns bucketed their timestamp to a bare day with to_char,
which is wrong for anything a user reads as an event rather than a period:
two departures on the same date, or a wagon request fulfilled hours after it
was raised, were indistinguishable in the output.

The renderer only shows the time when the value actually has one, keyed off
the string rather than a per-column flag — a genuine day bucket would
otherwise render as 12:00 AM, which reads as data rather than as absence.
2026-08-24 07:12:08 +00:00
Nathnael
c3894462e7 feat(billing): search invoices by PNR and transaction ref
Both are numbers a customer or a provider support desk quotes back, so they
belong in the free-text box rather than behind a filter pill.

The transaction id and merchant order id are plain ORs — the payment alias is
already joined by every caller of applyInvoiceFilters. The PNR folds into the
existing booking EXISTS block instead of adding a second subquery, so it
inherits that block's correlation and also matches warehouse-, first-mile-
and last-mile-sourced invoices, not just booking-sourced ones.

bk is promoted to alwaysJoin now that the export's scope() references it.
2026-08-24 07:03:08 +00:00
Nathnael
3da00e1f06 feat(billing): show the booking PNR on an invoice
The PNR is the CBE_BILL reference the customer actually pays against, but it
is stamped onto the booking at payment-initiation time — it is a column on
neither the invoice nor the payment. Both surfaces read it back by source id,
the same lookup the sealed invoice PDF already did, so screen, export and
document now agree.

The export's join casts bk.id::text rather than i.source_id::uuid: source_id
is a bare varchar pointer that is not always a UUID (EIMS self-test rows
carry a slug), and casting that direction throws on those rows.
2026-08-24 07:02:46 +00:00
Nathnael
018505d6fa feat(billing): filter, show and export invoice payment method
The settled method is split across two stores: a gateway settlement records
the real provider on the linked freight.payments row (cbe-bill, telebirr)
while the invoice's own payments ledger only writes a flat "GATEWAY"; a
manual settlement has no payments row at all and the ledger is the only
source (BANK_TRANSFER, OFFLINE, or whatever PayInvoiceDto.method carried).

invoicePaymentMethodExpr folds both into one UPPER_SNAKE vocabulary —
provider first, newest ledger entry as the fallback — and the list filter,
the export field and the export filter all use that same expression, so the
screen and the file can never disagree.

The paymentMethods param is deliberately not validated against a fixed list:
the manual pay endpoint takes a free-form method, so an IsIn would silently
drop real values.
2026-08-24 07:02:27 +00:00
Hagernesh
c937290019 feat(eims): resolve buyer geography from the MoR location master
BuyerDetails Country/Region/City/Wereda now resolve from the Ministry's own
EIMS_COUNTRY_REGION_VW master instead of the EIMS_BUYER_*_CODES env maps and
the ethiopia-geo-codes table. Both invented their codes and looked names up
globally, so KERSA/GORO/BABILE/BURE — each present in several zones with
different LOCALITY_NOs — could be filed against the wrong jurisdiction.

Resolution is hierarchical and refuses to guess: an unknown or ambiguous
address raises a local validation error naming the level that failed, and
never selects the first matching row. Spelling differences between EDR and
MoR live in a reviewed, parent-scoped alias layer; the dataset itself stays
verbatim so it remains traceable to the Ministry sheet.

Resolution now runs before the counter reservation in both the single and
bulk paths, so a bad company address no longer burns an EIMS sequence number.

Adds eims:import-locations to regenerate the dataset from a future workbook,
reporting duplicate rows and same-hierarchy code conflicts.
2026-08-24 06:59:50 +00:00
Marshal
31fa313c66 add draft declaration 2026-08-23 19:02:33 +00:00
Marshal
58f88b74f8 add contract link 2026-08-23 05:00:43 +00:00
Marshal
716444e60a feat: add pagination to schedule history and consolidation approvals
- Implemented pagination in ScheduleHistoryPanel to manage large history entries.
- Updated API to support pagination parameters for schedule history.
- Enhanced ConsolidationApprovalsPage with tabbed navigation and pagination for approval rows.
- Introduced new types for paginated responses in bookings and train scheduling services.
- Added a database migration to create an index on wagon_booking_allocations for performance improvements.
2026-08-23 04:51:34 +00:00
Marshal
e2189040fa feat: add pagination to schedule history and consolidation approvals
- Implemented pagination in ScheduleHistoryPanel to manage large history entries.
- Updated API to support pagination parameters for schedule history.
- Enhanced ConsolidationApprovalsPage with tabbed navigation and pagination for approval rows.
- Introduced new types for paginated responses in bookings and train scheduling services.
- Added a database migration to create an index on wagon_booking_allocations for performance improvements.
2026-08-23 04:49:58 +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
Hagernesh
7f5e8349da Intercity andd import export gating 2026-08-22 09:17:28 +00:00
marshal
f4115f658d Merge pull request #1389 from Tria-plc/freight_feature/usermanagement
fix issue
2026-08-22 04:24:35 +03:00
Marshal
1ab2cfdb3b fix issue 2026-08-22 01:23:50 +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
Nathnael Wondisha
a0822f9d4f Merge pull request #1381 from Tria-plc/freight/nati-2
Freight/nati 2
2026-08-21 22:48:14 +03:00
ghost2023
23b3f265e6 feat(operations-targets): plan at any of the eight report grains
Targets could only be committed weekly, monthly, quarterly or yearly, so a
figure the business quotes per half-year or per 90 days had to be split by
hand into buckets it was never expressed in. The reports already re-gather
a target into whatever grain the viewer asks for; this just lets the plan
be entered at the grain it was agreed in.

Adds day, half-year, nine-month and 90-day, matching the report units added
alongside. normalisePeriodStart snaps each to its block start with the same
calendar-year anchoring the SQL uses — Jan/Jul for half-years, Jan/Oct for
nine-months, days 1/91/181/271 for 90-day blocks, including the same cap on
the fourth block so late December does not snap into a stub of its own.

That agreement is the load-bearing part. The unique index is keyed on
period_start, and a target snapped to a boundary the report does not bucket
on is a plan measured against a period that does not exist. The two halves
live in different files and different languages, so the spec pins the
boundaries rather than trusting them to stay in step.

Adds operations-targets.service.spec.ts, which the module had none of:
every period type, idempotency, the leap year, and the block-four cap.
2026-08-21 17:40:51 +03:00