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). // 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. public static class EntradaImportacion { private const decimal Tolerancia = 0.0001m; // Devuelve el DocEntry de la entrada elegida, o 0 con el motivo en "error". public static int Elegir(string docNumFactura, List filas, List detalle, out string error) { error = null; var pedido = (detalle ?? new List()) .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 entrada, Dictionary 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); } } }