Browse Source

Order screen now can split/combine based on Jobs and JRIs.

Kenric Nugteren 1 year ago
parent
commit
219b8c80f8

+ 15 - 2
prs.desktop/Panels/Stock Forecast/OrderScreen/StockForecastOrderScreen.xaml

@@ -5,7 +5,7 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:PRSDesktop"
         mc:Ignorable="d"
-        Title="Order Stock" MinHeight="400" Width="1400"
+        Title="Order Stock" MinHeight="400" Width="1400" MaxHeight="800"
         WindowStartupLocation="CenterOwner"
         SizeToContent="Height"
         x:Name="Window">
@@ -42,11 +42,24 @@
                 Margin="0,5,5,5"
                 MinWidth="140"
                 SelectionChanged="OrderStrategyBox_OnSelectionChanged"/>
+            
+            <Label 
+                DockPanel.Dock="Left" 
+                Margin="0,5,5,5"
+                Content="Mode: "
+                VerticalAlignment="Stretch" 
+                VerticalContentAlignment="Center"/>
+            <ComboBox 
+                x:Name="CombineModeBox" 
+                DockPanel.Dock="Left" 
+                Margin="0,5,5,5"
+                MinWidth="140"
+                SelectionChanged="CollapseModeBox_SelectionChanged"/>
 
             <Button x:Name="StyleSelectButton"
                     DockPanel.Dock="Left"
                     IsEnabled="False"
-                    Margin="5" Padding="5"
+                    Margin="0,5,5,5" Padding="5"
                     Content="Select Style"
                     Click="StyleSelectButton_Click"/>
 

+ 18 - 0
prs.desktop/Panels/Stock Forecast/OrderScreen/StockForecastOrderScreen.xaml.cs

@@ -62,6 +62,12 @@ public partial class StockForecastOrderScreen : Window, INotifyPropertyChanged
         set => Grid.OrderStrategy = value;
     }
 
+    public StockForecastCombineMode CombineMode
+    {
+        get => Grid.CombineMode;
+        set => Grid.CombineMode = value;
+    }
+
     public IEnumerable<StockForecastOrderingResult> Results => Grid.Results;
 
     public StockForecastOrderScreen(List<StockForecastOrderData> items, bool allowstockOrder = true)
@@ -97,6 +103,13 @@ public partial class StockForecastOrderScreen : Window, INotifyPropertyChanged
         OrderStrategyBox.VerticalContentAlignment = VerticalAlignment.Center;
         OrderStrategyBox.Bind(ComboBox.SelectedValueProperty, this, x => x.Strategy);
 
+        CombineModeBox.ItemsSource = Enum.GetValues<StockForecastCombineMode>()
+            .Select(x => new KeyValuePair<StockForecastCombineMode, string>(x, CoreUtils.Neatify(x.ToString())));
+        CombineModeBox.SelectedValuePath = "Key";
+        CombineModeBox.DisplayMemberPath = "Value";
+        CombineModeBox.VerticalContentAlignment = VerticalAlignment.Center;
+        CombineModeBox.Bind(ComboBox.SelectedValueProperty, this, x => x.CombineMode);
+
         Grid.OrderData = items;
         Grid.Refresh(true, true);
     }
@@ -249,4 +262,9 @@ public partial class StockForecastOrderScreen : Window, INotifyPropertyChanged
     {
         StyleSelectButton.IsEnabled = e.Rows is not null && e.Rows.Length > 0;
     }
+
+    private void CollapseModeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+
+    }
 }

+ 148 - 18
prs.desktop/Panels/Stock Forecast/OrderScreen/StockForecastOrderingGrid.cs

@@ -148,6 +148,12 @@ public class StockOrderingItem : BaseObject
     [EnumLookupEditor(typeof(SupplierProductOrderStrategy))]
     public SupplierProductOrderStrategy OrderStrategy { get; set; }
 
+    public JobLink Job => InitializeField(ref _job, nameof(Job));
+    private JobLink? _job;
+
+    public JobRequisitionItemLink JRI => InitializeField(ref _jri, nameof(JRI));
+    private JobRequisitionItemLink? _jri;
+
     private Dictionary<StockForecastBreakupKey, double> JobRequiredQuantities { get; set; } = new()
     {
         { new(Guid.Empty, Guid.Empty), 0.0 }
@@ -210,6 +216,13 @@ public enum StockForecastOrderingStrategy
     LowestOverstock
 }
 
