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
Reproduces the monthly count sheet a port warehouse publishes: trains,
containers by size and laden state, wagons, TEU and bulk wagons per cargo
type, each split into export and import beside an overall total.
Two departures from the spreadsheet it replaces:
- Wagons are counted distinctly from the marshalling record rather than
derived as 20ft/2 + 40ft + bulk wagons, which overstates whenever a wagon
ran part-loaded.
- Total is counted over everything rather than summed across the direction
columns — a train carrying both an import and an export booking belongs to
both and would otherwise count twice.
Demurrage is billed on invoice lines and is left to Revenue by Category.
Adds a station filter matching either end of the corridor, so one warehouse
can report the trains it worked in both directions.
Carves cargo load/unload confirmation out of the coarse
trainScheduling.update permission into its own guard
(TrainSchedulingLoad/TrainSchedulingUnload), covering import, export,
and intercity — the generic per-booking route already serves all
directions, and the intercity-specific route gets the same two keys.
Adds the catalog entries and grants them to operationsOfficer/director
alongside the existing .update grant so current access is unchanged.
Adds edr_freight_app:overview:<layout>:view for each of the 6 overview
dashboard layouts (clearance, occ, operation, marketer, finance,
executive), seeded via OVERVIEW_LAYOUT_PERMISSIONS alongside the
existing report permissions.
Granted 1:1 to match today's role-dashboards.config.ts ROLE_LAYOUTS
key table, appended only at the terminal EDR_FREIGHT_ROLES /
EDR_FREIGHT_POSITIONS assembly points (never inside the reusable
ROLE_PERMISSION_PRESETS/POSITION_PERMISSION_PRESETS builders) so
composite positions like chief don't leak multiple layout grants from
the role arrays they spread.
The ~20 ad-hoc edr_freight_app/xxx department sub-positions are not
backfilled here and will fall back to the executive layout until
granted manually via the IAM positions admin screen.
Part of switching overview layout resolution from role/position-key
matching to permission checks, mirroring how reports already work.
New freight.additional_charge table, independent of BookingClearanceCharge
(unbounded per booking, free-text reason). Draft -> send issues an invoice
and notifies the customer in-app/SMS/email; settles via the standard
.invoice.paid event. Adds the Additional charges row-menu entry
next to Cancel booking, permission-gated.
Not included: the Additional Payments tab UI, add-charge modal, portal pay
flow.
- Add migration for consolidation approvals table and status enum
- Create ConsolidationApprovalService to handle approval logic
- Implement repository for managing consolidation approvals
- Add entity for consolidation approval with necessary fields
- Develop frontend components for displaying and managing consolidation approvals
- Create tests for consolidation approval service to ensure correct behavior
Conflict in ClearanceDocumentsPage: this branch migrated the page to the
pill FilterBar, dev added filters to the Select stack it replaced. Kept
the FilterBar and carried dev's additions across as a "Booked by"
(customerKind) FilterDef plus the shipping-line search placeholder; dev's
startOfDayIso/endOfDayIso went away because dateRangeParams already does
that. The Ship icon import is needed by dev's shipping-line customer cell,
which merged cleanly on its own.
Three gaps on the backoffice customer detail page:
- Rejecting a change request or sending it back for correction notified
nobody. Adds CompanyNotifierService.changeRequestReturned, which pings
the customer desk with the reviewer, the outcome and the note. Marketing
joins that desk via customers:view + customers:get_notification in the
role preset — grants still come from the IAM UI, the preset only sets
the default for new environments.
- submitted_by / reviewed_by / actor_id were stored but never resolved, so
the History tab could say what changed but never who asked or who sent
it back. Resolves them through a shared iam-user-name util (deduped from
the private copy in contract-document-history.service) and renders
"Requested by" / "Sent back to marketing by" lines. The
changes_requested badge is relabelled to match the workflow.
- "View" opened an in-page modal one document at a time. Adds
openFileInNewTab, which opens the tab inside the click gesture and fills
it once the authenticated fetch resolves, and an "Open all" button that
loops over the documents table so every file lands in its own tab.
- Updated API documentation and summaries to reflect support for both USD and ETB invoices.
- Modified data structures to include trade direction for invoices.
- Adjusted UI components to accommodate manual payment confirmations and display relevant information.
- Implemented filtering options for currency in the manual payments worklist.
POST billing/invoices/:id/memo files a MoR DEB/CRE memo by reusing
createInvoice unchanged. sourceId is the original invoice's own id, not its
source's — this structurally keeps memos out of findPayable/expirePayable/
billQuery's sourceId-keyed lookups regardless of status. Credit notes are
created settled; debit notes are created open/unpaid as a genuine new
receivable, not force-settled. memoIssue is granted to the chief position,
not the general finance role.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add ShippingLineBookingsPage for listing and managing shipping line bookings.
- Create ShippingLineDocumentsModal for document uploads related to bookings.
- Introduce ShippingLineInitiateModal for initiating new shipping line bookings.
- Implement booking document state management with booking-doc-state utility.
- Add shipping line bookings service for API interactions.
- Update index to export new components and services.
- Enhance types for freight to include shipping line credits.
New logo-settings module (mirrors stamp-settings): single uploaded logo,
stored via FilesService/MinIO, injected as a data URL into invoice/receipt,
contract, warehouse, train-scheduling, and payment-receipt PDFs. Adds a
matching backoffice settings page and settings:logo:view/manage permissions.
>
customer-status (company-profile roles, not Company — importer/
exporter/forwarder lives there), contract-lifecycle, customs-documents
(clearance milestones), invoicing-pipeline, first-last-mile-bookings
(one resolver, UNION ALL over first_mile/last_mile — verified the
raw-string .from() subquery against the live query builder, not just
hand-written SQL, after the join-alias bug earlier this branch),
invoices-by-status, payments-by-status, revenue-summary, cargo-summary.
payments carries no deleted_at column despite extending BaseEntity —
caught by column-checking against the live DB before shipping, dropped
the soft-delete filter for that one query.
Completes the ITLMS dashboard spec's 20-resolver dedup list (19 built,
freight-weight-variance dropped — no charged-vs-actual weight
distinction in the schema).
booking-status-breakdown (dedupes the same 'status per port/train/
cargo/contract' ask across 4 dashboards), train-schedule-status,
train-turnaround, wagon-teu-utilization, loaded-capacity,
global-logistics-wagons.
Dropped freight-weight-variance from this batch: the schema has no
'charged weight' distinct from VGM/actual, so a charged-vs-actual
variance report isn't buildable without a product decision on what
'charged' means here.
wagon-fleet-status, wagon-status-duration, wagon-requests,
locomotive-fleet-status. First batch off the ITLMS dashboard spec —
fleet data (wagons/locomotives/transfer-requests) needed no schema
work, just resolvers. No frontend changes: catalog is server-driven.
Each report key (REPORT_KEYS) mints its own edr_freight_app:reports:<key>:view
permission, derived the same way rule-engine resource permissions are.
reports:view stays the section master key; STAFF_DASHBOARD_KEYS grants every
report key alongside it so existing presets don't regress on reseed.
- Implement ShippingLineCompaniesService for registering and managing shipping line companies.
- Create ResendActivationAction component for resending activation links to shipping lines.
- Develop ShippingLineCompaniesPage for listing and registering shipping lines with validation.
- Introduce shippingLineCompanies.service for API interactions related to shipping lines.
- Define types for shipping line companies, including registration and pagination.
- Add placeholder pages for shipping line portal, including home, bookings, help, invoices, and settings.
- Implemented utility to calculate wagon usage metrics for train schedules.
- Created for sending wagons to maintenance with optional notes.
- Added unit tests for train builder maintenance functionalities, including formatting train run labels and building maintenance notes.
- Developed component for merging train schedules with detailed previews and reasons for merging.
- Introduced component for selecting wagons with search functionality and selection limits.
- Created for displaying and filtering audit logs, including detailed views of individual log entries.
- Added for handling API interactions related to audit logs, including fetching logs and entity types.
They hold a TIN but no business licence, so there is no eTrade record to look
their registration up in. A checkbox on the first wizard step marks them, and
everything that assumed a trade licence bends around it:
- The company step replaces the eTrade lookup with typed registration details
— name, region, zone, woreda, kebele, house number — required exactly because
they are now on screen. applyEtradeSourcedFields skips the lookup rather than
failing it, so what the customer sends is what is stored.
- No freight-forwarder role. Forwarding is licensed work, so the option is not
offered, and the API refuses it at start-onboarding and at every later
role-add rather than letting approval fail on a document they cannot produce.
- No per-role business-licence upload, client-side or in the completion gate.
- Their own document set (company_onboarding_documents_cooperative) merges on
top of the nationality one, admin-managed like every other set. Nationality
wins a fileKey collision so no slot renders twice, and the DARS paper is not
injected into it — the set it merges onto already carries one.
- The owner is typed in full; with no eTrade manager on file the licence
comparison reports "nothing to compare against", which backoffice now
explains rather than leaving as a bare dash.
Stored as an attributes flag, not a column: everything it changes is
behavioural, and nothing queries or joins on it.
The director position held no warehouse permissions at all. It now
carries the same warehouse set as the chief tier: dashboard, warehouse
/yard/zone CRUD, allocation and fee rule CRUD, the inventory operation
set, inspection reports, interchange documents and fee invoices.
Unlike the dispatcher, the director owns the allocation and fee rules
themselves. The positions seeder backfills existing environments on
boot.
feat(train-builder): update permissions checks for train actions in UI
feat(contracts): enhance contract view and shipment request pages with new features
test(shipment-preview): add tests for customs clearing logic in booking preview
style(contract-sign-bar): create CSS for fixed sign bar layout