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-16 00:22:11 -05:00
|
|
|
|
- **Versión actual: 2.1.9.0** (rama `limpieza-2.1.8.0`; `main` = 2.1.7.0) (`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`).
|
|
|
|
|
|
- **Git**: rama `main`, remoto `origin` =
|
|
|
|
|
|
`http://100.68.242.27:30000/george/itca_api_sap_wms.git` (HTTP sin cifrar,
|
|
|
|
|
|
red interna; confirmar que el repositorio sea **privado**). Etiqueta
|
|
|
|
|
|
`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`)
|
|
|
|
|
|
en los fallos de `PostAsync`, `PatchAsyncSBA` y `PatchNoContentAsync`. Guarda en
|
|
|
|
|
|
`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
|
|
|
|
|
|
la línea de `StockTransfers`.
|
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).
|
|
|
|
|
|
- `ConnectionServiceLayer.PatchAsyncSBA<T>`: con un `204` real devuelve `null`
|
2026-10-14 19:49:20 -05:00
|
|
|
|
sin marcar éxito.
|
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-14 19:52:53 -05:00
|
|
|
|
- Si una transferencia automática de stock falla (`TransferenciaAutomaticaNC.Crear`),
|
|
|
|
|
|
el fallo se ignora (la NC ya está creada) y no se informa al consumidor.
|
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`.
|