mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 23:00:57 +00:00
Join truck_types via vehicles.truck_type_id (normalized legacy vehicle_type only as fallback) so type renames can't unmatch detention rules and FK-less vehicles keep billing.
118 lines
4.2 KiB
TypeScript
118 lines
4.2 KiB
TypeScript
import { api } from '../auth/http';
|
|
import { URL_CONSTANTS } from '@/constants/URLS';
|
|
|
|
export const FIRST_MILE_STATUSES = [
|
|
'PAYMENT_PENDING',
|
|
'READY_TO_TRANSIT',
|
|
'IN_TRANSIT',
|
|
'RECEIVED_TO_PORT',
|
|
] as const;
|
|
export type FirstMileApiStatus = (typeof FIRST_MILE_STATUSES)[number];
|
|
|
|
export interface FirstMileBooking {
|
|
id: string;
|
|
reference: string;
|
|
firstMilePickupAddress?: string | null;
|
|
cargoFreeText?: string | null;
|
|
cargoTotalWeightVgm: number;
|
|
totalAmount: number;
|
|
paymentCurrency?: string | null;
|
|
scheduledDate?: string | null;
|
|
company?: { id: string; name?: string; phone?: string | null; contactPersonName?: string | null; contactPersonPhone?: string | null } | null;
|
|
serviceType?: { id: string; label?: string } | null;
|
|
originYard?: { id: string; label?: string } | null;
|
|
destinationYard?: { id: string; label?: string } | null;
|
|
cargoType?: { id: string; label?: string; cargoTypeName?: string; name?: string } | null;
|
|
freightType?: string | null;
|
|
/** Attached server-side: the train schedule this booking rides. */
|
|
trainSchedule?: { trainNumber: string | null; departureDate: string | null } | null;
|
|
/** Container lines — total container count drives how many trucks are needed. */
|
|
bookingContainers?: Array<{
|
|
id: string;
|
|
quantity: number;
|
|
containerNumber?: string | null;
|
|
containerSize?: string | null;
|
|
containerType?: { id: string; name?: string; label?: string; code?: string } | null;
|
|
/** Physical containers under this line — their real numbers (line-level
|
|
* containerNumber is often a TBD placeholder). */
|
|
units?: Array<{ id: string; containerNumber?: string | null; sortOrder?: number }>;
|
|
}>;
|
|
}
|
|
|
|
export interface FirstMileVehicle {
|
|
id: string;
|
|
plateNumber: string;
|
|
manufacturer: string;
|
|
model: string;
|
|
vehicleType?: string | null;
|
|
code?: string | null;
|
|
powerPlateNo?: string | null;
|
|
trailerPlateNo?: string | null;
|
|
assignedDriverId?: string | null;
|
|
assignedDriverName?: string | null;
|
|
pricePerKm?: number | string | null;
|
|
currency?: string | null;
|
|
}
|
|
|
|
export interface FirstMileRecord {
|
|
id: string;
|
|
bookingId: string;
|
|
status: FirstMileApiStatus;
|
|
advancedPayment: number;
|
|
remainingPayment: number;
|
|
estimatedKm?: number | null;
|
|
exactKm?: number | null;
|
|
vehicleId?: string | null;
|
|
booking?: FirstMileBooking | null;
|
|
vehicle?: FirstMileVehicle | null;
|
|
/** Full set of vehicles serving this pickup (multi-truck). */
|
|
vehicleAssignments?: Array<{
|
|
id: string;
|
|
vehicleId: string;
|
|
containerNumber?: string | null;
|
|
distanceKm?: number | null;
|
|
tons?: number | null;
|
|
quantity?: number | null;
|
|
vehicle?: FirstMileVehicle | null;
|
|
}>;
|
|
/** Present only when an invoice has actually been generated (not on distance). */
|
|
invoice?: { id: string; number: string; status: string } | null;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface FirstMileListResponse {
|
|
data: FirstMileRecord[];
|
|
meta: { total: number; page: number; pageSize: number; totalPages: number };
|
|
}
|
|
|
|
const FM = URL_CONSTANTS.FIRST_MILE;
|
|
|
|
export const firstMileService = {
|
|
list: (pageSize = 1000) =>
|
|
api.get<FirstMileListResponse>(`${FM.BASE}?pageSize=${pageSize}`),
|
|
getById: (id: string) => api.get<FirstMileRecord>(FM.BY_ID(id)),
|
|
update: (id: string, data: { status?: FirstMileApiStatus; vehicleId?: string | null; estimatedKm?: number | null; exactKm?: number | null; paid?: boolean }) =>
|
|
api.patch<FirstMileRecord>(FM.BY_ID(id), data),
|
|
accept: (bookingReference: string) =>
|
|
api.post<FirstMileRecord>(FM.ACCEPT(bookingReference)),
|
|
remove: (id: string) =>
|
|
api.delete<void>(FM.BY_ID(id)),
|
|
setVehicles: (
|
|
id: string,
|
|
vehicles: Array<{
|
|
vehicleId: string;
|
|
containerNumber?: string | null;
|
|
tons?: number | null;
|
|
quantity?: number | null;
|
|
}>,
|
|
) => api.post<FirstMileRecord>(`${FM.BASE}/${id}/vehicles`, { vehicles }),
|
|
setDistances: (
|
|
id: string,
|
|
distances: Array<{ vehicleId: string; distanceKm: number }>,
|
|
remainingPayment?: number,
|
|
) => api.post<FirstMileRecord>(`${FM.BASE}/${id}/distances`, { distances, remainingPayment }),
|
|
generateInvoice: (id: string) =>
|
|
api.post<{ id: string; invoiceNumber?: string } | null>(`${FM.BASE}/${id}/invoice`),
|
|
};
|