Log del JSON enviado al Service Layer cuando SAP rechaza, para todos los documentos. Versión 2.1.5.0

Se mueve de CreditNotesRepository a ConnectionServiceLayer (PostAsync,
PatchAsyncSBA, PatchNoContentAsync) con un hook asignado en Startup.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-14 17:06:07 -05:00
1 parent 1ce0da7735
commit e5ea57b673
5 files changed
+39 -24

No files matched your search

+11 -8
View File
@@ -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 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) 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`. 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**: - **v2.1.5.0 — log del JSON enviado al Service Layer cuando SAP lo rechaza**
`CreditNotesRepository.SetCreateCreditNotes` guarda en (cualquier documento, no solo la NC): `ConnectionServiceLayer` llama a
`ITC_WMS_SAP.ITCA_LOG_INTEGRACION` (vía `Net.Data/HelperData/Log/HelperLogServiceLayer`) `ErrorLogger` (asignado en `Startup` a `Net.Data/HelperData/Log/HelperLogServiceLayer.AddError`)
el JSON enviado al Service Layer y la respuesta de SAP, con `ORIGEN = en los fallos de `PostAsync`, `PatchAsyncSBA` y `PatchNoContentAsync`. Guarda en
"ServiceLayer"` y `PROCESO = "NotaCredito Error"`; `NRO_ORDEN`/`DOCENTRY` = `ITC_WMS_SAP.ITCA_LOG_INTEGRACION`: `ORIGEN = "ServiceLayer"`,
`BaseEntry` de la primera línea. Solo en error (no en éxito); si el log `PROCESO = "ServiceLayer Error"`, `NRO_ORDEN`/`DOCENTRY` = ruta del recurso
falla, no rompe el flujo. No cubre transferencias, solicitud de devolución (p. ej. `CreditNotes`, truncada a 30), `TRAMA_ORIGEN` = JSON enviado,
ni reapertura. `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 - 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. `BaseType`/`BaseEntry` en las líneas y `BatchNumbers` en las de la Entrega.
+2
View File
@@ -19,6 +19,8 @@ namespace Net.Business.Services
{ {
Configuration = configuration; Configuration = configuration;
Net.Data.LocalData.Configure(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; } public IConfiguration Configuration { get; }
@@ -19,6 +19,16 @@ namespace Net.Connection.ServiceLayer
public static bool ServicioActivo = false; public static bool ServicioActivo = false;
public static string SLSession; 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<string, object, string> 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 _url;
private readonly string _company; private readonly string _company;
private readonly string _user; private readonly string _user;
@@ -464,6 +474,7 @@ namespace Net.Connection.ServiceLayer
var estado = (int)response_.StatusCode; var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString(); responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString(); responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody; return responseBody;
} }
@@ -493,6 +504,7 @@ namespace Net.Connection.ServiceLayer
var estado = (int)response_.StatusCode; var estado = (int)response_.StatusCode;
responseBody.CodigoHttp = estado.ToString(); responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString(); responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody; return responseBody;
} }
@@ -1072,6 +1084,7 @@ namespace Net.Connection.ServiceLayer
var estado = (int)response_.StatusCode; var estado = (int)response_.StatusCode;
//responseBody.CodigoHttp = estado.ToString(); //responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString(); responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody; return responseBody;
} }
@@ -1096,6 +1109,7 @@ namespace Net.Connection.ServiceLayer
var estado = (int)response_.StatusCode; var estado = (int)response_.StatusCode;
//responseBody.CodigoHttp = estado.ToString(); //responseBody.CodigoHttp = estado.ToString();
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString(); responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
LogErrorEnvio(Query, obj, responseBody.Mensaje);
return responseBody; return responseBody;
} }
@@ -1163,7 +1177,9 @@ namespace Net.Connection.ServiceLayer
return; // exito real - sin body que parsear return; // exito real - sin body que parsear
} }
throw new Exception(ExtraerMensajeErrorSap(responseText_)); var mensajeError = ExtraerMensajeErrorSap(responseText_);
LogErrorEnvio(Query, obj, mensajeError);
throw new Exception(mensajeError);
} }
} }
@@ -5,14 +5,18 @@ using System.Text;
namespace Net.Data.HelperData.Log 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). // Misma tabla que Net.Business.Services.Log.B_Log (esa clase no se puede usar desde Net.Data).
public class HelperLogServiceLayer 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 try
{ {
var recurso = query ?? "";
if (recurso.Length > 30) recurso = recurso.Substring(0, 30);
var trama = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonEnviado)); var trama = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonEnviado));
var tramaRespuesta = Encoding.UTF8.GetBytes(respuesta ?? ""); 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("ORIGEN", HanaDbType.VarChar).Value = "ServiceLayer";
hanaCommand.Parameters.Add("TRAMA_ORIGEN", HanaDbType.Blob).Value = trama; hanaCommand.Parameters.Add("TRAMA_ORIGEN", HanaDbType.Blob).Value = trama;
hanaCommand.Parameters.Add("TRAMA_RESPUESTA", HanaDbType.Blob).Value = tramaRespuesta; 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("FECHA", HanaDbType.Date).Value = DateTime.Now.ToString("yyyy-MM-dd");
hanaCommand.Parameters.Add("NRO_ORDEN", HanaDbType.VarChar).Value = docEntryOrigen ?? ""; hanaCommand.Parameters.Add("NRO_ORDEN", HanaDbType.VarChar).Value = recurso;
hanaCommand.Parameters.Add("DOCENTRY", HanaDbType.VarChar).Value = docEntryOrigen ?? ""; hanaCommand.Parameters.Add("DOCENTRY", HanaDbType.VarChar).Value = recurso;
hanaCommand.Parameters.Add("DOCNUMSAP", HanaDbType.VarChar).Value = "0"; hanaCommand.Parameters.Add("DOCNUMSAP", HanaDbType.VarChar).Value = "0";
hanaCommand.Parameters.Add("DOCENTRYSAP", 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"); hanaCommand.Parameters.Add("HORA", HanaDbType.VarChar).Value = DateTime.Now.ToString("HH:mm:ss");
@@ -6,7 +6,6 @@ using Net.Business.Entities.ServicesLayer.CreditNotes;
using Net.Connection; using Net.Connection;
using Net.Connection.ServiceLayer; using Net.Connection.ServiceLayer;
using Net.CrossCotting; using Net.CrossCotting;
using Net.Data.HelperData.Log;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
@@ -51,8 +50,6 @@ namespace Net.Data.ServicesLayer.CreditNotes
if (!data.Exito) 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); return resultadoTransaccion.GetInformacionResultado(-1, -1, data.Mensaje);
} }
@@ -60,17 +57,10 @@ namespace Net.Data.ServicesLayer.CreditNotes
} }
catch (Exception ex) catch (Exception ex)
{ {
HelperLogServiceLayer.AddError("NotaCredito Error", DocEntryOrigen(entidad), entidad, ex.Message);
return resultadoTransaccion.GetInformacionResultado(-1, -1, ex.Message.ToString()); 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<BE_ResultadoTransaccion<BE_BaseResponseSap>> UpdateCreateCreditNotes(dynamic entidad, int DocEntry) public async Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> UpdateCreateCreditNotes(dynamic entidad, int DocEntry)
{ {