@tria-plc/iamapi-common throws BadRequestException with a raw,
untranslated code as the message (e.g. "user_role_not_found",
"unit_employee_limit_reached:5") — useErrorHandler's extractMessage
returned that string verbatim, so removing an org/unit admin whose
role row didn't match, or inviting past a unit's employee cap, toasted
the raw backend code instead of an explanation. Adds a small code→i18n
map checked before the raw-message fallback, shared by both the async
and sync error handlers so every caller (org-admin removal, employee
invites, etc.) picks it up for free.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was no UI to assign permissions to the Organization Admin role,
even though the backend's Role→Permission endpoints
(@tria-plc/iamapi-common's role-permissions routes) were already live
and unused. Adds a dedicated page — application picker + the existing
permission checklist — that assigns/reads permissions for the fixed
Organization Admin role, linked from the Organization Admins page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The "Copy Permissions From" dropdown in the position-type form only
filtered candidates by the selected organization's full unit set,
ignoring the form's own "Select Unit" field entirely — so switching
units never re-scoped the list, unlike the equivalent unit filter on
the position-management table.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
createGuestBooking (ONE_WAY) and createGuestRoundTripBooking overwrote the
authoritative discounted total with an undiscounted client-provided subtotal
(per-seat sum or reviewedTotalMinor) whenever one was present, silently
dropping a valid promos discount at booking-creation time, even though the
same promo was correctly applied in the fare-breakdown/quote step. Only the
no-client-subtotal fallback branch subtracted discountMinor.
Mirrors the existing usedClientSubtotal fix already present in
BookingsService.createOneWayBooking (H-13): subtract discountMinor from the
client subtotal before storing it, in ETB and display currency. TRANSIT and
ROUND_TRIP_TRANSIT were unaffected since neither overrides with a client
subtotal.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Searching on the last day of a month (e.g. 2026-07-31) built an invalid
"next day" string like "2026-07-32" for the Prisma date-range filter,
crashing POST /search with a PrismaClientValidationError in production.
Affected searchSchedules, searchAlternatives, classifyEmptySearch, and
searchTransitOptions — all four built the bound the same way.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Added functionality to cancel contracts, allowing users to provide a reason for cancellation.
- Updated contract statuses to include SUSPENDED and changed CLOSED to COMPLETED.
- Enhanced the UI to reflect the new cancellation option and updated messaging for contract statuses.
- Refactored contract booking actions to accommodate changes in booking logic for ONE_TIME and GENERAL contracts.
- Removed clearance document management from the contract detail page, as it is now handled per booking.
- Introduced a SQL script to reset bookings and train schedules for development purposes.