diff --git a/CLAUDE.md b/CLAUDE.md index f081b74..8dece2e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,14 +42,17 @@ transferencias siempre, sin depender de `Notificacion`. Detalle y tabla en 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 de la NC cuando SAP la rechaza**: - `CreditNotesRepository.SetCreateCreditNotes` guarda en - `ITC_WMS_SAP.ITCA_LOG_INTEGRACION` (vía `Net.Data/HelperData/Log/HelperLogServiceLayer`) - el JSON enviado al Service Layer y la respuesta de SAP, con `ORIGEN = - "ServiceLayer"` y `PROCESO = "NotaCredito Error"`; `NRO_ORDEN`/`DOCENTRY` = - `BaseEntry` de la primera línea. Solo en error (no en éxito); si el log - falla, no rompe el flujo. No cubre transferencias, solicitud de devolución - ni reapertura. +- **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"`, + `PROCESO = "ServiceLayer Error"`, `NRO_ORDEN`/`DOCENTRY` = ruta del recurso + (p. ej. `CreditNotes`, truncada a 30), `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`. Los tamaños de las + columnas del log no se verificaron. - 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. diff --git a/Net.Business.Services/Startup.cs b/Net.Business.Services/Startup.cs index 0a412ec..4e0468d 100644 --- a/Net.Business.Services/Startup.cs +++ b/Net.Business.Services/Startup.cs @@ -19,6 +19,8 @@ namespace Net.Business.Services { Configuration = configuration; Net.Data.LocalData.Configure(configuration); + // Guarda en ITCA_LOG_INTEGRACION el JSON enviado al Service Layer cuando SAP lo rechaza + Net.Connection.ServiceLayer.ConnectionServiceLayer.ErrorLogger = Net.Data.HelperData.Log.HelperLogServiceLayer.AddError; } public IConfiguration Configuration { get; } diff --git a/Net.Connection.ServiceLayer/ConnectionServiceLayer.cs b/Net.Connection.ServiceLayer/ConnectionServiceLayer.cs index 0ca46ac..84e2937 100644 --- a/Net.Connection.ServiceLayer/ConnectionServiceLayer.cs +++ b/Net.Connection.ServiceLayer/ConnectionServiceLayer.cs @@ -19,6 +19,16 @@ namespace Net.Connection.ServiceLayer public static bool ServicioActivo = false; public static string SLSession; + // Se invoca solo cuando SAP rechaza un envio: (ruta del recurso, JSON enviado, respuesta de SAP). + // Lo asigna Startup (esta capa no conoce HANA). + public static Action ErrorLogger; + + private static void LogErrorEnvio(string query, object jsonEnviado, string respuesta) + { + try { ErrorLogger?.Invoke(query, jsonEnviado, respuesta); } + catch { /* el log nunca debe romper el flujo principal */ } + } + private readonly string _url; private readonly string _company; private readonly string _user; @@ -464,6 +474,7 @@ namespace Net.Connection.ServiceLayer var estado = (int)response_.StatusCode; responseBody.CodigoHttp = estado.ToString(); responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString(); + LogErrorEnvio(Query, obj, responseBody.Mensaje); return responseBody; } @@ -493,6 +504,7 @@ namespace Net.Connection.ServiceLayer var estado = (int)response_.StatusCode; responseBody.CodigoHttp = estado.ToString(); responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString(); + LogErrorEnvio(Query, obj, responseBody.Mensaje); return responseBody; } @@ -1072,6 +1084,7 @@ namespace Net.Connection.ServiceLayer var estado = (int)response_.StatusCode; //responseBody.CodigoHttp = estado.ToString(); responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString(); + LogErrorEnvio(Query, obj, responseBody.Mensaje); return responseBody; } @@ -1096,6 +1109,7 @@ namespace Net.Connection.ServiceLayer var estado = (int)response_.StatusCode; //responseBody.CodigoHttp = estado.ToString(); responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString(); + LogErrorEnvio(Query, obj, responseBody.Mensaje); return responseBody; } @@ -1163,7 +1177,9 @@ namespace Net.Connection.ServiceLayer return; // exito real - sin body que parsear } - throw new Exception(ExtraerMensajeErrorSap(responseText_)); + var mensajeError = ExtraerMensajeErrorSap(responseText_); + LogErrorEnvio(Query, obj, mensajeError); + throw new Exception(mensajeError); } } diff --git a/Net.Data/HelperData/Log/HelperLogServiceLayer.cs b/Net.Data/HelperData/Log/HelperLogServiceLayer.cs index 563d45c..771d47c 100644 --- a/Net.Data/HelperData/Log/HelperLogServiceLayer.cs +++ b/Net.Data/HelperData/Log/HelperLogServiceLayer.cs @@ -5,14 +5,18 @@ using System.Text; namespace Net.Data.HelperData.Log { - // Guarda en ITCA_LOG_INTEGRACION el JSON enviado al Service Layer cuando SAP rechaza el documento. + // Guarda en ITCA_LOG_INTEGRACION el JSON enviado al Service Layer cuando SAP rechaza un envio (cualquier documento). // Misma tabla que Net.Business.Services.Log.B_Log (esa clase no se puede usar desde Net.Data). public class HelperLogServiceLayer { - public static void AddError(string proceso, string docEntryOrigen, object jsonEnviado, string respuesta) + // query: ruta del recurso del Service Layer (ej. "CreditNotes", "StockTransfers") + public static void AddError(string query, object jsonEnviado, string respuesta) { try { + var recurso = query ?? ""; + if (recurso.Length > 30) recurso = recurso.Substring(0, 30); + var trama = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonEnviado)); var tramaRespuesta = Encoding.UTF8.GetBytes(respuesta ?? ""); @@ -25,10 +29,10 @@ namespace Net.Data.HelperData.Log hanaCommand.Parameters.Add("ORIGEN", HanaDbType.VarChar).Value = "ServiceLayer"; hanaCommand.Parameters.Add("TRAMA_ORIGEN", HanaDbType.Blob).Value = trama; hanaCommand.Parameters.Add("TRAMA_RESPUESTA", HanaDbType.Blob).Value = tramaRespuesta; - hanaCommand.Parameters.Add("PROCESO", HanaDbType.VarChar).Value = proceso; + hanaCommand.Parameters.Add("PROCESO", HanaDbType.VarChar).Value = "ServiceLayer Error"; hanaCommand.Parameters.Add("FECHA", HanaDbType.Date).Value = DateTime.Now.ToString("yyyy-MM-dd"); - hanaCommand.Parameters.Add("NRO_ORDEN", HanaDbType.VarChar).Value = docEntryOrigen ?? ""; - hanaCommand.Parameters.Add("DOCENTRY", HanaDbType.VarChar).Value = docEntryOrigen ?? ""; + hanaCommand.Parameters.Add("NRO_ORDEN", HanaDbType.VarChar).Value = recurso; + hanaCommand.Parameters.Add("DOCENTRY", HanaDbType.VarChar).Value = recurso; hanaCommand.Parameters.Add("DOCNUMSAP", HanaDbType.VarChar).Value = "0"; hanaCommand.Parameters.Add("DOCENTRYSAP", HanaDbType.VarChar).Value = "0"; hanaCommand.Parameters.Add("HORA", HanaDbType.VarChar).Value = DateTime.Now.ToString("HH:mm:ss"); diff --git a/Net.Data/ServicesLayer/CreditNotes/CreditNotesRepository.cs b/Net.Data/ServicesLayer/CreditNotes/CreditNotesRepository.cs index 19a5c1b..118c63b 100644 --- a/Net.Data/ServicesLayer/CreditNotes/CreditNotesRepository.cs +++ b/Net.Data/ServicesLayer/CreditNotes/CreditNotesRepository.cs @@ -6,7 +6,6 @@ using Net.Business.Entities.ServicesLayer.CreditNotes; using Net.Connection; using Net.Connection.ServiceLayer; using Net.CrossCotting; -using Net.Data.HelperData.Log; using System; using System.Collections.Generic; using System.Net.Http; @@ -51,8 +50,6 @@ namespace Net.Data.ServicesLayer.CreditNotes if (!data.Exito) { - // Solo si SAP rechaza: guarda el JSON enviado al Service Layer para poder revisarlo - HelperLogServiceLayer.AddError("NotaCredito Error", DocEntryOrigen(entidad), entidad, data.Mensaje); return resultadoTransaccion.GetInformacionResultado(-1, -1, data.Mensaje); } @@ -60,17 +57,10 @@ namespace Net.Data.ServicesLayer.CreditNotes } catch (Exception ex) { - HelperLogServiceLayer.AddError("NotaCredito Error", DocEntryOrigen(entidad), entidad, ex.Message); return resultadoTransaccion.GetInformacionResultado(-1, -1, ex.Message.ToString()); } } - // DocEntry del documento base (factura o solicitud de devolucion) de la primera linea - private static string DocEntryOrigen(BE_CreditNotesNotes entidad) - { - return entidad?.DocumentLines?.Count > 0 ? entidad.DocumentLines[0].BaseEntry?.ToString() : null; - } - public async Task> UpdateCreateCreditNotes(dynamic entidad, int DocEntry) {