/** * Cliente API — Operaciones (Embarques y documentos de transporte). */ import { api } from '$lib/api'; export type ShipmentStatus = | 'abierta' | 'booking' | 'en_transito' | 'arribado' | 'entregada' | 'cerrada' | 'cancelada'; export interface Shipment { id: number; reference: string | null; quote_id: number | null; service_request_id: number | null; account_id: number | null; operation_type: string | null; transport_mode: string | null; service_type: string | null; incoterm: string | null; origin: string | null; destination: string | null; status: ShipmentStatus; booking_number: string | null; carrier_supplier_id: number | null; ground_carrier_supplier_id: number | null; customs_agent_id: number | null; destination_agent_id: number | null; cutoff_date: string | null; pickup_at: string | null; etd: string | null; previous_etd: string | null; eta: string | null; vessel_flight: string | null; container_number: string | null; notes: string | null; actual_cost_total: number | null; cost_currency: string | null; closed_at: string | null; closed_by: string | null; owner_user_id: string | null; created_by: string | null; updated_by: string | null; tenant_id: number; company_id: number; created_at: string; updated_at: string; } export type ShipmentInput = Partial>; export interface ShipmentEvent { id: number; shipment_id: number; event_type: string | null; title: string; kind: string; // hito | decision status: string; // pendiente | completado | omitido | rechazado | en_correccion outcome: string | null; // autorizado | rechazado parent_event_id: number | null; attempt: number; position: number; planned_date: string | null; actual_date: string | null; notes: string | null; tenant_id: number; company_id: number; created_at: string; updated_at: string; } export type ShipmentEventInput = Partial> & { shipment_id: number; title: string; }; export interface ShipmentDocument { id: number; shipment_id: number; doc_kind: string; doc_type: string; number: string | null; issue_date: string | null; file_url: string | null; file_key: string | null; notes: string | null; tenant_id: number; company_id: number; created_at: string; updated_at: string; } export type ShipmentDocumentInput = Partial> & { shipment_id: number; doc_type: string; }; function qp(companyId: number, extra?: Record) { const qs = new URLSearchParams({ company_id: String(companyId) }); for (const [k, v] of Object.entries(extra ?? {})) if (v !== undefined && v !== '') qs.set(k, String(v)); return qs.toString(); } async function unwrap(p: Promise<{ data?: T; error?: string }>): Promise { const res = await p; if (res.error) throw new Error(res.error); return res.data as T; } export const shipmentsAPI = { list: (companyId: number, params?: { search?: string; status?: string; account_id?: number }) => unwrap(api.get(`/v1/ops/shipments?${qp(companyId, params)}`)), get: (id: number, companyId: number) => unwrap(api.get(`/v1/ops/shipments/${id}?${qp(companyId)}`)), create: (data: ShipmentInput, companyId: number) => unwrap(api.post(`/v1/ops/shipments?${qp(companyId)}`, data)), createFromQuote: (quoteId: number, companyId: number, operationType?: string) => unwrap(api.post(`/v1/ops/shipments/from-quote?${qp(companyId, { quote_id: quoteId, operation_type: operationType })}`, {})), update: (id: number, data: Partial, companyId: number) => unwrap(api.patch(`/v1/ops/shipments/${id}?${qp(companyId)}`, data)), reschedule: (id: number, data: { etd?: string | null; cutoff_date?: string | null; reason?: string | null }, companyId: number) => unwrap(api.post(`/v1/ops/shipments/${id}/reschedule?${qp(companyId)}`, data)), close: (id: number, data: { actual_cost_total: number; cost_currency?: string; notes?: string | null }, companyId: number) => unwrap(api.post(`/v1/ops/shipments/${id}/close?${qp(companyId)}`, data)), remove: (id: number, companyId: number) => unwrap(api.delete(`/v1/ops/shipments/${id}?${qp(companyId)}`)), documents: (shipmentId: number, companyId: number) => unwrap(api.get(`/v1/ops/shipments/${shipmentId}/documents?${qp(companyId)}`)), events: (shipmentId: number, companyId: number) => unwrap(api.get(`/v1/ops/shipments/${shipmentId}/events?${qp(companyId)}`)), seedEvents: (shipmentId: number, companyId: number) => unwrap(api.post(`/v1/ops/shipments/${shipmentId}/events/seed?${qp(companyId)}`, {})) }; export const shipmentEventsAPI = { create: (data: ShipmentEventInput, companyId: number) => unwrap(api.post(`/v1/ops/shipment-events?${qp(companyId)}`, data)), update: (id: number, data: Partial, companyId: number) => unwrap(api.patch(`/v1/ops/shipment-events/${id}?${qp(companyId)}`, data)), complete: (id: number, companyId: number) => unwrap(api.patch(`/v1/ops/shipment-events/${id}/complete?${qp(companyId)}`, {})), decide: (id: number, outcome: 'autorizado' | 'rechazado', companyId: number, notes?: string | null) => unwrap(api.patch(`/v1/ops/shipment-events/${id}/decision?${qp(companyId)}`, { outcome, notes })), remove: (id: number, companyId: number) => unwrap(api.delete(`/v1/ops/shipment-events/${id}?${qp(companyId)}`)) }; export const shipmentDocumentsAPI = { create: (data: ShipmentDocumentInput, companyId: number) => unwrap(api.post(`/v1/ops/shipment-documents?${qp(companyId)}`, data)), update: (id: number, data: Partial, companyId: number) => unwrap(api.patch(`/v1/ops/shipment-documents/${id}?${qp(companyId)}`, data)), remove: (id: number, companyId: number) => unwrap(api.delete(`/v1/ops/shipment-documents/${id}?${qp(companyId)}`)) };