+public enum StockForecastCombineMode
+{
+    Combined,
+    SplitJobs,
+    SplitRequisitionItems
+}
+
 public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>, ISpecificGrid
 {
     #region Internal Data + Caches
@@ -244,7 +257,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
                 if (OrderData != null)
                 {
                     CalculateQuantities(true);
-                    UIComponent.UpdateOrderType(OrderType);
+                    UIComponent.Update();
                     foreach(var control in QuantityControls)
                     {
                         control.UpdateControl(OrderType);
@@ -276,6 +289,22 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
         }
     }
 
+    private StockForecastCombineMode _combineMode = StockForecastCombineMode.Combined;
+    public StockForecastCombineMode CombineMode
+    {
+        get => _combineMode;
+        set
+        {
+            _combineMode = value;
+            if(OrderData != null)
+            {
+                CalculateQuantities(true);
+                UIComponent.Update();
+                Refresh(true, true); 
+            }
+        }
+    }
+
     public double TotalQuantity => Items.Sum(x => x.GetTotalQuantity(OrderType));
     public IEnumerable<StockForecastOrderingResult> Results
     {
@@ -361,12 +390,17 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
             Parent = grid;
             Grid = grid;
 
-            UpdateOrderType(grid.OrderType);
+            Update();
         }
 
-        public void UpdateOrderType(StockForecastOrderingType type)
+        public void Update()
         {
-            DataGrid.FrozenColumnCount = 8;
+            DataGrid.FrozenColumnCount = 8 + (Grid.CombineMode switch
+            {
+                StockForecastCombineMode.SplitJobs => 1,
+                StockForecastCombineMode.SplitRequisitionItems => 3,
+                StockForecastCombineMode.Combined or _ => 0
+            });
         }
 
         protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column)
@@ -467,20 +501,101 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
 
         if (recreateItems)
         {
-            Items.Clear();
-            foreach(var dataItem in OrderData)
+            StockOrderingItem CreateItem(StockForecastOrderData dataItem)
             {
                 var item = new StockOrderingItem();
                 item.Product.CopyFrom(dataItem.Product);
                 item.Style.CopyFrom(dataItem.Style);
                 item.Dimensions.CopyFrom(dataItem.Dimensions);
                 item.OrderStrategy = CastOrderStrategyToProductOrderStrategy(OrderStrategy, item.Product.OrderStrategy);
-                item.RequiredQuantity = dataItem.RequiredQuantity;
-                foreach(var breakup in dataItem.GetRequiredQuantities())
+                return item;
+            }
+
+            Items.Clear();
+            foreach(var dataItem in OrderData)
+            {
+                if(CombineMode == StockForecastCombineMode.Combined)
                 {
-                    item.SetJobRequiredQuantity(breakup.JobID, breakup.JobRequiItemID, breakup.Quantity);
+                    var item = CreateItem(dataItem);
+                    item.RequiredQuantity = dataItem.RequiredQuantity;
+                    foreach(var breakup in dataItem.GetRequiredQuantities())
+                    {
+                        item.SetJobRequiredQuantity(breakup.JobID, breakup.JobRequiItemID, breakup.Quantity);
+                    }
+                    Items.Add(item);
+                }
+                else if(CombineMode == StockForecastCombineMode.SplitJobs)
+                {
+                    var jobItems = new Dictionary<Guid, StockOrderingItem>();
+                    foreach(var breakup in dataItem.GetRequiredQuantities())
+                    {
+                        if(!jobItems.TryGetValue(breakup.JobID, out var item))
+                        {
+                            item = CreateItem(dataItem);
+                            item.Job.ID = breakup.JobID;
+                            Items.Add(item);
+                            jobItems.Add(breakup.JobID, item);
+                        }
+                        item.RequiredQuantity += breakup.Quantity;
+                        item.SetJobRequiredQuantity(breakup.JobID, breakup.JobRequiItemID, breakup.Quantity);
+                    }
+                    LoadJobData(jobItems.Keys);
+                    foreach(var item in Items)
+                    {
+                        if(JobDetails.TryGetValue(item.Job.ID, out var jobDetails))
+                        {
+                            item.Job.Synchronise(jobDetails);
+                        }
+                    }
+                    Items.Sort((a, b) =>
+                    {
+                        var ret = a.Product.Code.CompareTo(b.Product.Code);
+                        if (ret == 0)
+                        {
+                            ret = a.Job.JobNumber.CompareTo(b.Job.JobNumber);
+                        }
+                        return ret;
+                    });
+                }
+                else
+                {
+                    foreach(var breakup in dataItem.GetRequiredQuantities())
+                    {
+                        var item = CreateItem(dataItem);
+                        item.RequiredQuantity = breakup.Quantity;
+                        item.Job.ID = breakup.JobID;
+                        item.JRI.ID = breakup.JobRequiItemID;
+                        item.SetJobRequiredQuantity(breakup.JobID, breakup.JobRequiItemID, breakup.Quantity);
+                        Items.Add(item);
+                    }
+                    LoadJobData(Items.Select(x => x.Job.ID));
+                    LoadJobRequiData(Items.Select(x => x.JRI.ID));
+                    foreach(var item in Items)
+                    {
+                        if(JobDetails.TryGetValue(item.Job.ID, out var jobDetails))
+                        {
+                            item.Job.Synchronise(jobDetails);
+                        }
+                        if(JobRequiDetails.TryGetValue(item.JRI.ID, out var jriDetails))
+                        {
+                            item.JRI.Synchronise(jriDetails);
+                        }
+                    }
+
+                    Items.Sort((a, b) =>
+                    {
+                        var ret = a.Product.Code.CompareTo(b.Product.Code);
+                        if (ret == 0)
+                        {
+                            ret = a.Job.JobNumber.CompareTo(b.Job.JobNumber);
+                        }
+                        if (ret == 0)
+                        {
+                            ret = a.JRI.Requisition.Number.CompareTo(b.JRI.Requisition.Number);
+                        }
+                        return ret;
+                    });
                 }
-                Items.Add(item);
             }
         }
 
