ReservationManagementTreatmentOrderGrid.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. using Comal.Classes;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using InABox.DynamicGrid;
  5. using InABox.Wpf;
  6. using InABox.WPF;
  7. using NPOI.SS.Formula.Functions;
  8. using Syncfusion.Data;
  9. using Syncfusion.Data.Extensions;
  10. using Syncfusion.UI.Xaml.Grid;
  11. using Syncfusion.Windows.Shared;
  12. using System;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.ComponentModel;
  16. using System.Data;
  17. using System.Linq;
  18. using System.Text;
  19. using System.Threading.Tasks;
  20. using System.Windows;
  21. using System.Windows.Controls;
  22. using System.Windows.Media;
  23. using System.Windows.Media.Imaging;
  24. using Columns = InABox.Core.Columns;
  25. namespace PRSDesktop.Panels.ReservationManagement.TreatmentPO;
  26. public class ReservationManagementTreatmentPOItem : BaseObject
  27. {
  28. public delegate void ChangedHandler(int idx, double quantity);
  29. public event ChangedHandler? Changed;
  30. public ProductLink TreatmentProduct { get; set; }
  31. public ProductStyleLink Finish { get; set; }
  32. public JobLink Job { get; set; }
  33. public ProductLink Product { get; set; }
  34. public ProductStyleLink Style { get; set; }
  35. public StockDimensions Dimensions { get; set; }
  36. public StockLocationLink Location { get; set; }
  37. public JobRequisitionItemLink JRI { get; set; }
  38. public double Multiplier { get; set; }
  39. [EditorSequence(4)]
  40. [DoubleEditor]
  41. public double RequiredQuantity { get; set; }
  42. private double[] Quantities = [];
  43. public double GetQuantity(int i) => Quantities[i];
  44. public void SetQuantity(int i, double quantity)
  45. {
  46. Quantities[i] = quantity;
  47. Changed?.Invoke(i, quantity);
  48. }
  49. public double GetTotalQuantity() => Quantities.Sum();
  50. public void SetQuantities(double[] quantities)
  51. {
  52. Quantities = quantities;
  53. }
  54. }
  55. public class StockForecastTreatmentOrderingResult(
  56. SupplierLink supplier,
  57. PurchaseOrder? purchaseOrder,
  58. ReservationManagementTreatmentPOItem item,
  59. double quantity,
  60. SupplierProduct supplierProduct)
  61. {
  62. public SupplierLink Supplier { get; set; } = supplier;
  63. public PurchaseOrder? PurchaseOrder { get; set; } = purchaseOrder;
  64. public ReservationManagementTreatmentPOItem Item { get; set; } = item;
  65. public SupplierProduct SupplierProduct { get; set; } = supplierProduct;
  66. public double Quantity { get; set; } = quantity;
  67. }
  68. public class ReservationManagementTreatmentOrderGrid: DynamicItemsListGrid<ReservationManagementTreatmentPOItem>, ISpecificGrid
  69. {
  70. private class OrderSupplier(SupplierLink supplier, PurchaseOrder? purchaseOrder)
  71. {
  72. public SupplierLink Supplier { get; set; } = supplier;
  73. public PurchaseOrder? PurchaseOrder { get; set; } = purchaseOrder;
  74. }
  75. private List<SupplierProduct> SupplierProducts = [];
  76. private OrderSupplier[] Suppliers = [];
  77. public double TotalQuantity => Items.Sum(x => x.GetTotalQuantity());
  78. private DynamicActionColumn[] QuantityColumns = [];
  79. private DynamicActionColumn[] CostColumns = [];
  80. private readonly Dictionary<Guid, Job> JobDetails = [];
  81. private static BitmapImage _warning = PRSDesktop.Resources.warning.AsBitmapImage();
  82. private static BitmapImage _search = PRSDesktop.Resources.menu.AsBitmapImage();
  83. public IEnumerable<StockForecastTreatmentOrderingResult> Results
  84. {
  85. get
  86. {
  87. for(int i = 0; i < Suppliers.Length; ++i)
  88. {
  89. var supplier = Suppliers[i];
  90. foreach(var item in Items)
  91. {
  92. var qty = item.GetQuantity(i);
  93. if(qty == 0)
  94. {
  95. continue;
  96. }
  97. var supplierProduct = GetSupplierProduct(item, supplier.Supplier.ID);
  98. if (supplierProduct is null)
  99. {
  100. continue;
  101. }
  102. yield return new(supplier.Supplier, supplier.PurchaseOrder, item, qty, supplierProduct);
  103. }
  104. }
  105. }
  106. }
  107. private DynamicGridCustomColumnsComponent<ReservationManagementTreatmentPOItem> ColumnsComponent;
  108. public ReservationManagementTreatmentOrderGrid()
  109. {
  110. HiddenColumns.Add(x => x.Product.Image.ID);
  111. ColumnsComponent = new(this, nameof(ReservationManagementTreatmentOrderGrid));
  112. }
  113. #region UI Component
  114. private Component? _uiComponent;
  115. private Component UIComponent
  116. {
  117. get
  118. {
  119. _uiComponent ??= new Component(this);
  120. return _uiComponent;
  121. }
  122. }
  123. protected override IDynamicGridUIComponent<ReservationManagementTreatmentPOItem> CreateUIComponent()
  124. {
  125. return UIComponent;
  126. }
  127. private class Component : DynamicGridGridUIComponent<ReservationManagementTreatmentPOItem>
  128. {
  129. private ReservationManagementTreatmentOrderGrid Grid;
  130. public Component(ReservationManagementTreatmentOrderGrid grid)
  131. {
  132. Parent = grid;
  133. Grid = grid;
  134. DataGrid.FrozenColumnCount = 9;
  135. }
  136. protected override Brush? GetCellSelectionBackgroundBrush()
  137. {
  138. return null;
  139. }
  140. protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column)
  141. {
  142. var item = Grid.LoadItem(row);
  143. if(column is DynamicActionColumn ac)
  144. {
  145. var qIdx = Grid.QuantityColumns.IndexOf(ac);
  146. var idx = Math.Max(qIdx, Grid.CostColumns.IndexOf(ac));
  147. if(idx != -1)
  148. {
  149. var supplierProduct = Grid.GetSupplierProduct(item, Grid.Suppliers[idx].Supplier.ID);
  150. if(supplierProduct is null)
  151. {
  152. return new SolidColorBrush(Colors.Gainsboro);
  153. }
  154. //if(item.GetTotalQuantity(Grid.OrderType) < item.RequiredQuantity)
  155. //{
  156. // return new SolidColorBrush(Colors.LightSalmon) { Opacity = 0.5 };
  157. //}
  158. //else
  159. //{
  160. // return new SolidColorBrush(Colors.LightGreen) { Opacity = 0.5 };
  161. //}
  162. }
  163. }
  164. return base.GetCellBackground(row, column);
  165. }
  166. protected override Style GetColumnGroupHeaderCellStyle(DynamicGridColumnGroup group)
  167. {
  168. var style = base.GetColumnGroupHeaderCellStyle(group);
  169. if(group.Tag is int index)
  170. {
  171. style.AddSetter(Control.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
  172. style.AddSetter(Control.VerticalContentAlignmentProperty, VerticalAlignment.Stretch);
  173. style.AddSetter(Control.PaddingProperty, new Thickness(0.0));
  174. style.AddSetter(GridStackedHeaderCellControl.ContentTemplateProperty, TemplateGenerator.CreateDataTemplate(() =>
  175. {
  176. var dock = new DockPanel { LastChildFill = true };
  177. var button = new Button();
  178. button.Content = new Image
  179. {
  180. Source = _search
  181. };
  182. button.Width = 25;
  183. button.BorderBrush = Colors.Silver.ToBrush();
  184. button.BorderThickness = new Thickness(0.75, 0.0, 0.0, 0.0);
  185. //button.Background = Colors.WhiteSmoke.ToBrush();
  186. DockPanel.SetDock(button, Dock.Right);
  187. dock.Children.Add(button);
  188. var border = new Border();
  189. border.Background = Colors.LightYellow.ToBrush();
  190. border.Margin = new Thickness(0.0, 0.0, 0.0, 0.0);
  191. border.BorderThickness = new(0.0);
  192. var textBox = new TextBox();
  193. textBox.IsEnabled = false;
  194. textBox.VerticalContentAlignment = VerticalAlignment.Center;
  195. textBox.HorizontalContentAlignment = HorizontalAlignment.Center;
  196. textBox.Padding = new Thickness(2.0, 0.0, 0.0, 0.0);
  197. textBox.Background = Colors.LightYellow.ToBrush();
  198. textBox.BorderThickness = new(0.0);
  199. textBox.Text = Grid.Suppliers[index].PurchaseOrder?.PONumber ?? "(New Order)";
  200. border.Child = textBox;
  201. DockPanel.SetDock(border, Dock.Left);
  202. dock.Children.Add(border);
  203. button.Click += (o, e) =>
  204. {
  205. var supplier = Grid.Suppliers[index];
  206. var dlg = new MultiSelectDialog<PurchaseOrder>(
  207. new Filter<PurchaseOrder>(x => x.ClosedDate).IsEqualTo(DateTime.MinValue)
  208. .And(x => x.SupplierLink.ID).IsEqualTo(supplier.Supplier.ID),
  209. Columns.None<PurchaseOrder>().Add(x => x.ID).Add(x => x.PONumber),
  210. multiselect: false);
  211. var result = dlg.ShowDialog();
  212. if(result == true)
  213. {
  214. var item = dlg.Data().ToObjects<PurchaseOrder>()?.FirstOrDefault();
  215. supplier.PurchaseOrder = item;
  216. textBox.Text = item?.PONumber ?? "(New Order)";
  217. }
  218. else if(result == false)
  219. {
  220. supplier.PurchaseOrder = null;
  221. textBox.Text = "(New Order)";
  222. }
  223. };
  224. return dock;
  225. }));
  226. }
  227. return style;
  228. }
  229. }
  230. #endregion
  231. #region Grid Stuff
  232. private bool _observing = true;
  233. private void SetObserving(bool observing)
  234. {
  235. _observing = observing;
  236. }
  237. protected override void Changed()
  238. {
  239. if (_observing)
  240. {
  241. base.Changed();
  242. }
  243. }
  244. protected override void DoReconfigure(DynamicGridOptions options)
  245. {
  246. options.Clear();
  247. options.FilterRows = true;
  248. }
  249. #endregion
  250. #region Data
  251. private bool _loadedData = false;
  252. private void LoadData()
  253. {
  254. var supplierColumns = Columns.None<SupplierProduct>().Add(x => x.ID)
  255. .Add(x => x.SupplierLink.ID)
  256. .Add(x => x.Job.ID)
  257. .Add(x => x.Product.ID)
  258. .Add(x => x.CostPrice)
  259. .Add(x => x.SupplierLink.Code)
  260. .Add(x => x.Product.TaxCode.ID)
  261. .Add(x => x.TaxCode.ID);
  262. SupplierProducts = Client.Query(
  263. new Filter<SupplierProduct>(x => x.Product.ID).InList(Items.Select(x => x.TreatmentProduct.ID).ToArray())
  264. .And(x => x.SupplierLink.ID).IsNotEqualTo(Guid.Empty),
  265. supplierColumns,
  266. new SortOrder<SupplierProduct>(x => x.SupplierLink.Code))
  267. .ToList<SupplierProduct>();
  268. Suppliers = SupplierProducts.Select(x => x.SupplierLink).DistinctBy(x => x.ID).Select(x => new OrderSupplier(x, null)).ToArray();
  269. foreach(var (itemIdx, item) in Items.WithIndex())
  270. {
  271. var quantities = new double[Suppliers.Length];
  272. for(int i = 0; i < Suppliers.Length; ++i)
  273. {
  274. quantities[i] = 0;
  275. }
  276. item.SetQuantities(quantities);
  277. item.Changed += (i, qty) =>
  278. {
  279. if (!_observing) return;
  280. var row = Data.Rows[itemIdx];
  281. foreach(var ac in ActionColumns)
  282. {
  283. if(ac != QuantityColumns[i])
  284. {
  285. UpdateCell(row, ac);
  286. }
  287. }
  288. DoChanged();
  289. };
  290. }
  291. CalculateQuantities();
  292. _loadedData = true;
  293. }
  294. private void CalculateQuantities()
  295. {
  296. SetObserving(false);
  297. foreach(var item in Items)
  298. {
  299. var supplierProduct = GetSupplierProduct(item);
  300. for(int i = 0; i < Suppliers.Length; ++i)
  301. {
  302. var supplier = Suppliers[i];
  303. if(supplierProduct is not null && supplier.Supplier.ID == supplierProduct.SupplierLink.ID)
  304. {
  305. item.SetQuantity(i, item.RequiredQuantity);
  306. }
  307. else
  308. {
  309. item.SetQuantity(i, 0);
  310. }
  311. }
  312. }
  313. SetObserving(true);
  314. DoChanged();
  315. InvalidateGrid();
  316. }
  317. #endregion
  318. #region Columns
  319. protected override void SaveColumns(DynamicGridColumns columns)
  320. {
  321. ColumnsComponent.SaveColumns(columns);
  322. }
  323. protected override void LoadColumnsMenu(ContextMenu menu)
  324. {
  325. ColumnsComponent.LoadColumnsMenu(menu);
  326. }
  327. public override DynamicGridColumns GenerateColumns()
  328. {
  329. var columns = new DynamicGridColumns();
  330. columns.Add<ReservationManagementTreatmentPOItem, string>(x => x.Product.Code, 120, "Product", "", Alignment.MiddleCenter);
  331. columns.Add<ReservationManagementTreatmentPOItem, string>(x => x.Style.Code, 120, "Style", "", Alignment.MiddleCenter);
  332. //columns.Add<ReservationManagementTreatmentPOItem, string>(x => x.Location.Code, 80, "Location", "", Alignment.MiddleLeft);
  333. columns.Add<ReservationManagementTreatmentPOItem, string>(x => x.Dimensions.UnitSize, 80, "Size", "", Alignment.MiddleCenter);
  334. columns.Add<ReservationManagementTreatmentPOItem, string>(x => x.TreatmentProduct.Code, 120, "Finish", "", Alignment.MiddleCenter);
  335. columns.Add<ReservationManagementTreatmentPOItem, string>(x => x.TreatmentProduct.Name, 0, "Treatment Product", "", Alignment.MiddleCenter);
  336. columns.Add<ReservationManagementTreatmentPOItem, double>(x => x.RequiredQuantity, 80, "Required", "", Alignment.MiddleCenter);
  337. columns.Add<ReservationManagementTreatmentPOItem, double>(x => x.Multiplier, 80, "Multiplier", "", Alignment.MiddleCenter);
  338. return columns;
  339. }
  340. protected override DynamicGridColumns LoadColumns()
  341. {
  342. if (!_loadedData)
  343. {
  344. LoadData();
  345. }
  346. ActionColumns.Clear();
  347. ActionColumns.Add(new DynamicImageColumn(Warning_Image) { Position = DynamicActionColumnPosition.Start });
  348. ActionColumns.Add(new DynamicImagePreviewColumn<ReservationManagementTreatmentPOItem>(x => x.Product.Image) { Position = DynamicActionColumnPosition.Start });
  349. var columns = ColumnsComponent.LoadColumns();
  350. QuantityColumns = new DynamicActionColumn[Suppliers.Length];
  351. CostColumns = new DynamicActionColumn[Suppliers.Length];
  352. QuantityControls.Clear();
  353. for(int i = 0; i < Suppliers.Length; ++i)
  354. {
  355. InitialiseSupplierColumn(i);
  356. }
  357. ActionColumns.Add(new DynamicMenuColumn(BuildMenu));
  358. return columns;
  359. }
  360. protected override void ConfigureColumnGroups()
  361. {
  362. // The first set of header groups is for the supplier Codes
  363. var codeGroup = GetColumnGrouping();
  364. for(int idx = 0; idx < Suppliers.Length; ++idx)
  365. {
  366. codeGroup.AddGroup(Suppliers[idx].Supplier.Code, QuantityColumns[idx], CostColumns[idx]);
  367. }
  368. // The next set of header groups is for the purchase order combo-boxes.
  369. var poGroup = AddColumnGrouping();
  370. for(int idx = 0; idx < Suppliers.Length; ++idx)
  371. {
  372. poGroup.AddGroup(Suppliers[idx].Supplier.Code, QuantityColumns[idx], CostColumns[idx], tag: idx);
  373. }
  374. }
  375. private BitmapImage? Warning_Image(CoreRow? row)
  376. {
  377. if (row is null) return _warning;
  378. var item = LoadItem(row);
  379. if(item.GetTotalQuantity() < item.RequiredQuantity)
  380. {
  381. return _warning;
  382. }
  383. else
  384. {
  385. return null;
  386. }
  387. }
  388. private class QuantityControl : ContentControl
  389. {
  390. private readonly ReservationManagementTreatmentPOItem Item;
  391. private readonly int SupplierIndex;
  392. private readonly ReservationManagementTreatmentOrderGrid Parent;
  393. public QuantityControl(ReservationManagementTreatmentOrderGrid parent, ReservationManagementTreatmentPOItem item, int supplierIndex)
  394. {
  395. Parent = parent;
  396. Item = item;
  397. SupplierIndex = supplierIndex;
  398. UpdateControl();
  399. }
  400. public void UpdateControl()
  401. {
  402. var supplierProduct = Parent.GetSupplierProduct(Item, Parent.Suppliers[SupplierIndex].Supplier.ID);
  403. if(supplierProduct is null)
  404. {
  405. Content = null;
  406. return;
  407. }
  408. var editor = new DoubleTextBox
  409. {
  410. VerticalAlignment = VerticalAlignment.Stretch,
  411. HorizontalContentAlignment = HorizontalAlignment.Center,
  412. HorizontalAlignment = HorizontalAlignment.Stretch,
  413. Background = new SolidColorBrush(Colors.LightYellow),
  414. BorderThickness = new Thickness(0.0),
  415. MinValue = 0.0,
  416. Value = Item.GetQuantity(SupplierIndex)
  417. };
  418. editor.ValueChanged += (o, e) =>
  419. {
  420. var maxValue = Item.RequiredQuantity - (Item.GetTotalQuantity() - Item.GetQuantity(SupplierIndex));
  421. var value = (double?)e.NewValue ?? default;
  422. if(value > maxValue)
  423. {
  424. Dispatcher.BeginInvoke(() => editor.Value = maxValue);
  425. }
  426. else
  427. {
  428. Item.SetQuantity(SupplierIndex, value);
  429. }
  430. };
  431. Content = editor;
  432. }
  433. }
  434. private List<QuantityControl> QuantityControls = [];
  435. private void InitialiseSupplierColumn(int idx)
  436. {
  437. var supplierProducts = SupplierProducts.Where(x => x.SupplierLink.ID == Suppliers[idx].Supplier.ID).ToArray();
  438. var contextMenuFunc = (CoreRow[]? rows) =>
  439. {
  440. var row = rows?.FirstOrDefault();
  441. if (row is null) return null;
  442. var item = LoadItem(row);
  443. var supplierProduct = GetSupplierProduct(item, Suppliers[idx].Supplier.ID);
  444. if (supplierProduct is not null)
  445. {
  446. return null;
  447. }
  448. var menu = new ContextMenu();
  449. menu.AddItem("Create Supplier Product", null, new Tuple<ReservationManagementTreatmentPOItem, int>(item, idx), CreateSupplierProduct_Click);
  450. return menu;
  451. };
  452. // Making local copy of index so that the lambda can use it, and not the changed value of 'i'.
  453. var qtyColumn = new Tuple<DynamicActionColumn, QuantityControl?>(null!, null);
  454. QuantityColumns[idx] = new DynamicTemplateColumn(row =>
  455. {
  456. var instance = LoadItem(row);
  457. var control = new QuantityControl(this, instance, idx);
  458. QuantityControls.Add(control);
  459. return control;
  460. })
  461. {
  462. HeaderText = "Qty.",
  463. Width = 60,
  464. ContextMenu = contextMenuFunc
  465. };
  466. CostColumns[idx] = new DynamicTextColumn(row =>
  467. {
  468. if(row is null)
  469. {
  470. return "Cost";
  471. }
  472. var instance = LoadItem(row);
  473. var qty = instance.GetQuantity(idx);
  474. var supplierProduct = GetSupplierProduct(instance, Suppliers[idx].Supplier.ID);
  475. if(supplierProduct is not null)
  476. {
  477. return $"{qty * supplierProduct.CostPrice * instance.Multiplier:C2}";
  478. }
  479. else
  480. {
  481. return "";
  482. }
  483. })
  484. {
  485. HeaderText = "Cost",
  486. Width = 70,
  487. ContextMenu = contextMenuFunc,
  488. GetSummary = () =>
  489. {
  490. return new DynamicGridCustomSummary((rows) => Cost_Aggregate(idx, rows), "C2");
  491. }
  492. };
  493. ActionColumns.Add(QuantityColumns[idx]);
  494. ActionColumns.Add(CostColumns[idx]);
  495. }
  496. private double Cost_Aggregate(int supplierIdx, IEnumerable<CoreRow> rows)
  497. {
  498. return rows.Sum(row =>
  499. {
  500. var item = LoadItem(row);
  501. var supplierProduct = GetSupplierProduct(item, Suppliers[supplierIdx].Supplier.ID);
  502. if (supplierProduct is not null)
  503. {
  504. var qty = item.GetQuantity(supplierIdx);
  505. return qty * item.Multiplier * supplierProduct.CostPrice;
  506. }
  507. else
  508. {
  509. return 0;
  510. }
  511. });
  512. }
  513. #endregion
  514. #region New Suppliers
  515. private void EditSupplierProductGrid(DynamicGrid<SupplierProduct> grid)
  516. {
  517. grid.OnCustomiseEditor += (sender, items, column, editor) =>
  518. {
  519. if(new Column<SupplierProduct>(x => x.SupplierLink.ID).IsEqualTo(column.ColumnName)
  520. || new Column<SupplierProduct>(x => x.Product.ID).IsEqualTo(column.ColumnName)
  521. || new Column<SupplierProduct>(x => x.Style.ID).IsEqualTo(column.ColumnName)
  522. || new Column<SupplierProduct>(x => x.Job.ID).IsEqualTo(column.ColumnName)
  523. //|| new Column<SupplierProduct>(x => x.Dimensions).IsEqualTo(column.ColumnName)
  524. )
  525. {
  526. editor.Editable = editor.Editable.Combine(Editable.Disabled);
  527. }
  528. };
  529. }
  530. private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
  531. {
  532. if (row is null) return;
  533. column.AddItem("New Supplier", null, row =>
  534. {
  535. if (row is null) return;
  536. var selection = new MultiSelectDialog<Supplier>(
  537. new Filter<Supplier>(x => x.ID).NotInList(Suppliers.ToArray(x => x.Supplier.ID)),
  538. Columns.None<Supplier>().Add(x => x.ID).Add(x => x.Code), multiselect: false);
  539. if (selection.ShowDialog() != true)
  540. {
  541. return;
  542. }
  543. var supplier = selection.Data().Rows.First().ToObject<Supplier>();
  544. var item = LoadItem(row);
  545. var supplierProduct = new SupplierProduct();
  546. LookupFactory.DoLookup<SupplierProduct, Product, ProductLink>(supplierProduct, x => x.Product, item.TreatmentProduct.ID);
  547. supplierProduct.SupplierLink.CopyFrom(supplier);
  548. if (DynamicGridUtils.EditEntity(supplierProduct, customiseGrid: EditSupplierProductGrid))
  549. {
  550. SupplierProducts.Add(supplierProduct);
  551. var newSuppliers = new OrderSupplier[Suppliers.Length + 1];
  552. var newIdx = Suppliers.Length;
  553. for (int i = 0; i < Suppliers.Length; i++)
  554. {
  555. newSuppliers[i] = Suppliers[i];
  556. }
  557. newSuppliers[newIdx] = new(supplierProduct.SupplierLink, null);
  558. foreach (var (itemIdx, oItem) in Items.WithIndex())
  559. {
  560. var populateSupplierProduct = GetSupplierProduct(oItem);
  561. var quantities = new double[newSuppliers.Length];
  562. for (int i = 0; i < Suppliers.Length; ++i)
  563. {
  564. quantities[i] = oItem.GetQuantity(i);
  565. }
  566. quantities[newIdx] = 0;
  567. oItem.SetQuantities(quantities);
  568. }
  569. Suppliers = newSuppliers;
  570. Refresh(true, true);
  571. }
  572. });
  573. }
  574. #endregion
  575. #region Supplier Product Matching
  576. private void CreateSupplierProduct_Click(Tuple<ReservationManagementTreatmentPOItem, int> tuple)
  577. {
  578. var (item, supplierIdx) = tuple;
  579. var supplierProduct = new SupplierProduct();
  580. LookupFactory.DoLookup<SupplierProduct, Product, ProductLink>(supplierProduct, x => x.Product, item.TreatmentProduct.ID);
  581. supplierProduct.SupplierLink.CopyFrom(Suppliers[supplierIdx].Supplier);
  582. if (DynamicGridUtils.EditEntity(supplierProduct, customiseGrid: EditSupplierProductGrid))
  583. {
  584. SupplierProducts.Add(supplierProduct);
  585. InvalidateGrid();
  586. }
  587. }
  588. private static bool Matches(ReservationManagementTreatmentPOItem item, SupplierProduct supplierProduct, bool matchJob)
  589. {
  590. return item.TreatmentProduct.ID == supplierProduct.Product.ID
  591. && (!matchJob || item.JRI.Job.ID == supplierProduct.Job.ID);
  592. }
  593. private SupplierProduct? GetSupplierProduct(ReservationManagementTreatmentPOItem item)
  594. {
  595. var defaultSupplierProduct = SupplierProducts.FirstOrDefault(x => x.ID == item.Product.Supplier.ID);
  596. if(defaultSupplierProduct is not null && Matches(item, defaultSupplierProduct, false))
  597. {
  598. return defaultSupplierProduct;
  599. }
  600. else
  601. {
  602. return SupplierProducts.FirstOrDefault(x => Matches(item, x, true))
  603. ?? SupplierProducts.FirstOrDefault(x => Matches(item, x, false));
  604. }
  605. }
  606. private SupplierProduct? GetSupplierProduct(ReservationManagementTreatmentPOItem item, Guid supplierID)
  607. {
  608. return SupplierProducts.FirstOrDefault(x => x.SupplierLink.ID == supplierID && Matches(item, x, false));
  609. }
  610. #endregion
  611. }