mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-06 07:43:38 +00:00
Merge branch 'dev' of github.com:Tria-plc/edr-platform into origin/freight_feature/transit
This commit is contained in:
@@ -76,9 +76,14 @@ export interface ETradeBusinessOption {
|
||||
|
||||
export interface CompanyRegistrationData {
|
||||
/**
|
||||
* The registered organization name — `ETradeCompanyInfo.BusinessName`, falling
|
||||
* back to the licence's `TradeName`. Never the manager/owner's personal name;
|
||||
* that is {@link managerName}.
|
||||
* The selected licence's trade name — `ETradeBusinessInfo.TradeName`, falling
|
||||
* back to the registered organization name (`ETradeCompanyInfo.BusinessName`)
|
||||
* when eTrade leaves the licence's trade name blank. Never the manager/owner's
|
||||
* personal name; that is {@link managerName}.
|
||||
*
|
||||
* NOT the legal entity name: a TIN often trades under a different name, and
|
||||
* some hold several licences with different trade names. Anything that needs
|
||||
* the registered name (tax/EIMS) must read `BusinessName` directly.
|
||||
*/
|
||||
companyName: string;
|
||||
licenceNumber: string;
|
||||
|
||||
@@ -439,6 +439,123 @@ export interface IWagonMovement extends BaseEntity {
|
||||
note?: string | null;
|
||||
}
|
||||
|
||||
/** Which slice of a wagon's life an event belongs to — the history filter axis. */
|
||||
export enum WagonEventCategory {
|
||||
Lifecycle = "LIFECYCLE",
|
||||
Yard = "YARD",
|
||||
Train = "TRAIN",
|
||||
Schedule = "SCHEDULE",
|
||||
Status = "STATUS",
|
||||
Cargo = "CARGO",
|
||||
}
|
||||
|
||||
/**
|
||||
* Every recorded transition in a wagon's history (`freight.wagon_events`).
|
||||
* One row per wagon per transition, append-only, written inside the same
|
||||
* transaction as the change itself.
|
||||
*/
|
||||
export enum WagonEventType {
|
||||
// Lifecycle
|
||||
Registered = "REGISTERED",
|
||||
DetailsUpdated = "DETAILS_UPDATED",
|
||||
Deleted = "DELETED",
|
||||
Purged = "PURGED",
|
||||
// Yard (where the wagon physically is)
|
||||
MovedManually = "MOVED_MANUALLY",
|
||||
MovedWithTrain = "MOVED_WITH_TRAIN",
|
||||
PassedCheckpoint = "PASSED_CHECKPOINT",
|
||||
CutAtYard = "CUT_AT_YARD",
|
||||
SettledOnArrival = "SETTLED_ON_ARRIVAL",
|
||||
ReleasedAtUnload = "RELEASED_AT_UNLOAD",
|
||||
ReturnedOnCancel = "RETURNED_ON_CANCEL",
|
||||
// Built train / consist
|
||||
CoupledToTrain = "COUPLED_TO_TRAIN",
|
||||
UncoupledFromTrain = "UNCOUPLED_FROM_TRAIN",
|
||||
SequenceChanged = "SEQUENCE_CHANGED",
|
||||
TrainMerged = "TRAIN_MERGED",
|
||||
TrainDisbanded = "TRAIN_DISBANDED",
|
||||
// Schedule slot
|
||||
PinnedToSchedule = "PINNED_TO_SCHEDULE",
|
||||
UnpinnedFromSchedule = "UNPINNED_FROM_SCHEDULE",
|
||||
Dispatched = "DISPATCHED",
|
||||
ReleasedFromSchedule = "RELEASED_FROM_SCHEDULE",
|
||||
// Status
|
||||
StatusChanged = "STATUS_CHANGED",
|
||||
// Cargo
|
||||
CargoLoaded = "CARGO_LOADED",
|
||||
CargoUnloaded = "CARGO_UNLOADED",
|
||||
BookingUnassigned = "BOOKING_UNASSIGNED",
|
||||
BookingCancelled = "BOOKING_CANCELLED",
|
||||
LoadMovedIn = "LOAD_MOVED_IN",
|
||||
LoadMovedOut = "LOAD_MOVED_OUT",
|
||||
ContainerPlaced = "CONTAINER_PLACED",
|
||||
ContainerRemoved = "CONTAINER_REMOVED",
|
||||
}
|
||||
|
||||
export const WAGON_EVENT_CATEGORY: Record<WagonEventType, WagonEventCategory> = {
|
||||
[WagonEventType.Registered]: WagonEventCategory.Lifecycle,
|
||||
[WagonEventType.DetailsUpdated]: WagonEventCategory.Lifecycle,
|
||||
[WagonEventType.Deleted]: WagonEventCategory.Lifecycle,
|
||||
[WagonEventType.Purged]: WagonEventCategory.Lifecycle,
|
||||
[WagonEventType.MovedManually]: WagonEventCategory.Yard,
|
||||
[WagonEventType.MovedWithTrain]: WagonEventCategory.Yard,
|
||||
[WagonEventType.PassedCheckpoint]: WagonEventCategory.Yard,
|
||||
[WagonEventType.CutAtYard]: WagonEventCategory.Yard,
|
||||
[WagonEventType.SettledOnArrival]: WagonEventCategory.Yard,
|
||||
[WagonEventType.ReleasedAtUnload]: WagonEventCategory.Yard,
|
||||
[WagonEventType.ReturnedOnCancel]: WagonEventCategory.Yard,
|
||||
[WagonEventType.CoupledToTrain]: WagonEventCategory.Train,
|
||||
[WagonEventType.UncoupledFromTrain]: WagonEventCategory.Train,
|
||||
[WagonEventType.SequenceChanged]: WagonEventCategory.Train,
|
||||
[WagonEventType.TrainMerged]: WagonEventCategory.Train,
|
||||
[WagonEventType.TrainDisbanded]: WagonEventCategory.Train,
|
||||
[WagonEventType.PinnedToSchedule]: WagonEventCategory.Schedule,
|
||||
[WagonEventType.UnpinnedFromSchedule]: WagonEventCategory.Schedule,
|
||||
[WagonEventType.Dispatched]: WagonEventCategory.Schedule,
|
||||
[WagonEventType.ReleasedFromSchedule]: WagonEventCategory.Schedule,
|
||||
[WagonEventType.StatusChanged]: WagonEventCategory.Status,
|
||||
[WagonEventType.CargoLoaded]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.CargoUnloaded]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.BookingUnassigned]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.BookingCancelled]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.LoadMovedIn]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.LoadMovedOut]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.ContainerPlaced]: WagonEventCategory.Cargo,
|
||||
[WagonEventType.ContainerRemoved]: WagonEventCategory.Cargo,
|
||||
};
|
||||
|
||||
/** One row of a wagon's history as served by `GET /wagons/:id/history` (labels resolved). */
|
||||
export interface WagonHistoryEvent {
|
||||
id: string;
|
||||
wagonId: string;
|
||||
wagonNumber: string | null;
|
||||
type: WagonEventType;
|
||||
category: WagonEventCategory;
|
||||
occurredAt: string;
|
||||
actorUserId: string | null;
|
||||
actorName: string | null;
|
||||
fromYardId: string | null;
|
||||
fromYardLabel: string | null;
|
||||
toYardId: string | null;
|
||||
toYardLabel: string | null;
|
||||
trainId: string | null;
|
||||
trainCode: string | null;
|
||||
trainScheduleId: string | null;
|
||||
scheduleLabel: string | null;
|
||||
bookingId: string | null;
|
||||
bookingReference: string | null;
|
||||
fromValue: string | null;
|
||||
toValue: string | null;
|
||||
reason: string | null;
|
||||
metadata: Record<string, unknown> | null;
|
||||
}
|
||||
|
||||
/** Keyset page of a wagon's history, newest first. `nextCursor` is null on the last page. */
|
||||
export interface WagonHistoryPage {
|
||||
items: WagonHistoryEvent[];
|
||||
nextCursor: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle of a two-person wagon-transfer request. A requester asks for N
|
||||
* wagons of a type to move from one yard to another (count only, no specific
|
||||
@@ -648,6 +765,25 @@ export interface ICustomerTruckContainer {
|
||||
containerNumber: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The truck-type vocabulary a customer picks from when self-hauling. The API
|
||||
* validates against this exact list (`@IsIn`), the portal's dropdown renders it,
|
||||
* and the bulk-upload template documents it — all three read this constant so a
|
||||
* value the customer can type can never be one the API rejects.
|
||||
*/
|
||||
export const CUSTOMER_TRUCK_TYPES = [
|
||||
"Flatbed",
|
||||
"Container Chassis",
|
||||
"Lowboy",
|
||||
"Box Truck",
|
||||
"Tipper",
|
||||
] as const;
|
||||
|
||||
export type CustomerTruckType = (typeof CUSTOMER_TRUCK_TYPES)[number];
|
||||
|
||||
/** ISO 6346 container number: four letters then seven digits, e.g. ABCD1234567. */
|
||||
export const ISO_CONTAINER_NUMBER = /^[A-Z]{4}\d{7}$/;
|
||||
|
||||
/** A customer self-haul truck on a booking, carrying 1–2 containers. */
|
||||
export interface ICustomerTruck {
|
||||
id: string;
|
||||
@@ -659,6 +795,10 @@ export interface ICustomerTruck {
|
||||
arrivedAt?: string | null;
|
||||
departedAt?: string | null;
|
||||
containers?: ICustomerTruckContainer[];
|
||||
/** Bulk: planned tonnage this truck hauls. `numeric` — serialises as a string. */
|
||||
plannedTons?: number | string | null;
|
||||
/** Bulk PER_ITEM: planned item/piece count on this truck. */
|
||||
plannedQuantity?: number | null;
|
||||
}
|
||||
|
||||
/** Payload to add a customer self-haul truck (1–2 container numbers). */
|
||||
@@ -666,7 +806,12 @@ export interface AddCustomerTruckPayload {
|
||||
truckPlateNumber: string;
|
||||
driverName: string;
|
||||
truckType: string;
|
||||
containerNumbers: string[];
|
||||
/** Container bookings only — bulk trucks haul loose tonnage instead. */
|
||||
containerNumbers?: string[];
|
||||
/** Bulk: planned tonnage, drawn down against the booking's declared VGM. */
|
||||
plannedTons?: number;
|
||||
/** Bulk PER_ITEM: planned item/piece count. */
|
||||
plannedQuantity?: number;
|
||||
}
|
||||
|
||||
export interface IBooking extends BaseEntity {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { BaseEntity } from "../common";
|
||||
export * from "./support-chat";
|
||||
export * from "./blocked-seat-revenue-loss";
|
||||
|
||||
|
||||
export enum TicketStatus {
|
||||
Reserved = "RESERVED",
|
||||
Confirmed = "CONFIRMED",
|
||||
@@ -38,9 +39,9 @@ export enum ScheduleStatus {
|
||||
/**
|
||||
* Why a /search leg (outbound or inbound) came back with zero bookable schedules.
|
||||
* Priority order applied by the API when classifying: NoRoute > NoScheduleOnDate >
|
||||
* Cancelled > PackageOnly > CheckinClosed > FullyBooked (see search.service.ts
|
||||
* classifyEmptySearch). The frontend uses this to show a specific empty-state
|
||||
* message instead of a generic "no trains available".
|
||||
* Cancelled > PackageOnly > GroupBookingOnly > CheckinClosed > FullyBooked (see
|
||||
* search.service.ts classifyEmptySearch). The frontend uses this to show a specific
|
||||
* empty-state message instead of a generic "no trains available".
|
||||
*/
|
||||
export enum SearchEmptyReasonCode {
|
||||
/** No route (in either direction) ever connects these two stations. */
|
||||
@@ -51,6 +52,8 @@ export enum SearchEmptyReasonCode {
|
||||
Cancelled = "CANCELLED",
|
||||
/** Every schedule for this pair on this date is package-only (excluded from ticket search). */
|
||||
PackageOnly = "PACKAGE_ONLY",
|
||||
/** Every schedule for this pair on this date is reserved for staff group bookings (excluded from normal ticket search). */
|
||||
GroupBookingOnly = "GROUP_BOOKING_ONLY",
|
||||
/** A bookable schedule exists, but its check-in cutoff has already passed for every option. */
|
||||
CheckinClosed = "CHECKIN_CLOSED",
|
||||
/** A bookable, still-open schedule exists but has no seats left for the requested party. */
|
||||
|
||||
Reference in New Issue
Block a user