NC de DESPACHO: lotes de la Entrega origen o de la factura, linea por linea. Versión 2.1.4.0

Si la linea de la factura viene de una Entrega (BaseType 15) los lotes se
toman de la linea de la Entrega (BaseLine); si no, de la linea de la factura
(LineNum). Se valida que los lotes cubran la cantidad y se devuelve un error
claro por linea en vez del error generico de SAP.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-14 10:29:02 -05:00
1 parent 6386070f4e
commit 14fffa8ba4
6 files changed
+94 -5

No files matched your search

@@ -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.3</Version> <Version>2.1.4</Version>
<AssemblyVersion>2.1.3.0</AssemblyVersion> <AssemblyVersion>2.1.4.0</AssemblyVersion>
<FileVersion>2.1.3.0</FileVersion> <FileVersion>2.1.4.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
@@ -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();
+41 -1
View File
@@ -213,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;
@@ -240,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;
+15
View File
@@ -38,6 +38,21 @@ 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 DESPACHO y PICKING no generaban la NC si no llegaba `"cierre"`. Corregido en
2.1.2.0. 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.
## Resumen del contrato ## Resumen del contrato
| Método | Ruta | Cambia hoy | Qué hace | | Método | Ruta | Cambia hoy | Qué hace |