Flujo de Packing

Documentación operativa de /#packing y su integración con /#expedicion y SAP B1.

COMFAR WMS · actualizado al 20/05/2026

1. Visión general

El packing es la etapa entre picking (recolección del stock desde los bins) y despacho (carga del camión y emisión de la Nota de Remisión).

SAP Sales Order
Pick List (COMPLETED)
Packing (COMPLETED)
Dispatch (DISPATCHED)
SAP DeliveryNote
Regla: la DeliveryNote en SAP no se crea al completar el packing. Se difiere al cierre del despacho, donde recién se conocen chofer, vehículo y kilómetros (UDFs obligatorios para SET-Paraguay).

2. La vista /#packing

Al abrir https://comfar.xp.com.py:8443/WMS/#packing el sistema dispara GET /api/packing/recent/{warehouse_id} y renderiza la tabla de órdenes.

Controles del header

ControlDescripción
+ Nuevo PackingAbre el modal para crear un packing desde una pick list COMPLETED o IN_PROGRESS.
Selector de almacénDefaulta a CEN. Cambiar el almacén recarga la tabla.
Selector de estadoFiltra por OPEN / IN_PROGRESS / COMPLETED / CANCELLED. «Todos» trae los últimos 60 días.

Columnas de la tabla

ColumnaOrigen
Númeropacking_orders.pack_number (PK-XXXXXXXX)
Pick Listpick_lists.pick_number
Clientepacking_orders.customer_name (heredado del SO)
ItemsCantidad de filas en packing_lines
EstadoDRAFT, OPEN, IN_PROGRESS, COMPLETED, CANCELLED
SAP DNpacking_orders.sap_delivery_num — vacío hasta cerrar el despacho
Fechacreated_at
AccionesVer (detalle) · Audit

3. Flujo operativo (paso a paso)

1

Crear el packing desde una pick list

Click en + Nuevo Packing. El modal lista las pick lists del almacén en estado COMPLETED o IN_PROGRESS (las que ya tienen stock pickeado). Seleccioná una y confirmá.

POST /api/packing  Body: { pick_list_id, notes? }

El backend:

  • Valida que la pick list esté en estado válido
  • Garantiza unicidad (no permite duplicar packing para misma pick list)
  • Asigna pack_number consecutivo (nextDocNumber('PACK'))
  • Inserta packing_orders con status=OPEN y hereda customer_code/customer_name/sap_doc_entry de la pick list
  • Para cada línea PICKED con picked_qty > 0 inserta una fila en packing_lines con status=PENDING
2

Abrir el detalle

Click en Ver. Se despliega el detalle inline con las líneas, el input de escaneo y el botón Completar Packing.

GET /api/packing/{id}

El backend devuelve la cabecera + lines con quantity, packed_qty, batch_number, sap_line_num, container_id.

3

Escanear el item

El operador escanea (o tipea) el código de barras del producto en pack-scan-input y presiona Enter.

POST /api/packing/{id}/scan  Body: { barcode | item_code }

El backend valida que el item esté esperado en la orden y no haya sido empacado todavía. Devuelve la línea matcheada, lo esperado, lo packed y lo restante.

4

Confirmar la línea

El operador confirma la cantidad empacada (total o parcial) y, opcionalmente, asigna el contenedor.

POST /api/packing/{id}/pack-line/{line_num}  Body: { quantity?, container_id? }

El backend acumula packed_qty. Si alcanza quantitystatus=PACKED; sino queda como PENDING (acepta empaque parcial en múltiples corridas).

5

Completar el packing

Una vez todas las líneas están PACKED, click en Completar Packing.

POST /api/packing/{id}/complete

El backend:

  • Verifica que no haya líneas pendientes (caso contrario rechaza)
  • Actualiza packing_orders.status=COMPLETED + completed_at
  • Inserta registro en sap_sync_log con status=PENDING y mensaje «Esperando despacho para crear DeliveryNote»
Importante: aquí no se crea la DeliveryNote en SAP. El packing queda listo para ser asignado a un despacho.

4. Continuación en /#expedicion

El operador cambia a /#expedicion y opera con el packing recién completado:

6

Crear el despacho

Click en + Nuevo Despacho. Al abrirse el modal dispara:

  • GET /api/sap/drivers — lista de CENT_CHOFERES (UDO de SAP)
  • GET /api/sap/vehicles — lista de CENT_VEHICULOS (UDO de SAP)

Operador selecciona chofer, vehículo (auto-completa patente y transportista), ingresa kilómetros estimados y confirma.

POST /api/dispatch

// payload
{
  "warehouse_id":  16,
  "driver_code":   "967186",        // CENT_CHOFERES.Code
  "driver_name":   "JOSE BENITEZ",
  "vehicle_code":  "0001",          // CENT_VEHICULOS.Code
  "vehicle_plate": "HDS255",
  "km_estimate":   15,
  "carrier":       "COMFAR S.A.E.C.A."
}
7

Asignar el packing al despacho

POST /api/dispatch/{id}/assign  Body: { packing_order_id }

