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
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.
+2
View File
@@ -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; }
@@ -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<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 _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);
}
}
@@ -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");
@@ -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<BE_ResultadoTransaccion<BE_BaseResponseSap>> UpdateCreateCreditNotes(dynamic entidad, int DocEntry)
{