Operaciones
Recolecciones y Traslados

Sincronización de Recolecciones y Traslados

En esta sección se documentan los endpoints para sincronizar las recolecciones necesarias antes de poder entregar una factura. Soporta dos tipos principales: OC (órdenes de compra a proveedores) y TRANSFER (traslados desde otras sedes).


1. Recolecciones (Pickups)

POST/transportes/sync/pickups

Sincroniza recolecciones de tipo OC o TRANSFER asociadas a una factura.

Caso de uso

  • Crear OCs ligadas a una factura.
  • Crear traslados ligados a una factura.
  • Actualizar cantidades por línea y estado de confirmación.

Campos del Payload

Requeridos

CampoTipoDescripción
source_idstringID único del registro en el sistema de origen
source_systemstringIdentificador del sistema externo (ej. external_erp)
pickup_typestringTipo de recolección: OC o TRANSFER
document_idintID del documento en el sistema externo

Opcionales

CampoTipoDescripción
is_activebooleanEstado activo de la recolección
receipt_codestringCódigo de la factura asociada
supplier_id / supplier_source_idint/stringProveedor (para OC)
supplier_modelstringModelo del proveedor
hub_id / hub_source_idint/stringSede origen (para TRANSFER)
hub_modelstringModelo del hub
receipt_type_id / receipt_type_source_idint/stringTipo de recibo
receipt_type_modelstringModelo del tipo de recibo
status_idintEstado de la recolección
is_confirmedbooleanFlag plano de confirmación. Aplica tanto a OC como TRANSFER. Tiene precedencia sobre is_purchase_confirmed / is_transfer_confirmed cuando se envía como boolean (no nulo). Ver sección Flujo Confirm-Later.
is_purchase_confirmedbooleanConfirmación de compra (alias tipado para OC). Solo se usa si is_confirmed viene nulo/omitido.
is_transfer_confirmedbooleanConfirmación de traslado (alias tipado para TRANSFER). Solo se usa si is_confirmed viene nulo/omitido.
source_warehousestringBodega de origen
target_warehousestringBodega de destino
weightnumberPeso total
product_modelstringModelo de producto
linesarrayLíneas de productos

Campos de lines[]

Requeridos

CampoTipoDescripción
product_codestringCódigo del producto
quantitynumberCantidad

Opcionales

CampoTipoDescripción
warehousestringBodega
status_idintEstado
source_warehousestringBodega origen
source_locationstringUbicación origen
source_lotstringLote origen
target_warehousestringBodega destino
target_locationstringUbicación destino
target_lotstringLote destino

Ejemplos

Request OC

{
  "source_id": "purchase.order:371",
  "source_system": "external_erp",
  "pickup_type": "OC",
  "document_id": 371,
  "document_code": "OC-371",
  "receipt_code": "FAC-10001",
  "supplier_source_id": "res.partner:7001",
  "supplier_model": "res.partner",
  "is_purchase_confirmed": false,
  "lines": [
    {
      "product_code": "00838",
      "quantity": 5,
      "warehouse": "WH/Stock"
    }
  ]
}

Request TRANSFER

{
  "source_id": "stock.picking:470",
  "source_system": "external_erp",
  "pickup_type": "TRANSFER",
  "document_id": 470,
  "document_code": "TR-470",
  "receipt_code": "FAC-10001",
  "hub_source_id": "stock.warehouse:2",
  "hub_model": "stock.warehouse",
  "is_transfer_confirmed": false,
  "source_warehouse": "ALAJUELA/Stock",
  "target_warehouse": "CEDI/Stock",
  "lines": [
    {
      "product_code": "00838",
      "quantity": 5,
      "source_warehouse": "ALAJUELA/Stock",
      "target_warehouse": "CEDI/Stock"
    }
  ]
}

Response

{
  "ok": true,
  "code": "SYNC_OK",
  "message": "Sync processed successfully.",
  "data": {
    "pickup_type": "OC",
    "document_id": 371,
    "document_code": "OC-371",
    "receipt_code": "FAC-10001",
    "upsert_action": "updated"
  },
  "meta": {
    "route": "/transportes/sync/pickups",
    "method": "PostPickupSync",
    "operation": "upsert",
    "upsert_action": "updated",
    "timestamp": "2026-04-07T12:00:00.000Z"
  }
}

2. Traslados (Alias)

Alias especializado de pickups para traslados. Internamente fuerza pickup_type = "TRANSFER".

POST/transportes/sync/transfers

Alias del endpoint de pickups que fuerza el tipo TRANSFER. Útil cuando el integrador prefiere un endpoint separado.

Caso de uso

El integrador prefiere un endpoint separado para traslados.

Campos del Payload

Requeridos

CampoTipoDescripción
source_idstringID único en el sistema de origen
source_systemstringSistema externo
document_id / document_codeint/stringAl menos uno de los dos

Opcionales

Los mismos campos compatibles con TRANSFER en /transportes/sync/pickups.