El backend valida que el packing esté COMPLETED, que no esté ya asignado a otro despacho, y crea una dispatch_lines por cada packing_lines. Pasa el despacho a status=LOADING.

8

(Opcional) Escanear contenedores para verificación

POST /api/dispatch/{id}/scan-container

Marca dispatch_lines.status=VERIFIED al matchear el LPN escaneado.

9

Cerrar el despacho — aquí se crea la SAP DeliveryNote

POST /api/dispatch/{id}/close

El backend ejecuta atomicamente:

  1. Valida que estén cargados driver_code, vehicle_code, km_estimate
  2. Por cada packing asignado:
    • Registra movimiento de stock DISPATCH (salida AVAILABLE)
    • Lee el SO origen de SAP para heredar CardCode, DocCurrency, DocRate
    • Construye el payload de la SAP DeliveryNote
    • POST /b1s/v1/DeliveryNotes
    • Persiste packing_orders.sap_delivery_entry y sap_delivery_num
    • Loguea en sap_sync_log con status=SUCCESS
  3. Actualiza dispatches.status=DISPATCHED + dispatched_at + dispatched_by

5. La DeliveryNote en SAP

El payload enviado a /b1s/v1/DeliveryNotes incluye:

Cabecera

CardCodeheredado del SO
DocDatehoy
DocCurrencyheredado del SO
DocRateheredado del SO
U_Chofer= driver_code
U_Vehiculo= vehicle_code
U_dKmR= km_estimate
U_CENT_TIPO_DOC_FE'7' (Nota Remisión Electrónica)
U_CENT_TIPO_DOC'16' (ObjType DN)
U_iMotEmiNR'1' (Traslado por venta)
U_iRespEmiNR'1' (Emisor)

Cada línea

ItemCode= items.sap_item_code
Quantity= packed_qty
BaseType17 (SalesOrder)
BaseEntry= sap_doc_entry
BaseLine= sap_line_num (con fallback*)
BatchNumbers[]{ BatchNumber, Quantity }

*Si pick_list_lines.sap_line_num es NULL, el sistema hace lookup en el SO de SAP mapeando ItemCode → LineNum.

6. Referencia de endpoints

MétodoRutaAcción
GET/api/packing/recent/{wid}Listar packings recientes (opcional ?status=&days=&limit=)
GET/api/packing/pending/{wid}Solo OPEN/IN_PROGRESS (legacy)
POST/api/packingCrear desde pick list
GET/api/packing/{id}Detalle con líneas
POST/api/packing/{id}/scanEscanear item
POST/api/packing/{id}/pack-line/{n}Confirmar línea
POST/api/packing/{id}/completeCompletar (sin crear DN)
GET/api/packing/{id}/customer-containersOtros containers del mismo cliente
GET/api/dispatch/recent/{wid}Despachos recientes
POST/api/dispatchCrear despacho
POST/api/dispatch/{id}/assignAsignar packing
POST/api/dispatch/{id}/closeCerrar + crear SAP DN
GET/api/sap/driversChoferes (CENT_CHOFERES)
GET/api/sap/vehiclesVehículos (CENT_VEHICULOS)
GET/api/sap/sync-log?type=DOC_DISPATCHLog de sync (errores SAP)

7. Tablas involucradas

TablaRol
pick_listsPick list origen (lleva sap_doc_entry del SO)
pick_list_linesLíneas con sap_line_num — clave para mapear a la SAP DN
packing_ordersCabecera de la orden de empaque
packing_linesDetalle de items empacados (status PENDING/PACKED/SHORT/CANCELLED)
dispatchesCabecera del despacho con driver_code, vehicle_code, km_estimate
dispatch_lines1 fila por packing_lines asignada
stock_movementsMovimiento DISPATCH registrado al cerrar el despacho
sap_sync_logLog de sincronizaciones WMS↔SAP (tipos DOC_PACKING, DOC_DISPATCH)

8. Casos especiales y errores comunes

Si SAP rechaza la DeliveryNote al cerrar despacho

El packing queda COMPLETED, el dispatch queda DISPATCHED y el stock ya salió. El error se registra en sap_sync_log con status=ERROR. Hay que:

  1. Revisar el error en /api/sap/sync-log?type=DOC_DISPATCH
  2. Verificar que el chofer y vehículo existan activos en SAP (no Canceled)
  3. Verificar que el SO origen no esté cerrado (bost_Close)
  4. Reintentar manualmente (futuro endpoint POST /api/dispatch/{id}/retry-sap)

Si el packing tiene múltiples líneas con el mismo item

Cada packing_lines se mantiene como fila individual y se envía a SAP como línea separada con su propio BaseLine resuelto independientemente.

Si la pick list ya tiene packing en otro estado

El sistema rechaza con «Ya existe la orden de empaque PK-XXXXXXXX para esta pick list». Si el packing previo está CANCELLED sí permite crear uno nuevo.

UDFs SAP-Paraguay (Centura/SET)

Los campos U_CENT_EST, U_CENT_PE, U_CENT_TIMB, U_CENT_FOLIO, U_DTE quedan en NULL al crear la DN desde el WMS. SAP los popula asíncronamente cuando procesa el timbrado vía el módulo Centura/SET.