Files
itca_api_sap_wms/docs/TRANSFERENCIA_IMPORTACION.md
T

6.9 KiB

Transferencia de stock desde ALM99 (importaciones) — v2.1.9.0

Documento de soporte. Código: Net.Data/WMS/Transferencia/TransferenciaRepository.cs (bloque ALM99), Net.Data/WMS/Transferencia/EntradaImportacion.cs (elección de la entrada) y Net.Data/HelperData/Invoices/HelperInvoice.GetEntradasPorFactura (consulta HANA). Endpoint: POST /api/Transferencia.

Proceso de negocio

  1. En SAP se crea una Factura de Reserva de proveedores y se envía al WMS para su recepción.
  2. El WMS recibe por partes: por cada recepción crea una Entrada de Mercadería (PurchaseDeliveryNotes) enlazada a la factura (BaseType 18, BaseEntry, BaseLine). Hay una o varias entradas por factura y todas ingresan al almacén ALM99 (costeo). El WMS no guarda el DocEntry de las entradas, solo sabe qué artículos recibió en cada una.
  3. En SAP se hace el costeo (precio de entrega) de las entradas.
  4. Terminado el costeo, el WMS notifica una transferencia por entrada hacia el almacén final.

JSON que envía el WMS

  • numorden = DocNum de la factura de reserva (único).
  • codigoSubAlmacenOrigen = ALM99; codigoSubAlmacenDestino = almacén final (p. ej. ALM21).
  • docEntry = 0 (no hay solicitud de traslado); docEntryEM no se envía.
  • detalle = los artículos y cantidades de una sola entrada. Solo se usan codigoarticulo y cantidadpedida; item y loteproducto se ignoran en este caso.

Qué hace la API (origen = ALM99 y sin docEntryEM)

  1. Consulta HANA (HelperInvoice.GetEntradasPorFactura): factura OPCH con DocNum = numorden y isIns = 'Y' (= factura de reserva) → líneas PDN1 con BaseType 18 y BaseEntry = factura → entrada OPDN no anulada (CANCELED = 'N').
  2. Una entrada ya tiene transferencia si la línea tiene TargetType = 67 y su TrgetEntry apunta a una transferencia OWTR con CANCELED = 'N'. Una transferencia anulada libera la entrada.
  3. EntradaImportacion.Elegir compara, por entrada, el conjunto ItemCode → cantidad (sumada por artículo) contra el detalle del JSON (también sumado). Debe coincidir exacto (mismos artículos, mismas cantidades, tolerancia 0.0001). Se toma la entrada más antigua (menor DocEntry) que coincida y no tenga transferencia.
  4. Se lee la entrada por Service Layer (PurchaseDeliveryNotes(docEntry)) y las líneas de la transferencia salen de la entrada: artículo, cantidad, lotes reales y base (BaseType "PurchaseDeliveryNotes", BaseEntry, BaseLine = línea de la entrada). Si los lotes de una línea no suman su cantidad, responde error antes de enviar a SAP.
  5. Se envía StockTransfers con U_SYP_MDMT = "21".

Respuestas de error (400, mensaje en la respuesta y en ITCA_LOG_INTEGRACION)

Mensaje Causa
SAP: Ninguna entrada de la factura de reserva X coincide con los articulos y cantidades enviados. Entradas pendientes de transferir (DocNum): ... El JSON no es igual a ninguna entrada (falta/sobra un artículo o cambia una cantidad). Lista las entradas aún sin transferir para comparar.
SAP: Todas las entradas de la factura de reserva X con esos articulos y cantidades ya estan transferidas: entrada N ya transferida en la transferencia M Reintento del mismo JSON o entrada ya transferida (evita duplicados).
SAP: Los lotes de la linea L (item) de la entrada N no cubren la cantidad Q La entrada tiene lotes que no suman la cantidad de la línea.
SAP: La entrada de mercaderia N no se puede leer Falló el GET al Service Layer.
Error de SAP al crear StockTransfers Ver la fila PROCESO='ServiceLayer Error' (JSON enviado + mensaje de SAP).

