|  | @@ -25,6 +25,29 @@ using Columns = InABox.Core.Columns;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace PRSDesktop.Panels.StockForecast.OrderScreen;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +public class StockForecastOrderData
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    public ProductLink Product { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public ProductStyleLink Style { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public StockDimensions Dimensions { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public double RequiredQuantity { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private Dictionary<Guid, double> JobRequiredQuantities { get; set; } = [];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    public Dictionary<Guid, double> GetJobRequiredQuantities()
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        return JobRequiredQuantities;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    public void SetJobRequiredQuantity(Guid jobID, double requiredQty)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        JobRequiredQuantities[jobID] = requiredQty;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  public enum StockForecastOrderingType
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      StockOrder,
 | 
	
	
		
			
				|  | @@ -35,29 +58,32 @@ public class StockForecastOrderingItemQuantity
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      public event Action? Changed;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    private double _stockTotal;
 | 
	
		
			
				|  |  | -    public double StockTotal
 | 
	
		
			
				|  |  | +    private double _total;
 | 
	
		
			
				|  |  | +    public double Total
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        get => _stockTotal;
 | 
	
		
			
				|  |  | +        get => _total;
 | 
	
		
			
				|  |  |          set
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            _stockTotal = value;
 | 
	
		
			
				|  |  | +            _total = value;
 | 
	
		
			
				|  |  |              Changed?.Invoke();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public Dictionary<Guid, double> JobTotals { get; init; } = [];
 | 
	
		
			
				|  |  | +    private SupplierProduct? _supplierProduct;
 | 
	
		
			
				|  |  | +    public SupplierProduct? SupplierProduct
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        get => _supplierProduct;
 | 
	
		
			
				|  |  | +        set
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            _supplierProduct = value;
 | 
	
		
			
				|  |  | +            Changed?.Invoke();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public void DoChanged()
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          Changed?.Invoke();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    public double JobTotal => JobTotals.Sum(x => x.Value);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    public double GetTotal(StockForecastOrderingType type) => type == StockForecastOrderingType.StockOrder
 | 
	
		
			
				|  |  | -        ? StockTotal
 | 
	
		
			
				|  |  | -        : JobTotal;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  public class StockForecastOrderingItem : BaseObject
 | 
	
	
		
			
				|  | @@ -72,19 +98,15 @@ public class StockForecastOrderingItem : BaseObject
 | 
	
		
			
				|  |  |      public StockDimensions Dimensions { get; set; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      [EditorSequence(4)]
 | 
	
		
			
				|  |  | +    public JobLink Job { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    [EditorSequence(5)]
 | 
	
		
			
				|  |  |      [DoubleEditor]
 | 
	
		
			
				|  |  |      public double RequiredQuantity { get; set; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    private Dictionary<Guid, double> JobRequiredQuantities { get; set; } = [];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    public Dictionary<Guid, double> GetJobRequiredQuantities()
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        return JobRequiredQuantities;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    public void SetJobRequiredQuantity(Guid jobID, double requiredQty)
 | 
	
		
			
				|  |  | -    {
 | 
	
		
			
				|  |  | -        JobRequiredQuantities[jobID] = requiredQty;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    [EditorSequence(6)]
 | 
	
		
			
				|  |  | +    [EnumLookupEditor(typeof(SupplierProductOrderStrategy))]
 | 
	
		
			
				|  |  | +    public SupplierProductOrderStrategy OrderStrategy { get; set; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      private StockForecastOrderingItemQuantity[] Quantities = [];
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -127,8 +149,11 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |      private List<SupplierProduct> SupplierProducts = [];
 | 
	
		
			
				|  |  |      private SupplierLink[] Suppliers = [];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    public IList<StockForecastOrderData> OrderData { get; set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      public double TotalQuantity => Items.Sum(x => x.GetTotalQuantity(OrderType));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    private DynamicActionColumn[] SupplierProductColumns = [];
 | 
	
		
			
				|  |  |      private DynamicActionColumn[] QuantityColumns = [];
 | 
	
		
			
				|  |  |      private DynamicActionColumn[] CostColumns = [];
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -291,7 +316,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |              .Add(x => x.SupplierLink.Code);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          SupplierProducts = Client.Query(
 | 
	
		
			
				|  |  | -            new Filter<SupplierProduct>(x => x.Product.ID).InList(Items.Select(x => x.Product.ID).ToArray())
 | 
	
		
			
				|  |  | +            new Filter<SupplierProduct>(x => x.Product.ID).InList(OrderData.Select(x => x.Product.ID).ToArray())
 | 
	
		
			
				|  |  |                  .And(x => x.SupplierLink.ID).IsNotEqualTo(Guid.Empty),
 | 
	
		
			
				|  |  |              supplierColumns,
 | 
	
		
			
				|  |  |              new SortOrder<SupplierProduct>(x => x.SupplierLink.Code))
 | 
	
	
		
			
				|  | @@ -299,16 +324,6 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          Suppliers = SupplierProducts.Select(x => x.SupplierLink).DistinctBy(x => x.ID).ToArray();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        foreach(var (itemIdx, item) in Items.WithIndex())
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            var quantities = new StockForecastOrderingItemQuantity[Suppliers.Length];
 | 
	
		
			
				|  |  | -            for(int i = 0; i < Suppliers.Length; ++i)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                quantities[i] = CreateQuantity(itemIdx);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            item.SetQuantities(quantities);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          CalculateQuantities();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -330,42 +345,72 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |      private void CalculateQuantities()
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          SetObserving(false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Items.Clear();
 | 
	
		
			
				|  |  | +        foreach(var dataItem in OrderData)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if(OrderType == StockForecastOrderingType.StockOrder)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var item = new StockForecastOrderingItem();
 | 
	
		
			
				|  |  | +                item.Product.CopyFrom(dataItem.Product);
 | 
	
		
			
				|  |  | +                item.Style.CopyFrom(dataItem.Style);
 | 
	
		
			
				|  |  | +                item.Dimensions.CopyFrom(dataItem.Dimensions);
 | 
	
		
			
				|  |  | +                item.RequiredQuantity = dataItem.RequiredQuantity;
 | 
	
		
			
				|  |  | +                item.OrderStrategy = item.Product.OrderStrategy;
 | 
	
		
			
				|  |  | +                Items.Add(item);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                foreach(var (id, q) in dataItem.GetJobRequiredQuantities())
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var item = new StockForecastOrderingItem();
 | 
	
		
			
				|  |  | +                    item.Product.CopyFrom(dataItem.Product);
 | 
	
		
			
				|  |  | +                    item.Style.CopyFrom(dataItem.Style);
 | 
	
		
			
				|  |  | +                    item.Dimensions.CopyFrom(dataItem.Dimensions);
 | 
	
		
			
				|  |  | +                    item.Job.ID = id;
 | 
	
		
			
				|  |  | +                    item.RequiredQuantity = q;
 | 
	
		
			
				|  |  | +                    item.OrderStrategy = item.Product.OrderStrategy;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    Items.Add(item);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        foreach(var (itemIdx, item) in Items.WithIndex())
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var quantities = new StockForecastOrderingItemQuantity[Suppliers.Length];
 | 
	
		
			
				|  |  | +            for(int i = 0; i < Suppliers.Length; ++i)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                quantities[i] = CreateQuantity(itemIdx);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            item.SetQuantities(quantities);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          foreach(var item in Items)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            var supplierProduct = GetSupplierProduct(item);
 | 
	
		
			
				|  |  | +            var selectedSupplierProducts = new List<SupplierProduct>();
 | 
	
		
			
				|  |  |              for(int i = 0; i < Suppliers.Length; ++i)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | +                var supplierProduct = SelectSupplierProduct(SupplierProducts.Where(x => x.Product.ID == item.Product.ID && x.Style.ID == item.Style.ID && x.SupplierLink.ID == Suppliers[i].ID), item);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                  var qty = item.GetQuantity(i);
 | 
	
		
			
				|  |  | +                qty.SupplierProduct = supplierProduct;
 | 
	
		
			
				|  |  | +                qty.Total = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                var supplier = Suppliers[i];
 | 
	
		
			
				|  |  | -                if(supplierProduct is not null && supplier.ID == supplierProduct.SupplierLink.ID)
 | 
	
		
			
				|  |  | +                if(supplierProduct is not null)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    if(OrderType == StockForecastOrderingType.StockOrder)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        qty.StockTotal = qty.JobTotal;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        qty.JobTotals.Clear();
 | 
	
		
			
				|  |  | -                        foreach(var (id, q) in item.GetJobRequiredQuantities())
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            qty.JobTotals[id] = q;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | +                    selectedSupplierProducts.Add(supplierProduct);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | -                else
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var selectedSupplierProduct = SelectSupplierProduct(selectedSupplierProducts, item);
 | 
	
		
			
				|  |  | +            if(selectedSupplierProduct is not null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var supplierIdx = Suppliers.WithIndex().FirstOrDefault(x => x.Value.ID == selectedSupplierProduct.SupplierLink.ID, new KeyValuePair<int, SupplierLink>(-1, null)).Key;
 | 
	
		
			
				|  |  | +                if(supplierIdx != -1)
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    if(OrderType == StockForecastOrderingType.StockOrder)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        qty.StockTotal = 0;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        foreach(var id in item.GetJobRequiredQuantities().Keys)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            qty.JobTotals[id] = 0;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | +                    item.GetQuantity(supplierIdx).Total = GetRequiredQuantity(item, selectedSupplierProduct);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -375,6 +420,16 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |          InvalidateGrid();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    private SupplierProduct? SelectSupplierProduct(IEnumerable<SupplierProduct> supplierProducts, StockForecastOrderingItem item)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    private double GetRequiredQuantity(StockForecastOrderingItem item, SupplierProduct supplierProduct)
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      protected override DynamicGridColumns LoadColumns()
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |          if (!_loadedData)
 | 
	
	
		
			
				|  | @@ -393,6 +448,16 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |          columns.Add<StockForecastOrderingItem, string>(x => x.Dimensions.UnitSize, 80, "Size", "", Alignment.MiddleCenter);
 | 
	
		
			
				|  |  |          columns.Add<StockForecastOrderingItem, double>(x => x.RequiredQuantity, 80, "Required", "", Alignment.MiddleCenter);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        ActionColumns.Add(new DynamicTemplateColumn(row =>
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            HeaderText = "Order Strategy.",
 | 
	
		
			
				|  |  | +            Width = 120
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        SupplierProductColumns = new DynamicActionColumn[Suppliers.Length];
 | 
	
		
			
				|  |  |          QuantityColumns = new DynamicActionColumn[Suppliers.Length];
 | 
	
		
			
				|  |  |          CostColumns = new DynamicActionColumn[Suppliers.Length];
 | 
	
		
			
				|  |  |          QuantityControls.Clear();
 | 
	
	
		
			
				|  | @@ -671,8 +736,15 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |              return menu;
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        // Making local copy of index so that the lambda can use it, and not the changed value of 'i'.
 | 
	
		
			
				|  |  |          var qtyColumn = new Tuple<DynamicActionColumn, QuantityControl?>(null!, null);
 | 
	
		
			
				|  |  | +        SupplierProductColumns[idx] = new DynamicTemplateColumn(row =>
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            HeaderText = "Supplier Product.",
 | 
	
		
			
				|  |  | +            Width = 80
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  |          QuantityColumns[idx] = new DynamicTemplateColumn(row =>
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var instance = LoadItem(row);
 | 
	
	
		
			
				|  | @@ -721,6 +793,7 @@ public class StockForecastOrderingGrid : DynamicItemsListGrid<StockForecastOrder
 | 
	
		
			
				|  |  |                  return summary;
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          };
 | 
	
		
			
				|  |  | +        ActionColumns.Add(SupplierProductColumns[idx]);
 | 
	
		
			
				|  |  |          ActionColumns.Add(QuantityColumns[idx]);
 | 
	
		
			
				|  |  |          ActionColumns.Add(CostColumns[idx]);
 | 
	
		
			
				|  |  |      }
 |