Hallazgos verificados (parte 2): alta bajo demanda de combos y componentes¶
Fecha de pruebas: 2026-07-16
Ambiente: dev ZZ_COMPU_3 (lecturas de contraste contra prod COMPU).
Herramienta: sl-helper.js (en _borradores/, no publicado) — ahora soporta headers custom vía env:
HEADERS='{"B1S-ReplaceCollectionsOnPatch":"true"}' node sl-helper.js PATCH ...
Contexto: el modelo de negocio es drop-shipping — se publican combos (y componentes) que aún no existen en SAP; se crean bajo demanda cuando se venden. Estas pruebas verifican los puntos que ese flujo necesita. Continúa 02-hallazgos-service-layer.md.
1. PATCH de ProductTrees: por defecto es MERGE, no replace ⚠¶
Verificado con ProductTrees('TESTBOM-PC'):
PATCH de ProductTreeLines |
Resultado |
|---|---|
| Sin header, enviando solo una línea nueva | Append: la línea se AGREGA a las existentes (4 → 5). No reemplaza nada. |
Con header B1S-ReplaceCollectionsOnPatch: true, enviando el set completo |
Replace: el árbol queda exactamente con las líneas enviadas. |
Implicancia: toda actualización de receta debe enviar la lista completa de componentes
con el header de replace (mismo patrón que ya usa updateOrder en orders.service.ts).
Un PATCH "incremental" sin header duplica/acumula componentes silenciosamente.
La actualización del ProductTree es segura para pedidos ya creados: SAP explota el BOM
al momento de crear el documento; los documentos existentes no se ven afectados.
2. Alta de componente por SL: el almacén es OBLIGATORIO (error críptico si falta)¶
POST Items con ItemCode explícito funciona (no hace falta Series). Pero un ítem
creado sin filas de almacén (ItemWarehouseInfoCollection vacío) rompe la explosión del
BOM: el POST Orders del combo falla con el error opaco Internal error (-10) sin
mensaje. Costó aislarlo — no es el grupo de artículos, ni el precio, ni el IVA.
- Fix verificado:
PATCH Items('X') { "ItemWarehouseInfoCollection": [{ "WarehouseCode": "CEN" }] }→ el mismo POST Orders pasa a 201. - En prod los ítems nuevos reciben todos los almacenes automáticamente
(parametrización de empresa "añadir todos los almacenes a artículos nuevos" — ítem
09696creado por el OMS el 2026-07-16 tiene la colección completa). En dev NO. - Regla para el OMS: el alta de componentes/padres debe enviar siempre
ItemWarehouseInfoCollectionexplícito (al menos el almacén de la venta) para no depender de esa parametrización.
Payload mínimo verificado para un componente (dev):
// POST Items → 201
{
"ItemCode": "TESTBOM-SSD",
"ItemName": "SSD NVME 1TB (TEST BOM)",
"ItemsGroupCode": 100,
"ItemType": "itItems",
"InventoryItem": "tYES",
"SalesItem": "tYES",
"PurchaseItem": "tNO",
"TaxType": "tt_Yes",
"ArTaxCode": "IVA_10",
"ItemPrices": [{ "PriceList": 1, "Price": 550000, "Currency": "GS" }],
"ItemWarehouseInfoCollection": [{ "WarehouseCode": "CEN" }] // ⚠ no omitir
}
3. Quirk de dev: ArTaxCode no persiste (en prod sí)¶
En dev, ArTaxCode/ApTaxCode se ignoran silenciosamente tanto en POST como en PATCH
(el SL devuelve 201/204 pero el campo queda null). En prod el mismo payload sí
persiste — todos los ítems creados por el OMS (Series 79) tienen ArTaxCode: "IVA_10",
incluso los del mismo día de la prueba. Es una diferencia de parametrización de la base
dev (no identificada; probablemente relacionada a la configuración impositiva).
- Coherente con el §5 de la parte 1: en dev los pedidos requieren
TaxCodeexplícito en la línea. - Mitigación de diseño (vale para ambas bases): enviar siempre
TaxCodeexplícito en la línea padre del combo — inmune a la configuración del ítem. Nota: el OMS hoy NO envíaTaxCodeen las líneas de pedido (lo determina SAP por el ítem); para la línea padre del combo hay que agregarlo.
4. Factura con componente en stock 0: FALLA — flujo drop-ship verificado¶
La empresa bloquea inventario negativo. Verificado con el pedido 33264 (combo de 5
componentes, TESTBOM-SSD con stock 0):
POST Ordersdel combo con componente en stock 0 → 201 OK (el pedido no mueve stock, solo compromete:Committedsube en los componentes).POST Invoicesreferenciando todas las líneas → 400:"Quantity falls into negative inventory [DocumentLines.ItemCode][line: 6]"(la línea del SSD; el índice del error es 1-based).- Entrada de mercancías:
POST InventoryGenEntriescon 1 unidad de SSD → 201 (DocEntry 1845). - Reintento de la misma factura → 201 OK (factura 724257, DocNum 835408,
total 5.500.000). El pedido quedó
bost_Closey el stock del SSD volvió a 0 (consumido por la factura).
Implicancia para el OMS: vender el combo funciona siempre; facturarlo requiere que
todos los componentes tengan stock. El flujo drop-ship es: pedido → compra/recepción de
mercadería → factura. La UI debería poder mostrar qué componentes del pedido están sin
stock (dato ya disponible: Committed/QuantityOnStock por ítem) para anticipar que la
factura va a fallar.
4b. El padre de un Sales BOM no puede ser ítem de inventario NI de compra ⚠¶
Descubierto al sincronizar PCM-12150 (2026-07-17): su SKU ya existía en SAP como
ítem simple (06550, creado 2026-03-03 por el alta drop-ship de pedidos, con
InventoryItem/PurchaseItem: tYES). El POST ProductTrees con iSalesTree falla:
Only a production BOM or a template BOM can be defined as a purchase item [OITT.Code]- corregido eso →
Only a production BOM can be defined as an Inventory Item [OITT.Code]
Verificado en dev: PATCH Items con {PurchaseItem:'tNO', InventoryItem:'tNO'} es
aceptado (con stock 0) y el POST del BOM pasa a 201. Si el ítem tuviera stock o
documentos que bloqueen el cambio, el PATCH falla → el sync responde 409 con mensaje
accionable.
Fix en el backend: CompositeService.ensureParentBomCompatible() — cuando el
padre ya existía como ítem simple, se convierte antes de crear/actualizar el BOM.
Este escenario es EL CASO COMÚN del catálogo actual: todo combo que se haya vendido
antes como ítem simple (drop-ship) tiene los flags incompatibles.
Bonus verificado en el mismo incidente: la idempotencia del sync funciona — el sync
fallido del usuario había dejado estado parcial (componentes 06560–06564 creados,
sin BOM) y el re-sync tras el fix convergió a ok sin duplicar nada.
Medición de latencia (justifica la propuesta de optimización en 05): verify de un combo de 10 componentes = 15,8 s; sync = 11,9 s.
5. Datos de prueba actualizados en dev (ZZ_COMPU_3)¶
Se suman a los de la parte 1 (§8):
| Objeto | Detalle |
|---|---|
| Ítem | TESTBOM-SSD (componente, lista 1 = 550.000, stock 0, almacén CEN asignado, grupo 100) — queda disponible para pruebas de "componente nuevo" |
| BOM | ProductTrees('TESTBOM-PC') restaurado a los 4 componentes originales (RAM ×2, CPU, MB, PSU) |
| Pedido cerrado por factura | 33264 (combo con 5 componentes, incluía el SSD) |
| Factura | 724257 (DocNum 835408) |
| Entrada de mercancías | 1845 (1 × TESTBOM-SSD, para poder facturar) |
| Pedido cancelado | 33260 (creado durante el aislamiento del error -10) |
6. ~~Pendiente de verificar~~ ~~Resuelto por decisión de negocio (2026-07-16)~~ Verificado (2026-07-17)¶
- PATCH de un pedido que contiene un combo: la decisión de bloquear la edición se revirtió (los pedidos con combos sí deben poder editarse, incluidos los seriales de los componentes) y la incógnita se verificó empíricamente. Resultados completos en 09-hallazgos-edicion-pedidos.md — resumen: el reenvío de líneas explotadas es seguro; SAP re-escala los hijos al cambiar la cantidad del padre e ignora cantidades de ingredientes; los seriales de componentes se cargan por PATCH reenviando todas las líneas; no enviar precios en ingredientes (queda sucio cosmético).