Files
itca_api_sap_wms/CLAUDE.md
T
2026-10-20 14:46:41 -05:00

256 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).
Esta carpeta (`ITCA_API_SAP_WMS`, antes `backend_octubre`) es **el proyecto
vigente**. Antes existía una copia paralela con la funcionalidad nueva portada
desde la reescritura Python; se portó aquí y esa copia quedó **archivada en un
comprimido (versión antigua)**.
## Versión y control de versiones
- **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`,
`AssemblyVersion`, `FileVersion`). Cada versión tiene su commit; al publicar
se sube la versión (ver `publicar.ps1`).
- **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`).
- **Git**: rama `main`, remoto `origin` =
`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
`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.
## 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
`PickingRepository.Create` tras `HelperProcesoPiciking.Set`, **solo para
`Proceso = "ULTIMA MILLA"`**; DESPACHO/PICKING generan NC sin depender de
él) y
`POST /api/Picking/HojaRuta/{docEntry}/Cerrar`.
3. **`ConnectionServiceLayer`**: `PatchNoContentAsync` y `PostActionAsync`
(métodos nuevos; los existentes no se tocaron).
## 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`.
## 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`.
- **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` y `PatchNoContentAsync` (hasta la 2.1.13.0 también `PatchAsyncSBA`). Guarda en
`ITC_WMS_SAP.ITCA_LOG_INTEGRACION`: `ORIGEN = "ServiceLayer"`,
`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,
`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
`PostActionAsync` (cuerpo `{}`) ni `PostReOpen`/`PostClose`. Las columnas `PROCESO`, `NRO_ORDEN`
y `DOCENTRY` son `VARCHAR(100)`.
- **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.
- **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`).
- **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
`RepositoryWrapper`. Además se unificó `LoginPost()` en `Login()` (eran idénticos;
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
(`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).
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`.
- **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`. 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.
- **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`).
- **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.
- **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.
- **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).
- **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.
- **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.
- 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.
## 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).
- El cliente HTTP `bypass-ssl-validation` acepta cualquier certificado TLS hacia
el Service Layer (se quitó el método `ValidarCertificado`, que no se usaba).
- `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.
## 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.
- 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`.