Преглед изворни кода

Merge remote-tracking branch 'origin/kenric' into frank

frogsoftware пре 1 година
родитељ
комит
76c944bd83

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

@@ -5,7 +5,8 @@
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:PRSDesktop.Panels.StockForecast.OrderScreen"
         mc:Ignorable="d"
-        Title="Order Stock" Height="450" Width="1000"
+        Title="Order Stock" Height="800" Width="1200"
+        WindowStartupLocation="CenterScreen"
         x:Name="Window">
     <Grid DataContext="{Binding ElementName=Window}">
         <Grid.RowDefinitions>

+ 122 - 14
prs.desktop/Panels/Stock Forecast/OrderScreen/StockForecastOrderingGrid.cs

@@ -191,6 +191,11 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
         }
     }
 
+    public StockForecastOrderingGrid()
+    {
+        HiddenColumns.Add(x => x.Product.Image.ID);
+    }
+
     #region UI Component
 
     private Component? _uiComponent;
@@ -214,6 +219,8 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
         {
             Parent = grid;
             Grid = grid;
+
+            DataGrid.FrozenColumnCount = 7;
         }
 
         protected override Brush? GetCellSelectionBackgroundBrush()
@@ -269,6 +276,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
         options.Clear().Add(DynamicGridOption.FilterRows);
     }
 
+    private bool _loadedData = false;
     private void LoadData()
     {
         var supplierColumns = new Columns<SupplierProduct>(x => x.ID)
@@ -293,20 +301,27 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
             var quantities = new StockForecastOrderingItemQuantity[Suppliers.Length];
             for(int i = 0; i < Suppliers.Length; ++i)
             {
-                var qty = new StockForecastOrderingItemQuantity();
-                quantities[i] = qty;
-                qty.Changed += () =>
-                {
-                    var row = Data.Rows[itemIdx];
-                    InvalidateRow(row);
-                    DoChanged();
-                };
+                quantities[i] = CreateQuantity(itemIdx);
             }
 
             item.SetQuantities(quantities);
         }
 
         CalculateQuantities();
+
+        _loadedData = true;
+    }
+
+    private StockForecastOrderingItemQuantity CreateQuantity(int itemIdx)
+    {
+        var qty = new StockForecastOrderingItemQuantity();
+        qty.Changed += () =>
+        {
+            var row = Data.Rows[itemIdx];
+            InvalidateRow(row);
+            DoChanged();
+        };
+        return qty;
     }
 
     private void CalculateQuantities()
@@ -359,15 +374,21 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 
     protected override DynamicGridColumns LoadColumns()
     {
-        LoadData();
+        if (!_loadedData)
+        {
+            LoadData();
+        }
+        ActionColumns.Clear();
 
         ActionColumns.Add(new DynamicImageColumn(Warning_Image) { Position = DynamicActionColumnPosition.Start });
+        ActionColumns.Add(new DynamicImagePreviewColumn<StockForecastOrderingItem>(x => x.Product.Image) { Position = DynamicActionColumnPosition.Start });
 
         var columns = new DynamicGridColumns();
-        columns.Add<StockForecastOrderingItem, string>(x => x.Product.Code, 120, "Product", "", Alignment.MiddleCenter);
-        columns.Add<StockForecastOrderingItem, string>(x => x.Style.Code, 120, "Style", "", Alignment.MiddleCenter);
-        columns.Add<StockForecastOrderingItem, string>(x => x.Dimensions.UnitSize, 0, "Size", "", Alignment.MiddleLeft);
-        columns.Add<StockForecastOrderingItem, double>(x => x.RequiredQuantity, 0, "Required", "", Alignment.MiddleLeft);
+        columns.Add<StockForecastOrderingItem, string>(x => x.Product.Code, 120, "Product Code", "", Alignment.MiddleCenter);
+        columns.Add<StockForecastOrderingItem, string>(x => x.Product.Name, 200, "Product Name", "", Alignment.MiddleLeft);
+        columns.Add<StockForecastOrderingItem, string>(x => x.Style.Code, 80, "Style", "", Alignment.MiddleCenter);
+        columns.Add<StockForecastOrderingItem, string>(x => x.Dimensions.UnitSize, 80, "Size", "", Alignment.MiddleCenter);
+        columns.Add<StockForecastOrderingItem, double>(x => x.RequiredQuantity, 80, "Required", "", Alignment.MiddleCenter);
 
         QuantityColumns = new DynamicActionColumn[Suppliers.Length];
         CostColumns = new DynamicActionColumn[Suppliers.Length];
@@ -378,9 +399,96 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
             InitialiseSupplierColumn(i);
         }
 
+        ActionColumns.Add(new DynamicMenuColumn(BuildMenu));
+
         return columns;
     }
 
