This commit is contained in:
Marshal
2026-07-14 13:11:38 +00:00
1915 changed files with 241099 additions and 165123 deletions

View File

@@ -0,0 +1,48 @@
import { api as client } from "../auth/http";
export interface AiExtractedBooking {
customerName: string | null;
origin: string | null;
destination: string | null;
cargoType: string | null;
containerType: "20FT" | "40FT" | "BULK" | "RO_RO" | null;
quantity: number | null;
direction: "IMPORT" | "EXPORT" | null;
weightKg: number | null;
pickupRequired: boolean | null;
deliveryRequired: boolean | null;
}
export interface AiValidationResult {
valid: boolean;
errors: string[];
}
export interface AiRecommendation {
action: "CREATE_DRAFT_BOOKING" | "REQUEST_MISSING_INFORMATION";
message: string;
confidence: number;
}
export interface AiBookingExtractResult {
provider: "mock";
extracted: AiExtractedBooking;
validation: AiValidationResult;
recommendation: AiRecommendation;
}
interface AiBookingExtractResponse {
success: boolean;
data: AiBookingExtractResult;
timestamp: string;
}
export const extractBookingFromText = async (
text: string,
): Promise<AiBookingExtractResult> => {
const response = await client.post<AiBookingExtractResponse>(
"/ai/booking/extract",
{ text },
);
return response.data.data;
};

View File

@@ -108,6 +108,20 @@ export const lastMileService = {
) => api.post<LastMileRecord>(`${LM.BASE}/${id}/distances`, { distances, remainingPayment }),
generateInvoice: (id: string) =>
api.post<{ id: string; invoiceNumber?: string } | null>(`${LM.BASE}/${id}/invoice`),
/** Record proof of delivery (recipient signature + photos) and complete the leg. */
recordProofOfDelivery: (
id: string,
payload: { recipientName: string; notes?: string; signature?: Blob | null; photos?: File[] },
) => {
const form = new FormData();
form.append("recipientName", payload.recipientName);
if (payload.notes) form.append("notes", payload.notes);
if (payload.signature) form.append("signature", payload.signature, "signature.png");
(payload.photos ?? []).forEach((photo) => form.append("photos", photo));
return api.post<LastMileRecord>(LM.PROOF_OF_DELIVERY(id), form, {
headers: { "Content-Type": "multipart/form-data" },
});
},
/** Generate a truck-detention invoice (per truck per day after the grace window). */
generateTruckDetentionInvoice: (id: string) =>
api.post<{ id: string; invoiceNumber?: string } | null>(

View File

@@ -4,6 +4,9 @@ import { api as apiClient } from '../auth/http';
import { URL_CONSTANTS } from '@/constants/URLS';
import type {
ZoneOccupancy,
WarehouseOpsStats,
AccrualDashboardRow,
AllocationCriteria,
AllocationPreviewResult,
AllocationRule,
@@ -365,6 +368,12 @@ export const warehouseService = {
// ── Batch 4.5: Arrival / Unload / Load automation ──────────────────────────
arrivalQueue: () =>
apiClient.get<ArrivalQueueItem[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.ARRIVAL_QUEUE),
zoneOccupancy: (yardId?: string) =>
apiClient.get<ZoneOccupancy[]>(
URL_CONSTANTS.WAREHOUSE_INVENTORY.ZONE_OCCUPANCY(yardId),
),
opsStats: () =>
apiClient.get<WarehouseOpsStats>(URL_CONSTANTS.WAREHOUSE_INVENTORY.OPS_STATS),
autoUnloadArrived: () =>
apiClient.post<AutoUnloadResult>(URL_CONSTANTS.WAREHOUSE_INVENTORY.AUTO_UNLOAD_ARRIVED),
autoLoadReady: () =>
@@ -417,6 +426,14 @@ export const warehouseService = {
apiClient.get<FeePreview[]>(URL_CONSTANTS.WAREHOUSE_RULES.FEE_PREVIEW(inventoryId), {
params: cleanParams({ billingCurrency }),
}),
accrualDashboard: (billingCurrency?: 'ETB' | 'USD') =>
apiClient.get<AccrualDashboardRow[]>(URL_CONSTANTS.WAREHOUSE_RULES.ACCRUAL_DASHBOARD, {
params: cleanParams({ billingCurrency }),
}),
acknowledgeAccrual: (inventoryId: string, body: { snoozeDays?: number; note?: string } = {}) =>
apiClient.post(URL_CONSTANTS.WAREHOUSE_RULES.ACCRUAL_ACK(inventoryId), body),
unacknowledgeAccrual: (inventoryId: string) =>
apiClient.delete(URL_CONSTANTS.WAREHOUSE_RULES.ACCRUAL_ACK(inventoryId)),
// ── Batch 6: Warehouse fee invoices ────────────────────────────────────────
listInvoices: (filter?: WarehouseInvoiceFilter) =>