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)
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
| Campo | Tipo | Descripción |
|---|---|---|
source_id | string | ID único del registro en el sistema de origen |
source_system | string | Identificador del sistema externo (ej. external_erp) |
pickup_type | string | Tipo de recolección: OC o TRANSFER |
document_id | int | ID del documento en el sistema externo |
Opcionales
| Campo | Tipo | Descripción |
|---|---|---|
is_active | boolean | Estado activo de la recolección |
receipt_code | string | Código de la factura asociada |
supplier_id / supplier_source_id | int/string | Proveedor (para OC) |
supplier_model | string | Modelo del proveedor |
hub_id / hub_source_id | int/string | Sede origen (para TRANSFER) |
hub_model | string | Modelo del hub |
receipt_type_id / receipt_type_source_id | int/string | Tipo de recibo |
receipt_type_model | string | Modelo del tipo de recibo |
status_id | int | Estado de la recolección |
is_confirmed | boolean | Flag 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_confirmed | boolean | Confirmación de compra (alias tipado para OC). Solo se usa si is_confirmed viene nulo/omitido. |
is_transfer_confirmed | boolean | Confirmación de traslado (alias tipado para TRANSFER). Solo se usa si is_confirmed viene nulo/omitido. |
source_warehouse | string | Bodega de origen |
target_warehouse | string | Bodega de destino |
weight | number | Peso total |
product_model | string | Modelo de producto |
lines | array | Líneas de productos |
Campos de lines[]
Requeridos
| Campo | Tipo | Descripción |
|---|---|---|
product_code | string | Código del producto |
quantity | number | Cantidad |
Opcionales
| Campo | Tipo | Descripción |
|---|---|---|
warehouse | string | Bodega |
status_id | int | Estado |
source_warehouse | string | Bodega origen |
source_location | string | Ubicación origen |
source_lot | string | Lote origen |
target_warehouse | string | Bodega destino |
target_location | string | Ubicación destino |
target_lot | string | Lote 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".
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
| Campo | Tipo | Descripción |
|---|---|---|
source_id | string | ID único en el sistema de origen |
source_system | string | Sistema externo |
document_id / document_code | int/string | Al menos uno de los dos |
Opcionales
Los mismos campos compatibles con TRANSFER en /transportes/sync/pickups.
| Campo | Tipo | Descripción |
|---|---|---|
hub_id | int | ID del hub |
source_hub_id / hub_source_id | string | ID 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 enviado | Resultado en BD |
|---|---|
is_confirmed: true | Confirma (sobrescribe el valor anterior) |
is_confirmed: false | Desconfirma (sobrescribe el valor anterior) |
is_confirmed omitido | Preserva el valor actual — no se toca la columna |
is_confirmed: true junto a is_transfer_confirmed: false | Gana is_confirmed → persiste true |
solo is_purchase_confirmed / is_transfer_confirmed | Se usa como fallback cuando is_confirmed viene nulo/omitido |
Regla de precedencia (desde v0.5.124): cuando el payload trae
is_confirmedcomo 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:
lines | Efecto |
|---|---|
| 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 items | Reemplaza 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
{
"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
{
"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
{
"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)
{
"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_actionen 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_systemidénticos, el upsert intentará crear un registro nuevo y fallará conCAPTURED_ERRORpor colisión dedocument_code. - Omitir campos como
supplier_id,hub_id,receipt_code,weight,status_idpreserva sus valores actuales (los spreads condicionales en el lambda los dejan intactos cuando el campo vieneundefined).