Documentación operativa de /#packing y su integración con
/#expedicion y SAP B1.
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).
/#packingAl abrir https://comfar.xp.com.py:8443/WMS/#packing el sistema dispara
GET /api/packing/recent/{warehouse_id} y renderiza la tabla de órdenes.
| Control | Descripción |
|---|---|
| + Nuevo Packing | Abre el modal para crear un packing desde una pick list COMPLETED o IN_PROGRESS. |
| Selector de almacén | Defaulta a CEN. Cambiar el almacén recarga la tabla. |
| Selector de estado | Filtra por OPEN / IN_PROGRESS / COMPLETED / CANCELLED. «Todos» trae los últimos 60 días. |
| Columna | Origen |
|---|---|
| Número | packing_orders.pack_number (PK-XXXXXXXX) |
| Pick List | pick_lists.pick_number |
| Cliente | packing_orders.customer_name (heredado del SO) |
| Items | Cantidad de filas en packing_lines |
| Estado | DRAFT, OPEN, IN_PROGRESS, COMPLETED, CANCELLED |
| SAP DN | packing_orders.sap_delivery_num — vacío hasta cerrar el despacho |
| Fecha | created_at |
| Acciones | Ver (detalle) · Audit |
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:
pack_number consecutivo (nextDocNumber('PACK'))packing_orders con status=OPEN y hereda customer_code/customer_name/sap_doc_entry de la pick listPICKED con picked_qty > 0 inserta una fila en packing_lines con status=PENDINGClick 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.
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.
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 quantity → status=PACKED;
sino queda como PENDING (acepta empaque parcial en múltiples corridas).
Una vez todas las líneas están PACKED, click en Completar Packing.
POST /api/packing/{id}/complete
El backend:
packing_orders.status=COMPLETED + completed_atsap_sync_log con status=PENDING y mensaje
«Esperando despacho para crear DeliveryNote»/#expedicionEl operador cambia a /#expedicion y opera con el packing recién completado:
Click en + Nuevo Despacho. Al abrirse el modal dispara:
/api/sap/drivers — lista de
CENT_CHOFERES (UDO de SAP)/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." }
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.
POST /api/dispatch/{id}/scan-container
Marca dispatch_lines.status=VERIFIED al matchear el LPN escaneado.
POST /api/dispatch/{id}/close
El backend ejecuta atomicamente:
driver_code, vehicle_code, km_estimateDISPATCH (salida AVAILABLE)CardCode, DocCurrency, DocRate/b1s/v1/DeliveryNotespacking_orders.sap_delivery_entry y sap_delivery_numsap_sync_log con status=SUCCESSdispatches.status=DISPATCHED + dispatched_at + dispatched_byEl payload enviado a /b1s/v1/DeliveryNotes incluye:
| CardCode | heredado del SO |
| DocDate | hoy |
| DocCurrency | heredado del SO |
| DocRate | heredado 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) |
| ItemCode | = items.sap_item_code |
| Quantity | = packed_qty |
| BaseType | 17 (SalesOrder) |
| BaseEntry | = sap_doc_entry |
| BaseLine | = sap_line_num (con fallback*) |
| BatchNumbers[] | { BatchNumber, Quantity } |
| Método | Ruta | Acció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/packing | Crear desde pick list |
| GET | /api/packing/{id} | Detalle con líneas |
| POST | /api/packing/{id}/scan | Escanear item |
| POST | /api/packing/{id}/pack-line/{n} | Confirmar línea |
| POST | /api/packing/{id}/complete | Completar (sin crear DN) |
| GET | /api/packing/{id}/customer-containers | Otros containers del mismo cliente |
| GET | /api/dispatch/recent/{wid} | Despachos recientes |
| POST | /api/dispatch | Crear despacho |
| POST | /api/dispatch/{id}/assign | Asignar packing |
| POST | /api/dispatch/{id}/close | Cerrar + crear SAP DN |
| GET | /api/sap/drivers | Choferes (CENT_CHOFERES) |
| GET | /api/sap/vehicles | Vehículos (CENT_VEHICULOS) |
| GET | /api/sap/sync-log?type=DOC_DISPATCH | Log de sync (errores SAP) |
| Tabla | Rol |
|---|---|
| pick_lists | Pick list origen (lleva sap_doc_entry del SO) |
| pick_list_lines | Líneas con sap_line_num — clave para mapear a la SAP DN |
| packing_orders | Cabecera de la orden de empaque |
| packing_lines | Detalle de items empacados (status PENDING/PACKED/SHORT/CANCELLED) |
| dispatches | Cabecera del despacho con driver_code, vehicle_code, km_estimate |
| dispatch_lines | 1 fila por packing_lines asignada |
| stock_movements | Movimiento DISPATCH registrado al cerrar el despacho |
| sap_sync_log | Log de sincronizaciones WMS↔SAP (tipos DOC_PACKING, DOC_DISPATCH) |
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:
/api/sap/sync-log?type=DOC_DISPATCHbost_Close)POST /api/dispatch/{id}/retry-sap)Cada packing_lines se mantiene como fila individual y se envía a SAP como línea
separada con su propio BaseLine resuelto independientemente.
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.
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.