+    private void EditSupplierProductGrid(DynamicGrid<SupplierProduct> grid)
+    {
+        grid.OnCustomiseEditor += (sender, items, column, editor) =>
+        {
+            if(new Column<SupplierProduct>(x => x.SupplierLink.ID).IsEqualTo(column.ColumnName)
+                || new Column<SupplierProduct>(x => x.Product.ID).IsEqualTo(column.ColumnName)
+                || new Column<SupplierProduct>(x => x.Style.ID).IsEqualTo(column.ColumnName)
+                || new Column<SupplierProduct>(x => x.Job.ID).IsEqualTo(column.ColumnName)
+                || new Column<SupplierProduct>(x => x.Dimensions).IsEqualTo(column.ColumnName))
+            {
+                editor.Editable = editor.Editable.Combine(Editable.Disabled);
+            }
+        };
+    }
+
+    private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
+    {
+        if (row is null) return;
+
+        column.AddItem("New Supplier", null, row =>
+        {
+            if (row is null) return;
+
+            var selection = new MultiSelectDialog<Supplier>(
+                new Filter<Supplier>(x => x.ID).NotInList(Suppliers.Select(x => x.ID).ToArray()),
+                new Columns<Supplier>(x => x.ID).Add(x => x.Code), multiselect: false);
+            if (selection.ShowDialog() != true)
+            {
+                return;
+            }
+
+            var supplier = selection.Data().Rows.First().ToObject<Supplier>();
+            var productInstance = LoadItem(row);
+
+            var supplierProduct = new SupplierProduct();
+            supplierProduct.Product.CopyFrom(productInstance.Product);
+            supplierProduct.Style.CopyFrom(productInstance.Style);
+            supplierProduct.Dimensions.CopyFrom(productInstance.Dimensions);
+            supplierProduct.SupplierLink.CopyFrom(supplier);
+
+            if (DynamicGridUtils.EditEntity(supplierProduct, customiseGrid: EditSupplierProductGrid))
+            {
+                SupplierProducts.Add(supplierProduct);
+                var newSuppliers = new SupplierLink[Suppliers.Length + 1];
+                var newIdx = Suppliers.Length;
+
+                for (int i = 0; i < Suppliers.Length; i++)
+                {
+                    newSuppliers[i] = Suppliers[i];
+                }
+                newSuppliers[newIdx] = supplierProduct.SupplierLink;
+
+                foreach (var (itemIdx, item) in Items.WithIndex())
+                {
+                    var populateSupplierProduct = GetSupplierProduct(item);
+
+                    var quantities = new StockForecastOrderingItemQuantity[newSuppliers.Length];
+                    for (int i = 0; i < Suppliers.Length; ++i)
+                    {
+                        quantities[i] = item.GetQuantity(i);
+                    }
+                    var newQty = CreateQuantity(itemIdx);
+
+                    quantities[newIdx] = newQty;
+                    if (OrderType == StockForecastOrderingType.StockOrder)
+                    {
+                        newQty.StockTotal = 0;
+                    }
+                    else
+                    {
+                        foreach (var id in item.GetJobRequiredQuantities().Keys)
+                        {
+                            newQty.JobTotals[id] = 0;
+                        }
+                    }
+                    item.SetQuantities(quantities);
+                }
+
+                Suppliers = newSuppliers;
+
+                Refresh(true, true);
+            }
+        });
+    }
+
     private BitmapImage? Warning_Image(CoreRow? row)
     {
         if (row is null) return _warning;
@@ -625,7 +733,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
         supplierProduct.Dimensions.CopyFrom(item.Dimensions);
         supplierProduct.SupplierLink.CopyFrom(Suppliers[supplierIdx]);
 
-        if (DynamicGridUtils.EditEntity(supplierProduct))
+        if (DynamicGridUtils.EditEntity(supplierProduct, customiseGrid: EditSupplierProductGrid))
         {
             SupplierProducts.Add(supplierProduct);
             InvalidateGrid();

+ 84 - 7
prs.desktop/Panels/Stock Forecast/StockForecastGrid.cs

@@ -253,7 +253,22 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
             Format=format, 
             Position = DynamicActionColumnPosition.End, 
             Tag = tag,
-            HeaderText = header
+            HeaderText = header,
+            Filters = [""],
+            FilterRecord = (row, filters) =>
+            {
+                if (filters.Length == 1 && filters[0].Length == 0) return true;
+
+                var value = GetColumnCalculatedData(tag, row.Get<ProductInstance, Guid>(x => x.ID));
+                if(!value.HasValue)
+                {
+                    return false;
+                }
+                else
+                {
+                    return filters.Contains(value.Value.ToString("F2"));
+                }
+            }
         };
         ActionColumns.Add(column);
     }
@@ -560,7 +575,51 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
     }
 
     private Dictionary<Guid, StockForecastInfo> _summaryinfo = new Dictionary<Guid, StockForecastInfo>();
