2026-10-05 17:53:41 -05:00
# ITCA_API_SAP_WMS (.NET) — proyecto principal
API de integración WMS ↔ SAP Business One, **ASP.NET Core 3.1** . Para
build/publish/despliegue en IIS ver [`README.md` ](./README.md ).
2026-10-14 19:17:14 -05:00
Esta carpeta (`ITCA_API_SAP_WMS` , antes `backend_octubre` ) es **el proyecto
vigente**. Antes existía una copia paralela con la funcionalidad nueva portada
2026-10-05 17:53:41 -05:00
desde la reescritura Python; se portó aquí y esa copia quedó **archivada en un
2026-10-14 19:17:14 -05:00
comprimido (versión antigua)**.
## Versión y control de versiones
2026-10-20 14:46:41 -05:00
- **Versión actual: 2.1.15.0** (rama única `main` ; la rama `limpieza-2.1.8.0` se unió a `main` el 2026-10-20 por avance directo) (`Net.Business.Services.csproj` : `Version` ,
2026-10-14 19:17:14 -05:00
`AssemblyVersion` , `FileVersion` ). Cada versión tiene su commit; al publicar
se sube la versión (ver `publicar.ps1` ).
2026-10-20 14:45:14 -05:00
- **Semver** (desde la 2.1.15): `MAJOR.MINOR.PATCH` ; el cuarto número del `csproj` (.NET lo pide) va siempre en `0` .
`MAJOR` = cambia el contrato de la API y el WMS debe adaptarse (campo obligatorio nuevo, ruta distinta);
`MINOR` = funcionalidad nueva compatible (endpoint o campo opcional nuevo, aviso en `Message` );
`PATCH` = corrección o limpieza sin cambio de contrato. Etiquetas de git nuevas sin el cuarto número (`v2.1.15` ;
las anteriores, como `v2.1.7.0` , no se tocan). Una versión de prueba para QA puede ir en `Version` como
`2.2.0-rc.1` , pero `AssemblyVersion` /`FileVersion` solo aceptan dígitos (`2.2.0.0` ).
2026-10-14 19:17:14 -05:00
- **Git**: rama `main` , remoto `origin` =
2026-10-20 14:45:14 -05:00
`https://unasgeorge.vaquita-hadar.ts.net/george/itca_api_sap_wms.git` (cambiado desde
`http://100.68.242.27:30000/...` ; confirmar que el repositorio sea **privado** ). Etiqueta
2026-10-14 19:17:14 -05:00
`v2.1.7.0` = último estado antes de la limpieza de código.
- `appsettings.json` y `appsettings.*.json` están en `.gitignore` (solo se
versiona `appsettings.example.json` ); las credenciales no están en el
historial (verificado con `git log -S` ).
- Los publish (`dist/` , zip del escritorio) no se versionan.
2026-10-05 17:53:41 -05:00
## Qué se portó desde `ITCA_API_SAP_WMS` (2026-10-05)
Detalle técnico en `docs/PORTE_FUNCIONALIDAD_NUEVA.md` ,
`docs/SOLICITUD_TRANSFERENCIA.md` y `docs/PICKING.md` .
1. **SolicitudTransferencia** : `PATCH /api/SolicitudTransferencia/{docEntry}` y
`POST /api/SolicitudTransferencia/{docEntry}/cerrar` .
2. **Picking diurno/nocturno** : campo `Notificacion` (early-return en
2026-10-14 08:47:44 -05:00
`PickingRepository.Create` tras `HelperProcesoPiciking.Set` , **solo para
`Proceso = "ULTIMA MILLA"` **; DESPACHO/PICKING generan NC sin depender de
él) y
2026-10-05 17:53:41 -05:00
`POST /api/Picking/HojaRuta/{docEntry}/Cerrar` .
3. ** `ConnectionServiceLayer` **: `PatchNoContentAsync` y `PostActionAsync`
(métodos nuevos; los existentes no se tocaron).
2026-10-14 08:47:44 -05:00
## Regla Proceso + Notificacion (v2.1.2.0)
`Notificacion = "cierre"` se exige **solo si `Proceso = "ULTIMA MILLA"`**
(si no, solo actualiza estado en HANA). `DESPACHO` y `PICKING` generan NC y
transferencias siempre, sin depender de `Notificacion` . Detalle y tabla en
`docs/PICKING.md` .
2026-10-14 10:33:20 -05:00
## Correcciones de la NC en Picking/DESPACHO (v2.1.3.0 y v2.1.4.0)
- **v2.1.3.0 — reapertura de factura**: `ConnectionServiceLayer.PostReOpen`
trata el `204` sin cuerpo como éxito (antes fallaba al marcar `Exito` sobre
`null` y respondía *"La Factura no se puede reabrir"* aunque SAP la
reabría). El error de Picking ahora incluye el motivo real de SAP.
- **v2.1.4.0 — lotes de la NC en DESPACHO, línea por línea**: si la línea de la
factura tiene Entrega de origen (`BaseType = 15` ) los lotes salen de la línea
de la Entrega (`DeliveryNotes(BaseEntry)` , línea `BaseLine` ); si no, de la
línea de la factura (`LineNum` ). Si los lotes no cubren la cantidad, o no se
lee la Entrega, responde un error con línea y artículo. PICKING (estado 13)
no cambió (lote nuevo por fecha y hora). Detalle en `docs/PICKING.md` .
2026-10-14 17:06:07 -05:00
- **v2.1.5.0 — log del JSON enviado al Service Layer cuando SAP lo rechaza**
(cualquier documento, no solo la NC): `ConnectionServiceLayer` llama a
`ErrorLogger` (asignado en `Startup` a `Net.Data/HelperData/Log/HelperLogServiceLayer.AddError` )
2026-10-19 16:57:46 -05:00
en los fallos de `PostAsync` y `PatchNoContentAsync` (hasta la 2.1.13.0 también `PatchAsyncSBA` ). Guarda en
2026-10-14 17:06:07 -05:00
`ITC_WMS_SAP.ITCA_LOG_INTEGRACION` : `ORIGEN = "ServiceLayer"` ,
2026-10-14 17:41:08 -05:00
`PROCESO = "ServiceLayer Error"` , `NRO_ORDEN` = ruta del recurso (p. ej.
`CreditNotes` ), `DOCENTRY` = `BaseEntry` de la primera línea del JSON (factura o
solicitud base; vacío si no hay), `DOCENTRYSAP` /`DOCNUMSAP` = `0` (SAP rechazó),
`TRAMA_ORIGEN` = JSON enviado,
2026-10-14 17:06:07 -05:00
`TRAMA_RESPUESTA` = mensaje de SAP. Solo en error. La respuesta de la API al
consumidor no cambia y si el log falla no rompe el flujo. No cubre
2026-10-14 17:41:08 -05:00
`PostActionAsync` (cuerpo `{}` ) ni `PostReOpen` /`PostClose` . Las columnas `PROCESO` , `NRO_ORDEN`
y `DOCENTRY` son `VARCHAR(100)` .
2026-10-14 17:27:29 -05:00
- **v2.1.6.0 — cantidades**: (1) la NC de PICKING (estado 13) solo incluye líneas
con `cantidad facturada − CantidadPedida > 0` , igual que DESPACHO (antes una
línea completa generaba una línea de NC con cantidad 0); (2) la transferencia
automática de stock (Picking y Recibo) junta los lotes de **todas** las líneas
del mismo artículo para el par origen/destino (antes solo tomaba los de la
primera línea y la suma no cuadraba con la cantidad). El almacén de la línea de
la NC sigue saliendo de la factura, no del `codigoSubAlmacen` del request.
2026-10-14 18:03:58 -05:00
- **v2.1.7.0 — NC de Recibo (Devolución, base Solicitud de Devolución)**: (1) los
lotes de cada línea eran los del request (`LoteProducto` ) **más** los de la
distribución (stock HANA o de la factura, o lote de respaldo por fecha/hora),
con lo que sumaban el doble y podían incluir un lote vacío; ahora se limpia el
lote inicial y quedan solo los de la distribución (el `LoteProducto` del
request ya no se usa en la NC); (2) la serie se elige por el **tipo** del
documento origen (`U_SYP_MDTO == "03"` → `BC10` , otro → `FC10` ); antes se
comparaba la serie origen (p. ej. `B005` ) con `"03"` y siempre salía `FC10` .
Pendiente: validar con contabilidad la serie de boletas, y que Recibo no
genera transferencias por almacén destino (nunca llena `U_ITC_ALMDES` ).
2026-10-14 19:31:06 -05:00
- **v2.1.8.0 — limpieza y comentarios** (rama `limpieza-2.1.8.0` , sin cambios de
comportamiento): se quitó código sin uso (`ValidarCertificado` , `Logout` ,
`CancelAsyncSBA` , `DeleteAsyncSBA` , el `throw` inalcanzable de `PatchAsyncSBA` ,
`HelperDB` , 11 propiedades de `RepositoryWrapper` sin uso, variables
`TotalDetalle_Parcial` /`_Invoice` /`SerieOrigen` y un `if` vacío en
`CreateHojaRuta` ) y se agregaron comentarios en Picking, Recibo,
`ConnectionServiceLayer` , `CreditNotesRepository` , `InvoiceRepository` y
2026-10-14 19:49:20 -05:00
`RepositoryWrapper` . Además se unificó `LoginPost()` en `Login()` (eran idénticos;
2026-10-14 19:51:11 -05:00
las 4 llamadas a `LoginPost` ahora llaman a `Login` ) y se quitaron dos copias
exactas sin llamadores: `HelperHojaRuta.GetConsolidado` (queda `HelperStock.GetConsolidado` )
y `HRRepository.UpdateCreateCreditNotes` (queda `CreditNotesRepository` ). Sigue pendiente: código
comentado, `PatchAsyncSBA` , repositorios de compras sin uso
2026-10-14 19:58:12 -05:00
(`SetCreatePurchaseInvoices` duplicado en `PurchaseOrdersRepository` ) y el resto de la redundancia (serie `BC10` /`FC10` y cabecera de la NC).
`PostAsync` , `PostReOpen` y `PostClose` de `ConnectionServiceLayer` comparten ahora un
núcleo privado (`EnviarPostAsync` : con/sin cuerpo, acepta o no el 204); se verificó con un
servidor simulado que el resultado es idéntico al anterior (reintento por 401, 204 sin
cuerpo, rechazo y log). `PatchAsyncSBA` sigue aparte: su manejo de errores es distinto y
mantiene su bug del 204 (sin marcar éxito; el único llamador ignora el resultado).
2026-10-14 19:52:53 -05:00
La transferencia automática de stock de la NC (3 copias en Picking x2 y Recibo)
pasó a un solo método: `Net.Data/ServicesLayer/StockTransfer/TransferenciaAutomaticaNC.Crear` .
2026-10-16 00:22:11 -05:00
- **v2.1.9.0 — Transferencia desde ALM99 (importaciones)**: WMS recibe por partes; cada
entrada de mercadería (base: factura de reserva, `BaseType 18` ) va a `ALM99` y, tras el
costeo, WMS notifica **una transferencia por entrada** enviando en `NumOrden` el `DocNum`
de la factura de reserva y en el detalle los artículos/cantidades de esa entrada. Si el
JSON no trae `DocEntryEM` , `TransferenciaRepository` busca por HANA
(`HelperInvoice.GetEntradasPorFactura` : `OPCH.isIns='Y'` → `PDN1` → `OPDN` , sin anuladas;
una entrada ya tiene transferencia si la línea tiene `TargetType 67` y su `OWTR` no está
anulada), compara **solo `ItemCode` y cantidad** (sumada por artículo) contra cada entrada y
transfiere la más antigua que coincida y no esté transferida (`EntradaImportacion.Elegir` ).
Las líneas de la transferencia salen de la entrada (lotes reales, validando que cubran la
cantidad) con base en ella. Errores claros: ninguna coincide / todas ya transferidas. Si la
factura no tiene entradas se mantiene el comportamiento anterior (lotes del stock de HANA,
sin amarre). Con `DocEntryEM` informado se respeta (antes reventaba con referencia nula si
la entrada o la línea no existían). Sin probar contra SAP: validar la consulta, que
`isIns='Y'` sea factura de reserva y que SAP acepte `BaseType "PurchaseDeliveryNotes"` en
2026-10-16 07:38:01 -05:00
la línea de `StockTransfers` . Detalle, errores y diagnóstico en
`docs/TRANSFERENCIA_IMPORTACION.md` . Probado con datos reales (SQL Server) solo la consulta: entradas
de 1 y 2 líneas, y una transferencia cancelada libera la entrada.
2026-10-16 12:36:09 -05:00
- **v2.1.10.0 — solo versión** (sin cambios de comportamiento): `Version` , `AssemblyVersion` y
`FileVersion` del `csproj` quedan iguales (2.1.10.0). Swagger muestra `AssemblyVersion`
(`Startup.cs` : `OpenApiInfo.Version` ); si Swagger muestra otro número el servidor corre
binarios viejos (pool sin reiniciar, carpeta equivocada o sitio desde `bin\Debug` ).
2026-10-19 16:42:12 -05:00
- **v2.1.11.0 — tabla de log configurable y lotes de la NC de Recibo**: (1) la tabla de log sale de
`Hana:logTable` en `appsettings.json` (`LocalData.LogTable` ; por defecto `ITCA_LOG_INTEGRACION` para
QA/Desarrollo, producción usa `ITCA_LOG_INTEGRACION_PROD` ); el esquema sigue fijo en `ITC_WMS_SAP` .
Aplica a `B_Log` y `HelperLogServiceLayer` . (2) Recibo/Devolución: si el reparto de lotes (stock HANA o
factura) no cubre la cantidad de la línea, el resto va a un lote nuevo por fecha/hora (antes SAP
respondía "No es posible añadir una línea sin la selección completa de los números de serie/lote");
una línea sin equivalente en la factura ya no revienta con referencia nula. Sin probar contra SAP.
2026-10-19 16:45:18 -05:00
- **v2.1.12.0 — más limpieza** (sin cambios de comportamiento): se quitó `PurchaseOrdersRepository.SetCreatePurchaseInvoices`
(duplicado sin llamadores; queda el de `PurchaseInvoicesRepository` ), el código comentado de `HRRepository`
(rama "Privado"), `Program.cs` (`CreateHostBuilder` viejo), `ConnectionServiceLayer` (líneas de header/éxito y un
`if` de `NoContent` vacío), `CreditNotesRepository` , `ReciboRepository` , `InventarioRepository` , `ConnectionSQL` , `DBParameter` y
`BE_BusinessPartners` (ya no queda código comentado). Sigue pendiente `PatchAsyncSBA` y la redundancia de serie/cabecera de la NC.
2026-10-19 16:52:23 -05:00
- **v2.1.13.0 — cabecera única de la NC** (sin cambios de comportamiento): la serie (`BC10` si el tipo del
documento origen es `03` , si no `FC10` ), el correlativo (`HelperCorrelativo` ) y los ~15 campos de la cabecera de
la NC estaban copiados en Picking DESPACHO, Picking PICKING (estado 13) y Recibo Devolución; ahora están en
`Net.Data/ServicesLayer/CreditNotes/CabeceraNotaCredito.Completar` (con comentarios de la regla de la 2.1.7.0).
Cada llamador pasa los datos de su origen (factura o, en Recibo sin factura, la solicitud de devolución).
2026-10-19 16:57:46 -05:00
- **v2.1.14.0 — se quitó `PatchAsyncSBA` **: su único llamador (`CreditNotesRepository.UpdateCreateCreditNotes` , que agrega
a la NC las referencias de las transferencias automáticas) usa ahora `PatchNoContentAsync` . En el Service Layer un PATCH
exitoso es un `204` sin cuerpo; `PatchAsyncSBA` devolvía `null` en ese caso (y en cualquier error de red) y el llamador
lo tomaba como fallo. Ahora el éxito es éxito y un rechazo de SAP lanza su mensaje (se captura y devuelve como error;
`Crear` sigue ignorando el resultado). Sigue sin reintentar el 401 (hace login antes de cada llamada). Los docs de
`docs/PORTE_FUNCIONALIDAD_NUEVA.md` y `docs/SOLICITUD_TRANSFERENCIA.md` mencionan `PatchAsyncSBA` como historia del porte.
2026-10-19 16:59:31 -05:00
- **v2.1.15.0 — se avisa al consumidor si falla la transferencia automática**: `TransferenciaAutomaticaNC.Crear` devuelve un
texto de advertencia (vacío si todo salió bien) cuando SAP rechaza una transferencia o no se puede agregar su referencia a
la NC. Los 3 llamadores (Picking DESPACHO y PICKING, Recibo Devolución) lo agregan al `Message` de la respuesta
(`"Se registro correctamente...!!! ADVERTENCIA: la nota de credito se creo, pero no se creo la transferencia A -> B: <SAP>."` ).
La respuesta sigue siendo 200 con el DocEntry/DocNum de la NC (la NC existe en SAP; responder 500 haría que el WMS
reintente y duplique la NC). El consumidor debe leer el `Message` . El detalle del rechazo también queda en `ITCA_LOG_INTEGRACION`
(`ServiceLayer Error` ). Sin probar contra SAP.
2026-10-14 10:33:20 -05:00
- Sin probar contra SAP: confirmar con la factura 292410 que SAP devuelve
`BaseType` /`BaseEntry` en las líneas y `BatchNumbers` en las de la Entrega.
2026-10-05 17:53:41 -05:00
## Cambios de configuración y correcciones hechas en esta carpeta
- **Credenciales y esquema HANA en `appsettings.json` **, sección `Hana`
(`server` , `user` , `password` , `schema` opcional), leída por
`LocalData.Configure` desde `Startup` . Antes estaban fijas en el código
(`LocalData.cs` , `Log/B_Log.cs` ). El esquema sale de `Hana:schema` o, si no
está, de `SapServiceLayer:company` ; **si falta la sección `Hana` o el
esquema, la app no arranca** (error claro). Ya no hay `DB_NAME` fijo.
- **Precio promedio solo en entradas** (`TipoMovimiento "01"` ) en
`InventarioRepository.Create` (los dos chequeos: `SubAlmacen` y `Almacen` ).
Si el artículo no tiene stock, se conserva el `PrecioPromedio` del request en
vez de abortar con *"No existe stock disponible para el articulo X"* (ese
error bloqueaba ingresos de artículos sin stock previo). En salidas ya no se
busca el promedio: `PriceAfterVAT` lleva el precio del request. El chequeo de
stock de la rama de **salida** de `PickingRepository` (~línea 363) no se tocó.
- **Lote de 100 líneas** (`InventarioRepository.Create` ): `var Inventario =
entidad` reutilizaba el mismo objeto, y con más de 100 líneas se generaban N
documentos iguales con el último bloque. Ahora se crea una copia por bloque y
la rama de salida lee ` entidad_inventario.Detalle`.
- **SQL injection**: parametrizadas las consultas de ` HelperProcesoPiciking`,
` HelperStock`, ` HelperInventario`, ` HelperInvoice`, ` HelperCorrelativo`,
` HelperHojaRuta` y ` HelperProcesoPermitido` (` ?` + ` HanaParameter`).
El esquema sigue interpolado (viene de configuración, no del request).
- ` ITCA_API_SAP_WMS.xml` ahora se genera también en Release (sin eso Swagger
revienta con ` FileNotFoundException` en un ` publish -c Release`).
## Funcionalidad propia de esta carpeta (no existe en la copia antigua)
Hoja de Ruta (` HojaRutaController`, ` HRRepository`, ` GlobalDataRepository`),
reapertura de facturas (` InvoiceRepository.ReOpen`, ` PostReOpen`), notas de
crédito con documentos de referencia, cierre automático de la solicitud de
traslado en ` Transferencia` (` PostClose`), ` Latitud`/` Longitud` y reproceso en
Picking, columna ` HORA` en ` B_Log`. Lo que **no** se trajo: ` Chatbots` y
` MessageController` (solo existen en la copia archivada).
## Sin verificar
- **Nada se probó contra SAP/HANA reales.** Solo se verificó que compila
(0 errores) y que el publish se genera.
- La sintaxis ` CALL "esquema"."proc"(?, ?)` con parámetros no está probada con
el driver HANA 2.1; si falla con un error de parámetro, mirar primero ahí.
- Para probar el lote de 100: un inventario de >100 líneas (p. ej. 250) debe
generar 3 documentos (100/100/50) sin repetir ni perder líneas, tanto en
entradas como en salidas.
## Bugs conocidos, sin corregir
- ` BE_ResultadoTransaccion<T>.NombreEstacion`: setter con recursión infinita
(bomba de tiempo; hoy nada lo asigna).
2026-10-14 19:31:06 -05:00
- El cliente HTTP ` bypass-ssl-validation` acepta cualquier certificado TLS hacia
el Service Layer (se quitó el método ` ValidarCertificado`, que no se usaba).
2026-10-14 19:17:14 -05:00
- ` appsettings.json` (fuera de git, en ` .gitignore`) contiene credenciales
reales en texto plano (SAP Service Layer, **HANA ` B1ADMIN`**, semilla JWT).
Rotar la contraseña de ` B1ADMIN` (estuvo en el código fuente) y evaluar un
usuario HANA de mínimos permisos.
- Los logs (` B_Log` y ` HelperLogServiceLayer`) escriben en el esquema fijo
` ITC_WMS_SAP` (` ITCA_LOG_INTEGRACION`), no en ` LocalData.Schema`; si la tabla
está en otro esquema el ` INSERT` falla. ` B_Log.Add` no tiene ` try/catch`, así
que un fallo del log puede devolver 500 tras haber creado el documento en SAP.
2026-10-05 17:53:41 -05:00
## Despliegue
Sitio IIS previsto: **` /integracion`** (antes ` /integracion_wms`). Publicar con
el comando del README **sin pisar** el ` appsettings.json` del servidor; agregar
a ese archivo la sección ` Hana` y revisar ` SapServiceLayer:company` (determina
contra qué base lee y escribe). El ` web.config` generado por ` dotnet publish`
usa ` processPath=".\ITCA_API_SAP_WMS.exe"`; el del código fuente apunta a
` bin\Debug\...` (solo para sitios que corren desde el código compilado).
## Pendiente
- Probar en QA: endpoints nuevos (SolicitudTransferencia, ` Notificacion`,
` HojaRuta/Cerrar`), un ingreso sin stock previo, el lote de 100 y las
consultas parametrizadas.
- Verificar que existan en el esquema del sitio los procedimientos ` ITCA_*`
y las tablas ` @ITCA_PROWMS `, ` @SYP_MOTIVOS `, ` @SYP_NUMDOC `.
- Decidir si se corrigen los bugs de la lista de arriba.
2026-10-14 19:17:14 -05:00
- Validar con contabilidad la serie de NC de boletas (` BC10`) en Recibo y si ya
hay NC de boletas emitidas con ` FC10` antes de la 2.1.7.0.
- Recibo (Devolución) no genera transferencias por almacén destino: nunca llena
` U_ITC_ALMDES` en las líneas de la NC.
- Confirmar en QA el log de errores del Service Layer (provocar un rechazo y
ver la fila con ` PROCESO = 'ServiceLayer Error'`) y el esquema de la tabla de
log en cada servidor.
- Confirmar el repositorio remoto como privado; hacer la limpieza de código en
una rama aparte (2.1.8.0) partiendo de la etiqueta ` v2.1.7.0`.