|
@@ -7,11 +7,15 @@ using System.Windows.Controls;
|
|
|
using System.Windows.Media;
|
|
|
using System.Windows.Media.Imaging;
|
|
|
using Comal.Classes;
|
|
|
+using InABox.Clients;
|
|
|
using InABox.Core;
|
|
|
using InABox.DynamicGrid;
|
|
|
using InABox.Wpf;
|
|
|
using InABox.WPF;
|
|
|
using Newtonsoft.Json;
|
|
|
+using PRSDesktop.Panels.StockSummary.OrderScreen;
|
|
|
+using Syncfusion.UI.Xaml.Diagram.Controls;
|
|
|
+using Syncfusion.Windows.PdfViewer;
|
|
|
|
|
|
namespace PRSDesktop;
|
|
|
|
|
@@ -37,12 +41,15 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
private CoreTable? _supplierProducts = null;
|
|
|
|
|
|
private static readonly BitmapImage _warning = InABox.Wpf.Resources.warning.AsBitmapImage();
|
|
|
+ private static readonly BitmapImage _tick = InABox.Wpf.Resources.tick.AsBitmapImage();
|
|
|
+ private static readonly BitmapImage _cart = PRSDesktop.Resources.purchase.AsBitmapImage();
|
|
|
|
|
|
public Guid[] GroupIDs { get; set; } = [];
|
|
|
public Guid[] JobIDs { get; set; } = [];
|
|
|
public HashSet<Guid> SupplierIDs { get; set; } = [];
|
|
|
|
|
|
- private readonly Button? OrderButton;
|
|
|
+ private readonly Button OrderButton;
|
|
|
+ private HashSet<Guid> SelectedForOrder = [];
|
|
|
|
|
|
public StockSummaryGrid() : base()
|
|
|
{
|
|
@@ -56,6 +63,7 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
HiddenColumns.Add(x => x.Dimensions.UnitSize);
|
|
|
HiddenColumns.Add(x => x.Product.Image.ID);
|
|
|
HiddenColumns.Add(x => x.Product.Image.FileName);
|
|
|
+ HiddenColumns.Add(x=>x.Product.Supplier.ID);
|
|
|
HiddenColumns.Add(x=>x.Product.Supplier.SupplierLink.ID);
|
|
|
HiddenColumns.Add(x=>x.MinimumStockLevel);
|
|
|
|
|
@@ -76,30 +84,14 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
CreateColumn(GetReservedStock, ColumnTag.JobStockHoldings, "Job Hld.","F2");
|
|
|
CreateColumn(GetReservedPurchaseOrder, ColumnTag.JobPurchaseOrders, "Job PO.","F2");
|
|
|
CreateColumn(GetBalanceRequired, ColumnTag.BalanceRequired,"Required","");
|
|
|
-
|
|
|
- OrderButton = AddButton("Order Stock", PRSDesktop.Resources.purchase.ToBitmapImage(), OrderStock_Click);
|
|
|
- OrderButton.IsEnabled = false;
|
|
|
- }
|
|
|
|
|
|
- private void CreateColumn(DynamicTextColumn.GetTextDelegate calculate, ColumnTag tag, string header, string format)
|
|
|
- {
|
|
|
- var column = new DynamicTextColumn(calculate)
|
|
|
+ ActionColumns.Add(new DynamicImageColumn(SelectForOrder_Image, SelectForOrder_Click)
|
|
|
{
|
|
|
- Width = 60,
|
|
|
- Format=format,
|
|
|
- Position = DynamicActionColumnPosition.End,
|
|
|
- Tag = tag,
|
|
|
- HeaderText = header
|
|
|
- };
|
|
|
- ActionColumns.Add(column);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- protected override void SelectItems(CoreRow[]? rows)
|
|
|
- {
|
|
|
- base.SelectItems(rows);
|
|
|
-
|
|
|
- OrderButton.IsEnabled = rows is not null && rows.Length > 0;
|
|
|
+ Position = DynamicActionColumnPosition.End
|
|
|
+ });
|
|
|
+
|
|
|
+ OrderButton = AddButton("Order Stock", _cart, OrderStock_Click);
|
|
|
+ OrderButton.IsEnabled = false;
|
|
|
}
|
|
|
|
|
|
private BitmapImage? Issues_Image(CoreRow? row)
|
|
@@ -118,6 +110,8 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
: column.TextToolTip(row.Get<ProductInstance, string>(x => x.Product.Issues));
|
|
|
}
|
|
|
|
|
|
+ #region UIComponent
|
|
|
+
|
|
|
private UIComponent? _uicomponent = null;
|
|
|
private class UIComponent : DynamicGridGridUIComponent<ProductInstance>
|
|
|
{
|
|
@@ -209,7 +203,9 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
{
|
|
|
return _uicomponent ??= new UIComponent(this);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
protected override void DoReconfigure(FluentList<DynamicGridOption> options)
|
|
|
{
|
|
|
base.DoReconfigure(options);
|
|
@@ -235,6 +231,70 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
return columns;
|
|
|
}
|
|
|
|
|
|
+ #region Column Data and Details
|
|
|
+
|
|
|
+ private void CreateColumn(DynamicTextColumn.GetTextDelegate calculate, ColumnTag tag, string header, string format)
|
|
|
+ {
|
|
|
+ var column = new DynamicTextColumn(calculate)
|
|
|
+ {
|
|
|
+ Width = 60,
|
|
|
+ Format=format,
|
|
|
+ Position = DynamicActionColumnPosition.End,
|
|
|
+ Tag = tag,
|
|
|
+ HeaderText = header
|
|
|
+ };
|
|
|
+ ActionColumns.Add(column);
|
|
|
+ }
|
|
|
+
|
|
|
+ private object GetMinimumStockLevel(CoreRow? row) => row?.Get<ProductInstance, double>(x => x.MinimumStockLevel) ?? 0.0F;
|
|
|
+
|
|
|
+ private object GetGeneralStockLevel(CoreRow? row)
|
|
|
+ {
|
|
|
+ if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
+ return info.GenStock;
|
|
|
+ return 0.0F;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object GetGeneralPurchaseOrder(CoreRow? row)
|
|
|
+ {
|
|
|
+ if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
+ return info.GenPO;
|
|
|
+ return 0.0F;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object GetBOMBalance(CoreRow? row)
|
|
|
+ {
|
|
|
+ if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
+ return info.JobBOM;
|
|
|
+ return 0.0F;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object GetReservedStock(CoreRow? row)
|
|
|
+ {
|
|
|
+ if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
+ return info.JobStock;
|
|
|
+ return 0.0F;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object GetReservedPurchaseOrder(CoreRow? row)
|
|
|
+ {
|
|
|
+ if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
+ return info.JobPO;
|
|
|
+ return 0.0F;
|
|
|
+ }
|
|
|
+
|
|
|
+ private object GetBalanceRequired(CoreRow? row)
|
|
|
+ {
|
|
|
+ if (row != null &&
|
|
|
+ _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
+ return Optimise
|
|
|
+ ? info.Optimised.IsEffectivelyEqual(0.0F) ? "" : $"{info.Optimised:F2}"
|
|
|
+ : info.Required.IsEffectivelyEqual(0.0F)
|
|
|
+ ? ""
|
|
|
+ : $"{info.Required:F2}";
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
private void ShowDetailGrid<TEntity>(
|
|
|
String tag,
|
|
|
Expression<Func<TEntity,object?>> productcol,
|
|
@@ -368,6 +428,10 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
|
|
|
}
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Refresh
|
|
|
+
|
|
|
private bool HasStyle()
|
|
|
{
|
|
|
return DataColumns().ColumnNames().Any(x => x.StartsWith("Style.") && !x.Equals("Style.ID"));
|
|
@@ -436,6 +500,17 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
}
|
|
|
return total;
|
|
|
}
|
|
|
+
|
|
|
+ private class StockSummaryJobInfo
|
|
|
+ {
|
|
|
+ public double BOM { get; set; }
|
|
|
+
|
|
|
+ public double Stock { get; set; }
|
|
|
+
|
|
|
+ public double PO { get; set; }
|
|
|
+
|
|
|
+ public double Required => Math.Max(BOM - (Stock + PO), 0.0F);
|
|
|
+ }
|
|
|
|
|
|
private class StockSummaryInfo
|
|
|
{
|
|
@@ -445,10 +520,29 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
public double JobBOM { get; set; }
|
|
|
public double JobStock { get; set; }
|
|
|
public double JobPO { get; set; }
|
|
|
+
|
|
|
+ public Dictionary<Guid, StockSummaryJobInfo> JobInfo { get; private init; } = [];
|
|
|
+
|
|
|
+ public void AddJobBOM(Guid jobID, double quantity)
|
|
|
+ {
|
|
|
+ var item = JobInfo.GetValueOrAdd(jobID);
|
|
|
+ item.BOM += quantity;
|
|
|
+ }
|
|
|
+ public void AddJobPO(Guid jobID, double quantity)
|
|
|
+ {
|
|
|
+ var item = JobInfo.GetValueOrAdd(jobID);
|
|
|
+ item.PO += quantity;
|
|
|
+ }
|
|
|
+ public void AddJobStock(Guid jobID, double quantity)
|
|
|
+ {
|
|
|
+ var item = JobInfo.GetValueOrAdd(jobID);
|
|
|
+ item.Stock += quantity;
|
|
|
+ }
|
|
|
+ public double StockRequired => Math.Max(MinStock - (GenStock + GenPO), 0.0F);
|
|
|
|
|
|
public double Required => Math.Max((MinStock + JobBOM) - (GenStock + GenPO + JobStock + JobPO), 0.0F);
|
|
|
|
|
|
- public double Optimised => Math.Max(Math.Max(MinStock,JobBOM) - (GenStock + GenPO + JobStock + JobPO), 0.0F);
|
|
|
+ public double Optimised => Math.Max(Math.Max(MinStock, JobBOM) - (GenStock + GenPO + JobStock + JobPO), 0.0F);
|
|
|
}
|
|
|
|
|
|
private Dictionary<Guid, StockSummaryInfo> _summaryinfo = new Dictionary<Guid, StockSummaryInfo>();
|
|
@@ -572,25 +666,62 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
var info = new StockSummaryInfo();
|
|
|
info.MinStock = row.Get<ProductInstance, double>(x => x.MinimumStockLevel);
|
|
|
|
|
|
- var genstockrows = GetRows<StockHolding>(_stockHoldings.Rows, _stockHoldingCols, _productid, _styleid, _unitsize, new Guid[] { Guid.Empty });
|
|
|
+ var genstockrows = GetRows(_stockHoldings.Rows, _stockHoldingCols, _productid, _styleid, _unitsize, [Guid.Empty]);
|
|
|
info.GenStock = Aggregate(genstockrows, _stockHoldingCols, true, true, x=>x.Units);
|
|
|
|
|
|
- var genporows = GetRows(_poItems.Rows, _poItemCols, _productid, _styleid, _unitsize, new Guid[] { Guid.Empty });
|
|
|
+ var genporows = GetRows(_poItems.Rows, _poItemCols, _productid, _styleid, _unitsize, [Guid.Empty]);
|
|
|
info.GenPO = Aggregate(genporows, _poItemCols, true, true, x=>x.Qty);
|
|
|
-
|
|
|
- var bomrows = GetRows(_jobBOMs.Rows, _jobBOMColumns, _productid, _styleid, _unitsize, JobIDs);
|
|
|
- var bom = Aggregate(bomrows, _jobBOMColumns, true, true, x=>x.Quantity);
|
|
|
+
|
|
|
+ // Job BOMs
|
|
|
+ {
|
|
|
+ var bomrows = GetRows(_jobBOMs.Rows, _jobBOMColumns, _productid, _styleid, _unitsize, JobIDs);
|
|
|
+ var bom = Aggregate(bomrows, _jobBOMColumns, true, true, x => x.Quantity);
|
|
|
|
|
|
- var mvmtrows = GetRows(_stockMovements.Rows, _stockMovementCols, _productid, _styleid, _unitsize, JobIDs);
|
|
|
- var mvmts = Aggregate(mvmtrows, _jobBOMColumns, true, true, x=>x.Quantity);
|
|
|
+ var mvmtrows = GetRows(_stockMovements.Rows, _stockMovementCols, _productid, _styleid, _unitsize, JobIDs);
|
|
|
+ var mvmts = Aggregate(mvmtrows, _stockMovementCols, true, true, x => x.Units);
|
|
|
|
|
|
- info.JobBOM = bom - mvmts;
|
|
|
-
|
|
|
- var jobstockrows = GetRows<StockHolding>(_stockHoldings.Rows, _stockHoldingCols, _productid, _styleid, _unitsize, JobIDs);
|
|
|
- info.JobStock = Aggregate(jobstockrows, _stockHoldingCols, true, true, x=>x.Units);
|
|
|
-
|
|
|
- var jobporows = GetRows(_poItems.Rows, _poItemCols, _productid, _styleid, _unitsize, JobIDs);
|
|
|
- info.JobPO = Aggregate(jobporows, _poItemCols, true, true, x=>x.Qty);
|
|
|
+ info.JobBOM = bom - mvmts;
|
|
|
+
|
|
|
+ var bomJobCol = _jobBOMColumns.IndexOf(x => x.Job.ID);
|
|
|
+ var bomQtyCol = _jobBOMColumns.IndexOf(x => x.Quantity);
|
|
|
+ foreach(var jobBOMRow in bomrows)
|
|
|
+ {
|
|
|
+ info.AddJobBOM(jobBOMRow.Get<Guid>(bomJobCol), jobBOMRow.Get<double>(bomQtyCol));
|
|
|
+ }
|
|
|
+
|
|
|
+ var mvtJobCol = _stockMovementCols.IndexOf(x => x.Job.ID);
|
|
|
+ var mvtQtyCol = _stockMovementCols.IndexOf(x => x.Qty);
|
|
|
+ foreach(var mvtRow in mvmtrows)
|
|
|
+ {
|
|
|
+ info.AddJobBOM(mvtRow.Get<Guid>(mvtJobCol), -mvtRow.Get<double>(mvtQtyCol));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Job Stock
|
|
|
+ {
|
|
|
+ var jobstockrows = GetRows(_stockHoldings.Rows, _stockHoldingCols, _productid, _styleid, _unitsize, JobIDs);
|
|
|
+ info.JobStock = Aggregate(jobstockrows, _stockHoldingCols, true, true, x=>x.Units);
|
|
|
+
|
|
|
+ var jobCol = _stockHoldingCols.IndexOf(x => x.Job.ID);
|
|
|
+ var qtyCol = _stockHoldingCols.IndexOf(x => x.Units);
|
|
|
+ foreach(var jobStockRow in jobstockrows)
|
|
|
+ {
|
|
|
+ info.AddJobStock(jobStockRow.Get<Guid>(jobCol), jobStockRow.Get<double>(qtyCol));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Job PO
|
|
|
+ {
|
|
|
+ var jobporows = GetRows(_poItems.Rows, _poItemCols, _productid, _styleid, _unitsize, JobIDs);
|
|
|
+ info.JobPO = Aggregate(jobporows, _poItemCols, true, true, x => x.Qty);
|
|
|
+
|
|
|
+ var jobCol = _poItemCols.IndexOf(x => x.Job.ID);
|
|
|
+ var qtyCol = _poItemCols.IndexOf(x => x.Qty);
|
|
|
+ foreach(var jobPORow in jobporows)
|
|
|
+ {
|
|
|
+ info.AddJobPO(jobPORow.Get<Guid>(jobCol), jobPORow.Get<double>(qtyCol));
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
_summaryinfo[_id] = info;
|
|
|
|
|
@@ -621,53 +752,51 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- private object GetMinimumStockLevel(CoreRow? row) => row?.Get<ProductInstance, double>(x => x.MinimumStockLevel) ?? 0.0F;
|
|
|
-
|
|
|
- private object GetGeneralStockLevel(CoreRow? row)
|
|
|
- {
|
|
|
- if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
- return info.GenStock;
|
|
|
- return 0.0F;
|
|
|
- }
|
|
|
-
|
|
|
- private object GetGeneralPurchaseOrder(CoreRow? row)
|
|
|
- {
|
|
|
- if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
- return info.GenPO;
|
|
|
- return 0.0F;
|
|
|
- }
|
|
|
-
|
|
|
- private object GetBOMBalance(CoreRow? row)
|
|
|
- {
|
|
|
- if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
- return info.JobBOM;
|
|
|
- return 0.0F;
|
|
|
- }
|
|
|
+ #endregion
|
|
|
|
|
|
- private object GetReservedStock(CoreRow? row)
|
|
|
- {
|
|
|
- if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
- return info.JobStock;
|
|
|
- return 0.0F;
|
|
|
- }
|
|
|
+ #region Ordering
|
|
|
|
|
|
- private object GetReservedPurchaseOrder(CoreRow? row)
|
|
|
+ private bool SelectForOrder_Click(CoreRow? row)
|
|
|
{
|
|
|
- if (row != null && _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
- return info.JobPO;
|
|
|
- return 0.0F;
|
|
|
+ if (row is null)
|
|
|
+ {
|
|
|
+ var menu = new ContextMenu();
|
|
|
+ menu.AddItem("Deselect all", null, () =>
|
|
|
+ {
|
|
|
+ SelectedForOrder.Clear();
|
|
|
+ InvalidateGrid();
|
|
|
+ OrderButton.IsEnabled = false;
|
|
|
+ });
|
|
|
+ menu.IsOpen = true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var id = row.Get<ProductInstance, Guid>(x => x.ID);
|
|
|
+ if (!SelectedForOrder.Remove(id))
|
|
|
+ {
|
|
|
+ SelectedForOrder.Add(id);
|
|
|
+ }
|
|
|
+ OrderButton.IsEnabled = SelectedForOrder.Count > 0;
|
|
|
+ InvalidateRow(row);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private object GetBalanceRequired(CoreRow? row)
|
|
|
+ private BitmapImage? SelectForOrder_Image(CoreRow? row)
|
|
|
{
|
|
|
- if (row != null &&
|
|
|
- _summaryinfo.TryGetValue(row.Get<ProductInstance, Guid>(x => x.ID), out StockSummaryInfo? info))
|
|
|
- return Optimise
|
|
|
- ? info.Optimised.IsEffectivelyEqual(0.0F) ? "" : $"{info.Optimised:F2}"
|
|
|
- : info.Required.IsEffectivelyEqual(0.0F)
|
|
|
- ? ""
|
|
|
- : $"{info.Required:F2}";
|
|
|
- return "";
|
|
|
+ if(row is null)
|
|
|
+ {
|
|
|
+ return _cart;
|
|
|
+ }
|
|
|
+ else if(SelectedForOrder.Contains(row.Get<ProductInstance, Guid>(x => x.ID)))
|
|
|
+ {
|
|
|
+ return _tick;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private bool OrderStock_Click(Button button, CoreRow[] rows)
|
|
@@ -677,61 +806,107 @@ public class StockSummaryGrid : DynamicDataGrid<ProductInstance>, IDataModelSour
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- var _instances = rows.ToObjects<ProductInstance>().ToArray();
|
|
|
+ rows = Data.Rows.Where(x => SelectedForOrder.Contains(x.Get<ProductInstance, Guid>(x => x.ID))).ToArray();
|
|
|
|
|
|
- var order = new PurchaseOrder();
|
|
|
- order.Description = "Purchase Order created from Stock Forecast Screen";
|
|
|
- order.RaisedBy.ID = App.EmployeeID;
|
|
|
- order.IssuedBy.ID = App.EmployeeID;
|
|
|
- order.IssuedDate = DateTime.Today;
|
|
|
+ var items = new List<StockSummaryOrderingItem>();
|
|
|
+ foreach(var instance in rows.ToObjects<ProductInstance>())
|
|
|
+ {
|
|
|
+ var info = _summaryinfo.GetValueOrDefault(instance.ID);
|
|
|
+
|
|
|
+ var item = new StockSummaryOrderingItem();
|
|
|
+ item.Product.CopyFrom(instance.Product);
|
|
|
+ item.Style.CopyFrom(instance.Style);
|
|
|
+ item.Dimensions.CopyFrom(instance.Dimensions);
|
|
|
+ item.RequiredQuantity = (Optimise ? info?.Optimised : info?.Required) ?? default;
|
|
|
|
|
|
- var orderItems = new List<PurchaseOrderItem>();
|
|
|
+ if(info is not null)
|
|
|
+ {
|
|
|
+ item.SetJobRequiredQuantity(Guid.Empty, info.StockRequired);
|
|
|
+ foreach(var (id, jobInfo) in info.JobInfo)
|
|
|
+ {
|
|
|
+ item.SetJobRequiredQuantity(id, jobInfo.Required);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ item.SetJobRequiredQuantity(Guid.Empty, 0.0);
|
|
|
+ }
|
|
|
+
|
|
|
+ items.Add(item);
|
|
|
+ }
|
|
|
|
|
|
- foreach(var stockSummary in _instances)
|
|
|
+ var window = new StockSummaryOrderScreen(items);
|
|
|
+ if(window.ShowDialog() != true)
|
|
|
{
|
|
|
- var orderItem = new PurchaseOrderItem();
|
|
|
- orderItem.Product.ID = stockSummary.Product.ID;
|
|
|
- orderItem.Style.ID = stockSummary.Style.ID;
|
|
|
-
|
|
|
- // Need to Breakout BOMs into individual Lines
|
|
|
- //orderItem.Job.ID = stockSummary.Job.ID;
|
|
|
-
|
|
|
- orderItem.Dimensions.CopyFrom(stockSummary.Dimensions);
|
|
|
-
|
|
|
- // Need to calculate Balance based on Supplier.OrderQty
|
|
|
- //orderItem.Qty = Math.Max(-stockSummary.BalanceAvailable, 0);
|
|
|
-
|
|
|
- orderItems.Add(orderItem);
|
|
|
+ return false;
|
|
|
}
|
|
|
- LookupFactory.DoLookups<PurchaseOrderItem, Product, ProductLink>(
|
|
|
- orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Product.ID)),
|
|
|
- x => x.Product);
|
|
|
- LookupFactory.DoLookups<PurchaseOrderItem, ProductStyle, ProductStyleLink>(
|
|
|
- orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Style.ID)),
|
|
|
- x => x.Style);
|
|
|
- LookupFactory.DoLookups<PurchaseOrderItem, Job, JobLink>(
|
|
|
- orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Job.ID)),
|
|
|
- x => x.Job);
|
|
|
-
|
|
|
- if (DynamicGridUtils.EditEntity(order, t =>
|
|
|
+
|
|
|
+ var orders = new List<Tuple<PurchaseOrder, List<PurchaseOrderItem>>>();
|
|
|
+ foreach(var perSupplier in window.Results.GroupBy(x => x.Supplier.ID))
|
|
|
{
|
|
|
- if (t == typeof(PurchaseOrderItem))
|
|
|
+ var order = new PurchaseOrder();
|
|
|
+ order.Description = "Purchase Order created from Stock Forecast Screen";
|
|
|
+ order.RaisedBy.ID = App.EmployeeID;
|
|
|
+
|
|
|
+ LookupFactory.DoLookup<PurchaseOrder, Supplier, SupplierLink>(order, x => x.SupplierLink, perSupplier.Key);
|
|
|
+
|
|
|
+ var orderItems = new List<PurchaseOrderItem>();
|
|
|
+ var results = perSupplier.ToArray();
|
|
|
+ foreach(var item in results)
|
|
|
{
|
|
|
- var table = new CoreTable();
|
|
|
- table.LoadColumns(typeof(PurchaseOrderItem));
|
|
|
- table.LoadRows(orderItems);
|
|
|
- return table;
|
|
|
+ var orderItem = new PurchaseOrderItem();
|
|
|
+ orderItem.Product.ID = item.Item.Product.ID;
|
|
|
+ orderItem.Style.ID = item.Item.Style.ID;
|
|
|
+ orderItem.Job.ID = item.Job?.ID ?? Guid.Empty;
|
|
|
+
|
|
|
+ orderItems.Add(orderItem);
|
|
|
}
|
|
|
- return null;
|
|
|
- }, preloadPages: true))
|
|
|
+
|
|
|
+ LookupFactory.DoLookups<PurchaseOrderItem, Product, ProductLink>(
|
|
|
+ orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Product.ID)),
|
|
|
+ x => x.Product);
|
|
|
+ LookupFactory.DoLookups<PurchaseOrderItem, ProductStyle, ProductStyleLink>(
|
|
|
+ orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Style.ID)),
|
|
|
+ x => x.Style);
|
|
|
+ LookupFactory.DoLookups<PurchaseOrderItem, Job, JobLink>(
|
|
|
+ orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x, x.Job.ID)),
|
|
|
+ x => x.Job);
|
|
|
+ LookupFactory.DoLookups<PurchaseOrderItem, TaxCode, TaxCodeLink>(
|
|
|
+ orderItems.WithIndex().Select(x => new Tuple<PurchaseOrderItem, Guid>(x.Value, results[x.Key].SupplierProduct.TaxCode.ID)),
|
|
|
+ x => x.TaxCode);
|
|
|
+
|
|
|
+ foreach(var (i, item) in results.WithIndex())
|
|
|
+ {
|
|
|
+ var orderItem = orderItems[i];
|
|
|
+ orderItem.Dimensions.CopyFrom(item.Item.Dimensions);
|
|
|
+
|
|
|
+ orderItem.Qty = item.Quantity;
|
|
|
+ orderItem.Cost = item.SupplierProduct.CostPrice;
|
|
|
+ }
|
|
|
+
|
|
|
+ orders.Add(new(order, orderItems));
|
|
|
+ }
|
|
|
+
|
|
|
+ Client.Save(orders.Select(x => x.Item1), "Created from Stock Forecast screen");
|
|
|
+ foreach(var (order, orderItems) in orders)
|
|
|
{
|
|
|
- MessageWindow.ShowMessage("Purchase order created.", "Success.");
|
|
|
+ foreach(var item in orderItems)
|
|
|
+ {
|
|
|
+ item.PurchaseOrderLink.ID = order.ID;
|
|
|
+ }
|
|
|
}
|
|
|
- return false;
|
|
|
+ Client.Save(orders.SelectMany(x => x.Item2), "Created from Stock Forecast screen");
|
|
|
+
|
|
|
+ SelectedForOrder.Clear();
|
|
|
+ OrderButton.IsEnabled = false;
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
#region IDataModelSource
|
|
|
-
|
|
|
+
|
|
|
public event DataModelUpdateEvent? OnUpdateDataModel;
|
|
|
|
|
|
public string SectionName => "Stock Summary";
|