2026-10-16 00:22:11 -05:00
using Net.Business.Entities.WMS.Transferencia ;
using System ;
using System.Collections.Generic ;
using System.Linq ;
namespace Net.Data.WMS.Transferencia
{
// Elige la Entrada de Mercaderia de una Factura de Reserva que corresponde a una transferencia desde ALM99.
// WMS recibe por partes: cada entrada tiene su propio juego de articulos/cantidades, y WMS notifica una
// transferencia por entrada con ese mismo juego (se compara solo ItemCode y cantidad, no el numero de item).
2026-10-16 07:38:01 -05:00
// Reglas: coincidencia exacta de articulos y cantidades (sumadas por articulo); entre las que coinciden se toma la mas antigua
// (menor DocEntry) sin transferencia; si todas las que coinciden ya estan transferidas se rechaza para no duplicar.
// Ver docs/TRANSFERENCIA_IMPORTACION.md.
2026-10-16 00:22:11 -05:00
public static class EntradaImportacion
{
private const decimal Tolerancia = 0.0001 m ;
// Devuelve el DocEntry de la entrada elegida, o 0 con el motivo en "error".
public static int Elegir ( string docNumFactura , List < BE_EntradaImportacionLinea > filas , List < BE_TransferenciaDetalle > detalle , out string error )
{
error = null ;
var pedido = ( detalle ?? new List < BE_TransferenciaDetalle >())
. GroupBy ( x => x . CodigoArticulo )
. ToDictionary ( g => g . Key , g => g . Sum ( x => x . CantidadPedida ));
var entradas = filas . GroupBy ( x => x . DocEntry ). OrderBy ( g => g . Key ). ToList ();
var coincidentes = entradas . Where ( g => Coincide ( g , pedido )). ToList ();
// La mas antigua que aun no tenga transferencia
var libre = coincidentes . FirstOrDefault ( g => ! g . Any ( l => l . TransferenciaDocEntry > 0 ));
if ( libre != null )
{
return libre . Key ;
}
if ( coincidentes . Count > 0 )
{
var detalleYa = coincidentes . Select ( g => $"entrada {g.First().DocNum} (DocEntry {g.Key}) ya transferida en la transferencia {g.First(l => l.TransferenciaDocEntry > 0).TransferenciaDocEntry}" );
error = $"SAP: Todas las entradas de la factura de reserva {docNumFactura} con esos articulos y cantidades ya estan transferidas: {string.Join(" ; ", detalleYa)}" ;
return 0 ;
}
var pendientes = entradas . Where ( g => ! g . Any ( l => l . TransferenciaDocEntry > 0 )). Select ( g => $"{g.First().DocNum}" );
error = $"SAP: Ninguna entrada de la factura de reserva {docNumFactura} coincide con los articulos y cantidades enviados. " +
$"Entradas pendientes de transferir (DocNum): {(pendientes.Any() ? string.Join(" , ", pendientes) : " ninguna ")}" ;
return 0 ;
}
private static bool Coincide ( IGrouping < int , BE_EntradaImportacionLinea > entrada , Dictionary < string , decimal > pedido )
{
var enEntrada = entrada . GroupBy ( x => x . ItemCode ). ToDictionary ( g => g . Key , g => g . Sum ( x => x . Quantity ));
if ( enEntrada . Count != pedido . Count ) return false ;
return enEntrada . All ( kv => pedido . TryGetValue ( kv . Key , out decimal cant ) && Math . Abs ( cant - kv . Value ) <= Tolerancia );
}
}
}