Otros casos del mismo endpoint (no cambiaron)

  • Transferencia simple (origen distinto de ALM99, docEntry = 0): lotes por stock HANA (FEFO), sin base.
  • Con solicitud de traslado (docEntry ≠ 0): la solicitud es la base y se cierra al terminar.
  • ALM99 con docEntryEM informado: se respeta; lotes y base de esa entrada, amarrando BaseLine del JSON con BaseLine de la entrada. Si la entrada o la línea no existen responde error claro.
  • ALM99 cuando la factura no tiene entradas (o numorden no es una factura de reserva): se mantiene el comportamiento anterior (lotes del stock de HANA, sin amarre).

Verificado y pendiente

  • Verificado con datos reales (SQL Server): la consulta encuentra las entradas por BaseType 18 y isIns='Y'; muestra el estado de transferencia por línea (entradas con 1 y con 2 líneas) y una transferencia cancelada vuelve a dejar la entrada libre (TransferenciaDocEntry = 0).
  • Verificado con simulación: la lógica de Elegir (coincidencia, entrada más antigua, ya transferida, no coincide).
  • Pendiente de confirmar contra SAP/HANA reales: que la consulta corra en HANA (la API usa HANA); que SAP acepte BaseType "PurchaseDeliveryNotes" en las líneas de StockTransfers; y el caso en que una entrada de varias líneas tenga transferida solo una línea (hoy cuenta como ya transferida).

Cómo diagnosticar ("no se genera la transferencia")

  1. Ver la fila en "ITC_WMS_SAP"."ITCA_LOG_INTEGRACION" con PROCESO = 'Transferencia' y NRO_ORDEN = <numorden>: trae el JSON del WMS y la respuesta (el mensaje de la tabla de arriba).
  2. Ejecutar la consulta de HelperInvoice.GetEntradasPorFactura (versión SQL Server/HANA al final) con el DocNum: si no devuelve filas, la factura no existe, no es de reserva (isIns) o sus entradas no tienen BaseType 18; si TransferenciaDocEntry ≠ 0, esa entrada ya fue transferida.
  3. Comparar artículos y cantidades del JSON contra las filas de esa entrada.
-- HANA (reemplazar <ESQUEMA> y el DocNum de la factura de reserva)
SELECT E."DocEntry", E."DocNum", L."LineNum", L."ItemCode", L."Quantity",
       CASE WHEN L."TargetType" = 67 AND W."DocEntry" IS NOT NULL AND W."CANCELED" = 'N'
            THEN W."DocEntry" ELSE 0 END AS "TransferenciaDocEntry"
FROM "<ESQUEMA>"."OPCH" F
INNER JOIN "<ESQUEMA>"."PDN1" L ON L."BaseType" = 18 AND L."BaseEntry" = F."DocEntry"
INNER JOIN "<ESQUEMA>"."OPDN" E ON E."DocEntry" = L."DocEntry"
LEFT JOIN "<ESQUEMA>"."OWTR" W ON L."TargetType" = 67 AND W."DocEntry" = L."TrgetEntry"
WHERE F."DocNum" = 262000082 AND F."isIns" = 'Y' AND E."CANCELED" = 'N'
ORDER BY E."DocEntry", L."LineNum";

En SQL Server es la misma consulta sin comillas dobles y con [<BASE>].dbo.OPCH, etc.

Historia

Antes (también en el código del desarrollador anterior y en el commit inicial) el bloque dependía de DocEntryEM, que el WMS no envía: nunca se amarraba a la entrada y los lotes salían solo del stock de HANA (sin validar que cubrieran la cantidad). La versión original buscaba la entrada por NumOrden con HelperInvoice.Get (procedimiento ITCA_WMS_SAP_GetEntradaPorImportacion, un solo DocEntry), que quedó comentado; no servía para varias entradas por factura. Esa función sigue en el código sin llamadores.