Operaciones
Guías (Dispatch)

Sincronización de Guías (Dispatch)

Importante: A diferencia de los demás endpoints de sync, /transportes/sync/dispatch trabaja con IDs internos de Smartfleet (driver_id, vehicle_id, hub_id, receipt_id). Esto significa que chofer, vehículo, sede y facturas deben estar ya sincronizados antes de crear la guía.

POST/transportes/sync/dispatch

Crea o actualiza una guía de despacho con chofer, vehículo y paradas.

Caso de uso

  • Crear guía desde un sistema externo cuando ya se eligieron chofer, vehículo y stops.
  • Actualizar una guía existente pasando dispatch_id.
  • Crear guías normales o de solo recolección.

Campos del Payload

Requeridos

CampoTipoDescripción
driver_idintID del chofer
vehicle_idintID del vehículo
total_weightnumberPeso total del despacho
dispatch_stepsobjectMapa de paradas de la guía

Opcionales

CampoTipoDescripción
dispatch_idintPara actualizar una guía existente
hub_idintSede de salida
userstringUsuario que crea la guía
uber / is_uberbooleanIndica si es despacho por Uber
default_pickup_notesstringNotas de recolección por defecto
extra_pickup_notesstringNotas adicionales de recolección
dropoff_notes / return_detailstringNotas de entrega o devolución
removed_receipts_ids / removed_receipt_idsint[]Facturas a remover de la guía
removed_returns_ids / removed_return_idsint[]Devoluciones a remover
removed_transfers_ids / removed_transfer_idsint[]Traslados a remover
dispatch_modestringNORMAL_DELIVERY (default) o PICKUP_ONLY
validate_hub_pickups_on_create / validate_pickups_on_createbooleanValida pickups al crear
source_idstringID externo de la guía (máx. 128 chars). Permite luego lookups por GET /sync/dispatch/{sourceId} e identificación vía dispatch_source_id en /sync/dispatch/start
source_systemstringSistema externo (ej. external_erp). Requerido junto con source_id

Tipos permitidos en dispatch_steps

Cada stop tiene order (entero), type y item. Los campos requeridos en item según tipo:

TipoCampos requeridos en itemDescripción
hubhub_id, name, latitude, longitudeParada en sede
receiptreceipt_id, receipt_code, hub_id, latitude, longitudeParada de entrega de factura
pickuppickup_type, document_id, receipt_idParada de recolección
returnreturn_id, receipt_idParada de devolución
transferpickup_type: "TRANSFER", document_id, receipt_idParada de traslado

Todos los IDs en item (receipt_id, hub_id, return_id, etc.) son IDs internos de Smartfleet, no source_id.

Notas Importantes

  • Para PICKUP_ONLY, el stop final de entrega de recolecciones usa ENT_REC cuando corresponde.
  • Si se intenta crear otra guía PICKUP_ONLY con pickups ya procesados, el backend bloquea la operación.
  • Si se crea una guía normal posterior, los pickups ya procesados no se vuelven a crear como stops de recolección.

ENT_REC vs ENT_FAC: cómo derivar el stop de factura

type en dispatch_steps solo acepta los 5 valores listados arriba — no existe ent_rec. Cuando una guía es solo recolección y la mercadería se deposita en una sede en lugar de entregarse al cliente, el integrador envía el step de la factura con type: "receipt" y deliver_to_hub: true en item. El backend convierte ese step en un stop ENT_REC durante buildStopsToCreate con esta regla:

deliverToHub = item.deliver_to_hub === true
            || item.latitude == null
            || item.longitude == null

stop_type_id = deliverToHub ? ENT_REC : ENT_FAC
Casotypeitem.deliver_to_hubitem.latitude/longitudeStop generado
Entrega normal al clientereceiptomitircoords del clienteENT_FAC
Depósito en sede tras recolecciónreceipttruecoords del hub destino (recomendado)ENT_REC
Depósito en sede sin coordsreceiptomitiromitir ambosENT_REC (fallback)

Cuando el chofer ejecuta el stop:

  • POST /transportes/sync/dispatch/task/start con task_type: "ENT_REC", document_id = receipt_id.
  • POST /transportes/sync/dispatch/task/complete con task_type: "ENT_REC". Las cantidades reportadas en lines[*] se acumulan en returned_quantity (vuelven al hub) en lugar de delivered_quantity.

Efecto al cerrar el stop ENT_REC:

  • receipts.status_id queda en SIN_ASIGNAR (1) — la entrega al cliente queda pendiente.
  • Se setean pickup_stored_hub_id (= item.hub_id enviado en el step) y pickup_stored_at.
  • En una guía posterior se podrá crear un step receipt ENT_FAC normal para entregar al cliente final.

Ejemplos

Request — Guía Normal

{
  "hub_id": 3,
  "driver_id": 1,
  "vehicle_id": 12,
  "total_weight": 25.5,
  "user": "erp-sync",
  "dispatch_mode": "NORMAL_DELIVERY",
  "dispatch_steps": {
    "1": {
      "order": 1,
      "type": "hub",
      "item": {
        "hub_id": 3,
        "name": "Cedi",
        "latitude": 9.9797944160071,
        "longitude": -84.1408946228684
      }
    },
    "2": {
      "order": 2,
      "type": "receipt",
      "item": {
        "receipt_id": 2108,
        "receipt_type_id": 1,
        "receipt_code": "FAC-10001",
        "receipt_type_code": "FAC",
        "hub_id": 3,
        "latitude": 9.93,
        "longitude": -84.14
      }
    }
  }
}

