RequisitionItemEditor.xaml.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. using Comal.Classes;
  2. using InABox.Clients;
  3. using InABox.Core;
  4. using InABox.DynamicGrid;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.ComponentModel;
  8. using System.Linq;
  9. using System.Runtime.CompilerServices;
  10. using System.Windows;
  11. using System.Windows.Controls;
  12. namespace PRSDesktop.Panels.Requisitions;
  13. /// <summary>
  14. /// Interaction logic for RequisitionItemEditor.xaml
  15. /// </summary>
  16. public partial class RequisitionItemEditor : INotifyPropertyChanged
  17. {
  18. private readonly RequisitionItem Item;
  19. public RequisitionItem[]? Result { get; private set; }
  20. private bool _loadedStockHoldings;
  21. private bool _loadedProductInstances;
  22. private bool _loadedBOMItems;
  23. private bool _loadedJobRequisitionItems;
  24. private bool _loadedCustom;
  25. private bool _allowActual;
  26. private bool _canSave;
  27. public bool CanSave
  28. {
  29. get => _canSave;
  30. private set
  31. {
  32. _canSave = value;
  33. OnPropertyChanged();
  34. }
  35. }
  36. public RequisitionItemEditor(Func<List<Product>> products, RequisitionItem requisitionItem, bool allowActual)
  37. {
  38. _allowActual = allowActual;
  39. InitializeComponent();
  40. StockHoldingProducts.ProductsFunction = products;
  41. ProductInstancesProducts.ProductsFunction = products;
  42. BOMItems.Item = requisitionItem;
  43. JobRequisitionItemsGrid.Item = requisitionItem;
  44. HoldingsPage.Visibility = _allowActual ? Visibility.Visible : Visibility.Collapsed;
  45. InstancesPage.Visibility = _allowActual ? Visibility.Collapsed : Visibility.Visible;
  46. BOMPage.Visibility = _allowActual
  47. ? Visibility.Collapsed
  48. : Visibility.Visible;
  49. RequisitionPage.Visibility = _allowActual
  50. ? Visibility.Collapsed
  51. : Visibility.Visible;
  52. Item = requisitionItem;
  53. TabControl.SelectedItem = requisitionItem.EditType == RequisitionItemEditType.Normal
  54. ? _allowActual
  55. ? HoldingsPage
  56. : requisitionItem.JobRequisitionItem.ID == Guid.Empty
  57. ? BOMPage
  58. : RequisitionPage
  59. : CustomPage;
  60. CanSave = false;
  61. UpdateState();
  62. }
  63. private void UpdateState()
  64. {
  65. if(TabControl.SelectedTab == HoldingsPage)
  66. {
  67. if (!_loadedStockHoldings)
  68. {
  69. LoadStockHoldings();
  70. _loadedStockHoldings = true;
  71. }
  72. }
  73. else if(TabControl.SelectedTab == BOMPage)
  74. {
  75. if (!_loadedBOMItems)
  76. {
  77. LoadBOMItems();
  78. _loadedBOMItems = true;
  79. }
  80. }
  81. else if(TabControl.SelectedTab == RequisitionPage)
  82. {
  83. if (!_loadedJobRequisitionItems)
  84. {
  85. LoadJobRequisitionItems();
  86. _loadedJobRequisitionItems = true;
  87. }
  88. }
  89. else if(TabControl.SelectedTab == InstancesPage)
  90. {
  91. if (!_loadedProductInstances)
  92. {
  93. LoadProductInstances();
  94. _loadedProductInstances = true;
  95. }
  96. }
  97. else if (TabControl.SelectedTab == CustomPage)
  98. {
  99. if (!_loadedCustom)
  100. {
  101. LoadCustom();
  102. _loadedCustom = true;
  103. }
  104. }
  105. CheckCanSave();
  106. }
  107. private void CheckCanSave()
  108. {
  109. if (TabControl.SelectedTab == HoldingsPage)
  110. CanSave = CanSaveStockHoldings();
  111. else if (TabControl.SelectedTab == BOMPage)
  112. CanSave = CanSaveBOMItems();
  113. else if (TabControl.SelectedTab == RequisitionPage)
  114. CanSave = CanSaveJobRequisitionItems();
  115. else if (TabControl.SelectedTab == InstancesPage)
  116. CanSave = CanSaveProductInstances();
  117. else if (TabControl.SelectedTab == CustomPage)
  118. CanSave = true;
  119. }
  120. private void DoSave()
  121. {
  122. if (TabControl.SelectedTab == HoldingsPage)
  123. SaveStockHoldings();
  124. else if (TabControl.SelectedTab == BOMPage)
  125. SaveBOMItems();
  126. else if (TabControl.SelectedTab == RequisitionPage)
  127. SaveJobRequisitionItems();
  128. else if (TabControl.SelectedTab == InstancesPage)
  129. SaveProductInstances();
  130. else if (TabControl.SelectedTab == CustomPage)
  131. SaveCustom();
  132. }
  133. private void OKButton_Click(object sender, RoutedEventArgs e)
  134. {
  135. DoSave();
  136. DialogResult = true;
  137. Close();
  138. }
  139. private void CancelButton_Click(object sender, RoutedEventArgs e)
  140. {
  141. Item.CancelChanges();
  142. DialogResult = false;
  143. Close();
  144. }
  145. private void TabChanged(object sender, SelectionChangedEventArgs e)
  146. {
  147. if (e.OriginalSource == sender)
  148. UpdateState();
  149. }
  150. #region StockHoldings
  151. private void LoadStockHoldings()
  152. {
  153. StockHoldingProducts.Refresh(true, true);
  154. foreach(var column in StockHolding.Columns)
  155. {
  156. StockHoldings.HiddenColumns.Add(column);
  157. }
  158. foreach(var column in new Columns<StockHolding>()
  159. .AddSubColumns(x => x.Product, LookupFactory.DefineLookupColumns<RequisitionItem, Product, ProductLink>(x => x.Product).CastIntersection<ProductLink>())
  160. .AddSubColumns(x => x.Style, LookupFactory.DefineLookupColumns<RequisitionItem, ProductStyle, ProductStyleLink>(x => x.Style).CastIntersection<ProductStyleLink>())
  161. .AddSubColumns(x => x.Location, LookupFactory.DefineLookupColumns<RequisitionItem, StockLocation, StockLocationLink>(x => x.Location).CastIntersection<StockLocationLink>())
  162. .AddSubColumns(x => x.Job, LookupFactory.DefineLookupColumns<RequisitionItem, Job, JobLink>(x => x.JobLink).CastIntersection<JobLink>())
  163. )
  164. {
  165. StockHoldings.HiddenColumns.Add(column);
  166. }
  167. StockHoldings.HiddenColumns.Add(x => x.Available);
  168. StockHoldings.Refresh(true, false);
  169. if(Item.Product.ID != Guid.Empty)
  170. {
  171. // Delaying, cause otherwise it doesn't work.
  172. Dispatcher.BeginInvoke(() =>
  173. {
  174. StockHoldingProducts.SelectedRows = StockHoldingProducts.Data.Rows.Where(x => x.Get<Product, Guid>(x => x.ID) == Item.Product.ID).ToArray();
  175. StockHoldingProducts.ScrollIntoView(StockHoldingProducts.SelectedRows[0]);
  176. });
  177. }
  178. }
  179. private void StockHoldingProducts_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e)
  180. {
  181. StockHoldings.Product = e.Rows is not null && e.Rows.Length > 0 ? e.Rows[0].ToObject<Product>() : null;
  182. StockHoldings.Refresh(false, true);
  183. CheckCanSave();
  184. }
  185. private void StockHoldings_OnAfterRefresh(object sender, AfterRefreshEventArgs args)
  186. {
  187. var row = StockHoldings.Data.Rows.FirstOrDefault();
  188. if (row != null)
  189. {
  190. StockHoldings.SelectedRows = new CoreRow[] { row };
  191. SelectHolding(new CoreRow[] { row });
  192. }
  193. }
  194. private void StockHoldings_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e)
  195. {
  196. SelectHolding(e.Rows);
  197. }
  198. private void SelectHolding(CoreRow[]? rows)
  199. {
  200. StockHolding = rows?.FirstOrDefault()?.ToObject<StockHolding>();
  201. RefreshJobRequisitionItems();
  202. JRIRow.Height = _allowActual && StockHolding is not null ? new GridLength(1, GridUnitType.Star) : new GridLength(0);
  203. TotalRow.Height = _allowActual && StockHolding is not null ? new GridLength(40) : new GridLength(0);
  204. RequiredEditor.SetValue(Grid.ColumnProperty, _allowActual && StockHolding is not null ? 4 : 6);
  205. CheckCanSave();
  206. }
  207. private bool CanSaveStockHoldings()
  208. {
  209. return StockHolding is not null && TotalTaken > 0;
  210. }
  211. private void SaveStockHoldings()
  212. {
  213. if (StockHolding is null) return;
  214. var items = JRIItems.Where(x => x.Taken > 0).ToArray();
  215. if (items.Length == 0) return;
  216. Item.Product.CopyFrom(StockHolding.Product);
  217. Item.Style.CopyFrom(StockHolding.Style);
  218. Item.Location.CopyFrom(StockHolding.Location);
  219. Item.Dimensions.CopyFrom(StockHolding.Dimensions, true);
  220. Item.JobLink.CopyFrom(StockHolding.Job);
  221. Item.EditType = RequisitionItemEditType.Normal;
  222. var remainder = Item.Quantity;
  223. var newItems = new List<RequisitionItem>();
  224. foreach(var item in items)
  225. {
  226. RequisitionItem newItem;
  227. if(newItems.Count == 0)
  228. {
  229. newItem = Item;
  230. }
  231. else
  232. {
  233. newItem = new RequisitionItem();
  234. newItem.Done = Item.Done;
  235. newItem.Description = Item.Description;
  236. newItem.Image.CopyFrom(Item.Image);
  237. newItem.Invoice.CopyFrom(Item.Invoice);
  238. newItem.RequisitionLink.ID = Item.RequisitionLink.ID;
  239. newItem.JobRequisitionItem.ID = item.ID;
  240. newItem.Product.CopyFrom(Item.Product);
  241. newItem.Style.CopyFrom(Item.Style);
  242. newItem.Location.CopyFrom(Item.Location);
  243. newItem.Dimensions.CopyFrom(Item.Dimensions, true);
  244. newItem.JobLink.CopyFrom(Item.JobLink);
  245. newItem.EditType = RequisitionItemEditType.Normal;
  246. }
  247. newItem.JobRequisitionItem.ID = item.ID;
  248. newItem.Quantity = item.Taken;
  249. newItem.ActualQuantity = item.Taken;
  250. remainder -= item.Taken;
  251. newItems.Add(newItem);
  252. }
  253. if(remainder > 0)
  254. {
  255. var newItem = new RequisitionItem();
  256. newItem.Done = false;
  257. newItem.Description = Item.Description;
  258. newItem.Image.CopyFrom(Item.Image);
  259. newItem.Invoice.CopyFrom(Item.Invoice);
  260. newItem.RequisitionLink.ID = Item.RequisitionLink.ID;
  261. newItem.JobRequisitionItem.ID = Guid.Empty;
  262. newItem.Product.CopyFrom(Item.Product);
  263. newItem.Style.CopyFrom(Item.Style);
  264. newItem.Dimensions.CopyFrom(Item.Dimensions, true);
  265. newItem.Quantity = remainder;
  266. newItems.Add(newItem);
  267. }
  268. Client.Save(newItems, "Edited by user.");
  269. Result = newItems.ToArray();
  270. }
  271. #region JobRequisitionItem Selection
  272. public event PropertyChangedEventHandler? PropertyChanged;
  273. protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
  274. {
  275. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  276. }
  277. private bool _observing = false;
  278. public void SetObserving(bool observing)
  279. {
  280. if(_observing != observing)
  281. {
  282. _observing = observing;
  283. if (_observing)
  284. {
  285. Recalculate();
  286. }
  287. }
  288. }
  289. private StockHolding? StockHolding;
  290. private List<RequisitionItemStockHoldingItem> _jriItems;
  291. public List<RequisitionItemStockHoldingItem> JRIItems
  292. {
  293. get => _jriItems;
  294. set
  295. {
  296. _jriItems = value;
  297. OnPropertyChanged();
  298. }
  299. }
  300. private void RefreshJobRequisitionItems()
  301. {
  302. SetObserving(false);
  303. if(StockHolding is null)
  304. {
  305. JRIItems = [];
  306. }
  307. else
  308. {
  309. var jris = StockHolding.LoadRequisitionItems(true);
  310. JRIItems = jris.Select(x =>
  311. {
  312. var newItem = new RequisitionItemStockHoldingItem
  313. {
  314. Quantity = x.Qty,
  315. Taken = 0,
  316. ID = x.ID,
  317. Text = x.ID == Guid.Empty
  318. ? "General Stock"
  319. : $"{x.Job.JobNumber}:{x.Requisition.Number} {x.Requisition.Description} ({x.Qty})",
  320. };
  321. newItem.PropertyChanged += (o, e) => Recalculate();
  322. return newItem;
  323. }).ToList();
  324. }
  325. SetObserving(true);
  326. }
  327. private void Recalculate()
  328. {
  329. if (!_observing) return;
  330. TotalTaken = JRIItems.Sum(x => x.Taken);
  331. }
  332. private double _totalTaken;
  333. public double TotalTaken
  334. {
  335. get => _totalTaken;
  336. set
  337. {
  338. _totalTaken = value;
  339. OnPropertyChanged();
  340. CheckCanSave();
  341. }
  342. }
  343. public double RequiredQuantity
  344. {
  345. get => Item.Quantity;
  346. set
  347. {
  348. Item.Quantity = value;
  349. CheckCanSave();
  350. OnPropertyChanged();
  351. }
  352. }
  353. private void None_Click(object sender, RoutedEventArgs e)
  354. {
  355. if (sender is not FrameworkElement element || element.Tag is not RequisitionItemStockHoldingItem item) return;
  356. item.Taken = 0;
  357. }
  358. private void Minus_Click(object sender, RoutedEventArgs e)
  359. {
  360. if (sender is not FrameworkElement element || element.Tag is not RequisitionItemStockHoldingItem item) return;
  361. item.Taken = Math.Max(0, item.Taken - 1);
  362. }
  363. private void Plus_Click(object sender, RoutedEventArgs e)
  364. {
  365. if (sender is not FrameworkElement element || element.Tag is not RequisitionItemStockHoldingItem item) return;
  366. item.Taken = Math.Min(item.Taken + 1, item.Quantity);
  367. }
  368. private void All_Click(object sender, RoutedEventArgs e)
  369. {
  370. if (sender is not FrameworkElement element || element.Tag is not RequisitionItemStockHoldingItem item) return;
  371. item.Taken = Math.Min(Math.Max(RequiredQuantity - (TotalTaken - item.Taken), 0), item.Quantity);
  372. }
  373. #endregion
  374. #endregion
  375. #region BOM Items
  376. private void LoadBOMItems()
  377. {
  378. BOMItems.Refresh(true,true);
  379. }
  380. private bool CanSaveBOMItems()
  381. {
  382. return BOMItems.Data.Rows.Any(r =>!r.Get<JobBOMSummary,double>(x=>x.Quantity).IsEffectivelyEqual(0.0));
  383. }
  384. private void SaveBOMItems()
  385. {
  386. var result = new List<RequisitionItem>() { Item };
  387. var bomItems = BOMItems.Data.Rows
  388. .Where(r => !r.Get<JobBOMSummary, double>(x => x.Quantity).IsEffectivelyEqual(0.0))
  389. .Select(r => r.ToObject<JobBOMSummary>()).ToArray();
  390. var first = bomItems.FirstOrDefault();
  391. if (first is null)
  392. return;
  393. Item.Product.CopyFrom(first.Product);
  394. Item.Style.CopyFrom(first.Style);
  395. Item.Dimensions.CopyFrom(first.Dimensions, true);
  396. Item.EditType = RequisitionItemEditType.Normal;
  397. Item.Quantity = first.Quantity;
  398. foreach (var item in bomItems.Skip(1).ToArray())
  399. {
  400. var newItem = new RequisitionItem();
  401. newItem.RequisitionLink.ID = Item.RequisitionLink.ID;
  402. newItem.Done = false;
  403. newItem.Description = item.Product.Name;
  404. newItem.Product.CopyFrom(item.Product);
  405. newItem.Style.CopyFrom(item.Style);
  406. newItem.Dimensions.CopyFrom(item.Dimensions, true);
  407. newItem.EditType = RequisitionItemEditType.Normal;
  408. newItem.Quantity = item.Quantity;
  409. result.Add(newItem);
  410. }
  411. Client.Save(result, "Edited by user.");
  412. Result = result.ToArray();
  413. }
  414. private void BOMItems_OnOnChanged(object? sender, EventArgs e)
  415. {
  416. CheckCanSave();
  417. }
  418. #endregion
  419. #region Job Requisition Items
  420. private void LoadJobRequisitionItems()
  421. {
  422. JobRequisitionItemsGrid.Refresh(true,true);
  423. }
  424. private bool CanSaveJobRequisitionItems()
  425. {
  426. return JobRequisitionItemsGrid.Data.Rows.Any(r =>!r.Get<JobJRISummary,double>(x=>x.Quantity).IsEffectivelyEqual(0.0));
  427. }
  428. private void SaveJobRequisitionItems()
  429. {
  430. var result = new List<RequisitionItem>() { Item };
  431. var items = JobRequisitionItemsGrid.Data.Rows
  432. .Where(r => !r.Get<JobJRISummary, double>(x => x.Quantity).IsEffectivelyEqual(0.0))
  433. .Select(r => r.ToObject<JobJRISummary>()).ToArray();
  434. var first = items.FirstOrDefault();
  435. if (first is null)
  436. return;
  437. Item.Product.CopyFrom(first.JRI.Product);
  438. Item.Style.CopyFrom(first.JRI.Style);
  439. Item.Dimensions.CopyFrom(first.JRI.Dimensions, true);
  440. Item.JobRequisitionItem.CopyFrom(first.JRI);
  441. Item.EditType = RequisitionItemEditType.Normal;
  442. Item.Quantity = first.Quantity;
  443. foreach (var item in items.Skip(1).ToArray())
  444. {
  445. var newItem = new RequisitionItem();
  446. newItem.RequisitionLink.ID = Item.RequisitionLink.ID;
  447. newItem.Done = false;
  448. newItem.Description = item.JRI.Product.Name;
  449. newItem.Product.CopyFrom(item.JRI.Product);
  450. newItem.Style.CopyFrom(item.JRI.Style);
  451. newItem.Dimensions.CopyFrom(item.JRI.Dimensions, true);
  452. newItem.JobRequisitionItem.CopyFrom(item.JRI);
  453. newItem.EditType = RequisitionItemEditType.Normal;
  454. newItem.Quantity = item.Quantity;
  455. result.Add(newItem);
  456. }
  457. Client.Save(result, "Edited by user.");
  458. Result = result.ToArray();
  459. }
  460. private void JobRequisitionItems_OnOnChanged(object? sender, EventArgs e)
  461. {
  462. CheckCanSave();
  463. }
  464. #endregion
  465. #region Product Instances
  466. private ProductInstance? SelectedProductInstance;
  467. private void LoadProductInstances()
  468. {
  469. ProductInstancesProducts.Refresh(true, true);
  470. ProductInstances.Refresh(true, false);
  471. foreach(var column in new Columns<ProductInstance>(x => x.Style.ID).AddDimensionsColumns(x => x.Dimensions))
  472. {
  473. ProductInstances.HiddenColumns.Add(column);
  474. }
  475. if(Item.Product.ID != Guid.Empty)
  476. {
  477. // Delaying, cause otherwise it doesn't work.
  478. Dispatcher.BeginInvoke(() =>
  479. {
  480. ProductInstancesProducts.SelectedRows = ProductInstancesProducts.Data.Rows.Where(x => x.Get<Product, Guid>(x => x.ID) == Item.Product.ID).ToArray();
  481. if (ProductInstancesProducts.SelectedRows.Any())
  482. ProductInstancesProducts.ScrollIntoView(ProductInstancesProducts.SelectedRows[0]);
  483. });
  484. }
  485. }
  486. private bool CanSaveProductInstances()
  487. {
  488. return ProductInstances.Product is not null && SelectedProductInstance is not null && RequiredQuantity > 0;
  489. }
  490. private void SaveProductInstances()
  491. {
  492. if (ProductInstances.Product is null || SelectedProductInstance is null) return;
  493. Item.Product.CopyFrom(ProductInstances.Product);
  494. Item.Style.CopyFrom(SelectedProductInstance.Style);
  495. Item.Dimensions.CopyFrom(SelectedProductInstance.Dimensions, true);
  496. Item.Location.ID = Guid.Empty;
  497. Item.EditType = RequisitionItemEditType.Normal;
  498. Client.Save(Item, "Edited by user.");
  499. Result = [Item];
  500. }
  501. private void ProductInstancesProducts_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e)
  502. {
  503. ProductInstances.Product = e.Rows is not null && e.Rows.Length > 0 ? e.Rows[0].ToObject<Product>() : null;
  504. ProductInstances.Refresh(false, true);
  505. CheckCanSave();
  506. }
  507. private void ProductInstances_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
  508. {
  509. SelectedProductInstance = e.Rows is not null && e.Rows.Length > 0 ? e.Rows[0].ToObject<ProductInstance>() : null;
  510. CheckCanSave();
  511. }
  512. #endregion
  513. #region Custom
  514. private void LoadCustom()
  515. {
  516. CustomEditorGrid.Setup(typeof(RequisitionItem));
  517. CustomEditorGrid.Items = new RequisitionItem[] { Item };
  518. }
  519. private static readonly Columns<RequisitionItem> ActualCustomColumns = new Columns<RequisitionItem>()
  520. .Add(x => x.Product.ID)
  521. .Add(x => x.Style.ID)
  522. .Add(x => x.Dimensions)
  523. .Add(x => x.Description)
  524. .Add(x => x.Location.ID)
  525. .Add(x => x.Quantity)
  526. .Add(x => x.ActualQuantity);
  527. private static readonly Columns<RequisitionItem> RequstedCustomColumns = new Columns<RequisitionItem>()
  528. .Add(x => x.Product.ID)
  529. .Add(x => x.Style.ID)
  530. .Add(x => x.Dimensions)
  531. .Add(x => x.Description)
  532. .Add(x => x.Location.ID)
  533. .Add(x => x.Quantity)
  534. .Add(x => x.ActualQuantity);
  535. // private static readonly Columns<RequisitionItem> ProductInstanceCustomColumns = new Columns<RequisitionItem>()
  536. // .Add(x => x.Product.ID)
  537. // .Add(x => x.Style.ID)
  538. // .Add(x => x.Dimensions)
  539. // .Add(x => x.Description)
  540. // .Add(x => x.Quantity);
  541. private void CustomEditorGrid_OnFormCustomiseEditor(IDynamicEditorForm sender, object items, DynamicGridColumn column, BaseEditor editor)
  542. {
  543. var columns = _allowActual ? ActualCustomColumns : RequstedCustomColumns;
  544. editor.Editable = columns.Contains(column.ColumnName)
  545. ? Editable.Enabled
  546. : Editable.Hidden;
  547. }
  548. /*
  549. private void LoadCustom()
  550. {
  551. var host = new DefaultDynamicEditorHost<RequisitionItem>
  552. {
  553. Items = [Item]
  554. };
  555. var editors = new Dictionary<string, IDynamicEditorControl>();
  556. BaseDynamicEditorControl? CreateControl(Expression<Func<RequisitionItem, object?>> exp, int row)
  557. {
  558. var property = DatabaseSchema.Property(exp)!;
  559. BaseEditor? editor;
  560. if (property.HasParentEditor())
  561. {
  562. property = property.GetParentWithEditor();
  563. }
  564. if (property is null) return null;
  565. editor = property.Editor;
  566. editor = editor.CloneEditor();
  567. var control = DynamicEditorControlFactory.CreateControl(editor, host)!;
  568. Grid.SetRow(control, row);
  569. Grid.SetColumn(control, 1);
  570. control.Margin = new Thickness(5, 2.5, 5, 2.5);
  571. CustomEditorGrid.Children.Add(control);
  572. editors[property.Name] = control;
  573. control.IsEnabled = true;
  574. control.ColumnName = property.Name;
  575. control.Color = editor is UniqueCodeEditor ? Color.FromArgb(0xFF, 0xF6, 0xC9, 0xE8) : Colors.LightYellow;
  576. control.Configure();
  577. control.Loaded = true;
  578. foreach(var (k, v) in control.GetValues())
  579. {
  580. var value = DatabaseSchema.Property(typeof(RequisitionItem), k)!.Getter()(Item);
  581. if(!Equals(v, value))
  582. {
  583. bool bLoaded = control.Loaded;
  584. control.Loaded = false;
  585. control.SetValue(k, value);
  586. control.Loaded = bLoaded;
  587. }
  588. }
  589. control.OnEditorValueChanged += (sender, values) =>
  590. {
  591. var changededitors = new Dictionary<string, object?>();
  592. void ExtractChanged(Dictionary<string, object?>? columns)
  593. {
  594. if (columns != null)
  595. foreach (var (change, value) in columns)
  596. if (!changededitors.ContainsKey(change) && !change.Equals(sender.ColumnName))
  597. changededitors[change] = value;
  598. }
  599. var name = sender.ColumnName;
  600. var resetAll = false;
  601. if(values.Remove(name, out var value))
  602. {
  603. var changedcolumns = DynamicGridUtils.UpdateEditorValue([Item], sender.ColumnName, value);
  604. resetAll = changedcolumns?.ContainsKey(name) ?? false;
  605. ExtractChanged(changedcolumns);
  606. }
  607. foreach(var (k, v) in values)
  608. {
  609. var changes = new Dictionary<string, object?>();
  610. if (resetAll)
  611. {
  612. var prop = DatabaseSchema.Property(typeof(RequisitionItem), k);
  613. if(prop is not null)
  614. {
  615. var def = CoreUtils.GetDefault(prop.PropertyType);
  616. var resetChanges = DynamicGridUtils.UpdateEditorValue([Item], k, def);
  617. if(resetChanges is not null)
  618. {
  619. changes = resetChanges;
  620. }
  621. }
  622. else
  623. {
  624. }
  625. }
  626. var changedOtherColumns = DynamicGridUtils.UpdateEditorValue([Item], k, v);
  627. if(changedOtherColumns is not null)
  628. {
  629. foreach (var (k1, v1) in changedOtherColumns)
  630. {
  631. changes[k1] = v1;
  632. }
  633. }
  634. ExtractChanged(changes);
  635. }
  636. if (changededitors.Count != 0)
  637. {
  638. foreach(var (k, v) in changededitors)
  639. {
  640. var editor = editors.GetValueOrDefault(k) ?? editors.FirstOrDefault(x => k.StartsWith(x.Key + ".")).Value;
  641. if(editor is not null)
  642. {
  643. editor.Loaded = false;
  644. editor.SetValue(k, v);
  645. editor.Loaded = true;
  646. }
  647. }
  648. }
  649. };
  650. return control;
  651. }
  652. var productEditor = CreateControl(x => x.Product.ID, 0);
  653. var styleEditor = CreateControl(x => x.Style.ID, 1);
  654. var dimensionsEditor = CreateControl(x => x.Dimensions.Quantity, 2);
  655. var descriptionEditor = CreateControl(x => x.Description, 3);
  656. var locationEditor = CreateControl(x => x.Location.ID, 4);
  657. var quantityEditor = CreateControl(x => x.Quantity, 5);
  658. }
  659. */
  660. private void SaveCustom()
  661. {
  662. Item.EditType = RequisitionItemEditType.Custom;
  663. Client.Save(Item, "Custom edited by user.");
  664. Result = [Item];
  665. }
  666. #endregion
  667. }