Version 2.1.14.0: se quita PatchAsyncSBA; UpdateCreateCreditNotes usa PatchNoContentAsync (PATCH exitoso = 204 sin cuerpo)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a65cd4d90a
commit
e664799de7
5 files changed
+17
-129
No files matched your search
@@ -10,7 +10,7 @@ comprimido (versión antigua)**.
|
|||||||
|
|
||||||
## Versión y control de versiones
|
## Versión y control de versiones
|
||||||
|
|
||||||
- **Versión actual: 2.1.13.0** (rama `limpieza-2.1.8.0`; `main` = 2.1.7.0) (`Net.Business.Services.csproj`: `Version`,
|
- **Versión actual: 2.1.14.0** (rama `limpieza-2.1.8.0`; `main` = 2.1.7.0) (`Net.Business.Services.csproj`: `Version`,
|
||||||
`AssemblyVersion`, `FileVersion`). Cada versión tiene su commit; al publicar
|
`AssemblyVersion`, `FileVersion`). Cada versión tiene su commit; al publicar
|
||||||
se sube la versión (ver `publicar.ps1`).
|
se sube la versión (ver `publicar.ps1`).
|
||||||
- **Git**: rama `main`, remoto `origin` =
|
- **Git**: rama `main`, remoto `origin` =
|
||||||
@@ -59,7 +59,7 @@ transferencias siempre, sin depender de `Notificacion`. Detalle y tabla en
|
|||||||
- **v2.1.5.0 — log del JSON enviado al Service Layer cuando SAP lo rechaza**
|
- **v2.1.5.0 — log del JSON enviado al Service Layer cuando SAP lo rechaza**
|
||||||
(cualquier documento, no solo la NC): `ConnectionServiceLayer` llama a
|
(cualquier documento, no solo la NC): `ConnectionServiceLayer` llama a
|
||||||
`ErrorLogger` (asignado en `Startup` a `Net.Data/HelperData/Log/HelperLogServiceLayer.AddError`)
|
`ErrorLogger` (asignado en `Startup` a `Net.Data/HelperData/Log/HelperLogServiceLayer.AddError`)
|
||||||
en los fallos de `PostAsync`, `PatchAsyncSBA` y `PatchNoContentAsync`. Guarda en
|
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"`,
|
`ITC_WMS_SAP.ITCA_LOG_INTEGRACION`: `ORIGEN = "ServiceLayer"`,
|
||||||
`PROCESO = "ServiceLayer Error"`, `NRO_ORDEN` = ruta del recurso (p. ej.
|
`PROCESO = "ServiceLayer Error"`, `NRO_ORDEN` = ruta del recurso (p. ej.
|
||||||
`CreditNotes`), `DOCENTRY` = `BaseEntry` de la primera línea del JSON (factura o
|
`CreditNotes`), `DOCENTRY` = `BaseEntry` de la primera línea del JSON (factura o
|
||||||
@@ -145,6 +145,12 @@ transferencias siempre, sin depender de `Notificacion`. Detalle y tabla en
|
|||||||
la NC estaban copiados en Picking DESPACHO, Picking PICKING (estado 13) y Recibo Devolución; ahora están en
|
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).
|
`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).
|
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.
|
||||||
- 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.
|
||||||
|
|
||||||
@@ -197,8 +203,6 @@ Picking, columna `HORA` en `B_Log`. Lo que **no** se trajo: `Chatbots` y
|
|||||||
|
|
||||||
- `BE_ResultadoTransaccion<T>.NombreEstacion`: setter con recursión infinita
|
- `BE_ResultadoTransaccion<T>.NombreEstacion`: setter con recursión infinita
|
||||||
(bomba de tiempo; hoy nada lo asigna).
|
(bomba de tiempo; hoy nada lo asigna).
|
||||||
- `ConnectionServiceLayer.PatchAsyncSBA<T>`: con un `204` real devuelve `null`
|
|
||||||
sin marcar éxito.
|
|
||||||
- El cliente HTTP `bypass-ssl-validation` acepta cualquier certificado TLS hacia
|
- El cliente HTTP `bypass-ssl-validation` acepta cualquier certificado TLS hacia
|
||||||
el Service Layer (se quitó el método `ValidarCertificado`, que no se usaba).
|
el Service Layer (se quitó el método `ValidarCertificado`, que no se usaba).
|
||||||
- `appsettings.json` (fuera de git, en `.gitignore`) contiene credenciales
|
- `appsettings.json` (fuera de git, en `.gitignore`) contiene credenciales
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<AssemblyName>ITCA_API_SAP_WMS</AssemblyName>
|
<AssemblyName>ITCA_API_SAP_WMS</AssemblyName>
|
||||||
<Version>2.1.13.0</Version>
|
<Version>2.1.14.0</Version>
|
||||||
<AssemblyVersion>2.1.12.0</AssemblyVersion>
|
<AssemblyVersion>2.1.12.0</AssemblyVersion>
|
||||||
<FileVersion>2.1.12.0</FileVersion>
|
<FileVersion>2.1.12.0</FileVersion>
|
||||||
<UserSecretsId>24763424-3300-4c85-87e3-503f8fdebd14</UserSecretsId>
|
<UserSecretsId>24763424-3300-4c85-87e3-503f8fdebd14</UserSecretsId>
|
||||||
|
|||||||
@@ -366,126 +366,13 @@ namespace Net.Connection.ServiceLayer
|
|||||||
// PASAMOS LA EXCEPCIÓN A LA APP.
|
// PASAMOS LA EXCEPCIÓN A LA APP.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// PATCH con cuerpo JSON. OJO: con un 204 real devuelve null sin marcar exito (bug conocido); para PATCH sin respuesta usar PatchNoContentAsync
|
|
||||||
public async Task<T> PatchAsyncSBA<T>(string Query, object obj)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// CONSTRUIMOS LA URL DE LA ACCIÓN
|
|
||||||
var urlBuilder_ = new StringBuilder();
|
|
||||||
urlBuilder_.Append(_url != null ? _url.TrimEnd('/') : "")
|
|
||||||
.Append("/" + Query);
|
|
||||||
var url_ = urlBuilder_.ToString();
|
|
||||||
|
|
||||||
// RECUPERAMOS EL HttpClient
|
|
||||||
var client_ = _httpClient.CreateClient("bypass-ssl-validation");
|
|
||||||
|
|
||||||
int NumError = 0;
|
|
||||||
|
|
||||||
band:
|
|
||||||
|
|
||||||
using (var request_ = new HttpRequestMessage())
|
|
||||||
{
|
|
||||||
///////////////////////////////////////
|
|
||||||
// CONSTRUIMOS LA PETICIÓN (REQUEST) //
|
|
||||||
///////////////////////////////////////
|
|
||||||
// DEFINIMOS EL MÉTODO HTTP GET
|
|
||||||
request_.Method = new HttpMethod("PATCH");
|
|
||||||
|
|
||||||
// DEFINIMOS LA URI
|
|
||||||
request_.RequestUri = new Uri(url_, System.UriKind.RelativeOrAbsolute);
|
|
||||||
|
|
||||||
// DEFINIMOS EL Accept, EN ESTE CASO ES "application/json"
|
|
||||||
request_.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
|
||||||
request_.Content = new StringContent(JsonConvert.SerializeObject(obj), System.Text.Encoding.UTF8, "application/json");
|
|
||||||
|
|
||||||
// ASIGNAMOS A LA CABECERA DE LA PETICIÓN EL TOKEN JWT.
|
|
||||||
if (_responseLoginServiceLayer.ServicioActivo)
|
|
||||||
request_.Headers.Add("Cookie", "B1SESSION=" + _responseLoginServiceLayer.SessionId);
|
|
||||||
|
|
||||||
/////////////////////////////////////////
|
|
||||||
// CONSTRUIMOS LA RESPUESTA (RESPONSE) //
|
|
||||||
/////////////////////////////////////////
|
|
||||||
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
|
|
||||||
var response_ = await client_.SendAsync(request_, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// OBTENEMOS EL Content DEL RESPONSE como un String
|
|
||||||
// Utilizamos ConfigureAwait(false) para evitar el DeadLock.
|
|
||||||
var responseText_ = await response_.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
// SI ES LA RESPUESTA ESPERADA !! ...
|
|
||||||
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created) // 200 or Created
|
|
||||||
{
|
|
||||||
// DESERIALIZAMOS Content DEL RESPONSE
|
|
||||||
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
|
|
||||||
var estado = (int)response_.StatusCode;
|
|
||||||
responseBody.Mensaje = "SE ENVIO CORRECTAMENTE A SAP BO ";
|
|
||||||
return responseBody;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// SI NO SE ESTÁ AUTORIZADO ...
|
|
||||||
if (response_.StatusCode == System.Net.HttpStatusCode.Unauthorized) // 401
|
|
||||||
{
|
|
||||||
|
|
||||||
NumError += 1;
|
|
||||||
|
|
||||||
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
|
|
||||||
_responseLoginServiceLayer.ServicioActivo = false;
|
|
||||||
|
|
||||||
if (NumError == 2)
|
|
||||||
{
|
|
||||||
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
|
|
||||||
var estado = (int)response_.StatusCode;
|
|
||||||
responseBody.Mensaje = "Services Unauthorized : " + _responseLoginServiceLayer.error.message.ToString();
|
|
||||||
LogErrorEnvio(Query, obj, responseBody.Mensaje);
|
|
||||||
return responseBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (_responseLoginServiceLayer.error.code.ToString() == "301")
|
|
||||||
{
|
|
||||||
await Login();
|
|
||||||
goto band;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
// CUALQUIER OTRA RESPUESTA ...
|
|
||||||
if (response_.StatusCode != System.Net.HttpStatusCode.OK && response_.StatusCode != System.Net.HttpStatusCode.NoContent) // 204
|
|
||||||
{
|
|
||||||
|
|
||||||
//NumError += 1;
|
|
||||||
|
|
||||||
_responseLoginServiceLayer = JsonConvert.DeserializeObject<ResponseLoginServiceLayer>(responseText_);
|
|
||||||
_responseLoginServiceLayer.ServicioActivo = false;
|
|
||||||
|
|
||||||
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
|
|
||||||
var estado = (int)response_.StatusCode;
|
|
||||||
responseBody.Mensaje = "Error Services : " + _responseLoginServiceLayer.error.message.ToString();
|
|
||||||
LogErrorEnvio(Query, obj, responseBody.Mensaje);
|
|
||||||
return responseBody;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RETORNAMOS EL OBJETO POR DEFECTO ESPERADO
|
|
||||||
return default(T);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
return default(T);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === NUEVO (SolicitudTransferencia / Picking HojaRuta Cerrar) ===
|
// === NUEVO (SolicitudTransferencia / Picking HojaRuta Cerrar) ===
|
||||||
//
|
//
|
||||||
// PatchAsyncSBA<T>/PostAsync<T> estan pensados para respuestas con body
|
// PatchNoContentAsync/PostActionAsync no devuelven un T deserializado, solo exito (sin excepcion)
|
||||||
// (200/201) que se deserializan a T y se les "inyecta" Exito/Mensaje/CodigoHttp
|
// o fallo (excepcion con el mensaje real de SAP). En el Service Layer un PATCH exitoso es un 204 sin cuerpo,
|
||||||
// via dynamic - no sirven para una respuesta sin body como el 204 real que
|
// asi que no hay nada que deserializar. (v2.1.14.0: se quito PatchAsyncSBA, que con el 204 devolvia null
|
||||||
// devuelve SAP en un PATCH exitoso o en una accion /Close, y PatchAsyncSBA
|
// sin marcar exito y con un error de red devolvia lo mismo.)
|
||||||
// tiene ademas un bug conocido ahi (ver docs/PORTE_FUNCIONALIDAD_NUEVA.md,
|
|
||||||
// hallazgo #2): con un 204 real cae a "return default(T)" sin marcar exito.
|
|
||||||
// Por eso estos dos metodos nuevos son deliberadamente simples: no devuelven
|
|
||||||
// un T deserializado, solo exito (sin excepcion) o fallo (excepcion con el
|
|
||||||
// mensaje real de SAP).
|
|
||||||
|
|
||||||
public async Task PatchNoContentAsync(string Query, object obj, Dictionary<string, string> extraHeaders = null)
|
public async Task PatchNoContentAsync(string Query, object obj, Dictionary<string, string> extraHeaders = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -73,13 +73,10 @@ namespace Net.Data.ServicesLayer.CreditNotes
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cadena = $"CreditNotes({DocEntry})";
|
var cadena = $"CreditNotes({DocEntry})";
|
||||||
var data = await _connectServiceLayer.PatchAsyncSBA<BE_BaseResponseSap>(cadena, entidad);
|
// PATCH exitoso = 204 sin cuerpo; si SAP rechaza lanza excepcion con su mensaje (y deja el JSON en el log)
|
||||||
if (!data.Exito)
|
await _connectServiceLayer.PatchNoContentAsync(cadena, entidad);
|
||||||
{
|
|
||||||
return resultadoTransaccion.GetInformacionResultado(-1, -1, data.Mensaje);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultadoTransaccion.GetInformacionResultado(0, "", "Se Listo correctamento...!!!", data);
|
return resultadoTransaccion.GetInformacionResultado(0, "", "Se Listo correctamento...!!!", new BE_BaseResponseSap { Exito = true });
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ git switch -c recuperar-2.1.7.0 v2.1.7.0 # trabajar desde ahí en una rama nue
|
|||||||
respuesta de la API (`TRAMA_RESPUESTA`), con `PROCESO` (Picking, Recibo...),
|
respuesta de la API (`TRAMA_RESPUESTA`), con `PROCESO` (Picking, Recibo...),
|
||||||
`NRO_ORDEN`, `DOCENTRY`, `DOCNUMSAP` y `DOCENTRYSAP`.
|
`NRO_ORDEN`, `DOCENTRY`, `DOCNUMSAP` y `DOCENTRYSAP`.
|
||||||
- **Log de errores del Service Layer** (desde 2.1.5.0): cuando SAP rechaza un
|
- **Log de errores del Service Layer** (desde 2.1.5.0): cuando SAP rechaza un
|
||||||
envío con cuerpo JSON (`PostAsync`, `PatchAsyncSBA`, `PatchNoContentAsync`)
|
envío con cuerpo JSON (`PostAsync`, `PatchNoContentAsync`)
|
||||||
se guarda en esa misma tabla el JSON enviado y el mensaje de SAP, con
|
se guarda en esa misma tabla el JSON enviado y el mensaje de SAP, con
|
||||||
`PROCESO = 'ServiceLayer Error'`, `NRO_ORDEN` = ruta del recurso y `DOCENTRY`
|
`PROCESO = 'ServiceLayer Error'`, `NRO_ORDEN` = ruta del recurso y `DOCENTRY`
|
||||||
= `BaseEntry` del documento base. Solo en error; no cambia la respuesta de la
|
= `BaseEntry` del documento base. Solo en error; no cambia la respuesta de la
|
||||||
|
|||||||
Reference in new issue
Block a user