- 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.
Export cargo reaches a train two ways, but the platform only modelled
one. Direct truck-to-train cargo loads straight onto the wagon, never
enters a warehouse and so never has a GRN — yet assertExportReceivedWithGrn
required one before the carriage acceptance sheet could be issued or the
booking loaded from inside its schedule.
Adds export_handover_mode to freight.bookings (null = WAREHOUSE, so
existing bookings are unaffected) and teaches the shared gate to skip
DIRECT_TO_TRAIN. Both call sites are fixed by that single early return.
For direct bookings the carriage acceptance sheet builds its lines from
the booking's own containers, falling back to the declared bulk tonnage,
and is issuable as soon as the mode is chosen. Direct bookings are also
removed from the warehouse receive queue, since that cargo is never
coming to the shed.
Staff choose the mode from the booking detail page via a new endpoint
reusing bookings:operations. Switching to direct is refused once
warehouse inventory exists, so the two flows cannot cross.
Warehouse-then-train keeps every gate it had.
3300000000000 collided with BookingWagonCancellations after the rebase.
3320000000000 is also unavailable: BulkContractTemplates3320000000000 is
already recorded in freight.migrations on the shared dev database from a
branch not present in this checkout, so checking only src/migrations is not
sufficient.
3330000000000 is unique across src/migrations and greater than the current
maximum timestamp recorded in freight.migrations.
Rename the migration file and class. The migration has no explicit name field
and no other code references its previous identity.
Verify migration discovery through the actual runtime path:
scripts/migrate.js loads compiled dist/migrations/*.js migrations, while
application boot does not run migrations automatically. Confirm the renamed
migration is present in dist.
For controlled dev verification, remove its migration-history row and run
pnpm migration:run again. The migration is discovered and applied under
3330000000000; its idempotent DDL produces no schema changes where the EIMS
schema already exists.
Two gaps that only bite in production: nobody could see an invoice's filing
state, and a blocked chain was visible only in the logs.
A failed filing now notifies the staff who can act on it. An ambiguous result
is HIGH priority because it blocks every further invoice for the system number
until someone resolves it, and nothing else would surface that -- the sweep
just goes quiet. A deterministic rejection affects one invoice, so it is
normal priority. The alert never throws: it must not mask the filing outcome.
The backoffice invoice detail page gains an EIMS card showing status, IRN,
counter, submitted and acknowledged timestamps, and the gateway's own error
message, with actions gated on invoices:eims_register. FAILED offers "File
again" -- the reservation model already allows re-registering a rejected
invoice, so retry needed no new endpoint. UNKNOWN offers no re-file button at
all, since resubmitting risks a duplicate registration, and instead explains
that a supervisor must record the IRN or discard the attempt.
Also aligns the migration class name with its renamed file. The DDL is
idempotent, so re-applying under the new name is a no-op against the columns;
it leaves one superseded row in freight.migrations.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add manual single-invoice registration, verification and reconciliation.
Nothing submits automatically; invoice creation is untouched.
Sequencing uses a durable reservation. The counter is consumed and the
holder recorded in a committed transaction before the request leaves the
process, and the HTTP call runs outside every transaction. A counter is
therefore never reused once an attempt begins, a crash mid-flight leaves the
reservation standing instead of inviting a blind resubmission, and an
ambiguous result blocks the whole system number rather than one invoice --
PreviousIrn is unknown, so any later document would chain to a stale IRN.
Deterministic rejections (400/406/401/403) mark the invoice FAILED and clear
the block. Timeouts and 5xx mark it UNKNOWN and keep it. Since /v1/verify
takes an IRN we never received in that case, POST :id/eims/resolve is the
exit: record the IRN confirmed in the MoR portal, or discard. A recorded IRN
is verified against the gateway first and refused unless EIMS reports it
against this invoice's document number.
Business and tax configuration is validated locally before anything is
locked, allocated or sent, so a missing tax code fails naming the exact
environment variables instead of at the gateway. No tax value is defaulted.
Filing gets its own permission (invoices:eims_register) rather than riding
on invoices:export -- registration is irreversible at MoR and must not
follow from the right to download a PDF.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- tierList field type in rule-engine form dialog (add/remove rows,
overlap + open-ended validation, From km auto-continues)
- create submits one rate row per tier sequentially
- editing a band row keeps the single From/To/value form
The sheet attests EDR has taken custody. Export custody happens at
warehouse receipt, so the shared received-with-GRN gate now runs even
when wagons are already allocated. Receipt-row query also accepts the
legacy notes GRN fallback, matching the loading gate.
Top Returned Containers table ignored the EDR/Customer tab because
the backend never persisted which truck type performed the return.
Added returned_by column + DTO/entity field, wired create payload to
send it, and filtered the table by the active tab.
- Updated OverviewContractsTabPanel to include a new donut chart for freight type distribution.
- Modified OverviewOperationsTabPanel to improve data visualization with additional charts and refactored data handling.
- Introduced CreateScheduleWindowFields component for configuring booking windows in train scheduling.
- Added new API endpoints for allocation candidates and booking allocation in trainScheduling.service.
- Enhanced BookingRequestsPage to support allocation of paid bookings with a modal for selecting alternative dates.
- Updated QUERY_KEYS and URLS constants to accommodate new operations and features.
- Improved type definitions for overview and train scheduling to support new functionalities.
- Implemented in the to manage the physical item capacity for each wagon type.
- Added a new migration to create the column in the table.
- Introduced method in to update rate units when cargo type unit of measure changes.
- Updated booking calculations to consider items per wagon for break-bulk cargo.
- Refactored various components to utilize the new items fit logic and ensure consistent date formatting across the application.
- Added tests for the new display timezone functionality to ensure consistent date/time representation across different user settings.
Ticket #238 — pre-approval edits and document uploads write straight
to the live company row with no approval gate and, until now, no
trace. Adds an append-only company_revisions log (diffed field
changes, document uploads) recorded from updateProfile and
uploadCompanyDocuments, exposed via GET /companies/:id/revisions and
shown as "Version history" on the backoffice customer detail page.
Ticket #420 — add approved_at to companies (migration), stamped at
both promotion sites (first-profile auto-approve and manual staff
status change). Surfaced as Submitted on/Approved on in the backoffice
customer list and detail views.