@@ -507,12 +622,22 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
 
     #region Order Strategy
 
-    private SupplierProduct? CalculateSupplierProduct(StockOrderingItem item, int supplierIdx)
+    private IEnumerable<SupplierProduct> AvailableSupplierProducts(StockOrderingItem item, int supplierIdx)
     {
         var supplierProducts = string.IsNullOrWhiteSpace(item.Dimensions.Unit.Conversion)
             ? SupplierProducts.Where(x => x.Dimensions.Equals(item.Dimensions))
             : SupplierProducts;
-        var supplierProduct = SelectSupplierProduct(supplierProducts.Where(x => x.Product.ID == item.Product.ID && x.Style.ID == item.Style.ID && x.SupplierLink.ID == Suppliers[supplierIdx].ID), item);
+        supplierProducts = supplierProducts.Where(x => x.Product.ID == item.Product.ID && x.Style.ID == item.Style.ID && x.SupplierLink.ID == Suppliers[supplierIdx].ID);
+        if(CombineMode == StockForecastCombineMode.SplitJobs || CombineMode == StockForecastCombineMode.SplitRequisitionItems)
+        {
+            supplierProducts = supplierProducts.Where(x => x.Job.ID == item.Job.ID || x.Job.ID == Guid.Empty);
+        }
+        return supplierProducts;
+    }
+
+    private SupplierProduct? CalculateSupplierProduct(StockOrderingItem item, int supplierIdx)
+    {
+        var supplierProduct = SelectSupplierProduct(AvailableSupplierProducts(item, supplierIdx), item);
 
         var qty = item.GetQuantity(supplierIdx);
         qty.SupplierProduct = supplierProduct;
@@ -646,6 +771,15 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
         var columns = new DynamicGridColumns();
         columns.Add<StockOrderingItem, string>(x => x.Product.Code, 120, "Product Code", "", Alignment.MiddleCenter);
         columns.Add<StockOrderingItem, string>(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleLeft);
+        if(CombineMode == StockForecastCombineMode.SplitJobs || CombineMode == StockForecastCombineMode.SplitRequisitionItems)
+        {
+            columns.Add<StockOrderingItem, string>(x => x.Job.JobNumber, width: 70);
+        }
+        if(CombineMode == StockForecastCombineMode.SplitRequisitionItems)
+        {
+            columns.Add<StockOrderingItem, int>(x => x.JRI.Requisition.Number, width: 50, alignment: Alignment.MiddleCenter);
+            columns.Add<StockOrderingItem, string>(x => x.JRI.Requisition.Description, width: 200);
+        }
         columns.Add<StockOrderingItem, string>(x => x.Dimensions.UnitSize, 80, "Size", "", Alignment.MiddleCenter);
         columns.Add<StockOrderingItem, string>(x => x.Style.Code, 80, "Style", "", Alignment.MiddleCenter);
         columns.Add<StockOrderingItem, double>(x => x.RequiredQuantity, 80, "Required", "", Alignment.MiddleCenter);
@@ -900,11 +1034,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
             var comboBox = new ComboBox();
             comboBox.Tag = idx;
 
-            var supplierProducts = string.IsNullOrWhiteSpace(instance.Dimensions.Unit.Conversion)
-                ? SupplierProducts.Where(x => x.Dimensions.Equals(instance.Dimensions))
-                : SupplierProducts;
-
-            var items = supplierProducts.Where(x => x.SupplierLink.ID == Suppliers[idx].ID && x.Product.ID == instance.Product.ID && x.Style.ID == instance.Style.ID)
+            var items = AvailableSupplierProducts(instance, idx)
                 .Select(x => new KeyValuePair<SupplierProduct?, string>(x, x.Job.ID == Guid.Empty ? x.Dimensions.UnitSize : $"Job {x.Job.JobNumber}: {x.Dimensions.UnitSize}"));
             if (items.Any())
                 items = items.Prepend(new KeyValuePair<SupplierProduct?, string>(null, ""));
@@ -1127,7 +1257,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockOrderingItem>
 
     private void LoadJobData(IEnumerable<Guid> ids)
     {
-        var neededIDs = ids.Where(x => x != Guid.Empty && !JobDetails.ContainsKey(x)).ToArray();
+        var neededIDs = ids.Where(x => x != Guid.Empty && !JobDetails.ContainsKey(x)).Distinct().ToArray();
         if(neededIDs.Length > 0)
         {
             var details = Client.Query(