Request — Solo Recolección (Pickup Only)

{
  "hub_id": 3,
  "driver_id": 1,
  "vehicle_id": 12,
  "total_weight": 10,
  "user": "erp-sync",
  "dispatch_mode": "PICKUP_ONLY",
  "dispatch_steps": {
    "1": {
      "order": 1,
      "type": "hub",
      "item": {
        "hub_id": 2,
        "name": "Alajuela",
        "latitude": 10.01064731315831,
        "longitude": -84.21583404686814
      }
    },
    "2": {
      "order": 2,
      "type": "pickup",
      "item": {
        "pickup_type": "OC",
        "document_id": 371,
        "receipt_code": "FAC-10001",
        "receipt_id": 2108,
        "origin_description": "Acme Manufacturing",
        "latitude": 9.93276239628712,
        "longitude": -84.08577070478509
      }
    },
    "3": {
      "order": 3,
      "type": "hub",
      "item": {
        "hub_id": 3,
        "name": "Cedi",
        "latitude": 9.9797944160071,
        "longitude": -84.1408946228684
      }
    }
  }
}

Response

{
  "ok": true,
  "code": "SYNC_OK",
  "message": "Sync processed successfully.",
  "data": {
    "statusOk": true,
    "message": "Dispatch created successfully.",
    "dispatch_id": 501
  },
  "meta": {
    "route": "/transportes/sync/dispatch",
    "method": "PostDispatchSync",
    "operation": "upsert",
    "upsert_action": "created",
    "timestamp": "2026-04-07T12:00:00.000Z"
  }
}

Cancelación de guías desde sistema externo

El mismo endpoint POST /transportes/sync/dispatch maneja el flujo de solicitud y aprobación de cancelación usando el campo sync_operation.

Paso 1 — Solicitar cancelación

POST /transportes/sync/dispatch — solicitar cancelación
{
  "dispatch_id": 501,
  "sync_operation": "CANCELLATION_REQUEST",
  "reason": "El cliente canceló el pedido",
  "detail": "Detalle opcional adicional",
  "user": "erp-sync"
}

Response:

Response — CANCELLATION_REQUEST
{
  "ok": true,
  "code": "SYNC_OK",
  "meta": {
    "upsert_action": "cancellation_requested",
    "sync_operation": "CANCELLATION_REQUEST"
  }
}

Paso 2 — Reenviar solicitud (si está pendiente)

POST /transportes/sync/dispatch — reenviar solicitud
{
  "dispatch_id": 501,
  "sync_operation": "CANCELLATION_RESEND"
}

Paso 3 — Aprobar o rechazar la cancelación

POST /transportes/sync/dispatch — aprobar
{
  "dispatch_id": 501,
  "sync_operation": "CANCELLATION_DECISION",
  "action": "APPROVED",
  "comment": "Confirmado por supervisor"
}
POST /transportes/sync/dispatch — rechazar
{
  "dispatch_id": 501,
  "sync_operation": "CANCELLATION_DECISION",
  "action": "REJECTED",
  "comment": "No procede la cancelación"
}

Aliases de sync_operation

El campo acepta múltiples variantes para facilitar la integración:

AliasOperación
CANCELLATION_REQUEST, CANCEL_REQUEST, REQUEST_CANCELLATION, REQUESTED, CREATESolicitar cancelación
CANCELLATION_RESEND, CANCEL_RESEND, RESENDReenviar solicitud
CANCELLATION_DECISION, CANCEL_DECISION, DECISION, APPROVED, REJECTEDAprobar / rechazar

Nota: La cancelación de guía es distinta de la cancelación de un stop (task/cancel). La cancelación de stop revierte el dispatch a ASIGNADA para reprogramarlo; la cancelación de guía la lleva a ANULADA tras aprobación.

Ubicación del chofer en lote

Un sistema de telemetría externo puede empujar los puntos GPS que recolectó mientras el chofer estaba en ruta. Es la ruta que usa un adapter de flota cuando la app del chofer no es la fuente de la ubicación.

POST /transportes/sync/dispatch/location/batch
Authorization: Bearer YOUR_SYNC_TOKEN_HERE
Content-Type: application/json
{
  "driver_id": "1",
  "locations": [
    {
      "lat": 9.93,
      "lng": -84.08,
      "speed": 42.5,
      "heading": 180,
      "gps_precision": 8,
      "route_id": "R-2026-08-19-01",
      "status": "EN_RUTA",
      "recorded_at": "2026-08-19T16:00:00.000Z"
    }
  ]
}
CampoTipoRequeridoDescripción
driver_idstring | numbersíChofer en Smartfleet.
locationsarraysíEntre 1 y 1000 puntos por request. Más de 1000 → 400.
locations[].latnumber -90..90síLatitud.
locations[].lngnumber -180..180síLongitud.
locations[].recorded_atstring ISO 8601síInstante de la lectura.
locations[].speednumbernoVelocidad reportada.
locations[].headingnumbernoRumbo.
locations[].gps_precisionnumbernoPrecisión del GPS, en metros.
locations[].route_idstringnoIdentificador de la ruta en el sistema de origen.
locations[].statusstringnoEstado reportado por el origen.

Los puntos se ordenan por recorded_at antes de guardarse, así que un lote que llega desordenado no deja el rastro invertido.