using System; using System.Collections.Generic; using System.Linq; using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.Wpf; using InABox.WPF; namespace PRSDesktop; public static class StockUtils { public static bool RecalculateHoldingsOfLocations(Guid[] locationIDs, out List report) { return RecalculateHoldings(new Filter(x => x.Location.ID).InList(locationIDs), out report); } public static bool RecalculateHoldingsOfProducts(Guid[] productIDs, out List report) { return RecalculateHoldings(new Filter(x => x.Product.ID).InList(productIDs), out report); } public static bool RecalculateHoldings(Filter filter, out List report) { bool result = false; Dictionary messages = new(); void AddMessage(String type) { messages.TryGetValue(type, out int count); messages[type] = ++count; } Progress.ShowModal("Recalculating", progress => { progress.Report("Loading Data"); MultiQuery query = new MultiQuery(); query.Add( filter.Cast(), Columns.Required().Add(x => x.ID) .Add(x => x.Location.ID) .Add(x => x.Product.ID) .Add(x => x.Job.ID) .Add(x => x.Style.ID) .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local) .Add(x => x.Units) .Add(x => x.AverageValue) .Add(x => x.Available) .Add(x => x.Qty) .Add(x => x.Weight) .Add(x => x.Value) ); query.Add( filter.Cast(), Columns.None().Add(x => x.ID) .Add(x=>x.Location.ID) .Add(x => x.Product.ID) .Add(x => x.Job.ID) .Add(x => x.Style.ID) .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local) .Add(x => x.Units) .Add(x => x.Cost) .Add(x => x.JobRequisitionItem.ID) ); query.Query(); var holdings = query.Get(); var toDelete = new List(); var movements = query.Get(); double movementcount = (double)movements.Rows.Count; progress.Report("Processing"); var updates = new List(); while (movements.Rows.Any()) { double percent = ((movementcount - movements.Rows.Count) / movementcount) * 100.0; progress.Report($"Processing ({percent:F2}% complete)"); var first = movements.Rows.First(); var selected = movements.Rows.Where(x => x.IsEqualTo(first)).ToList(); var holdingrow = holdings.Rows.FirstOrDefault(x => x.IsEqualTo(first)); StockHolding holding = null; if (holdingrow != null) { holdings.Rows.Remove(holdingrow); holding = holdingrow.ToObject(); } if (holding == null) { var firstmovement = first.ToObject(); holding = new StockHolding(); holding.Location.ID = firstmovement.Location.ID; holding.Product.ID = firstmovement.Product.ID; holding.Style.ID = firstmovement.Style.ID; holding.Job.ID = firstmovement.Job.ID; holding.Dimensions.CopyFrom(firstmovement.Dimensions); } holding.Recalculate(selected.ToObjects()); if (holding.Units.IsEffectivelyEqual(0.0) && holding.Available.IsEffectivelyEqual(0.0)) { if (holding.ID != Guid.Empty) toDelete.Add(holding); } else if (holding.IsChanged()) { AddMessage(holding.ID != Guid.Empty ? "updated" : "added"); updates.Add(holding); } foreach (var row in selected) movements.Rows.Remove(row); } toDelete.AddRange(holdings.Rows.ToObjects()); foreach (var holding in toDelete) AddMessage("deleted"); if (updates.Any()) { result = true; progress.Report($"Updating {updates.Count} Holdings"); new Client().Save(updates.Where(x => x.IsChanged()), "Updated by Recalculation"); } if (toDelete.Any()) { result = true; progress.Report($"Deleting {toDelete.Count} Holdings"); new Client().Delete(toDelete, "Removed by Recalculation"); } }); report = new List(); if (messages.Any()) report.AddRange(messages.Select(x => $"{x.Value} holdings {x.Key}")); else report.Add("Nothing to Update"); return result; } }