Compare commits
10
Commits
b6d7767828
...
d0118d1848
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0118d1848 | ||
|
|
0a2dc12305 | ||
|
|
4ad0754ba0 | ||
|
|
e5ea57b673 | ||
|
|
1ce0da7735 | ||
|
|
ded1638cd0 | ||
|
|
14fffa8ba4 | ||
|
|
6386070f4e | ||
|
|
e475b7f48c | ||
|
|
e31524ab6b |
No files matched your search
@@ -16,11 +16,65 @@ Detalle técnico en `docs/PORTE_FUNCIONALIDAD_NUEVA.md`,
|
|||||||
1. **SolicitudTransferencia**: `PATCH /api/SolicitudTransferencia/{docEntry}` y
|
1. **SolicitudTransferencia**: `PATCH /api/SolicitudTransferencia/{docEntry}` y
|
||||||
`POST /api/SolicitudTransferencia/{docEntry}/cerrar`.
|
`POST /api/SolicitudTransferencia/{docEntry}/cerrar`.
|
||||||
2. **Picking diurno/nocturno**: campo `Notificacion` (early-return en
|
2. **Picking diurno/nocturno**: campo `Notificacion` (early-return en
|
||||||
`PickingRepository.Create` tras `HelperProcesoPiciking.Set`) y
|
`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`.
|
`POST /api/Picking/HojaRuta/{docEntry}/Cerrar`.
|
||||||
3. **`ConnectionServiceLayer`**: `PatchNoContentAsync` y `PostActionAsync`
|
3. **`ConnectionServiceLayer`**: `PatchNoContentAsync` y `PostActionAsync`
|
||||||
(métodos nuevos; los existentes no se tocaron).
|
(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`, `PatchAsyncSBA` y `PatchNoContentAsync`. 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`).
|
||||||
|
- 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
|
## Cambios de configuración y correcciones hechas en esta carpeta
|
||||||
|
|
||||||
- **Credenciales y esquema HANA en `appsettings.json`**, sección `Hana`
|
- **Credenciales y esquema HANA en `appsettings.json`**, sección `Hana`
|
||||||
|
|||||||
@@ -33,6 +33,20 @@ namespace Net.Business.Entities.ServicesLayer.Invoices
|
|||||||
public string U_SYP_MDSD { get; set; }
|
public string U_SYP_MDSD { get; set; }
|
||||||
public string U_SYP_MDCD { get; set; }
|
public string U_SYP_MDCD { get; set; }
|
||||||
public string U_SYP_MDTD { get; set; }
|
public string U_SYP_MDTD { get; set; }
|
||||||
public List<BE_InvoicesLine> DocumentLines { get; set; }
|
public List<BE_InvoicesConsultaLine> DocumentLines { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linea de factura leida de SAP: agrega el documento origen (BaseType 15 = Entrega)
|
||||||
|
public class BE_InvoicesConsultaLine : BE_InvoicesLine
|
||||||
|
{
|
||||||
|
public int? BaseType { get; set; }
|
||||||
|
public int? BaseEntry { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entrega (DeliveryNotes) leida de SAP, solo para obtener los lotes por linea
|
||||||
|
public class BE_DeliveryNotesConsulta
|
||||||
|
{
|
||||||
|
public int DocEntry { get; set; }
|
||||||
|
public List<BE_InvoicesConsultaLine> DocumentLines { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
<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.0</Version>
|
<Version>2.1.7</Version>
|
||||||
<AssemblyVersion>2.1.0.0</AssemblyVersion>
|
<AssemblyVersion>2.1.7.0</AssemblyVersion>
|
||||||
<FileVersion>2.1.0.0</FileVersion>
|
<FileVersion>2.1.7.0</FileVersion>
|
||||||
<UserSecretsId>24763424-3300-4c85-87e3-503f8fdebd14</UserSecretsId>
|
<UserSecretsId>24763424-3300-4c85-87e3-503f8fdebd14</UserSecretsId>
|
||||||
<!-- Antes solo estaba condicionado a Debug|AnyCPU - un "dotnet publish -c Release"
|
<!-- Antes solo estaba condicionado a Debug|AnyCPU - un "dotnet publish -c Release"
|
||||||
(lo normal para IIS) se quedaba sin este archivo, y Startup.cs revienta con
|
(lo normal para IIS) se quedaba sin este archivo, y Startup.cs revienta con
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,7 +580,11 @@ namespace Net.Connection.ServiceLayer
|
|||||||
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created || response_.StatusCode == HttpStatusCode.NoContent) // 200 or Created
|
if (response_.StatusCode == System.Net.HttpStatusCode.OK || response_.StatusCode == System.Net.HttpStatusCode.Created || response_.StatusCode == HttpStatusCode.NoContent) // 200 or Created
|
||||||
{
|
{
|
||||||
// DESERIALIZAMOS Content DEL RESPONSE
|
// DESERIALIZAMOS Content DEL RESPONSE
|
||||||
dynamic responseBody = JsonConvert.DeserializeObject<T>(responseText_);
|
// Reopen responde 204 sin cuerpo: DeserializeObject devuelve null, asi que
|
||||||
|
// se crea una instancia vacia para poder marcar el exito.
|
||||||
|
dynamic responseBody = string.IsNullOrWhiteSpace(responseText_)
|
||||||
|
? Activator.CreateInstance<T>()
|
||||||
|
: JsonConvert.DeserializeObject<T>(responseText_);
|
||||||
responseBody.Exito = true;
|
responseBody.Exito = true;
|
||||||
var estado = (int)response_.StatusCode;
|
var estado = (int)response_.StatusCode;
|
||||||
responseBody.CodigoHttp = estado.ToString();
|
responseBody.CodigoHttp = estado.ToString();
|
||||||
@@ -1068,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using Sap.Data.Hana;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Net.Data.HelperData.Log
|
||||||
|
{
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
// 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 > 100) recurso = recurso.Substring(0, 100);
|
||||||
|
|
||||||
|
var json = JsonConvert.SerializeObject(jsonEnviado);
|
||||||
|
var docEntryBase = ObtenerDocEntryBase(json);
|
||||||
|
var trama = Encoding.UTF8.GetBytes(json);
|
||||||
|
var tramaRespuesta = Encoding.UTF8.GetBytes(respuesta ?? "");
|
||||||
|
|
||||||
|
using (var hana = new HanaConnection(LocalData.ConnectionString))
|
||||||
|
{
|
||||||
|
hana.Open();
|
||||||
|
HanaCommand hanaCommand = hana.CreateCommand();
|
||||||
|
hanaCommand.CommandText = "INSERT INTO \"ITC_WMS_SAP\".\"ITCA_LOG_INTEGRACION\" (\"CODIGO\", \"ORIGEN\", \"TRAMA_ORIGEN\", \"TRAMA_RESPUESTA\", \"PROCESO\", \"FECHA\", \"NRO_ORDEN\", \"DOCENTRY\", \"DOCNUMSAP\", \"DOCENTRYSAP\", \"HORA\") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||||
|
hanaCommand.Parameters.Add("CODIGO", HanaDbType.VarChar).Value = Guid.NewGuid().ToString();
|
||||||
|
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 = "ServiceLayer Error";
|
||||||
|
hanaCommand.Parameters.Add("FECHA", HanaDbType.Date).Value = DateTime.Now.ToString("yyyy-MM-dd");
|
||||||
|
hanaCommand.Parameters.Add("NRO_ORDEN", HanaDbType.VarChar).Value = recurso;
|
||||||
|
hanaCommand.Parameters.Add("DOCENTRY", HanaDbType.VarChar).Value = docEntryBase;
|
||||||
|
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");
|
||||||
|
hanaCommand.CommandType = System.Data.CommandType.Text;
|
||||||
|
hanaCommand.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// el log nunca debe romper el flujo principal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocEntry del documento base (factura o solicitud) de la primera linea del JSON; vacio si no hay
|
||||||
|
private static string ObtenerDocEntryBase(string json)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var baseEntry = JObject.Parse(json)["DocumentLines"]?[0]?["BaseEntry"];
|
||||||
|
return baseEntry == null || baseEntry.Type == JTokenType.Null ? "" : baseEntry.ToString();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,5 +13,6 @@ namespace Net.Data.ServicesLayer
|
|||||||
Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> SetCreateInvoices(BE_Invoices entidad);
|
Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> SetCreateInvoices(BE_Invoices entidad);
|
||||||
Task<BE_ResultadoTransaccion<BE_InvoicesConsulta>> GetInvoice(int docEntry);
|
Task<BE_ResultadoTransaccion<BE_InvoicesConsulta>> GetInvoice(int docEntry);
|
||||||
Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> ReOpen(int docEntry);
|
Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> ReOpen(int docEntry);
|
||||||
|
Task<BE_ResultadoTransaccion<BE_DeliveryNotesConsulta>> GetDeliveryNote(int docEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,6 +92,25 @@ namespace Net.Data.ServicesLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET DELIVERY NOTE (para obtener los lotes de la entrega origen de una factura)
|
||||||
|
public async Task<BE_ResultadoTransaccion<BE_DeliveryNotesConsulta>> GetDeliveryNote(int docEntry)
|
||||||
|
{
|
||||||
|
_metodoName = regex.Match(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name).Groups[1].Value.ToString();
|
||||||
|
|
||||||
|
ResultadoTransaccion<BE_DeliveryNotesConsulta> resultadoTransaccion = new ResultadoTransaccion<BE_DeliveryNotesConsulta>(_metodoName, _aplicacionName);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string cadena = $"DeliveryNotes({docEntry})";
|
||||||
|
List<BE_DeliveryNotesConsulta> objectList = await _connectServiceLayer.GetAsync<BE_DeliveryNotesConsulta>(cadena, 0, true);
|
||||||
|
|
||||||
|
return resultadoTransaccion.GetInformacionResultado(0, 0, "Se Listo correctamento...!!!", objectList);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return resultadoTransaccion.GetInformacionResultado(-1, -1, ex.Message.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> ReOpen(int docEntry)
|
public async Task<BE_ResultadoTransaccion<BE_BaseResponseSap>> ReOpen(int docEntry)
|
||||||
{
|
{
|
||||||
_metodoName = regex.Match(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name).Groups[1].Value.ToString();
|
_metodoName = regex.Match(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name).Groups[1].Value.ToString();
|
||||||
|
|||||||
@@ -120,11 +120,12 @@ namespace Net.Data.WMS.Picking
|
|||||||
//=== REALIZA PROCESO COMPLETO DE ACTUALIZACION
|
//=== REALIZA PROCESO COMPLETO DE ACTUALIZACION
|
||||||
HelperProcesoPiciking.Set(entidad.Proceso, entidad.IdEstadoCubico, entidad.DocEntry, entidad.CodMotivo, Proceso.Code);
|
HelperProcesoPiciking.Set(entidad.Proceso, entidad.IdEstadoCubico, entidad.DocEntry, entidad.CodMotivo, Proceso.Code);
|
||||||
|
|
||||||
// === NUEVO (Picking diurno/nocturno): "notificacion" distinta de "cierre"
|
// === Solo para el proceso "ULTIMA MILLA": "notificacion" distinta de "cierre"
|
||||||
// (o ausente) es la notificacion preliminar en tiempo real - solo actualiza
|
// (o ausente) es la notificacion preliminar en tiempo real - solo actualiza
|
||||||
// estado en HANA (ya hecho arriba), NUNCA debe crear documentos en SAP.
|
// estado en HANA (ya hecho arriba), NUNCA debe crear documentos en SAP.
|
||||||
// Default seguro: cualquier valor que no sea "cierre" exacto cae aca.
|
// DESPACHO, PICKING y demas procesos no dependen de este campo.
|
||||||
if (!string.Equals(entidad.Notificacion, "cierre", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(entidad.Proceso, "ULTIMA MILLA", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& !string.Equals(entidad.Notificacion, "cierre", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return resultadoTransaccion.GetInformacionResultado(entidad.DocEntry, entidad.NumOrden, "Estado actualizado correctamente", entidad);
|
return resultadoTransaccion.GetInformacionResultado(entidad.DocEntry, entidad.NumOrden, "Estado actualizado correctamente", entidad);
|
||||||
}
|
}
|
||||||
@@ -162,7 +163,7 @@ namespace Net.Data.WMS.Picking
|
|||||||
var Response_Reopen = invoicestRepository.ReOpen(_invoices.DocEntry).Result;
|
var Response_Reopen = invoicestRepository.ReOpen(_invoices.DocEntry).Result;
|
||||||
if (Response_Reopen.DocEntry == -1)
|
if (Response_Reopen.DocEntry == -1)
|
||||||
{
|
{
|
||||||
return resultadoTransaccion.GetInformacionResultado("SAP: La Factura no se puede reabrir", entidad);
|
return resultadoTransaccion.GetInformacionResultado("SAP: La Factura no se puede reabrir. " + Response_Reopen.Message, entidad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,13 +213,42 @@ namespace Net.Data.WMS.Picking
|
|||||||
});
|
});
|
||||||
|
|
||||||
// == REALIZA DISTRIBUCION DE STOCK POR LOTE / ALMACEN
|
// == REALIZA DISTRIBUCION DE STOCK POR LOTE / ALMACEN
|
||||||
|
// Linea por linea: si la factura tiene una Entrega (BaseType 15) como documento
|
||||||
|
// origen, los lotes salen de la linea de esa Entrega (BaseLine); si no, de la
|
||||||
|
// propia linea de la factura (LineNum).
|
||||||
|
var Entregas = new Dictionary<int, BE_DeliveryNotesConsulta>();
|
||||||
|
var ErroresLote = new List<string>();
|
||||||
creditNotesNotes.DocumentLines.ForEach(line =>
|
creditNotesNotes.DocumentLines.ForEach(line =>
|
||||||
{
|
{
|
||||||
#region CONSULTA A HANA
|
#region CONSULTA A HANA
|
||||||
|
|
||||||
//List<BE_ItemStock> ListaStock = HelperStock.Get(line.ItemCode, entidad.CodigoAlmacen);
|
//List<BE_ItemStock> ListaStock = HelperStock.Get(line.ItemCode, entidad.CodigoAlmacen);
|
||||||
var ReferenciaFactura = _invoices.DocumentLines.FirstOrDefault(t => t.LineNum == line.LineNum);
|
var ReferenciaFactura = _invoices.DocumentLines.FirstOrDefault(t => t.LineNum == line.LineNum);
|
||||||
var ListaStock = _invoices.DocumentLines.FirstOrDefault(InvoiceLine => InvoiceLine.LineNum == ReferenciaFactura.BaseLine).BatchNumbers;
|
List<BE_InvoicesBatchNumbers> ListaStock;
|
||||||
|
|
||||||
|
if (ReferenciaFactura.BaseType == 15 && ReferenciaFactura.BaseEntry.HasValue && ReferenciaFactura.BaseLine.HasValue)
|
||||||
|
{
|
||||||
|
int DocEntryEntrega = ReferenciaFactura.BaseEntry.Value;
|
||||||
|
if (!Entregas.TryGetValue(DocEntryEntrega, out BE_DeliveryNotesConsulta Entrega))
|
||||||
|
{
|
||||||
|
var response_entrega = invoicestRepository.GetDeliveryNote(DocEntryEntrega).Result;
|
||||||
|
Entrega = (response_entrega.DocEntry == -1) ? null : response_entrega.ListData?.FirstOrDefault();
|
||||||
|
Entregas[DocEntryEntrega] = Entrega;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Entrega == null)
|
||||||
|
{
|
||||||
|
ErroresLote.Add($"Linea {line.LineNum} ({line.ItemCode}): no se pudo leer la Entrega {DocEntryEntrega} origen de la factura");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var LineaEntrega = Entrega.DocumentLines?.FirstOrDefault(t => t.LineNum == ReferenciaFactura.BaseLine.Value);
|
||||||
|
ListaStock = LineaEntrega?.BatchNumbers ?? new List<BE_InvoicesBatchNumbers>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ListaStock = ReferenciaFactura.BatchNumbers ?? new List<BE_InvoicesBatchNumbers>();
|
||||||
|
}
|
||||||
|
|
||||||
double CantidadPendiente = (double)line.Quantity;
|
double CantidadPendiente = (double)line.Quantity;
|
||||||
var ListOrdenadaFecha = ListaStock;
|
var ListOrdenadaFecha = ListaStock;
|
||||||
@@ -239,9 +269,20 @@ namespace Net.Data.WMS.Picking
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Hay lotes de origen pero no alcanzan para la cantidad a devolver
|
||||||
|
if (ListaStock.Count > 0 && CantidadPendiente > 0.000001)
|
||||||
|
{
|
||||||
|
ErroresLote.Add($"Linea {line.LineNum} ({line.ItemCode}): los lotes de origen no cubren la cantidad {line.Quantity} (faltan {CantidadPendiente})");
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (ErroresLote.Count > 0)
|
||||||
|
{
|
||||||
|
return resultadoTransaccion.GetInformacionResultado("SAP: No se pudo asignar lotes a la nota de credito. " + string.Join(" | ", ErroresLote), entidad);
|
||||||
|
}
|
||||||
|
|
||||||
if (creditNotesNotes.DocumentLines.Count > 0)
|
if (creditNotesNotes.DocumentLines.Count > 0)
|
||||||
{
|
{
|
||||||
var result_creditNotesRepository = _creditNotesRepository.SetCreateCreditNotes(creditNotesNotes).Result;
|
var result_creditNotesRepository = _creditNotesRepository.SetCreateCreditNotes(creditNotesNotes).Result;
|
||||||
@@ -277,12 +318,13 @@ namespace Net.Data.WMS.Picking
|
|||||||
ListaUnicaArticulo.ForEach(x =>
|
ListaUnicaArticulo.ForEach(x =>
|
||||||
{
|
{
|
||||||
var ListLote = new List<BE_StockTransferLineBatchNumber>();
|
var ListLote = new List<BE_StockTransferLineBatchNumber>();
|
||||||
ListaDetalle_PorAlmacen.Where(t => t.ItemCode == x).FirstOrDefault().BatchNumbers.ForEach(r =>
|
// Lotes de todas las lineas del articulo (si el mismo lote esta en varias lineas se suma)
|
||||||
|
ListaDetalle_PorAlmacen.Where(t => t.ItemCode == x).SelectMany(t => t.BatchNumbers).GroupBy(r => r.BatchNumber).ToList().ForEach(g =>
|
||||||
{
|
{
|
||||||
ListLote.Add(new BE_StockTransferLineBatchNumber()
|
ListLote.Add(new BE_StockTransferLineBatchNumber()
|
||||||
{
|
{
|
||||||
BatchNumber = r.BatchNumber,
|
BatchNumber = g.Key,
|
||||||
Quantity = r.Quantity
|
Quantity = g.Sum(r => r.Quantity)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Transfer.StockTransferLines.Add(new BE_StockTransferLine()
|
Transfer.StockTransferLines.Add(new BE_StockTransferLine()
|
||||||
@@ -481,7 +523,7 @@ namespace Net.Data.WMS.Picking
|
|||||||
var Response_Reopen = invoicestRepository.ReOpen(_invoices.DocEntry).Result;
|
var Response_Reopen = invoicestRepository.ReOpen(_invoices.DocEntry).Result;
|
||||||
if (Response_Reopen.DocEntry == -1)
|
if (Response_Reopen.DocEntry == -1)
|
||||||
{
|
{
|
||||||
return resultadoTransaccion.GetInformacionResultado("SAP: La Factura no se puede reabrir", entidad);
|
return resultadoTransaccion.GetInformacionResultado("SAP: La Factura no se puede reabrir. " + Response_Reopen.Message, entidad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,7 +550,8 @@ namespace Net.Data.WMS.Picking
|
|||||||
entidad.Detalle.ForEach(x =>
|
entidad.Detalle.ForEach(x =>
|
||||||
{
|
{
|
||||||
var Item = _invoices.DocumentLines.ToList().FirstOrDefault(t => t.LineNum == x.Item);
|
var Item = _invoices.DocumentLines.ToList().FirstOrDefault(t => t.LineNum == x.Item);
|
||||||
if (Item != null)
|
// Solo lineas con diferencia a devolver (igual que DESPACHO): una linea completa daria cantidad 0
|
||||||
|
if (Item != null && Item.Quantity - x.CantidadPedida > 0)
|
||||||
{
|
{
|
||||||
creditNotesNotes.DocumentLines.Add(new BE_CreditNotesLine()
|
creditNotesNotes.DocumentLines.Add(new BE_CreditNotesLine()
|
||||||
{
|
{
|
||||||
@@ -572,12 +615,13 @@ namespace Net.Data.WMS.Picking
|
|||||||
ListaUnicaArticulo.ForEach(x =>
|
ListaUnicaArticulo.ForEach(x =>
|
||||||
{
|
{
|
||||||
var ListLote = new List<BE_StockTransferLineBatchNumber>();
|
var ListLote = new List<BE_StockTransferLineBatchNumber>();
|
||||||
ListaDetalle_PorAlmacen.Where(t => t.ItemCode == x).FirstOrDefault().BatchNumbers.ForEach(r =>
|
// Lotes de todas las lineas del articulo (si el mismo lote esta en varias lineas se suma)
|
||||||
|
ListaDetalle_PorAlmacen.Where(t => t.ItemCode == x).SelectMany(t => t.BatchNumbers).GroupBy(r => r.BatchNumber).ToList().ForEach(g =>
|
||||||
{
|
{
|
||||||
ListLote.Add(new BE_StockTransferLineBatchNumber()
|
ListLote.Add(new BE_StockTransferLineBatchNumber()
|
||||||
{
|
{
|
||||||
BatchNumber = r.BatchNumber,
|
BatchNumber = g.Key,
|
||||||
Quantity = r.Quantity
|
Quantity = g.Sum(r => r.Quantity)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Transfer.StockTransferLines.Add(new BE_StockTransferLine()
|
Transfer.StockTransferLines.Add(new BE_StockTransferLine()
|
||||||
|
|||||||
@@ -403,7 +403,8 @@ namespace Net.Data.WMS.Recibo
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
string Serie = SerieOrigen == "03" ? "BC10" : "FC10";
|
// Serie segun el TIPO de documento origen (03 = boleta), no segun su serie
|
||||||
|
string Serie = U_SYP_MDTO == "03" ? "BC10" : "FC10";
|
||||||
string Correlativo = HelperCorrelativo.Get(Serie);
|
string Correlativo = HelperCorrelativo.Get(Serie);
|
||||||
creditNotesNotes.DocCurrency = returnRequest.DocCurrency;
|
creditNotesNotes.DocCurrency = returnRequest.DocCurrency;
|
||||||
creditNotesNotes.CardCode = returnRequest.CardCode;
|
creditNotesNotes.CardCode = returnRequest.CardCode;
|
||||||
@@ -456,6 +457,10 @@ namespace Net.Data.WMS.Recibo
|
|||||||
//=== REALIZA DISTRIBUCION DE STOCK POR LOTE
|
//=== REALIZA DISTRIBUCION DE STOCK POR LOTE
|
||||||
creditNotesNotes.DocumentLines.ForEach(line =>
|
creditNotesNotes.DocumentLines.ForEach(line =>
|
||||||
{
|
{
|
||||||
|
// La linea nace con un lote del request (LoteProducto); se descarta para que
|
||||||
|
// los lotes finales sean solo los de la distribucion y sumen la cantidad de la linea
|
||||||
|
line.BatchNumbers.Clear();
|
||||||
|
|
||||||
#region CONSULTA A HANA
|
#region CONSULTA A HANA
|
||||||
|
|
||||||
var ListaStock = HelperStock.Get(line.ItemCode, line.WarehouseCode);
|
var ListaStock = HelperStock.Get(line.ItemCode, line.WarehouseCode);
|
||||||
@@ -492,6 +497,7 @@ namespace Net.Data.WMS.Recibo
|
|||||||
{
|
{
|
||||||
creditNotesNotes.DocumentLines.ForEach(line =>
|
creditNotesNotes.DocumentLines.ForEach(line =>
|
||||||
{
|
{
|
||||||
|
line.BatchNumbers.Clear();
|
||||||
var ReferenciaFactura = returnRequest.DocumentLines.FirstOrDefault(t => t.LineNum == line.LineNum);
|
var ReferenciaFactura = returnRequest.DocumentLines.FirstOrDefault(t => t.LineNum == line.LineNum);
|
||||||
var ListaStock = _Invoice.DocumentLines.FirstOrDefault(InvoiceLine => InvoiceLine.LineNum == ReferenciaFactura.BaseLine).BatchNumbers;
|
var ListaStock = _Invoice.DocumentLines.FirstOrDefault(InvoiceLine => InvoiceLine.LineNum == ReferenciaFactura.BaseLine).BatchNumbers;
|
||||||
if (ListaStock.Count > 0)
|
if (ListaStock.Count > 0)
|
||||||
@@ -556,12 +562,13 @@ namespace Net.Data.WMS.Recibo
|
|||||||
ListaUnicaArticulo.ForEach(x =>
|
ListaUnicaArticulo.ForEach(x =>
|
||||||
{
|
{
|
||||||
var ListLote = new List<BE_StockTransferLineBatchNumber>();
|
var ListLote = new List<BE_StockTransferLineBatchNumber>();
|
||||||
ListaDetalle_PorAlmacen.Where(t => t.ItemCode == x).FirstOrDefault().BatchNumbers.ForEach(r =>
|
// Lotes de todas las lineas del articulo (si el mismo lote esta en varias lineas se suma)
|
||||||
|
ListaDetalle_PorAlmacen.Where(t => t.ItemCode == x).SelectMany(t => t.BatchNumbers).GroupBy(r => r.BatchNumber).ToList().ForEach(g =>
|
||||||
{
|
{
|
||||||
ListLote.Add(new BE_StockTransferLineBatchNumber()
|
ListLote.Add(new BE_StockTransferLineBatchNumber()
|
||||||
{
|
{
|
||||||
BatchNumber = r.BatchNumber,
|
BatchNumber = g.Key,
|
||||||
Quantity = r.Quantity
|
Quantity = g.Sum(r => r.Quantity)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
Transfer.StockTransferLines.Add(new BE_StockTransferLine()
|
Transfer.StockTransferLines.Add(new BE_StockTransferLine()
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ namespace Net.Data.WMS.SolicitudTransferencia
|
|||||||
|
|
||||||
await connectServiceLayer.PatchNoContentAsync(
|
await connectServiceLayer.PatchNoContentAsync(
|
||||||
$"InventoryTransferRequests({docEntry})",
|
$"InventoryTransferRequests({docEntry})",
|
||||||
new { StockTransferLines = lines },
|
new { U_SYP_MDTS = "TSE", StockTransferLines = lines },
|
||||||
new Dictionary<string, string> { ["B1S-ReplaceCollectionsOnPatch"] = "true" });
|
new Dictionary<string, string> { ["B1S-ReplaceCollectionsOnPatch"] = "true" });
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
+58
-14
@@ -22,11 +22,51 @@ recorre esas mismas facturas con un `FOR` de su lado llamando otra vez al
|
|||||||
mismo endpoint pero en modo **cierre** (ahí sí se crean los documentos SAP),
|
mismo endpoint pero en modo **cierre** (ahí sí se crean los documentos SAP),
|
||||||
y al final cierra la hoja de ruta completa **una sola vez**.
|
y al final cierra la hoja de ruta completa **una sola vez**.
|
||||||
|
|
||||||
|
## Regla Proceso + Notificacion (versión 2.1.2.0)
|
||||||
|
|
||||||
|
`Notificacion` **solo se valida cuando `Proceso = "ULTIMA MILLA"`**. En los
|
||||||
|
demás procesos el campo se ignora.
|
||||||
|
|
||||||
|
| `Proceso` | `Notificacion` | Resultado |
|
||||||
|
|---|---|---|
|
||||||
|
| `ULTIMA MILLA` | `"cierre"` | Lógica completa: crea documentos en SAP (solicitud de devolución, estado 23). |
|
||||||
|
| `ULTIMA MILLA` | ausente u otro valor | Solo actualiza estado en HANA; **no** crea nada en SAP. |
|
||||||
|
| `DESPACHO` | cualquiera / ausente | Lógica completa siempre: NC y transferencias automáticas (estados 5 y 6). |
|
||||||
|
| `PICKING` | cualquiera / ausente | Lógica completa siempre: NC y transferencias automáticas (estado 13). |
|
||||||
|
|
||||||
|
Historial: en 2.1.1.0 el filtro se aplicaba a todos los procesos, por lo que
|
||||||
|
DESPACHO y PICKING no generaban la NC si no llegaba `"cierre"`. Corregido en
|
||||||
|
2.1.2.0.
|
||||||
|
|
||||||
|
## Lotes de la nota de crédito en DESPACHO (versión 2.1.4.0)
|
||||||
|
|
||||||
|
Se resuelve **línea por línea** según el documento origen de la línea de la factura:
|
||||||
|
|
||||||
|
| La línea de la factura tiene... | Los lotes salen de... |
|
||||||
|
|---|---|
|
||||||
|
| Entrega como origen (`BaseType = 15`) | La línea de la **Entrega** (`DeliveryNotes(BaseEntry)`, línea `BaseLine`). |
|
||||||
|
| Otro origen o ninguno | La **propia línea de la factura** (`LineNum`). |
|
||||||
|
|
||||||
|
Si hay lotes de origen y no cubren la cantidad a devolver, o no se puede leer
|
||||||
|
la Entrega, la API responde un error con la línea y el artículo en vez de
|
||||||
|
enviar lotes incompletos a SAP. Si no hay lotes de origen (artículo sin
|
||||||
|
control por lote) la línea se envía sin lotes. PICKING (estado 13) no cambia:
|
||||||
|
genera un lote nuevo por fecha y hora.
|
||||||
|
|
||||||
|
## Cantidades de la NC y de las transferencias (versión 2.1.6.0)
|
||||||
|
|
||||||
|
- **Cantidad de la línea de NC** (DESPACHO y PICKING estado 13): `cantidad
|
||||||
|
facturada − CantidadPedida`; solo entran las líneas con resultado mayor a 0.
|
||||||
|
- **Transferencia automática** (cuando `U_ITC_ALMDES` difiere del almacén de la
|
||||||
|
línea): una línea por artículo, con la cantidad sumada de las líneas de la NC
|
||||||
|
de ese par origen/destino y los lotes de todas esas líneas (el mismo lote en
|
||||||
|
varias líneas se suma).
|
||||||
|
|
||||||
## Resumen del contrato
|
## Resumen del contrato
|
||||||
|
|
||||||
| Método | Ruta | Cambia hoy | Qué hace |
|
| Método | Ruta | Cambia hoy | Qué hace |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `POST` | `/api/picking` | **Sí** — agrega campo `Notificacion` | `"cierre"` → lógica actual completa (crea documento SAP); cualquier otro valor/ausente → solo actualiza estado en HANA, nunca toca SAP. |
|
| `POST` | `/api/picking` | **Sí** — agrega campo `Notificacion` | **Solo con `Proceso = "ULTIMA MILLA"`**: `"cierre"` → lógica completa (crea documento SAP); cualquier otro valor/ausente → solo actualiza estado en HANA, nunca toca SAP. Con `DESPACHO`, `PICKING` y demás procesos el campo se ignora y la lógica corre siempre (NC y transferencias). |
|
||||||
| `POST` | `/api/picking/ruta` | No | Sin cambios — `CreateHojaRuta` ya existe y sigue igual. |
|
| `POST` | `/api/picking/ruta` | No | Sin cambios — `CreateHojaRuta` ya existe y sigue igual. |
|
||||||
| `POST` | `/api/picking/hojaruta/{docEntry}/cerrar` | **Nuevo** | Cierra el UDO `ARD_PHR` completo en SAP. Sin body. |
|
| `POST` | `/api/picking/hojaruta/{docEntry}/cerrar` | **Nuevo** | Cierra el UDO `ARD_PHR` completo en SAP. Sin body. |
|
||||||
|
|
||||||
@@ -36,7 +76,7 @@ y al final cierra la hoja de ruta completa **una sola vez**.
|
|||||||
|
|
||||||
**Archivo**: `Net.Business.Entities/WMS/Picking/BE_PickingRequest.cs` — agregar:
|
**Archivo**: `Net.Business.Entities/WMS/Picking/BE_PickingRequest.cs` — agregar:
|
||||||
```csharp
|
```csharp
|
||||||
public string Notificacion { get; set; } // "preliminar" | "cierre"; cualquier otro valor o ausente = "preliminar"
|
public string Notificacion { get; set; } // solo se evalua con Proceso "ULTIMA MILLA": "cierre" | otro/ausente = preliminar
|
||||||
```
|
```
|
||||||
|
|
||||||
**Archivo**: `Net.Business.DTO/WMS/Picking/Dto_PickingRequest.cs` — agregar la
|
**Archivo**: `Net.Business.DTO/WMS/Picking/Dto_PickingRequest.cs` — agregar la
|
||||||
@@ -73,8 +113,10 @@ alcanza con un `if` adentro del mismo método).
|
|||||||
HelperProcesoPiciking.Set(entidad.Proceso, entidad.IdEstadoCubico, entidad.DocEntry, entidad.CodMotivo, Proceso.Code);
|
HelperProcesoPiciking.Set(entidad.Proceso, entidad.IdEstadoCubico, entidad.DocEntry, entidad.CodMotivo, Proceso.Code);
|
||||||
// <-- linea 96 actual, sin tocar
|
// <-- linea 96 actual, sin tocar
|
||||||
|
|
||||||
// === NUEVO: notificacion preliminar (diurna) - nunca toca SAP
|
// === Solo ULTIMA MILLA: notificacion preliminar (diurna) - nunca toca SAP.
|
||||||
if (!string.Equals(entidad.Notificacion, "cierre", StringComparison.OrdinalIgnoreCase))
|
// DESPACHO / PICKING no dependen de Notificacion.
|
||||||
|
if (string.Equals(entidad.Proceso, "ULTIMA MILLA", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& !string.Equals(entidad.Notificacion, "cierre", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return resultadoTransaccion.GetInformacionResultado(entidad.DocEntry, entidad.NumOrden, "Estado actualizado correctamente", entidad);
|
return resultadoTransaccion.GetInformacionResultado(entidad.DocEntry, entidad.NumOrden, "Estado actualizado correctamente", entidad);
|
||||||
}
|
}
|
||||||
@@ -85,8 +127,10 @@ if (!string.Equals(entidad.Notificacion, "cierre", StringComparison.OrdinalIgnor
|
|||||||
```
|
```
|
||||||
|
|
||||||
Es decir: **todo lo que hoy hace `Create()` (líneas 45-341 completas)** sigue
|
Es decir: **todo lo que hoy hace `Create()` (líneas 45-341 completas)** sigue
|
||||||
siendo exactamente la lógica de `notificacion == "cierre"` — no se toca nada
|
siendo exactamente la lógica de cierre — no se toca nada de ahí. Solo se
|
||||||
de ahí. Solo se agrega el `if` de corte después de la línea 96.
|
agrega el `if` de corte después de la línea 96, y **únicamente para
|
||||||
|
`ULTIMA MILLA`**. Para `DESPACHO` y `PICKING` la NC se genera sin importar
|
||||||
|
`Notificacion`.
|
||||||
|
|
||||||
> **Nota de contrato**: `detalle` ya es obligatorio hoy en este endpoint (la
|
> **Nota de contrato**: `detalle` ya es obligatorio hoy en este endpoint (la
|
||||||
> validación de arriba lo necesita para desambiguar `Existe > 1`), así que no
|
> validación de arriba lo necesita para desambiguar `Existe > 1`), así que no
|
||||||
@@ -96,15 +140,15 @@ de ahí. Solo se agrega el `if` de corte después de la línea 96.
|
|||||||
|
|
||||||
### Bodies de ejemplo
|
### Bodies de ejemplo
|
||||||
|
|
||||||
**Notificación preliminar** (reparto en curso — `Notificacion` ausente o
|
**Notificación preliminar** (solo `ULTIMA MILLA`, reparto en curso —
|
||||||
distinto de `"cierre"`):
|
`Notificacion` ausente o distinto de `"cierre"`):
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"numOrden": "OT-2026-001",
|
"numOrden": "OT-2026-001",
|
||||||
"docEntry": 500,
|
"docEntry": 500,
|
||||||
"proceso": "DESPACHO",
|
"proceso": "ULTIMA MILLA",
|
||||||
"codMotivo": "M01",
|
"codMotivo": "M01",
|
||||||
"idEstadoCubico": 6,
|
"idEstadoCubico": 23,
|
||||||
"codigoAlmacen": "ALM01",
|
"codigoAlmacen": "ALM01",
|
||||||
"detalle": [
|
"detalle": [
|
||||||
{ "item": 0, "codigoArticulo": "ART-001", "cantidadPedida": 3, "estado": "C" }
|
{ "item": 0, "codigoArticulo": "ART-001", "cantidadPedida": 3, "estado": "C" }
|
||||||
@@ -112,15 +156,15 @@ distinto de `"cierre"`):
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Cierre** (mismo shape, agrega `notificacion: "cierre"` — crea el documento
|
**Cierre** (`ULTIMA MILLA`, mismo shape, agrega `notificacion: "cierre"` —
|
||||||
SAP real, misma respuesta que hoy):
|
crea el documento SAP real, misma respuesta que hoy):
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"numOrden": "OT-2026-001",
|
"numOrden": "OT-2026-001",
|
||||||
"docEntry": 500,
|
"docEntry": 500,
|
||||||
"proceso": "DESPACHO",
|
"proceso": "ULTIMA MILLA",
|
||||||
"codMotivo": "M01",
|
"codMotivo": "M01",
|
||||||
"idEstadoCubico": 6,
|
"idEstadoCubico": 23,
|
||||||
"codigoAlmacen": "ALM01",
|
"codigoAlmacen": "ALM01",
|
||||||
"notificacion": "cierre",
|
"notificacion": "cierre",
|
||||||
"detalle": [
|
"detalle": [
|
||||||
|
|||||||
Reference in new issue
Block a user