CampoTipoDescripción
hub_idintID del hub
source_hub_id / hub_source_idstringID externo del hub

Ejemplos

Request

{
  "source_id": "stock.picking:470",
  "source_system": "external_erp",
  "document_id": 470,
  "document_code": "TR-470",
  "receipt_code": "FAC-10001",
  "hub_source_id": "stock.warehouse:2",
  "lines": [
    {
      "product_code": "00838",
      "quantity": 5
    }
  ]
}

Response

{
  "ok": true,
  "code": "SYNC_OK",
  "message": "Sync processed successfully.",
  "data": {
    "pickup_type": "TRANSFER",
    "document_id": 470,
    "document_code": "TR-470",
    "receipt_code": "FAC-10001",
    "upsert_action": "created"
  },
  "meta": {
    "route": "/transportes/sync/transfers",
    "method": "PostTransferSync",
    "operation": "upsert",
    "upsert_action": "created",
    "timestamp": "2026-04-07T12:00:00.000Z"
  }
}

3. Flujo Confirm-Later

Los sistemas externos pueden crear una recolección primero y confirmarla después reenviando el mismo par (source_id, source_system) con is_confirmed: true. El upsert detecta el registro por el origen, entra en modo UPDATE y persiste el nuevo valor sin duplicar el documento.

Aplica a OC (purchase_orders) y TRANSFER (transfers) por igual, a través de POST /transportes/sync/pickups o POST /transportes/sync/transfers.

Semántica del flag

Campo enviadoResultado en BD
is_confirmed: trueConfirma (sobrescribe el valor anterior)
is_confirmed: falseDesconfirma (sobrescribe el valor anterior)
is_confirmed omitidoPreserva el valor actual — no se toca la columna
is_confirmed: true junto a is_transfer_confirmed: falseGana is_confirmed → persiste true
solo is_purchase_confirmed / is_transfer_confirmedSe usa como fallback cuando is_confirmed viene nulo/omitido

Regla de precedencia (desde v0.5.124): cuando el payload trae is_confirmed como boolean no-nulo, el backend lo usa como fuente de verdad y ignora los aliases tipados. Esto permite que un mismo payload sirva para OC y TRANSFER sin tener que decidir cuál alias enviar.

Reglas sobre lines en confirm-later

persistPickupLines es reemplazo total (hace deleteMany y luego createMany con lo enviado). Por eso el comportamiento depende de cómo venga el campo:

linesEfecto
omitido (no aparece en el payload)No se tocan las líneas existentes ✅
[] (array vacío)Se borran todas las líneas existentes ⚠️
array con itemsReemplaza completamente las líneas (delete + insert)

Recomendación: para un confirm-only, omitir lines. Si se envía un array vacío se pierden las líneas ya registradas.

Ejemplo 1 — Crear OC sin confirmar

POST /transportes/sync/pickups
{
  "source_id": "purchase.order:371",
  "source_system": "external_erp",
  "pickup_type": "OC",
  "document_code": "OC-371",
  "receipt_code": "FAC-10001",
  "supplier_source_id": "res.partner:7001",
  "is_confirmed": false,
  "lines": [
    { "product_code": "00838", "quantity": 5, "warehouse": "WH/Stock" }
  ]
}

Resultado: purchase_orders.is_confirmed = false, líneas creadas.

Ejemplo 2 — Confirmar la misma OC más tarde

POST /transportes/sync/pickups
{
  "source_id": "purchase.order:371",
  "source_system": "external_erp",
  "pickup_type": "OC",
  "document_code": "OC-371",
  "is_confirmed": true
}

El upsert encuentra la OC por (source_id, source_system), entra en UPDATE y actualiza is_confirmed = true. Como lines fue omitido, las líneas existentes se preservan.

Ejemplo 3 — Confirmar un TRANSFER ya creado

POST /transportes/sync/transfers
{
  "source_id": "stock.picking:470",
  "source_system": "external_erp",
  "document_code": "TR-470",
  "is_confirmed": true
}

Equivalente vía alias: POST /transportes/sync/transfers fuerza pickup_type = "TRANSFER" y delega a la misma lógica de upsert. Resultado: transfers.is_confirmed = true, líneas intactas.

Ejemplo 4 — Desconfirmar (rollback)

POST /transportes/sync/pickups
{
  "source_id": "purchase.order:371",
  "source_system": "external_erp",
  "pickup_type": "OC",
  "document_code": "OC-371",
  "is_confirmed": false
}

Actualiza is_confirmed = false sobre el registro existente.

Notas operativas

  • El upsert_action en la respuesta será "updated" en las llamadas de confirmación posteriores a la creación inicial.
  • Si el ERP no reenvía source_id/source_system idénticos, el upsert intentará crear un registro nuevo y fallará con CAPTURED_ERROR por colisión de document_code.
  • Omitir campos como supplier_id, hub_id, receipt_code, weight, status_id preserva sus valores actuales (los spreads condicionales en el lambda los dejan intactos cuando el campo viene undefined).