booking operations and trains scheduling also allocations

This commit is contained in:
marshal
2026-06-10 00:48:32 +03:00
parent 675975bc08
commit 5774d7db9d
180 changed files with 13423 additions and 3877 deletions

View File

@@ -6,6 +6,7 @@ import {
MessageSquareWarning,
Play,
ShieldCheck,
TrainTrack,
Truck,
XCircle,
} from "lucide-react";
@@ -30,6 +31,7 @@ export type BookingActionId =
| "rejectApproval"
| "viewContract"
| "signContractStaff"
| "allocateBooking"
| "startTransit"
| "complete"
| "cancel";
@@ -53,9 +55,25 @@ export interface BookingActionDef {
export type BookingActionContext = Pick<
BookingDetail,
"status" | "paymentCurrency" | "approvalSteps" | "reference"
"status" | "paymentCurrency" | "approvalSteps" | "reference" | "schedulingStatus"
>;
const ALLOCATABLE_SCHEDULING_STATUSES = new Set([
"NOT_SCHEDULED",
"HOLDING",
"ELIGIBLE",
undefined,
null,
"",
]);
export function canAllocateBooking(booking: Pick<BookingDetail, "status" | "schedulingStatus">) {
return (
booking.status === "PAID" &&
ALLOCATABLE_SCHEDULING_STATUSES.has(booking.schedulingStatus ?? undefined)
);
}
export function getNextPendingApprovalStep(
steps?: BookingApprovalStep[] | null,
): BookingApprovalStep | undefined {
@@ -270,19 +288,45 @@ export function getBookingActions(
actions = [{ ...VIEW_CONTRACT_ACTION, label: "View executed contract", primary: true }];
break;
case "PAID":
actions = [
{
id: "startTransit",
label: "Start transit",
shortLabel: "Transit",
description: "Begin rail movement",
confirmTitle: "Start transit?",
confirmDescription: "The booking will move to in transit status.",
variant: "default",
icon: Truck,
primary: true,
},
];
if (canAllocateBooking({ status, schedulingStatus: ctx.schedulingStatus })) {
actions = [
{
id: "allocateBooking",
label: "Allocate booking",
shortLabel: "Allocate",
description: "Assign to train, wagons, and finalize schedule",
confirmTitle: "Allocate booking?",
confirmDescription: "Opens the train allocation wizard.",
variant: "default",
icon: TrainTrack,
primary: true,
},
{
id: "startTransit",
label: "Start transit",
shortLabel: "Transit",
description: "Begin rail movement",
confirmTitle: "Start transit?",
confirmDescription: "The booking will move to in transit status.",
variant: "default",
icon: Truck,
},
];
} else {
actions = [
{
id: "startTransit",
label: "Start transit",
shortLabel: "Transit",
description: "Begin rail movement",
confirmTitle: "Start transit?",
confirmDescription: "The booking will move to in transit status.",
variant: "default",
icon: Truck,
primary: true,
},
];
}
break;
case "IN_TRANSIT":
actions = [
@@ -316,6 +360,11 @@ export function isContractNavAction(id: BookingActionId): boolean {
return id === "viewContract" || id === "signContractStaff";
}
/** Opens allocation wizard without confirmation dialog. */
export function isAllocateAction(id: BookingActionId): boolean {
return id === "allocateBooking";
}
export function listRowHasActions(
row: {
status: BookingStatus;
@@ -329,7 +378,8 @@ export function listRowHasActions(
status: row.status,
paymentCurrency: row.paymentCurrency,
reference: "",
approvalSteps: row.approvalSteps,
approvalSteps: row.approvalSteps ?? undefined,
schedulingStatus: row.schedulingStatus,
},
user,
);

View File

@@ -19,7 +19,9 @@ export function toBookingListRow(booking: BookingDetail): BookingListRow {
id: booking.id,
reference: booking.reference,
approvalSteps: booking.approvalSteps,
customerLabel: labelFromRef(booking.company, booking.companyId),
customerLabel: booking.isGovernment
? (booking.governmentInstitution ?? "Government")
: labelFromRef(booking.company, booking.companyId ?? undefined),
// customerLabel: labelFromRef(booking.customer, booking.customerId),
status: booking.status,
scheduledDate: booking.scheduledDate,
@@ -31,6 +33,15 @@ export function toBookingListRow(booking: BookingDetail): BookingListRow {
originLabel: labelFromRef(booking.originYard),
destinationLabel: labelFromRef(booking.destinationYard),
priorityScore: booking.priorityScore ?? 0,
schedulingStatus: booking.schedulingStatus,
serviceTypeLabel:
booking.serviceType?.label ??
booking.serviceType?.name ??
booking.serviceType?.code,
serviceTypeBonus: booking.serviceType?.priorityBonusPoints ?? 0,
trainScheduleId: booking.trainScheduleId ?? null,
isGovernment: booking.isGovernment ?? false,
governmentInstitution: booking.governmentInstitution ?? null,
createdAt: booking.createdAt,
};
}