-    
+
+    private double? GetColumnCalculatedData(ColumnTag tag, Guid productInstanceID)
+    {
+        if (!_summaryinfo.TryGetValue(productInstanceID, out var info)) return null;
+
+        return tag switch
+        {
+            ColumnTag.MinimumStockRequired => info.MinStock,
+            ColumnTag.GeneralStockHoldings => info.GenStock,
+            ColumnTag.GeneralPurchaseOrders => info.GenPO,
+            ColumnTag.JobStockRequired => info.JobBOM,
+            ColumnTag.JobStockHoldings => info.JobStock,
+            ColumnTag.JobPurchaseOrders => info.JobPO,
+            ColumnTag.BalanceRequired => (Optimise ? info.Optimised : info.Required),
+            _ => null
+        };
+    }
+
+    private string[] GetColumnFilterItems(ColumnTag tag)
+    {
+        var selectedIDs = FilterRows(Data.Rows).Select(x => x.Get<ProductInstance, Guid>(x => x.ID));
+
+        var items = new HashSet<string>();
+        foreach(var id in selectedIDs)
+        {
+            var value = GetColumnCalculatedData(tag, id);
+            if (value.HasValue)
+            {
+                items.Add(value.Value.ToString("F2"));
+            }
+        }
+        var arr = items.ToArray();
+        Array.Sort(arr);
+        return arr;
+    }
+
+    protected override IEnumerable<string>? GetColumnFilterItems(DynamicColumnBase column)
+    {
+        if (column.Tag is ColumnTag tag)
+        {
+            return GetColumnFilterItems(tag);
+        }
+        return base.GetColumnFilterItems(column);
+    }
+
     protected override void Reload(Filters<ProductInstance> criteria, Columns<ProductInstance> columns, ref SortOrder<ProductInstance>? sort,
         Action<CoreTable?, Exception?> action)
     {
@@ -671,6 +730,7 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
             var _poItemCols = new Columns<PurchaseOrderItem>(_poItems.Columns);
             var _jobBOMColumns = new Columns<JobBillOfMaterialsItem>(_jobBOMs.Columns);
             var _stockMovementCols = new Columns<StockMovement>(_stockMovements.Columns);
+
             foreach (var row in products.Rows)
             {
                 var _id = row.Values[_idCol] as Guid? ?? Guid.Empty;
@@ -704,7 +764,7 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
                     }
 
                     var mvtJobCol = _stockMovementCols.IndexOf(x => x.Job.ID);
-                    var mvtQtyCol = _stockMovementCols.IndexOf(x => x.Qty);
+                    var mvtQtyCol = _stockMovementCols.IndexOf(x => x.Units);
                     foreach(var mvtRow in mvmtrows)
                     {
                         info.AddJobBOM(mvtRow.Get<Guid>(mvtJobCol), -mvtRow.Get<double>(mvtQtyCol));
@@ -738,10 +798,10 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
                 }
 
                 _summaryinfo[_id] = info;
-
             }
+
             // Process the tables here
-            action.Invoke(query.Get<ProductInstance>(), null);
+            action.Invoke(products, null);
         });
             
     }
@@ -770,11 +830,29 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
 
     #region Ordering
 
+    private IEnumerable<CoreRow> FilterRows(IEnumerable<CoreRow> rows)
+    {
+        var predicates = GetFilterPredicates();
+        return rows.Where(r =>
+        {
+            return predicates.All(x => x.Item2(r));
+        });
+    }
+
     private bool SelectForOrder_Click(CoreRow? row)
     {
         if (row is null)
         {
             var menu = new ContextMenu();
+            menu.AddItem("Select all", null, () =>
+            {
+                foreach (var row in FilterRows(Data.Rows))
+                {
+                    SelectedForOrder.Add(row.Get<ProductInstance, Guid>(x => x.ID));
+                    InvalidateRow(row);
+                }
+                OrderButton.IsEnabled = SelectedForOrder.Count > 0;
+            });
             menu.AddItem("Deselect all", null, () =>
             {
                 SelectedForOrder.Clear();
@@ -815,13 +893,12 @@ public class StockForecastGrid : DynamicDataGrid<ProductInstance>, IDataModelSou
     
     private bool OrderStock_Click(Button button, CoreRow[] rows)
     {
+        rows = FilterRows(Data.Rows.Where(x => SelectedForOrder.Contains(x.Get<ProductInstance, Guid>(x => x.ID)))).ToArray();
         if(rows.Length == 0)
         {
             return false;
         }
 
-        rows = Data.Rows.Where(x => SelectedForOrder.Contains(x.Get<ProductInstance, Guid>(x => x.ID))).ToArray();
-
         var items = new List<StockForecastOrderingItem>();
         foreach(var instance in rows.ToObjects<ProductInstance>())
         {