namespace Domain.Dtos.Stock { /// /// Contexto de lo ya agregado en la expedición (no se persiste). /// Sirve para evitar duplicados y calcular disponible efectivo. /// public class StockSnapshotItem { public int ProductId { get; set; } public string? ProductName { get; set; } = string.Empty; public int LocationId { get; set; } public string Batch { get; set; } = string.Empty; public DateOnly? Expiration { get; set; } public string Serial { get; set; } = string.Empty; /// 1=No aplica, 2=Por cantidad, 3=Por lote y vencimiento (solo UI/validación; no se persiste). public int TraceabilityType { get; set; } /// Cantidad ya agregada en la expedición para esta clave de negocio. public decimal Quantity { get; set; } /// Clave de fusión para idempotencia (no se persiste). public string BusinessKey { get; set; } = string.Empty; } public static class StockKeys { public static string BuildBusinessKey(int productId, int locationId, string batch, DateOnly? expiration, string serial) { if (!string.IsNullOrWhiteSpace(serial)) return $"P{productId}-S{serial.Trim()}"; batch = batch?.Trim() ?? string.Empty; if (!string.IsNullOrEmpty(batch) && expiration.HasValue) return $"P{productId}-L{locationId}-B{batch}-E{expiration.Value:yyyyMMdd}"; if (!string.IsNullOrEmpty(batch)) return $"P{productId}-L{locationId}-B{batch}"; return $"P{productId}-L{locationId}"; } } }