Files
edr-platform/apps/edr-freight-web/backoffice/src/services/api.ts

2936 lines
85 KiB
TypeScript

import type { Freight, PaginatedResponse } from "@edr/types";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import type { FleetResourceSlug } from "@/pages/fleet/config/resources";
import type { BookingDetail } from "@/types/booking";
import type {
Company,
CompanyChangeRequest,
CompanyListFilter,
CompanyProfile,
CompanyRevision,
CompanyStats,
CustomerBooking,
CustomerDocument,
CustomerPayment,
CustomerResetTarget,
PaginatedCompanies,
ProfileStatus,
ResetChannel,
ResetPasswordResult,
} from "@/types/customer";
import {
CreateDropdownOptionDto,
CreateDropdownSettingDto,
DropdownOption,
DropdownSetting,
DropdownSettingListQuery,
PaginatedDropdownSettings,
UpdateDropdownOptionDto,
UpdateDropdownSettingDto,
} from "@/types/dropdownSettings";
import type {
CreateFileUploadFieldDto,
CreateFileUploadSettingDto,
FileUploadField,
FileUploadSetting,
UpdateFileUploadFieldDto,
UpdateFileUploadSettingDto,
} from "@/types/fileUploadSettings";
import type {
Invoice,
InvoiceListFilter,
PaginatedInvoices,
} from "@/types/invoice";
import type { IOverviewDashboard, OverviewRange } from "@/types/overview";
import {
RuleEngineListResult,
RuleEngineRecord,
RuleEngineResourceSlug,
} from "@/types/rule-engine";
import type {
AssignBookingsPayload,
BatchBoardFilters,
BatchBoardListResponse,
BatchBoardScheduleDetail,
BookableSchedule,
BookingWindow,
CompositionRemovalEntry,
CreateTrainSchedulePayload,
EligibleContainerBookingsResponse,
FreightType,
ImportLoadingBookingsResponse,
DocReviewAlert,
LoadingStatus,
LocomotiveRecord,
PinWagonsPayload,
RecordCheckpointPayload,
StaffBookingWindow,
TrainScheduleDetail,
TrainScheduleFilters,
TrainScheduleListFilters,
TrainScheduleListResponse,
UpdateScheduleWindowRulePayload,
TrainSchedulePreviewPayload,
TrainSchedulePreviewResponse,
TrainTrackResponse,
UnassignedBookingsResponse,
WagonAllocationAttemptResult,
YardOption,
} from "@/types/trainScheduling";
import type {
AllocationCriteria,
AllocationPreviewResult,
AllocationRule,
ArrivalQueueItem,
AutoLoadResult,
AutoUnloadArrivedResult,
AutoUnloadResult,
BookingScheduleView,
BulkDispatchResult,
BulkInspectPayload,
BulkInspectResult,
BulkReceivePayload,
BulkReceiveResult,
DeliverInventoryPayload,
EligibleBooking,
FeePreview,
FeeRule,
ImportTrain,
ImportTrainItem,
ImportUnloadedItem,
InspectionAttachment,
InspectionReport,
InspectionReportPayload,
InventoryFilter,
InventoryInquiryFilter,
InventoryInquiryResult,
InventoryMovement,
InitiateWarehouseInvoicePaymentPayload,
LoadableWagon,
LoadInventoryPayload,
MoveInventoryPayload,
StoreInventoryPayload,
PayInvoicePayload,
ReadyToLoadRow,
ReceiveInventoryPayload,
ReleaseOrderPayload,
ReserveInventoryPayload,
SaveAllocationRulePayload,
SaveFeeRulePayload,
SaveWarehousePayload,
SaveYardPayload,
SaveZonePayload,
Warehouse,
WarehouseActivityLog,
WarehouseDashboard,
WarehouseFeeInvoice,
WarehouseInvoicePaymentResponse,
WarehouseFilter,
WarehouseInventoryItem,
WarehouseInvoiceFilter,
WarehouseLoading,
WarehouseYard,
WarehouseZone,
} from "@/types/warehouse";
import { endpoint } from "@/utils/endpoint";
import {
BookingListFilter,
bookingsService,
type PaginatedBookings,
} from "./bookings.service";
import { cargoTypesService } from "./cargo-types.service";
import {
cargoService,
type Cargo,
type DeliverCargoPayload,
} from "./cargoService";
import { containerTypesService } from "./container-types.service";
import { containerService, type Container } from "./containerService";
import { customersService } from "./customers.service";
import { invoicesService } from "./invoices.service";
import { dropdownSettingsService } from "./dropdownSettings.service";
import { fileUploadSettingsService } from "./fileUploadSettings.service";
import {
fleetService,
type FleetListFilters,
type FleetRecord,
} from "./fleet/fleet.service";
import {
locomotivesService,
type Locomotive,
type LocomotiveListFilters,
type SaveLocomotivePayload,
} from "./locomotives.service";
import { overviewService } from "./overview.service";
import {
auditService,
type AuditLogListFilter,
type PaginatedAuditLogs,
} from "./audit.service";
import { reportsService } from "./reports.service";
import type { ReportQueryInput, ReportResult } from "@/types/reports";
import {
paymentsService,
type PaginatedPayments,
type PaymentListFilter,
type PaymentSummary,
} from "./payments.service";
import {
routesService,
type RouteListFilters,
type RouteRecord,
type SaveRoutePayload,
type YardRef,
} from "./routes.service";
import {
RuleEngineListParams,
ruleEngineService,
} from "./ruleEngine/ruleEngine.service";
import {
signaturesService,
type SavedSignature,
type SaveSignaturePayload,
} from "./signatures.service";
import { trainService, type Train } from "./trains.service";
import {
trainBuilderService,
type AdjustConsistPayload,
type AdjustConsistResult,
type AvailableTrain,
type BuildTrainPayload,
type BuiltTrainListFilters,
type BuiltTrainListResponse,
type ScheduleConsist,
type ScheduleHistoryEntry,
type TrainComposition,
type UpdateTrainDetailsPayload,
type UsedTrainNumbers,
} from "./trainBuilder.service";
import { trainSchedulingService } from "./trainScheduling.service";
import { truckTypesService, type TruckType } from "./truck-types.service";
import { wagonTypesService, type WagonType } from "./wagon-types.service";
import {
wagonService,
wagonTransferRequestService,
type Wagon,
type WagonListFilters,
type WagonMovementRecord,
type WagonStatusLog,
type WagonTransferRequest,
type CreateTransferRequestPayload,
type BulkFulfillResult,
type TransferHistory,
type TransferRequestListFilter,
} from "./wagon.service";
import { warehouseService } from "./warehouse.service";
/** Query keys for inventory-lifecycle mutations that ripple across views. */
const INVENTORY_INVALIDATIONS: ReadonlyArray<readonly unknown[]> = [
["warehouse-inventory"],
["warehouse-loadings"],
["warehouses"],
// Singular `"warehouse"` root covers loadableWagons / bookingSchedule, which
// change when inventory is loaded/dispatched. Distinct from the `warehouse-*`
// roots above (prefix matching is element-exact, not string-prefix).
["warehouse"],
];
/**
* Train-scheduling mutations broadly affect the schedule board and bookings.
* The grouped hooks invalidated TRAIN_SCHEDULING.ROOT + BOOKINGS.ROOT; since
* every train-scheduling key is prefixed with `"train-scheduling"`, the two
* roots below cover all of them via React Query's prefix matching.
*/
const TRAIN_SCHEDULING_INVALIDATIONS: ReadonlyArray<readonly unknown[]> = [
QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
QUERY_KEYS.BOOKINGS.ROOT,
];
/**
* Train Builder mutations change wagon/locomotive availability and the
* schedule-creation train picker alongside the builder's own lists.
*/
const TRAIN_BUILDER_INVALIDATIONS: ReadonlyArray<readonly unknown[]> = [
QUERY_KEYS.TRAIN_BUILDER.ROOT,
QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
["wagons"],
["locomotives"],
["trains"],
QUERY_KEYS.FLEET.ROOT,
];
export const api = {
trainScheduling: {
// ── Queries ────────────────────────────────────────────────────────────
scheduleList: endpoint<
{ freightType?: FreightType; filters?: TrainScheduleListFilters },
TrainScheduleListResponse
>(
"train-scheduling",
"schedules",
({ freightType, filters }) =>
trainSchedulingService.listSchedules(freightType, filters),
({ filters }) => QUERY_KEYS.TRAIN_SCHEDULING.schedules(filters),
),
batchBoard: endpoint<
{ filters?: BatchBoardFilters },
BatchBoardListResponse
>(
"train-scheduling",
"batch-board",
({ filters }) => trainSchedulingService.getBatchBoard(filters),
({ filters }) => QUERY_KEYS.TRAIN_SCHEDULING.batchBoard(filters),
),
allBookingWindows: endpoint<void, StaffBookingWindow[]>(
"train-scheduling",
"all-booking-windows",
() => trainSchedulingService.getAllBookingWindows(),
() => ["train-scheduling", "all-booking-windows"],
),
docReviewAlert: endpoint<void, DocReviewAlert | null>(
"train-scheduling",
"doc-review-alert",
() => trainSchedulingService.getDocReviewAlert(),
() => ["train-scheduling", "doc-review-alert"],
),
batchBoardDetail: endpoint<
{ scheduleId: string },
BatchBoardScheduleDetail
>(
"train-scheduling",
"batch-board-detail",
({ scheduleId }) =>
trainSchedulingService.getBatchBoardDetail(scheduleId),
({ scheduleId }) =>
QUERY_KEYS.TRAIN_SCHEDULING.batchBoardDetail(scheduleId),
),
scheduleDetail: endpoint<
{ id: string; freightType?: FreightType },
TrainScheduleDetail
>(
"train-scheduling",
"schedule-detail",
({ id, freightType }) =>
trainSchedulingService.getScheduleById(id, freightType),
({ id }) => QUERY_KEYS.TRAIN_SCHEDULING.scheduleById(id),
),
eligibleBookings: endpoint<
{ filters?: TrainScheduleFilters; freightType?: FreightType },
EligibleContainerBookingsResponse
>(
"train-scheduling",
"eligible-bookings",
({ filters, freightType }) =>
trainSchedulingService.getEligibleBookings(filters, freightType),
({ filters, freightType }) =>
QUERY_KEYS.TRAIN_SCHEDULING.eligible(freightType, filters),
),
availableLocomotives: endpoint<{ routeId?: string }, LocomotiveRecord[]>(
"train-scheduling",
"locomotives",
({ routeId }) => trainSchedulingService.getAvailableLocomotives(routeId),
({ routeId }) => QUERY_KEYS.TRAIN_SCHEDULING.locomotives(routeId),
),
availableTrains: endpoint<{ routeId: string }, AvailableTrain[]>(
"train-scheduling",
"available-trains",
({ routeId }) =>
trainBuilderService.availableTrains(routeId).then((r) => r.data),
({ routeId }) => QUERY_KEYS.TRAIN_SCHEDULING.availableTrains(routeId),
),
scheduleConsist: endpoint<{ scheduleId: string }, ScheduleConsist>(
"train-scheduling",
"schedule-consist",
({ scheduleId }) =>
trainBuilderService.scheduleConsist(scheduleId).then((r) => r.data),
({ scheduleId }) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"consist",
scheduleId,
],
),
adjustConsist: endpoint<
{ scheduleId: string; payload: AdjustConsistPayload },
AdjustConsistResult
>(
"train-scheduling",
"adjust-consist",
({ scheduleId, payload }) =>
trainBuilderService.adjustConsist(scheduleId, payload).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
scheduleHistory: endpoint<{ scheduleId: string }, ScheduleHistoryEntry[]>(
"train-scheduling",
"schedule-history",
({ scheduleId }) =>
trainBuilderService.scheduleHistory(scheduleId).then((r) => r.data),
({ scheduleId }) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"history",
scheduleId,
],
),
bookableSchedules: endpoint<
{ originYardId?: string | null; destinationYardId?: string | null },
BookableSchedule[]
>(
"train-scheduling",
"bookable",
({ originYardId, destinationYardId }) =>
trainSchedulingService.getBookableSchedules(
originYardId ?? undefined,
destinationYardId ?? undefined,
),
({ originYardId, destinationYardId }) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"bookable",
originYardId ?? "",
destinationYardId ?? "",
],
),
contractBookingWindows: endpoint<{ contractId: string }, BookingWindow[]>(
"train-scheduling",
"contract-booking-windows",
({ contractId }) =>
trainSchedulingService.getContractBookingWindows(contractId),
({ contractId }) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"contract-booking-windows",
contractId,
],
),
availableDays: endpoint<
{ originYardId?: string | null; destinationYardId?: string | null },
string[]
>(
"train-scheduling",
"available-days",
({ originYardId, destinationYardId }) =>
trainSchedulingService.getAvailableDays(
originYardId ?? undefined,
destinationYardId ?? undefined,
),
({ originYardId, destinationYardId }) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"available-days",
originYardId ?? "",
destinationYardId ?? "",
],
),
availableDaysForCargo: endpoint<
{
originYardId?: string;
destinationYardId?: string;
freightType: "CONTAINER" | "BULK";
cargoTypeCode?: string;
totalWeightTons?: number;
containers?: { containerSize: string; quantity: number }[];
},
string[]
>(
"train-scheduling",
"available-days-for-cargo",
(input) => trainSchedulingService.getAvailableDaysForCargo(input),
(input) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"available-days-for-cargo",
input.originYardId ?? "",
input.destinationYardId ?? "",
input.freightType,
input.cargoTypeCode ?? "",
input.totalWeightTons ?? 0,
JSON.stringify(input.containers ?? []),
],
),
exportTrains: endpoint<
{
bookingId: string;
date: string;
cargo?: {
containerSizes?: string[];
cargoTypeCode?: string;
wagons?: number;
};
},
Freight.ExportTrainOption[]
>(
"train-scheduling",
"export-trains",
({ bookingId, date, cargo }) =>
trainSchedulingService.getExportTrains(bookingId, date, cargo),
({ bookingId, date, cargo }) => [
...QUERY_KEYS.TRAIN_SCHEDULING.ROOT,
"export-trains",
bookingId,
date,
JSON.stringify(cargo ?? {}),
],
),
trainTrack: endpoint<{ id: string }, TrainTrackResponse>(
"train-scheduling",
"track",
({ id }) => trainSchedulingService.getTrack(id),
({ id }) => QUERY_KEYS.TRAIN_SCHEDULING.track(id),
),
unassignedBookings: endpoint<
{ scheduleId: string },
UnassignedBookingsResponse
>(
"train-scheduling",
"unassigned-bookings",
({ scheduleId }) =>
trainSchedulingService.getUnassignedBookings(scheduleId),
({ scheduleId }) =>
QUERY_KEYS.TRAIN_SCHEDULING.unassignedBookings(scheduleId),
),
compositionRemovals: endpoint<
{ scheduleId: string },
CompositionRemovalEntry[]
>(
"train-scheduling",
"composition-removals",
({ scheduleId }) =>
trainSchedulingService.getCompositionRemovals(scheduleId),
({ scheduleId }) =>
QUERY_KEYS.TRAIN_SCHEDULING.compositionRemovals(scheduleId),
),
importLoadingBookings: endpoint<{ id: string }, ImportLoadingBookingsResponse>(
"train-scheduling",
"import-loading-bookings",
({ id }) => trainSchedulingService.getImportLoadingBookings(id),
({ id }) => QUERY_KEYS.TRAIN_SCHEDULING.importLoadingBookings(id),
),
updateImportLoadingStatus: endpoint<
{ id: string; bookingIds: string[]; loadingStatus: LoadingStatus },
ImportLoadingBookingsResponse
>(
"train-scheduling",
"update-import-loading-status",
({ id, bookingIds, loadingStatus }) =>
trainSchedulingService.updateImportLoadingStatus(id, { bookingIds, loadingStatus }),
undefined,
({ id }) => [QUERY_KEYS.TRAIN_SCHEDULING.importLoadingBookings(id)],
),
// ── Mutations ──────────────────────────────────────────────────────────
runAllocation: endpoint<
{ scheduleId: string },
WagonAllocationAttemptResult
>(
"train-scheduling",
"run-allocation",
({ scheduleId }) => trainSchedulingService.runAllocation(scheduleId),
undefined,
() => [QUERY_KEYS.TRAIN_SCHEDULING.ROOT],
),
runBatch: endpoint<string, BatchBoardScheduleDetail>(
"train-scheduling",
"run-batch",
(id) => trainSchedulingService.runBatch(id),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
completeDocReview: endpoint<string, BatchBoardScheduleDetail>(
"train-scheduling",
"doc-review-complete",
(id) => trainSchedulingService.completeDocReview(id),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
setBookingWindow: endpoint<
{ id: string; status: "OPEN" | "CLOSED" },
TrainScheduleDetail
>(
"train-scheduling",
"set-booking-window",
({ id, status }) => trainSchedulingService.setBookingWindow(id, status),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
updateScheduleWindowRule: endpoint<
{ id: string; payload: UpdateScheduleWindowRulePayload },
TrainScheduleDetail
>(
"train-scheduling",
"update-schedule-window-rule",
({ id, payload }) =>
trainSchedulingService.updateScheduleWindowRule(id, payload),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
updateScheduleDate: endpoint<
{ id: string; scheduleDate: string },
TrainScheduleDetail
>(
"train-scheduling",
"update-schedule-date",
({ id, scheduleDate }) =>
trainSchedulingService.updateScheduleDate(id, scheduleDate),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
markBookingPaid: endpoint<string, void>(
"train-scheduling",
"mark-booking-paid",
(bookingId) => trainSchedulingService.markBookingPaid(bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
expireBooking: endpoint<string, void>(
"train-scheduling",
"expire-booking",
(bookingId) => trainSchedulingService.expireBooking(bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
moveBookingSchedule: endpoint<
{ bookingId: string; trainScheduleId: string },
void
>(
"train-scheduling",
"move-booking-schedule",
({ bookingId, trainScheduleId }) =>
trainSchedulingService.moveBookingSchedule(bookingId, trainScheduleId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
createSchedule: endpoint<
{ freightType?: FreightType; payload: CreateTrainSchedulePayload },
TrainScheduleDetail
>(
"train-scheduling",
"create-schedule",
({ freightType, payload }) =>
trainSchedulingService.createSchedule(payload, freightType),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
preview: endpoint<
{ freightType?: FreightType; payload: TrainSchedulePreviewPayload },
TrainSchedulePreviewResponse
>("train-scheduling", "preview", ({ freightType, payload }) =>
trainSchedulingService.preview(payload, freightType),
),
assignBookings: endpoint<
{ id: string; freightType?: FreightType; payload: AssignBookingsPayload },
TrainScheduleDetail
>(
"train-scheduling",
"assign-bookings",
({ id, freightType, payload }) =>
trainSchedulingService.assignBookings(id, payload, freightType),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
assignUnassignedBooking: endpoint<
{ id: string; bookingId: string },
TrainScheduleDetail
>(
"train-scheduling",
"assign-unassigned-booking",
({ id, bookingId }) =>
trainSchedulingService.assignUnassignedBooking(id, bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
unassignBooking: endpoint<
{ id: string; bookingId: string },
TrainScheduleDetail
>(
"train-scheduling",
"unassign-booking",
({ id, bookingId }) =>
trainSchedulingService.unassignBooking(id, bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
switchGovernmentBooking: endpoint<
{ id: string; governmentBookingId: string; removeBookingIds: string[] },
TrainScheduleDetail
>(
"train-scheduling",
"switch-government-booking",
({ id, governmentBookingId, removeBookingIds }) =>
trainSchedulingService.switchGovernmentBooking(
id,
governmentBookingId,
removeBookingIds,
),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
setLoadingStatus: endpoint<
{ id: string; bookingIds: string[]; loadingStatus: LoadingStatus },
TrainScheduleDetail
>(
"train-scheduling",
"set-loading-status",
({ id, bookingIds, loadingStatus }) =>
trainSchedulingService.setLoadingStatus(id, { bookingIds, loadingStatus }),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
confirmLoading: endpoint<{ id: string }, TrainScheduleDetail>(
"train-scheduling",
"confirm-loading",
({ id }) => trainSchedulingService.confirmLoading(id),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
pinWagons: endpoint<
{ id: string; payload: PinWagonsPayload },
TrainScheduleDetail
>(
"train-scheduling",
"pin-wagons",
({ id, payload }) => trainSchedulingService.pinWagons(id, payload),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
finalizeSchedule: endpoint<string, TrainScheduleDetail>(
"train-scheduling",
"finalize-schedule",
(id) => trainSchedulingService.finalizeSchedule(id),
undefined,
// Finalize only flips statuses (schedule DRAFT→SCHEDULED + each booking's
// schedulingStatus) — it never touches allocation or loading. Refresh only
// the schedule detail/list + booking views instead of the broad
// train-scheduling ROOT, which refired the eligible-bookings / pool /
// yard-work queries and made the booking lists visibly reload.
() => [
["train-scheduling", "schedule"],
["train-scheduling", "schedules"],
QUERY_KEYS.BOOKINGS.ROOT,
],
),
dispatchSchedule: endpoint<string, TrainScheduleDetail>(
"train-scheduling",
"dispatch-schedule",
(id) => trainSchedulingService.dispatchSchedule(id),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
yardWork: endpoint<
{ scheduleId: string },
import("@/types/trainScheduling").YardWorkResult
>(
"train-scheduling",
"yard-work",
({ scheduleId }) => trainSchedulingService.getYardWork(scheduleId),
({ scheduleId }) => ["train-scheduling", "yard-work", scheduleId],
),
loadScheduleBooking: endpoint<
{ scheduleId: string; bookingId: string },
import("@/types/trainScheduling").BookingLoadResult
>(
"train-scheduling",
"booking-load",
({ scheduleId, bookingId }) =>
trainSchedulingService.loadScheduleBooking(scheduleId, bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
unloadScheduleBooking: endpoint<
{ scheduleId: string; bookingId: string },
import("@/types/trainScheduling").BookingUnloadResult
>(
"train-scheduling",
"booking-unload",
({ scheduleId, bookingId }) =>
trainSchedulingService.unloadScheduleBooking(scheduleId, bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
intercityBookings: endpoint<
void,
import("@/types/trainScheduling").IntercityRideAlongRow[]
>(
"train-scheduling",
"intercity-bookings",
() => trainSchedulingService.listIntercityBookings(),
() => ["train-scheduling", "intercity-bookings"],
),
intercityCandidates: endpoint<
{ scheduleId: string },
import("@/types/trainScheduling").IntercityCandidatesResult
>(
"train-scheduling",
"intercity-candidates",
({ scheduleId }) => trainSchedulingService.getIntercityCandidates(scheduleId),
({ scheduleId }) => ["train-scheduling", "intercity-candidates", scheduleId],
),
acceptIntercityBookings: endpoint<
{ scheduleId: string; bookingIds: string[] },
import("@/types/trainScheduling").IntercityAcceptResult
>(
"train-scheduling",
"intercity-accept",
({ scheduleId, bookingIds }) =>
trainSchedulingService.acceptIntercityBookings(scheduleId, bookingIds),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
loadIntercityBooking: endpoint<
{ scheduleId: string; bookingId: string },
void
>(
"train-scheduling",
"intercity-load",
({ scheduleId, bookingId }) =>
trainSchedulingService.loadIntercityBooking(scheduleId, bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
unloadIntercityBooking: endpoint<
{ scheduleId: string; bookingId: string },
void
>(
"train-scheduling",
"intercity-unload",
({ scheduleId, bookingId }) =>
trainSchedulingService.unloadIntercityBooking(scheduleId, bookingId),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
cancelSchedule: endpoint<
{ id: string; freightType?: FreightType },
TrainScheduleDetail
>(
"train-scheduling",
"cancel-schedule",
({ id, freightType }) =>
trainSchedulingService.cancelSchedule(id, freightType ?? "CONTAINER"),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
recordCheckpoint: endpoint<
{ id: string; payload: RecordCheckpointPayload },
TrainTrackResponse
>(
"train-scheduling",
"record-checkpoint",
({ id, payload }) => trainSchedulingService.recordCheckpoint(id, payload),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
arriveSchedule: endpoint<string, TrainScheduleDetail>(
"train-scheduling",
"arrive-schedule",
(id) => trainSchedulingService.arriveSchedule(id),
undefined,
() => TRAIN_SCHEDULING_INVALIDATIONS,
),
removeWagonSlot: endpoint<
{ scheduleId: string; wagonId: string },
TrainScheduleDetail
>(
"train-scheduling",
"remove-wagon-slot",
({ scheduleId, wagonId }) =>
trainSchedulingService.removeWagonSlot(scheduleId, wagonId),
undefined,
() => [QUERY_KEYS.TRAIN_SCHEDULING.ROOT],
),
updateContainerItem: endpoint<
{ scheduleId: string; itemId: string; containerNumber: string | null },
{ id: string; containerNumber: string | null }
>(
"train-scheduling",
"update-container-item",
({ scheduleId, itemId, containerNumber }) =>
trainSchedulingService.updateContainerItem(scheduleId, itemId, {
containerNumber,
}),
undefined,
() => [QUERY_KEYS.TRAIN_SCHEDULING.ROOT],
),
moveWagonLoad: endpoint<
{ scheduleId: string; wagonId: string; targetWagonId: string },
TrainScheduleDetail
>(
"train-scheduling",
"move-wagon-load",
({ scheduleId, wagonId, targetWagonId }) =>
trainSchedulingService.moveWagonLoad(scheduleId, wagonId, {
targetWagonId,
}),
undefined,
() => [QUERY_KEYS.TRAIN_SCHEDULING.ROOT],
),
},
warehouses: {
// ── Warehouses ─────────────────────────────────────────────────────────
list: endpoint<{ filter?: WarehouseFilter }, Warehouse[]>(
"warehouses",
"list",
({ filter }) => warehouseService.list(filter).then((r) => r.data),
),
getById: endpoint<{ id: string }, Warehouse>(
"warehouses",
"getById",
({ id }) => warehouseService.getById(id).then((r) => r.data),
),
dashboard: endpoint<void, WarehouseDashboard>(
"warehouses",
"dashboard",
() => warehouseService.dashboard().then((r) => r.data),
),
create: endpoint<SaveWarehousePayload, Warehouse>(
"warehouses",
"create",
(payload) => warehouseService.create(payload).then((r) => r.data),
undefined,
() => [["warehouses"]],
),
update: endpoint<
{ id: string; payload: Partial<SaveWarehousePayload> },
Warehouse
>(
"warehouses",
"update",
({ id, payload }) =>
warehouseService.update(id, payload).then((r) => r.data),
undefined,
() => [["warehouses"]],
),
// ── Yards ──────────────────────────────────────────────────────────────
listYards: endpoint<{ warehouseId: string }, WarehouseYard[]>(
"warehouses",
"listYards",
({ warehouseId }) =>
warehouseService.listYards(warehouseId).then((r) => r.data),
),
createYard: endpoint<
{ warehouseId: string; payload: SaveYardPayload },
WarehouseYard
>(
"warehouses",
"createYard",
({ warehouseId, payload }) =>
warehouseService.createYard(warehouseId, payload).then((r) => r.data),
undefined,
() => [["warehouses"]],
),
updateYard: endpoint<
{ id: string; payload: Partial<SaveYardPayload> },
WarehouseYard
>(
"warehouses",
"updateYard",
({ id, payload }) =>
warehouseService.updateYard(id, payload).then((r) => r.data),
undefined,
() => [["warehouses"], ["warehouse-yards"]],
),
// ── Zones ──────────────────────────────────────────────────────────────
listZones: endpoint<{ yardId: string }, WarehouseZone[]>(
"warehouses",
"listZones",
({ yardId }) => warehouseService.listZones(yardId).then((r) => r.data),
({ yardId }) => ["warehouse-yards", yardId, "zones"],
),
createZone: endpoint<
{ yardId: string; payload: SaveZonePayload },
WarehouseZone
>(
"warehouses",
"createZone",
({ yardId, payload }) =>
warehouseService.createZone(yardId, payload).then((r) => r.data),
undefined,
({ yardId }) => [["warehouse-yards", yardId, "zones"]],
),
updateZone: endpoint<
{ id: string; payload: Partial<SaveZonePayload> },
WarehouseZone
>(
"warehouses",
"updateZone",
({ id, payload }) =>
warehouseService.updateZone(id, payload).then((r) => r.data),
undefined,
() => [["warehouse-yards"]],
),
// ── Inventory (queries) ────────────────────────────────────────────────
listInventory: endpoint<
{ filter?: InventoryFilter },
WarehouseInventoryItem[]
>("warehouse-inventory", "list", ({ filter }) =>
warehouseService.listInventory(filter).then((r) => r.data),
),
inquiry: endpoint<
{ filter: InventoryInquiryFilter },
InventoryInquiryResult[]
>(
"warehouse-inventory",
"inquiry",
({ filter }) => warehouseService.inquiry(filter).then((r) => r.data),
({ filter }) => ["warehouse-inventory", "inquiry", filter],
),
eligibleBookings: endpoint<
{ direction?: "IMPORT" | "EXPORT" } | void,
EligibleBooking[]
>(
"warehouse-inventory",
"eligible-bookings",
(input) =>
warehouseService.eligibleBookings(input?.direction).then((r) => r.data),
(input) => [
"warehouse-inventory",
"eligible-bookings",
input?.direction ?? "ALL",
],
),
readyToLoadExport: endpoint<void, ReadyToLoadRow[]>(
"warehouse-inventory",
"ready-to-load-export",
() => warehouseService.readyToLoadExport().then((r) => r.data),
() => ["warehouse-inventory", "ready-to-load-export"],
),
receivedExport: endpoint<void, ReadyToLoadRow[]>(
"warehouse-inventory",
"received-export",
() => warehouseService.receivedExport().then((r) => r.data),
() => ["warehouse-inventory", "received-export"],
),
loadedExport: endpoint<void, ReadyToLoadRow[]>(
"warehouse-inventory",
"loaded-export",
() => warehouseService.loadedExport().then((r) => r.data),
() => ["warehouse-inventory", "loaded-export"],
),
importArriveQueue: endpoint<void, ImportTrain[]>(
"warehouse-inventory",
"import-arrive-queue",
() => warehouseService.importArriveQueue().then((r) => r.data),
() => ["warehouse-inventory", "import-arrive-queue"],
),
importTrainItems: endpoint<{ scheduleId: string }, ImportTrainItem[]>(
"warehouse-inventory",
"import-train-items",
({ scheduleId }) =>
warehouseService.importTrainItems(scheduleId).then((r) => r.data),
({ scheduleId }) => [
"warehouse-inventory",
"import-train-items",
scheduleId,
],
),
importUnloadedQueue: endpoint<void, ImportUnloadedItem[]>(
"warehouse-inventory",
"import-unloaded-queue",
() => warehouseService.importUnloadedQueue().then((r) => r.data),
() => ["warehouse-inventory", "import-unloaded-queue"],
),
importPickupReadyQueue: endpoint<void, ImportUnloadedItem[]>(
"warehouse-inventory",
"import-pickup-ready-queue",
() => warehouseService.importPickupReadyQueue().then((r) => r.data),
() => ["warehouse-inventory", "import-pickup-ready-queue"],
),
loadableWagons: endpoint<void, LoadableWagon[]>(
"warehouse",
"loadable-wagons",
() => warehouseService.loadableWagons().then((r) => r.data),
() => ["warehouse", "loadable-wagons"],
),
loadings: endpoint<
{ params?: { bookingId?: string; wagonId?: string } },
WarehouseLoading[]
>(
"warehouse-loadings",
"list",
({ params }) => warehouseService.loadings(params).then((r) => r.data),
({ params }) => ["warehouse-loadings", params ?? {}],
),
bookingSchedule: endpoint<{ bookingId: string }, BookingScheduleView>(
"warehouse",
"booking-schedule",
({ bookingId }) =>
warehouseService.bookingSchedule(bookingId).then((r) => r.data),
({ bookingId }) => ["warehouse", "booking-schedule", bookingId],
),
movements: endpoint<{ id: string }, InventoryMovement[]>(
"warehouse-inventory",
"movements",
({ id }) => warehouseService.movements(id).then((r) => r.data),
({ id }) => ["warehouse-inventory", id, "movements"],
),
activity: endpoint<{ id: string }, WarehouseActivityLog[]>(
"warehouse-inventory",
"activity",
({ id }) => warehouseService.activity(id).then((r) => r.data),
({ id }) => ["warehouse-inventory", id, "activity"],
),
arrivalQueue: endpoint<void, ArrivalQueueItem[]>(
"warehouse-inventory",
"arrival-queue",
() => warehouseService.arrivalQueue().then((r) => r.data),
() => ["warehouse-inventory", "arrival-queue"],
),
inspectionReports: endpoint<{ inventoryId: string }, InspectionReport[]>(
"warehouse-inventory",
"inspection-reports",
({ inventoryId }) =>
warehouseService.listInspectionReports(inventoryId).then((r) => r.data),
({ inventoryId }) => [
"warehouse-inventory",
inventoryId,
"inspection-reports",
],
),
allocationRules: endpoint<void, AllocationRule[]>(
"warehouse-allocation-rules",
"list",
() => warehouseService.listAllocationRules().then((r) => r.data),
() => ["warehouse-allocation-rules"],
),
feeRules: endpoint<void, FeeRule[]>(
"warehouse-fee-rules",
"list",
() => warehouseService.listFeeRules().then((r) => r.data),
() => ["warehouse-fee-rules"],
),
feePreview: endpoint<
{ inventoryId: string; billingCurrency?: "ETB" | "USD" },
FeePreview[]
>(
"warehouse-inventory",
"fee-preview",
({ inventoryId, billingCurrency }) =>
warehouseService
.feePreview(inventoryId, billingCurrency)
.then((r) => r.data),
({ inventoryId, billingCurrency }) => [
"warehouse-inventory",
inventoryId,
"fee-preview",
billingCurrency ?? "USD",
],
),
invoices: endpoint<
{ filter?: WarehouseInvoiceFilter },
WarehouseFeeInvoice[]
>(
"warehouse-fee-invoices",
"list",
({ filter }) => warehouseService.listInvoices(filter).then((r) => r.data),
({ filter }) => ["warehouse-fee-invoices", filter ?? {}],
),
invoice: endpoint<{ id: string }, WarehouseFeeInvoice>(
"warehouse-fee-invoices",
"detail",
({ id }) => warehouseService.getInvoice(id).then((r) => r.data),
({ id }) => ["warehouse-fee-invoices", "detail", id],
),
invoicesForInventory: endpoint<
{ inventoryId: string },
WarehouseFeeInvoice[]
>(
"warehouse-inventory",
"fee-invoices",
({ inventoryId }) =>
warehouseService.invoicesForInventory(inventoryId).then((r) => r.data),
({ inventoryId }) => ["warehouse-inventory", inventoryId, "fee-invoices"],
),
// ── Inventory (mutations) ──────────────────────────────────────────────
receiveInventory: endpoint<ReceiveInventoryPayload, WarehouseInventoryItem>(
"warehouse-inventory",
"receive",
(payload) =>
warehouseService.receiveInventory(payload).then((r) => r.data),
undefined,
() => [["warehouse-inventory"], ["warehouses"]],
),
store: endpoint<
{ id: string; payload?: StoreInventoryPayload },
WarehouseInventoryItem
>(
"warehouse-inventory",
"store",
({ id, payload }) => warehouseService.store(id, payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
reserve: endpoint<ReserveInventoryPayload, WarehouseInventoryItem>(
"warehouse-inventory",
"reserve",
(payload) => warehouseService.reserve(payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
markReadyForLoading: endpoint<string, WarehouseInventoryItem>(
"warehouse-inventory",
"mark-ready-for-loading",
(id) => warehouseService.markReadyForLoading(id).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
load: endpoint<
{ id: string; payload: LoadInventoryPayload },
WarehouseInventoryItem
>(
"warehouse-inventory",
"load",
({ id, payload }) =>
warehouseService.load(id, payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
dispatch: endpoint<string, WarehouseInventoryItem>(
"warehouse-inventory",
"dispatch",
(id) => warehouseService.dispatch(id).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
move: endpoint<
{ id: string; payload: MoveInventoryPayload },
WarehouseInventoryItem
>(
"warehouse-inventory",
"move",
({ id, payload }) =>
warehouseService.move(id, payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
markReadyForPickup: endpoint<string, WarehouseInventoryItem>(
"warehouse-inventory",
"mark-ready-for-pickup",
(id) => warehouseService.markReadyForPickup(id).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
release: endpoint<
{ id: string; payload: ReleaseOrderPayload },
WarehouseInventoryItem
>(
"warehouse-inventory",
"release",
({ id, payload }) =>
warehouseService.release(id, payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
deliver: endpoint<
{ id: string; payload: DeliverInventoryPayload },
WarehouseInventoryItem
>(
"warehouse-inventory",
"deliver",
({ id, payload }) =>
warehouseService.deliver(id, payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
bulkReceive: endpoint<BulkReceivePayload, BulkReceiveResult>(
"warehouse-inventory",
"bulk-receive",
(payload) => warehouseService.receiveBulk(payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
bulkMarkInspected: endpoint<BulkInspectPayload, BulkInspectResult>(
"warehouse-inventory",
"bulk-mark-inspected",
(payload) =>
warehouseService.bulkMarkInspected(payload).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
bulkDispatchExport: endpoint<string[], BulkDispatchResult>(
"warehouse-inventory",
"bulk-dispatch-export",
(inventoryIds) =>
warehouseService.bulkDispatchExport(inventoryIds).then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
autoUnloadArrivedBookings: endpoint<
{
scheduleId: string;
warehouseId?: string;
assignments?: {
bookingId: string;
warehouseId: string;
yardId: string;
zoneId: string;
}[];
},
AutoUnloadArrivedResult
>(
"warehouse-inventory",
"auto-unload-arrived-bookings",
({ scheduleId, warehouseId, assignments }) =>
warehouseService
.autoUnloadArrivedBookings({ scheduleId, warehouseId, assignments })
.then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
autoUnloadArrived: endpoint<void, AutoUnloadResult>(
"warehouse-inventory",
"auto-unload-arrived",
() => warehouseService.autoUnloadArrived().then((r) => r.data),
undefined,
() => [["warehouse-inventory"], ["warehouses"]],
),
autoLoadReady: endpoint<void, AutoLoadResult>(
"warehouse-inventory",
"auto-load-ready",
() => warehouseService.autoLoadReady().then((r) => r.data),
undefined,
() => INVENTORY_INVALIDATIONS,
),
unloadBooking: endpoint<
{ bookingId: string; payload?: Record<string, unknown> },
WarehouseInventoryItem
>(
"warehouse-inventory",
"unload-booking",
({ bookingId, payload }) =>
warehouseService.unloadBooking(bookingId, payload).then((r) => r.data),
undefined,
() => [["warehouse-inventory"], ["warehouses"]],
),
createInspectionReport: endpoint<
{ inventoryId: string; payload: InspectionReportPayload },
InspectionReport
>(
"warehouse-inventory",
"create-inspection-report",
({ inventoryId, payload }) =>
warehouseService
.createInspectionReport(inventoryId, payload)
.then((r) => r.data),
undefined,
({ inventoryId }) => [
["warehouse-inventory", inventoryId, "inspection-reports"],
["warehouse-inventory"],
],
),
uploadInspectionAttachments: endpoint<
{ reportId: string; files: File[] },
InspectionAttachment[]
>(
"warehouse-inventory",
"upload-inspection-attachments",
({ reportId, files }) =>
warehouseService
.uploadInspectionAttachments(reportId, files)
.then((r) => r.data),
),
// ── Allocation + fee rules ─────────────────────────────────────────────
previewAllocation: endpoint<
AllocationCriteria,
AllocationPreviewResult | null
>("warehouse-allocation-rules", "preview", (criteria) =>
warehouseService.previewAllocation(criteria).then((r) => r.data),
),
createAllocationRule: endpoint<SaveAllocationRulePayload, AllocationRule>(
"warehouse-allocation-rules",
"create",
(payload) =>
warehouseService.createAllocationRule(payload).then((r) => r.data),
undefined,
() => [["warehouse-allocation-rules"]],
),
updateAllocationRule: endpoint<
{ id: string; payload: Partial<SaveAllocationRulePayload> },
AllocationRule
>(
"warehouse-allocation-rules",
"update",
({ id, payload }) =>
warehouseService.updateAllocationRule(id, payload).then((r) => r.data),
undefined,
() => [["warehouse-allocation-rules"]],
),
deleteAllocationRule: endpoint<string, void>(
"warehouse-allocation-rules",
"delete",
(id) => warehouseService.deleteAllocationRule(id).then(() => undefined),
undefined,
() => [["warehouse-allocation-rules"]],
),
createFeeRule: endpoint<SaveFeeRulePayload, FeeRule>(
"warehouse-fee-rules",
"create",
(payload) => warehouseService.createFeeRule(payload).then((r) => r.data),
undefined,
() => [["warehouse-fee-rules"]],
),
updateFeeRule: endpoint<
{ id: string; payload: Partial<SaveFeeRulePayload> },
FeeRule
>(
"warehouse-fee-rules",
"update",
({ id, payload }) =>
warehouseService.updateFeeRule(id, payload).then((r) => r.data),
undefined,
() => [["warehouse-fee-rules"]],
),
deleteFeeRule: endpoint<string, void>(
"warehouse-fee-rules",
"delete",
(id) => warehouseService.deleteFeeRule(id).then(() => undefined),
undefined,
() => [["warehouse-fee-rules"]],
),
// ── Invoices ───────────────────────────────────────────────────────────
generateInvoice: endpoint<
{
inventoryId: string;
confirmZero?: boolean;
billingCurrency?: "ETB" | "USD";
},
WarehouseFeeInvoice
>(
"warehouse-fee-invoices",
"generate",
({ inventoryId, confirmZero, billingCurrency }) =>
warehouseService
.generateInvoice(inventoryId, confirmZero, billingCurrency)
.then((r) => r.data),
undefined,
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
),
cancelInvoice: endpoint<string, WarehouseFeeInvoice>(
"warehouse-fee-invoices",
"cancel",
(id) => warehouseService.cancelInvoice(id).then((r) => r.data),
undefined,
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
),
payInvoice: endpoint<
{ id: string; payload: PayInvoicePayload },
WarehouseFeeInvoice
>(
"warehouse-fee-invoices",
"pay",
({ id, payload }) =>
warehouseService.payInvoice(id, payload).then((r) => r.data),
undefined,
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
),
payInvoiceOnline: endpoint<
{ id: string; payload: InitiateWarehouseInvoicePaymentPayload },
WarehouseInvoicePaymentResponse
>(
"warehouse-fee-invoices",
"pay-online",
({ id, payload }) =>
warehouseService.payInvoiceOnline(id, payload).then((r) => r.data),
undefined,
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
),
gateClearance: endpoint<string, WarehouseInventoryItem>(
"warehouse-fee-invoices",
"gate-clearance",
(inventoryId) =>
warehouseService.gateClearance(inventoryId).then((r) => r.data),
undefined,
() => [["warehouse-fee-invoices"], ["warehouse-inventory"]],
),
},
routes: {
list: endpoint<
{ status?: import("./routes.service").RouteStatus } | void,
RouteRecord[]
>(
"routes",
"list",
(input) =>
routesService
.getAll(input?.status ? { status: input.status } : undefined)
.then((r) => r.data),
(input) => ["routes", input?.status ?? "all"],
),
listPaged: endpoint<RouteListFilters, PaginatedResponse<RouteRecord>>(
"routes",
"listPaged",
(filters) => routesService.getPaged(filters).then((r) => r.data),
(filters) => ["routes", "paged", filters],
),
yards: endpoint<void, YardRef[]>(
"routes",
"yards",
() => routesService.getYards(),
() => ["routes", "yards"],
),
create: endpoint<SaveRoutePayload, RouteRecord>(
"routes",
"create",
(payload) => routesService.create(payload).then((r) => r.data),
undefined,
() => [["routes"]],
),
update: endpoint<
{ id: string; data: Partial<SaveRoutePayload> },
RouteRecord
>(
"routes",
"update",
({ id, data }) => routesService.update(id, data).then((r) => r.data),
undefined,
() => [["routes"]],
),
deactivate: endpoint<string, void>(
"routes",
"deactivate",
(id) => routesService.deactivate(id).then(() => undefined),
undefined,
() => [["routes"]],
),
/** Irreversible purge — refused while any train schedule uses the route. */
purge: endpoint<string, void>(
"routes",
"purge",
(id) => routesService.purge(id).then(() => undefined),
undefined,
() => [["routes"]],
),
},
stations: {
list: endpoint<void, YardOption[]>(
"train-scheduling",
"stations",
() => trainSchedulingService.getStations(),
() => QUERY_KEYS.TRAIN_SCHEDULING.stations(),
),
},
containers: {
list: endpoint<void, Container[]>("containers", "list", () =>
containerService.getAll().then((r) => r.data),
),
listByWagon: endpoint<{ wagonId: string }, Container[]>(
"containers",
"listByWagon",
({ wagonId }) => containerService.getByWagon(wagonId).then((r) => r.data),
({ wagonId }) => ["containers", "wagon", wagonId],
),
getById: endpoint<{ id: string }, Container>(
"containers",
"getById",
({ id }) => containerService.getById(id).then((r) => r.data),
),
create: endpoint<Partial<Container>, Container>(
"containers",
"create",
(payload) => containerService.create(payload).then((r) => r.data),
undefined,
() => [["containers"]],
),
update: endpoint<{ id: string; data: Partial<Container> }, Container>(
"containers",
"update",
({ id, data }) => containerService.update(id, data).then((r) => r.data),
undefined,
() => [["containers"]],
),
remove: endpoint<string, void>(
"containers",
"remove",
(id) => containerService.delete(id).then(() => undefined),
undefined,
() => [["containers"]],
),
assignToWagon: endpoint<
{ containerId: string; wagonId: string; position?: number },
Container
>(
"containers",
"assignToWagon",
({ containerId, wagonId, position }) =>
containerService
.assignToWagon(containerId, wagonId, position)
.then((r) => r.data),
undefined,
() => [["containers"]],
),
unassign: endpoint<string, void>(
"containers",
"unassign",
(containerId) =>
containerService.unassign(containerId).then(() => undefined),
undefined,
() => [["containers"]],
),
},
containerTypes: {
list: endpoint<void, unknown[]>("container-types", "list", () =>
containerTypesService.getContainerTypes(),
),
},
wagons: {
/** Every match, page-walked — for pickers and yard views. Lists use `listPaged`. */
list: endpoint<{ filters?: WagonListFilters }, Wagon[]>(
"wagons",
"list",
({ filters }) => wagonService.listAll(filters ?? {}),
({ filters }) => ["wagons", "list", filters ?? {}],
),
listPaged: endpoint<{ filters?: WagonListFilters }, PaginatedResponse<Wagon>>(
"wagons",
"listPaged",
({ filters }) => wagonService.getAll(filters ?? {}).then((r) => r.data),
({ filters }) => ["wagons", "listPaged", filters ?? {}],
),
listByTrain: endpoint<{ trainId: string }, Wagon[]>(
"wagons",
"listByTrain",
({ trainId }) => wagonService.getByTrain(trainId),
({ trainId }) => ["wagons", "train", trainId],
),
getById: endpoint<{ id: string }, Wagon>("wagons", "getById", ({ id }) =>
wagonService.getById(id).then((r) => r.data),
),
movements: endpoint<{ id: string }, WagonMovementRecord[]>(
"wagons",
"movements",
({ id }) => wagonService.getMovements(id).then((r) => r.data),
({ id }) => ["wagons", "movements", id],
),
assignToTrain: endpoint<
{ wagonId: string; trainId: string; sequenceNumber?: number },
Wagon
>(
"wagons",
"assignToTrain",
({ wagonId, trainId, sequenceNumber }) =>
wagonService
.assignToTrain(wagonId, trainId, sequenceNumber)
.then((r) => r.data),
undefined,
() => [["wagons"]],
),
unassign: endpoint<string, void>(
"wagons",
"unassign",
(wagonId) => wagonService.unassign(wagonId).then(() => undefined),
undefined,
() => [["wagons"]],
),
create: endpoint<Partial<Wagon>, Wagon>(
"wagons",
"create",
(payload) => wagonService.create(payload).then((r) => r.data),
undefined,
() => [["wagons"]],
),
update: endpoint<{ id: string; data: Partial<Wagon> }, Wagon>(
"wagons",
"update",
({ id, data }) => wagonService.update(id, data).then((r) => r.data),
undefined,
() => [["wagons"]],
),
remove: endpoint<string, void>(
"wagons",
"remove",
(id) => wagonService.delete(id).then(() => undefined),
undefined,
() => [["wagons"]],
),
bulkTransfer: endpoint<
{ wagonIds: string[]; toYardId: string },
{ moved: number }
>(
"wagons",
"bulkTransfer",
({ wagonIds, toYardId }) =>
wagonService.bulkTransfer(wagonIds, toYardId).then((r) => r.data),
undefined,
() => [["wagons"]],
),
bulkSetStatus: endpoint<
{ wagonIds: string[]; status: Wagon["status"]; note?: string },
{ updated: number }
>(
"wagons",
"bulkSetStatus",
({ wagonIds, status, note }) =>
wagonService.bulkSetStatus(wagonIds, status, note).then((r) => r.data),
undefined,
// The fleet desk lists wagons under the "fleet" key root, not "wagons".
() => [["wagons"], QUERY_KEYS.FLEET.list("wagons")],
),
statusHistory: endpoint<{ id: string }, WagonStatusLog[]>(
"wagons",
"statusHistory",
({ id }) => wagonService.getStatusHistory(id).then((r) => r.data),
({ id }) => ["wagons", "status-history", id],
),
},
wagonTransferRequests: {
list: endpoint<
{ filter?: TransferRequestListFilter },
PaginatedResponse<WagonTransferRequest>
>(
"wagonTransferRequests",
"list",
({ filter }) =>
wagonTransferRequestService.list(filter).then((r) => r.data),
({ filter }) => ["wagonTransferRequests", "list", filter ?? {}],
),
getById: endpoint<{ id: string }, WagonTransferRequest>(
"wagonTransferRequests",
"getById",
({ id }) => wagonTransferRequestService.getById(id).then((r) => r.data),
({ id }) => ["wagonTransferRequests", "detail", id],
),
create: endpoint<CreateTransferRequestPayload, WagonTransferRequest>(
"wagonTransferRequests",
"create",
(payload) =>
wagonTransferRequestService.create(payload).then((r) => r.data),
undefined,
() => [["wagonTransferRequests"]],
),
fulfill: endpoint<
{ id: string; wagonIds: string[] },
WagonTransferRequest
>(
"wagonTransferRequests",
"fulfill",
({ id, wagonIds }) =>
wagonTransferRequestService.fulfill(id, wagonIds).then((r) => r.data),
undefined,
() => [["wagonTransferRequests"], ["wagons"]],
),
bulkFulfill: endpoint<{ requestIds: string[] }, BulkFulfillResult>(
"wagonTransferRequests",
"bulkFulfill",
({ requestIds }) =>
wagonTransferRequestService.bulkFulfill(requestIds).then((r) => r.data),
undefined,
() => [["wagonTransferRequests"], ["wagons"]],
),
cancel: endpoint<{ id: string }, WagonTransferRequest>(
"wagonTransferRequests",
"cancel",
({ id }) => wagonTransferRequestService.cancel(id).then((r) => r.data),
undefined,
() => [["wagonTransferRequests"]],
),
closeShort: endpoint<{ id: string; note?: string }, WagonTransferRequest>(
"wagonTransferRequests",
"closeShort",
({ id, note }) =>
wagonTransferRequestService.closeShort(id, note).then((r) => r.data),
undefined,
() => [["wagonTransferRequests"]],
),
history: endpoint<{ page?: number; pageSize?: number }, TransferHistory>(
"wagonTransferRequests",
"history",
({ page, pageSize }) =>
wagonTransferRequestService.myHistory(page, pageSize).then((r) => r.data),
({ page, pageSize }) => [
"wagonTransferRequests",
"history",
"mine",
page ?? 1,
pageSize ?? 20,
],
),
historyAll: endpoint<
{ userId?: string; page?: number; pageSize?: number },
TransferHistory
>(
"wagonTransferRequests",
"historyAll",
({ userId, page, pageSize }) =>
wagonTransferRequestService
.allHistory(userId, page, pageSize)
.then((r) => r.data),
({ userId, page, pageSize }) => [
"wagonTransferRequests",
"history",
"all",
userId ?? "",
page ?? 1,
pageSize ?? 20,
],
),
},
trains: {
list: endpoint<void, Train[]>(
"trains",
"list",
() => trainService.getAll().then((r) => r.data),
() => ["trains", "list"],
),
getById: endpoint<{ id: string }, Train>(
"trains",
"getById",
({ id }) => trainService.getById(id).then((r) => r.data),
({ id }) => ["trains", "detail", id],
),
create: endpoint<Partial<Train>, Train>(
"trains",
"create",
(payload) => trainService.create(payload).then((r) => r.data),
undefined,
() => [["trains"]],
),
update: endpoint<{ id: string; data: Partial<Train> }, Train>(
"trains",
"update",
({ id, data }) => trainService.update(id, data).then((r) => r.data),
undefined,
() => [["trains"]],
),
remove: endpoint<string, void>(
"trains",
"remove",
(id) => trainService.delete(id).then(() => undefined),
undefined,
() => [["trains"]],
),
},
// Train Builder — persistent coded consists (2+ locomotives + ordered wagons)
// that train scheduling can reference as a unit. Every mutation also touches
// wagon/locomotive availability, so those roots are invalidated together.
trainBuilder: {
list: endpoint<{ filters?: BuiltTrainListFilters }, BuiltTrainListResponse>(
"train-builder",
"list",
({ filters }) => trainBuilderService.list(filters).then((r) => r.data),
({ filters }) => QUERY_KEYS.TRAIN_BUILDER.list(filters),
),
composition: endpoint<{ id: string }, TrainComposition>(
"train-builder",
"composition",
({ id }) => trainBuilderService.getComposition(id).then((r) => r.data),
({ id }) => QUERY_KEYS.TRAIN_BUILDER.composition(id),
),
// Key derives to ["train-builder", "usedTrainNumbers"], so the shared
// TRAIN_BUILDER.ROOT invalidation refreshes it after every build/edit.
usedTrainNumbers: endpoint<void, UsedTrainNumbers>(
"train-builder",
"usedTrainNumbers",
() => trainBuilderService.usedTrainNumbers().then((r) => r.data),
),
build: endpoint<BuildTrainPayload, TrainComposition>(
"train-builder",
"build",
(payload) => trainBuilderService.build(payload).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
setLocomotives: endpoint<
{ id: string; locomotiveIds: string[] },
TrainComposition
>(
"train-builder",
"setLocomotives",
({ id, locomotiveIds }) =>
trainBuilderService.setLocomotives(id, locomotiveIds).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
setYard: endpoint<{ id: string; currentYardId: string }, TrainComposition>(
"train-builder",
"setYard",
({ id, currentYardId }) =>
trainBuilderService.setYard(id, currentYardId).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
updateDetails: endpoint<
{ id: string; payload: UpdateTrainDetailsPayload },
TrainComposition
>(
"train-builder",
"updateDetails",
({ id, payload }) =>
trainBuilderService.updateDetails(id, payload).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
assignWagons: endpoint<{ id: string; wagonIds: string[] }, TrainComposition>(
"train-builder",
"assignWagons",
({ id, wagonIds }) =>
trainBuilderService.assignWagons(id, wagonIds).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
removeWagon: endpoint<{ id: string; wagonId: string }, TrainComposition>(
"train-builder",
"removeWagon",
({ id, wagonId }) =>
trainBuilderService.removeWagon(id, wagonId).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
sendWagonToMaintenance: endpoint<{ id: string; wagonId: string }, TrainComposition>(
"train-builder",
"sendWagonToMaintenance",
({ id, wagonId }) =>
trainBuilderService.sendWagonToMaintenance(id, wagonId).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
reorderWagons: endpoint<{ id: string; wagonIds: string[] }, TrainComposition>(
"train-builder",
"reorderWagons",
({ id, wagonIds }) =>
trainBuilderService.reorderWagons(id, wagonIds).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
deactivate: endpoint<string, TrainComposition>(
"train-builder",
"deactivate",
(id) => trainBuilderService.deactivate(id).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
activate: endpoint<string, TrainComposition>(
"train-builder",
"activate",
(id) => trainBuilderService.activate(id).then((r) => r.data),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
disband: endpoint<string, void>(
"train-builder",
"disband",
(id) => trainBuilderService.disband(id).then(() => undefined),
undefined,
() => TRAIN_BUILDER_INVALIDATIONS,
),
},
locomotives: {
list: endpoint<void, Locomotive[]>(
"locomotives",
"list",
() => locomotivesService.getAll().then((r) => r.data),
() => ["locomotives"],
),
listFiltered: endpoint<{ filters?: LocomotiveListFilters }, Locomotive[]>(
"locomotives",
"listFiltered",
({ filters }) => locomotivesService.getAll(filters ?? {}).then((r) => r.data),
({ filters }) => ["locomotives", "list", filters ?? {}],
),
create: endpoint<Partial<SaveLocomotivePayload>, Locomotive>(
"locomotives",
"create",
(payload) => locomotivesService.create(payload).then((r) => r.data),
undefined,
() => [["locomotives"]],
),
update: endpoint<
{ id: string; data: Partial<SaveLocomotivePayload> },
Locomotive
>(
"locomotives",
"update",
({ id, data }) => locomotivesService.update(id, data).then((r) => r.data),
undefined,
() => [["locomotives"]],
),
decommission: endpoint<string, void>(
"locomotives",
"decommission",
(id) => locomotivesService.decommission(id).then(() => undefined),
undefined,
() => [["locomotives"]],
),
},
cargoTypes: {
list: endpoint<void, unknown[]>("cargo-types", "list", () =>
cargoTypesService.getCargoTypes(),
),
},
payments: {
list: endpoint<{ filter?: PaymentListFilter }, PaginatedPayments>(
"payments",
"list",
({ filter }) => paymentsService.list(filter),
({ filter }) => ["payments", "list", filter ?? {}],
),
summary: endpoint<void, PaymentSummary>(
"payments",
"summary",
() => paymentsService.getSummary(),
() => ["payments", "summary"],
),
},
audit: {
list: endpoint<{ filter?: AuditLogListFilter }, PaginatedAuditLogs>(
"audit",
"list",
({ filter }) => auditService.list(filter),
({ filter }) => ["audit", "list", filter ?? {}],
),
},
signatures: {
mySignature: endpoint<void, SavedSignature | null>(
"me",
"signature",
() => signaturesService.getMySignature(),
() => ["me", "signature"],
),
save: endpoint<SaveSignaturePayload, SavedSignature | null>(
"me",
"save-signature",
(payload) => signaturesService.saveMySignature(payload),
undefined,
() => [["me", "signature"]],
),
},
fleet: {
list: endpoint<
{ slug: FleetResourceSlug; filters?: FleetListFilters },
FleetRecord[]
>(
"fleet",
"list",
({ slug, filters }) => fleetService.list(slug, filters),
({ slug, filters }) => [...QUERY_KEYS.FLEET.list(slug), filters ?? {}],
),
listPaged: endpoint<
{ slug: FleetResourceSlug; filters?: FleetListFilters },
PaginatedResponse<FleetRecord>
>(
"fleet",
"listPaged",
({ slug, filters }) => fleetService.listPaged(slug, filters),
({ slug, filters }) => [...QUERY_KEYS.FLEET.list(slug), "paged", filters ?? {}],
),
create: endpoint<
{ slug: FleetResourceSlug; data: Record<string, unknown> },
unknown
>(
"fleet",
"create",
({ slug, data }) => fleetService.create(slug, data),
undefined,
({ slug }) => [QUERY_KEYS.FLEET.list(slug)],
),
update: endpoint<
{ slug: FleetResourceSlug; id: string; data: Record<string, unknown> },
unknown
>(
"fleet",
"update",
({ slug, id, data }) => fleetService.update(slug, id, data),
undefined,
({ slug }) => [QUERY_KEYS.FLEET.list(slug)],
),
remove: endpoint<{ slug: FleetResourceSlug; id: string }, unknown>(
"fleet",
"remove",
({ slug, id }) => fleetService.remove(slug, id),
undefined,
({ slug }) => [QUERY_KEYS.FLEET.list(slug)],
),
/** Irreversible purge — locomotives and wagons only. */
purge: endpoint<{ slug: FleetResourceSlug; id: string }, unknown>(
"fleet",
"purge",
({ slug, id }) => fleetService.purge(slug, id),
undefined,
({ slug }) => [QUERY_KEYS.FLEET.list(slug)],
),
},
truckTypes: {
list: endpoint<void, TruckType[]>("truck-types", "list", () =>
truckTypesService.getTruckTypes(),
),
create: endpoint<Partial<TruckType>, TruckType>(
"truck-types",
"create",
(payload) => truckTypesService.create(payload).then((r) => r.data),
undefined,
() => [["truck-types"]],
),
update: endpoint<{ id: string; data: Partial<TruckType> }, TruckType>(
"truck-types",
"update",
({ id, data }) => truckTypesService.update(id, data).then((r) => r.data),
undefined,
() => [["truck-types"]],
),
remove: endpoint<string, void>(
"truck-types",
"remove",
(id) => truckTypesService.delete(id).then(() => undefined),
undefined,
() => [["truck-types"]],
),
},
wagonTypes: {
list: endpoint<void, WagonType[]>("wagon-types", "list", () =>
wagonTypesService.getWagonTypes(),
),
create: endpoint<Partial<WagonType>, WagonType>(
"wagon-types",
"create",
(payload) => wagonTypesService.create(payload).then((r) => r.data),
undefined,
() => [["wagon-types"]],
),
update: endpoint<{ id: string; data: Partial<WagonType> }, WagonType>(
"wagon-types",
"update",
({ id, data }) => wagonTypesService.update(id, data).then((r) => r.data),
undefined,
() => [["wagon-types"]],
),
remove: endpoint<string, void>(
"wagon-types",
"remove",
(id) => wagonTypesService.delete(id).then(() => undefined),
undefined,
() => [["wagon-types"]],
),
},
cargoes: {
list: endpoint<void, Cargo[]>("cargoes", "list", () =>
cargoService.getAll().then((r) => r.data),
),
listByContainer: endpoint<{ containerId: string }, Cargo[]>(
"cargoes",
"listByContainer",
({ containerId }) =>
cargoService.getByContainer(containerId).then((r) => r.data),
),
getById: endpoint<{ id: string }, Cargo>("cargoes", "getById", ({ id }) =>
cargoService.getById(id).then((r) => r.data),
),
create: endpoint<Partial<Cargo>, Cargo>(
"cargoes",
"create",
(payload) => cargoService.create(payload).then((r) => r.data),
undefined,
() => [["cargoes"]],
),
update: endpoint<{ id: string; data: Partial<Cargo> }, Cargo>(
"cargoes",
"update",
({ id, data }) => cargoService.update(id, data).then((r) => r.data),
undefined,
() => [["cargoes"]],
),
remove: endpoint<string, void>(
"cargoes",
"remove",
(id) => cargoService.delete(id).then(() => undefined),
undefined,
() => [["cargoes"]],
),
load: endpoint<
{ id: string; quantity: number; weight: number; volume?: number },
Cargo
>(
"cargoes",
"load",
({ id, quantity, weight, volume }) =>
cargoService.load(id, quantity, weight, volume).then((r) => r.data),
undefined,
() => [["cargoes"]],
),
deliver: endpoint<{ id: string; payload?: DeliverCargoPayload }, Cargo>(
"cargoes",
"deliver",
({ id, payload }) =>
cargoService.deliver(id, payload).then((r) => r.data),
undefined,
() => [["cargoes"]],
),
unload: endpoint<{ id: string }, Cargo>(
"cargoes",
"unload",
({ id }) => cargoService.unload(id).then((r) => r.data),
undefined,
() => [["cargoes"]],
),
},
fileUploadSettings: {
list: endpoint<void, FileUploadSetting[]>(
"file-upload-settings",
"list",
fileUploadSettingsService.list,
),
getById: endpoint<{ id: string }, FileUploadSetting>(
"file-upload-settings",
"getById",
({ id }) => fileUploadSettingsService.getById(id),
),
getByCode: endpoint<{ code: string }, FileUploadSetting>(
"file-upload-settings",
"getByCode",
({ code }) => fileUploadSettingsService.getByCode(code),
),
create: endpoint<CreateFileUploadSettingDto, FileUploadSetting>(
"file-upload-settings",
"create",
(payload) => fileUploadSettingsService.create(payload),
undefined,
() => [["file-upload-settings"]],
),
update: endpoint<
{ id: string; dto: UpdateFileUploadSettingDto },
FileUploadSetting
>(
"file-upload-settings",
"update",
({ id, dto }) => fileUploadSettingsService.update(id, dto),
undefined,
() => [["file-upload-settings"]],
),
remove: endpoint<{ id: string }, void>(
"file-upload-settings",
"remove",
({ id }) => fileUploadSettingsService.remove(id),
undefined,
() => [["file-upload-settings"]],
),
replaceFields: endpoint<
{ id: string; fields: CreateFileUploadFieldDto[] },
FileUploadField[]
>(
"file-upload-settings",
"replaceFields",
({ id, fields }) => fileUploadSettingsService.replaceFields(id, fields),
undefined,
() => [["file-upload-settings"]],
),
addField: endpoint<
{ settingId: string; dto: CreateFileUploadFieldDto },
FileUploadField
>(
"file-upload-settings",
"addField",
({ settingId, dto }) =>
fileUploadSettingsService.addField(settingId, dto),
undefined,
() => [["file-upload-settings"]],
),
updateField: endpoint<
{ fieldId: string; dto: UpdateFileUploadFieldDto },
FileUploadField
>(
"file-upload-settings",
"updateField",
({ fieldId, dto }) => fileUploadSettingsService.updateField(fieldId, dto),
undefined,
() => [["file-upload-settings"]],
),
removeField: endpoint<{ fieldId: string }, void>(
"file-upload-settings",
"removeField",
({ fieldId }) => fileUploadSettingsService.removeField(fieldId),
undefined,
() => [["file-upload-settings"]],
),
},
dropdownSettings: {
list: endpoint<void, DropdownSetting[]>(
"dropdown-settings",
"list",
dropdownSettingsService.list,
),
listPaged: endpoint<
{ query: DropdownSettingListQuery },
PaginatedDropdownSettings
>(
"dropdown-settings",
"listPaged",
({ query }) => dropdownSettingsService.listPaged(query),
),
getById: endpoint<{ id: string }, DropdownSetting>(
"dropdown-settings",
"getById",
({ id }) => dropdownSettingsService.getById(id),
),
getByCode: endpoint<{ code: string }, DropdownSetting>(
"dropdown-settings",
"getByCode",
({ code }) => dropdownSettingsService.getByCode(code),
),
create: endpoint<CreateDropdownSettingDto, DropdownSetting>(
"dropdown-settings",
"create",
(payload) => dropdownSettingsService.create(payload),
undefined,
() => [["dropdown-settings"]],
),
update: endpoint<
{ id: string; dto: UpdateDropdownSettingDto },
DropdownSetting
>(
"dropdown-settings",
"update",
({ id, dto }) => dropdownSettingsService.update(id, dto),
undefined,
() => [["dropdown-settings"]],
),
remove: endpoint<{ id: string }, void>(
"dropdown-settings",
"remove",
({ id }) => dropdownSettingsService.remove(id),
undefined,
() => [["dropdown-settings"]],
),
replaceOptions: endpoint<
{ id: string; options: CreateDropdownOptionDto[] },
DropdownOption[]
>(
"dropdown-settings",
"replaceOptions",
({ id, options }) => dropdownSettingsService.replaceOptions(id, options),
undefined,
() => [["dropdown-settings"]],
),
addOption: endpoint<
{ id: string; dto: CreateDropdownOptionDto },
DropdownOption
>(
"dropdown-settings",
"addOption",
({ id, dto }) => dropdownSettingsService.addOption(id, dto),
undefined,
() => [["dropdown-settings"]],
),
updateOption: endpoint<
{ optionId: string; dto: UpdateDropdownOptionDto },
DropdownOption
>(
"dropdown-settings",
"updateOption",
({ optionId, dto }) =>
dropdownSettingsService.updateOption(optionId, dto),
undefined,
() => [["dropdown-settings"]],
),
removeOption: endpoint<{ optionId: string }, void>(
"dropdown-settings",
"removeOption",
({ optionId }) => dropdownSettingsService.removeOption(optionId),
undefined,
() => [["dropdown-settings"]],
),
},
ruleEngine: {
list: endpoint<
{ resource: RuleEngineResourceSlug; params?: RuleEngineListParams },
RuleEngineListResult<RuleEngineRecord>
>(
"rule-engine",
"list",
({ resource, params }) => ruleEngineService.list(resource, params),
({ resource, params }) => QUERY_KEYS.RULE_ENGINE.list(resource, params),
),
getById: endpoint<
{ resource: RuleEngineResourceSlug; id: string },
RuleEngineRecord
>(
"rule-engine",
"getById",
({ resource, id }) => ruleEngineService.getById(resource, id),
({ resource, id }) => QUERY_KEYS.RULE_ENGINE.detail(resource, id),
),
create: endpoint<
{ resource: RuleEngineResourceSlug; payload: Record<string, unknown> },
RuleEngineRecord
>("rule-engine", "create", ({ resource, payload }) =>
ruleEngineService.create(resource, payload),
),
update: endpoint<
{
resource: RuleEngineResourceSlug;
id: string;
payload: Record<string, unknown>;
},
RuleEngineRecord
>("rule-engine", "update", ({ resource, id, payload }) =>
ruleEngineService.update(resource, id, payload),
),
remove: endpoint<{ resource: RuleEngineResourceSlug; id: string }, void>(
"rule-engine",
"remove",
({ resource, id }) => ruleEngineService.remove(resource, id),
),
submitRate: endpoint<{ id: string }, RuleEngineRecord>(
"rule-engine",
"submitRate",
({ id }) => ruleEngineService.submitRate(id),
),
approveRate: endpoint<{ id: string }, RuleEngineRecord>(
"rule-engine",
"approveRate",
({ id }) => ruleEngineService.approveRate(id),
),
getApprovalChain: endpoint<void, RuleEngineRecord[]>(
"rule-engine",
"getApprovalChain",
() => ruleEngineService.getApprovalChain(),
() => QUERY_KEYS.RULE_ENGINE.chain,
),
reorder: endpoint<
{
resource: RuleEngineResourceSlug;
payload: { ids: string[]; requiresDirectorApproval?: boolean };
},
void
>("rule-engine", "reorder", ({ resource, payload }) =>
ruleEngineService.reorder(resource, payload),
),
moveOrder: endpoint<
{
resource: RuleEngineResourceSlug;
id: string;
direction: "up" | "down";
},
void
>("rule-engine", "moveOrder", ({ resource, id, direction }) =>
ruleEngineService.moveOrder(resource, id, direction),
),
},
bookings: {
list: endpoint<{ filter?: BookingListFilter }, PaginatedBookings>(
"bookings",
"list",
({ filter }) => bookingsService.list(filter),
({ filter }) => QUERY_KEYS.BOOKINGS.list(filter),
),
getById: endpoint<{ id: string }, BookingDetail>(
"bookings",
"getById",
({ id }) => bookingsService.getById(id),
({ id }) => QUERY_KEYS.BOOKINGS.byId(id),
),
remove: endpoint<{ id: string }, void>("bookings", "remove", ({ id }) =>
bookingsService.remove(id),
),
staffAccept: endpoint<{ id: string; validityDays: number }, BookingDetail>(
"bookings",
"staffAccept",
({ id, validityDays }) => bookingsService.staffAccept(id, validityDays),
),
requestChanges: endpoint<{ id: string; note: string }, BookingDetail>(
"bookings",
"requestChanges",
({ id, note }) => bookingsService.requestChanges(id, note),
),
staffReject: endpoint<{ id: string; reason: string }, BookingDetail>(
"bookings",
"staffReject",
({ id, reason }) => bookingsService.staffReject(id, reason),
),
reviewOperation: endpoint<
{
id: string;
decision: "ACCEPT" | "REQUEST_CHANGES";
note?: string;
},
BookingDetail
>("bookings", "reviewOperation", ({ id, decision, note }) =>
bookingsService.reviewOperation(id, decision, { note }),
),
proceedToOperation: endpoint<
{ id: string; scheduledDate: string },
BookingDetail
>("bookings", "proceedToOperation", ({ id, scheduledDate }) =>
bookingsService.proceedToOperation(id, scheduledDate),
),
generateContract: endpoint<{ id: string }, BookingDetail>(
"bookings",
"generateContract",
({ id }) => bookingsService.generateContract(id),
),
getContractView: endpoint<
{ id: string },
import("./bookings.service").ContractView
>("bookings", "getContractView", ({ id }) =>
bookingsService.getContractView(id),
),
signContract: endpoint<
{ id: string } & import("./bookings.service").SignContractPayload,
BookingDetail
>("bookings", "signContract", ({ id, ...payload }) =>
bookingsService.signContract(id, payload),
),
payBooking: endpoint<{ id: string }, BookingDetail>(
"bookings",
"payBooking",
({ id }) => bookingsService.payBooking(id),
),
startTransit: endpoint<{ id: string }, BookingDetail>(
"bookings",
"startTransit",
({ id }) => bookingsService.startTransit(id),
),
complete: endpoint<{ id: string }, BookingDetail>(
"bookings",
"complete",
({ id }) => bookingsService.complete(id),
),
cancel: endpoint<{ id: string; reason: string }, BookingDetail>(
"bookings",
"cancel",
({ id, reason }) => bookingsService.cancel(id, reason),
),
},
customers: {
stats: endpoint<Record<string, never>, CompanyStats>(
"customers",
"stats",
() => customersService.stats(),
() => QUERY_KEYS.CUSTOMERS.stats,
),
list: endpoint<{ filter: CompanyListFilter }, PaginatedCompanies>(
"customers",
"list",
({ filter }) => customersService.list(filter),
({ filter }) => QUERY_KEYS.CUSTOMERS.list(filter),
),
getById: endpoint<{ id: string }, Company | undefined>(
"customers",
"getById",
({ id }) => customersService.getById(id),
({ id }) => QUERY_KEYS.CUSTOMERS.byId(id),
),
bookings: endpoint<{ id: string }, CustomerBooking[]>(
"customers",
"bookings",
({ id }) => customersService.bookingsFor(id),
({ id }) => QUERY_KEYS.CUSTOMERS.bookings(id),
),
documents: endpoint<{ id: string }, CustomerDocument[]>(
"customers",
"documents",
({ id }) => customersService.documentsFor(id),
({ id }) => QUERY_KEYS.CUSTOMERS.documents(id),
),
payments: endpoint<{ id: string }, CustomerPayment[]>(
"customers",
"payments",
({ id }) => customersService.paymentsFor(id),
({ id }) => QUERY_KEYS.CUSTOMERS.payments(id),
),
resetTarget: endpoint<{ companyId: string }, CustomerResetTarget>(
"customers",
"resetTarget",
({ companyId }) => customersService.resetTarget(companyId),
({ companyId }) => QUERY_KEYS.CUSTOMERS.resetTarget(companyId),
),
resetPassword: endpoint<
{ companyId: string; channel: ResetChannel },
ResetPasswordResult
>(
"customers",
"resetPassword",
({ companyId, channel }) =>
customersService.resetPassword(companyId, channel),
),
setProfileStatus: endpoint<
{ profileId: string; status: ProfileStatus; note?: string },
CompanyProfile
>(
"customers",
"setProfileStatus",
({ profileId, status, note }) =>
customersService.setProfileStatus(profileId, status, note),
undefined,
(_input, data) => [
QUERY_KEYS.CUSTOMERS.byId(data.companyId),
QUERY_KEYS.CUSTOMERS.ROOT,
],
),
changeRequests: endpoint<{ id: string }, CompanyChangeRequest[]>(
"customers",
"changeRequests",
({ id }) => customersService.changeRequests(id),
({ id }) => QUERY_KEYS.CUSTOMERS.changeRequests(id),
),
revisions: endpoint<{ id: string }, CompanyRevision[]>(
"customers",
"revisions",
({ id }) => customersService.revisions(id),
({ id }) => QUERY_KEYS.CUSTOMERS.revisions(id),
),
approveChangeRequest: endpoint<{ id: string }, CompanyChangeRequest>(
"customers",
"approveChangeRequest",
({ id }) => customersService.approveChangeRequest(id),
undefined,
(_input, data) => [
QUERY_KEYS.CUSTOMERS.changeRequests(data.companyId),
QUERY_KEYS.CUSTOMERS.byId(data.companyId),
QUERY_KEYS.CUSTOMERS.ROOT,
],
),
rejectChangeRequest: endpoint<{ id: string; note: string }, CompanyChangeRequest>(
"customers",
"rejectChangeRequest",
({ id, note }) => customersService.rejectChangeRequest(id, note),
undefined,
(_input, data) => [
QUERY_KEYS.CUSTOMERS.changeRequests(data.companyId),
QUERY_KEYS.CUSTOMERS.byId(data.companyId),
QUERY_KEYS.CUSTOMERS.ROOT,
],
),
requestChangeRequestChanges: endpoint<
{ id: string; note: string },
CompanyChangeRequest
>(
"customers",
"requestChangeRequestChanges",
({ id, note }) => customersService.requestChangeRequestChanges(id, note),
undefined,
(_input, data) => [
QUERY_KEYS.CUSTOMERS.changeRequests(data.companyId),
QUERY_KEYS.CUSTOMERS.byId(data.companyId),
QUERY_KEYS.CUSTOMERS.ROOT,
],
),
/**
* Ask the customer to correct one document. Invalidates the documents list
* and the company itself, since an open request blocks role approval.
*/
requestDocumentChange: endpoint<
{ companyId: string; fileId: string; note: string },
CustomerDocument
>(
"customers",
"requestDocumentChange",
({ fileId, note }) =>
customersService.requestDocumentChange(fileId, note),
undefined,
({ companyId }) => [
QUERY_KEYS.CUSTOMERS.documents(companyId),
QUERY_KEYS.CUSTOMERS.byId(companyId),
],
),
setCompanyStatus: endpoint<{ companyId: string; status: string }, unknown>(
"customers",
"setCompanyStatus",
({ companyId, status }) =>
customersService.setCompanyStatus(companyId, status),
undefined,
(input) => [
QUERY_KEYS.CUSTOMERS.byId(input.companyId),
QUERY_KEYS.CUSTOMERS.ROOT,
],
),
},
invoices: {
list: endpoint<{ filter: InvoiceListFilter }, PaginatedInvoices>(
"invoices",
"list",
({ filter }) => invoicesService.list(filter),
({ filter }) => QUERY_KEYS.INVOICES.list(filter),
),
getById: endpoint<{ id: string }, Invoice>(
"invoices",
"getById",
({ id }) => invoicesService.getById(id),
({ id }) => QUERY_KEYS.INVOICES.byId(id),
),
},
overview: {
get: endpoint<{ range?: OverviewRange }, IOverviewDashboard>(
"overview",
"get",
({ range }) => overviewService.getDashboard(range),
),
},
reports: {
run: endpoint<ReportQueryInput, ReportResult>(
"reports",
"run",
(input) => reportsService.run(input),
(input) => ["reports", input.key, input],
),
},
};