JobRequisitionItemGrid.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.Immutable;
  4. using System.Linq;
  5. using System.Reactive.Linq;
  6. using System.Threading;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using Comal.Classes;
  10. using InABox.Clients;
  11. using InABox.Core;
  12. using InABox.DynamicGrid;
  13. using InABox.Wpf;
  14. using InABox.WPF;
  15. using Syncfusion.Windows.Controls.RichTextBoxAdv;
  16. namespace PRSDesktop;
  17. internal class JobRequisitionItemGrid : DynamicDataGrid<JobRequisitionItem>, IMasterDetailControl<JobRequisition, JobRequisitionItem>, ISpecificGrid
  18. {
  19. public Job? Job { get; set; }
  20. private JobRequisition? _master;
  21. public JobRequisition? Master
  22. {
  23. get => _master;
  24. set
  25. {
  26. _master = value;
  27. // CheckVisibility();
  28. Reconfigure();
  29. }
  30. }
  31. public Filter<JobRequisitionItem> MasterDetailFilter => Master != null
  32. ? Master.ID != Guid.Empty
  33. ? new Filter<JobRequisitionItem>(x => x.Requisition.ID).IsEqualTo(Master.ID)
  34. : new Filter<JobRequisitionItem>().None()
  35. : Job is not null && Job.ID != Guid.Empty
  36. ? new Filter<JobRequisitionItem>(x => x.Requisition.Job.ID).IsEqualTo(Job.ID)
  37. : new Filter<JobRequisitionItem>().None();
  38. private Button CreatePickingList;
  39. private Button CreateOrder;
  40. public JobRequisitionItemGrid()
  41. {
  42. HiddenColumns.Add(x=>x.Product.ID);
  43. HiddenColumns.Add(x=>x.Style.ID);
  44. HiddenColumns.Add(x=>x.Dimensions.Unit.ID);
  45. HiddenColumns.Add(x=>x.Dimensions.Unit.HasHeight);
  46. HiddenColumns.Add(x=>x.Dimensions.Unit.HasLength);
  47. HiddenColumns.Add(x=>x.Dimensions.Unit.HasWidth);
  48. HiddenColumns.Add(x=>x.Dimensions.Unit.HasQuantity);
  49. HiddenColumns.Add(x=>x.Dimensions.Unit.HasWeight);
  50. HiddenColumns.Add(x=>x.Dimensions.Unit.Formula);
  51. HiddenColumns.Add(x=>x.Dimensions.Unit.Format);
  52. HiddenColumns.Add(x=>x.Dimensions.Height);
  53. HiddenColumns.Add(x=>x.Dimensions.Length);
  54. HiddenColumns.Add(x=>x.Dimensions.Width);
  55. HiddenColumns.Add(x=>x.Dimensions.Quantity);
  56. HiddenColumns.Add(x=>x.Dimensions.Weight);
  57. HiddenColumns.Add(x=>x.Dimensions.Value);
  58. HiddenColumns.Add(x=>x.Dimensions.UnitSize);
  59. HiddenColumns.Add(x=>x.UnitCost);
  60. HiddenColumns.Add(x=>x.PickRequested);
  61. CreateOrder = AddButton("Create Order", PRSDesktop.Resources.purchase.AsBitmapImage(), DoCreatePurchaseOrder);
  62. CreatePickingList = AddButton("Create Picking List", PRSDesktop.Resources.trolley.AsBitmapImage(), DoCreatePickingList);
  63. }
  64. protected override void SelectItems(CoreRow[]? rows)
  65. {
  66. base.SelectItems(rows);
  67. CreatePickingList.IsEnabled = rows?.Any() == true;
  68. }
  69. #region CreatePurchaseOrder
  70. private bool DoCreatePurchaseOrder(Button button, CoreRow[] rows)
  71. {
  72. if (rows.Length == 0)
  73. return false;
  74. var dlg = new MultiSelectDialog<Supplier>(
  75. LookupFactory.DefineFilter<Supplier>(),
  76. Columns.None<Supplier>()
  77. .Add(x => x.ID)
  78. .Add(x => x.Code)
  79. .Add(x => x.Name),
  80. false);
  81. var _po = new PurchaseOrder();
  82. if (dlg.ShowDialog())
  83. {
  84. Progress.ShowModal("Creating Purchase Order", progress =>
  85. {
  86. _po.Description = "Created from Job Requisition Screen" + System.Environment.NewLine;
  87. _po.RaisedBy.ID = App.EmployeeID;
  88. _po.SupplierLink.ID = dlg.IDs().First();
  89. Client.Save(_po, "Created From Requisition Screen");
  90. progress.Report("Creating Order Items");
  91. var _pois = new Dictionary<JobRequisitionItem,PurchaseOrderItem>();
  92. foreach (CoreRow row in SelectedRows)
  93. {
  94. var _jri = row.ToObject<JobRequisitionItem>();
  95. var _poi = new PurchaseOrderItem();
  96. _poi.PurchaseOrderLink.ID = _po.ID;
  97. _poi.Product.ID = _jri.Product.ID;
  98. _poi.Product.Code = _jri.Product.Code;
  99. _poi.Product.Name = _jri.Product.Name;
  100. _poi.Qty = _jri.Qty;
  101. _poi.Dimensions.CopyFrom(_jri.Dimensions);
  102. _poi.Dimensions.Value = _jri.Dimensions.Value;
  103. _poi.Style.ID = _jri.Style.ID;
  104. _poi.Style.Code = _jri.Style.Code;
  105. _poi.Style.Description = _jri.Style.Description;
  106. _poi.Dimensions.UnitSize = _jri.Dimensions.UnitSize;
  107. _poi.Description = _jri.Product.Name + " (" + _jri.Dimensions.ToString() + ")";
  108. _poi.Cost = _jri.UnitCost;
  109. _poi.Job.ID = _jri.Job.ID;
  110. _pois[_jri] = _poi;
  111. }
  112. Client.Save(_pois.Values, "Created From Requisition Screen");
  113. var poias = new List<PurchaseOrderItemAllocation>();
  114. foreach (var _jri in _pois.Keys)
  115. {
  116. var poia = new PurchaseOrderItemAllocation();
  117. poia.Job.ID = _jri.Job.ID;
  118. poia.JobRequisitionItem.ID = _jri.ID;
  119. poia.Quantity = _pois[_jri].Qty;
  120. poia.Item.ID = _pois[_jri].ID;
  121. }
  122. Client.Save(poias,"Created From Requisition Screen");
  123. });
  124. }
  125. new SupplierPurchaseOrders().EditItems(new[] { _po });
  126. return true;
  127. }
  128. #endregion
  129. #region CreatePickingList
  130. private bool DoCreatePickingList(Button button, CoreRow[]? rows)
  131. {
  132. if (rows?.Any() != true)
  133. return false;
  134. if (rows.All(r =>
  135. r.Get<JobRequisitionItem, double>(x => x.PickRequested)
  136. .IsEffectivelyEqual(r.Get<JobRequisitionItem, double>(x => x.Qty))))
  137. {
  138. MessageWindow.ShowMessage("All Items have been picked!","Error");
  139. return false;
  140. }
  141. var picklist = new Requisition();
  142. if (Job != null)
  143. picklist.JobLink.CopyFrom(Job);
  144. else
  145. picklist.JobLink.CopyFrom(Master?.Job ?? new JobLink());
  146. if (new RequisitionGrid().EditItems(new Requisition[] { picklist }))
  147. {
  148. Progress.ShowModal("Creating Picking List", (progress) =>
  149. {
  150. List<RequisitionItem> pickitems = new();
  151. foreach (var item in rows.Select(x => x.ToObject<JobRequisitionItem>()))
  152. {
  153. if (!item.PickRequested.IsEffectivelyEqual(item.Qty))
  154. {
  155. var pickitem = new RequisitionItem();
  156. pickitem.RequisitionLink.ID = picklist.ID;
  157. pickitem.RequisitionLink.Synchronise(picklist);
  158. pickitem.SourceJRI.ID = item.ID;
  159. pickitem.SourceJRI.Synchronise(item);
  160. pickitem.Product.ID = item.Product.ID;
  161. pickitem.Product.Synchronise(item.Product);
  162. pickitem.Style.ID = item.Style.ID;
  163. pickitem.Style.Synchronise(item.Style);
  164. pickitem.Dimensions.CopyFrom(item.Dimensions);
  165. pickitem.Quantity = item.Qty - item.PickRequested;
  166. pickitems.Add(pickitem);
  167. }
  168. }
  169. Client.Save(pickitems, "Created from Job Requisition");
  170. });
  171. }
  172. return true;
  173. }
  174. #endregion
  175. // private void CheckVisibility()
  176. // {
  177. // CancelItemsButton.Visibility = Master is not null && Security.CanEdit<JobRequisition>() && Security.CanEdit<JobRequisitionItem>()
  178. // ? System.Windows.Visibility.Visible
  179. // : System.Windows.Visibility.Hidden;
  180. // }
  181. // protected override void SelectItems(CoreRow[]? rows)
  182. // {
  183. // base.SelectItems(rows);
  184. // CancelItemsButton.IsEnabled = rows is not null && rows.Length > 0;
  185. // }
  186. //private bool CancelItems(Button button, CoreRow[] rows)
  187. //{
  188. // if (Master is null) return false;
  189. // if(rows.Length == 0)
  190. // {
  191. // MessageWindow.ShowMessage("Please select at least one item to cancel.", "Select items");
  192. // return false;
  193. // }
  194. // // Reloading so I can ensure the correct columns without having to add hidden columns to JobRequisitionGrid.
  195. // var oldRequi = Client.Query(
  196. // new Filter<JobRequisition>(x => x.ID).IsEqualTo(Master?.ID ?? Guid.Empty),
  197. // Columns.None<JobRequisition>().Add(x => x.Description)
  198. // .Add(x => x.Number)
  199. // .Add(x => x.DueDate))
  200. // .ToObjects<JobRequisition>()
  201. // .First();
  202. // var oldRequiItems = Client.Query(
  203. // new Filter<JobRequisitionItem>(x => x.ID).InList(rows.Select(x => x.Get<JobRequisitionItem, Guid>(x => x.ID)).ToArray()),
  204. // Columns.None<JobRequisitionItem>().Add(x => x.Qty)
  205. // .Add(x => x.Sequence)
  206. // .Add(x => x.Job.ID)
  207. // .Add(x => x.Product.ID)
  208. // .Add(x => x.Product.Code)
  209. // .Add(x => x.Style.ID)
  210. // .Add(x => x.Style.Code)
  211. // .Add(x => x.Style.Description)
  212. // .Add(x => x.Dimensions.Unit.ID)
  213. // .Add(x => x.Dimensions.Quantity)
  214. // .Add(x => x.Dimensions.Length)
  215. // .Add(x => x.Dimensions.Width)
  216. // .Add(x => x.Dimensions.Height)
  217. // .Add(x => x.Dimensions.Weight)
  218. // .Add(x => x.Dimensions.UnitSize)
  219. // .Add(x => x.Supplier.ID));
  220. // var requisition = new JobRequisition
  221. // {
  222. // Description = $"Adjustment Requisition for Requisition {oldRequi.Number}",
  223. // DueDate = oldRequi.DueDate
  224. // };
  225. // requisition.Job.ID = Master.Job.ID;
  226. // requisition.Job.Synchronise(Master.Job);
  227. // var requiItems = new List<JobRequisitionItem>();
  228. // foreach(var oldItem in oldRequiItems.ToObjects<JobRequisitionItem>())
  229. // {
  230. // var newItem = new JobRequisitionItem
  231. // {
  232. // Notes = "Adjustment Requisition item",
  233. // Qty = -oldItem.Qty,
  234. // Sequence = oldItem.Sequence
  235. // };
  236. // newItem.Job.ID = requisition.Job.ID;
  237. // newItem.Product.ID = oldItem.Product.ID;
  238. // newItem.Style.ID = oldItem.Style.ID;
  239. // newItem.Supplier.ID = oldItem.Supplier.ID;
  240. // requiItems.Add(newItem);
  241. // }
  242. // var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(JobRequisition));
  243. // if (grid.EditItems(new JobRequisition[] { requisition }, t =>
  244. // {
  245. // if (t == typeof(JobRequisitionItem))
  246. // {
  247. // var table = new CoreTable();
  248. // table.LoadColumns(new Columns<JobRequisitionItem>(ColumnTypeFlags.Local | ColumnTypeFlags.IncludeAggregates | ColumnTypeFlags.IncludeFormulae | ColumnTypeFlags.Required));
  249. // table.LoadRows(requiItems);
  250. // return table;
  251. // }
  252. // return null;
  253. // }))
  254. // {
  255. // MessageWindow.ShowMessage($"Created requisition {requisition.Number}", "Created Requisition");
  256. // return true;
  257. // }
  258. // else
  259. // {
  260. // return false;
  261. // }
  262. //}
  263. protected override void DoReconfigure(DynamicGridOptions options)
  264. {
  265. base.DoReconfigure(options);
  266. options.RecordCount = true;
  267. options.SelectColumns = true;
  268. options.FilterRows = true;
  269. options.MultiSelect = true;
  270. if(Master is not null)
  271. {
  272. options.AddRows = true;
  273. }
  274. else
  275. {
  276. options.AddRows = false;
  277. }
  278. }
  279. protected override void Reload(
  280. Filters<JobRequisitionItem> criteria, Columns<JobRequisitionItem> columns, ref SortOrder<JobRequisitionItem>? sort,
  281. CancellationToken token, Action<CoreTable?, Exception?> action)
  282. {
  283. criteria.Add(MasterDetailFilter);
  284. base.Reload(criteria, columns, ref sort, token, action);
  285. }
  286. protected override bool CanCreateItems()
  287. {
  288. return base.CanCreateItems() && (Master?.ID ?? Guid.Empty) != Guid.Empty;
  289. }
  290. public override JobRequisitionItem CreateItem()
  291. {
  292. var result = base.CreateItem();
  293. if(Master is not null)
  294. {
  295. result.Requisition.ID = Master.ID;
  296. result.Requisition.Synchronise(Master);
  297. result.Job.ID = Master.Job.ID;
  298. result.Job.Synchronise(Master.Job);
  299. }
  300. result.Qty = 1;
  301. return result;
  302. }
  303. private JobRequisitionItem.JRICostData? _jriCostData;
  304. protected override void OnAfterEditorValueChanged(DynamicEditorGrid? grid, JobRequisitionItem[] items, AfterEditorValueChangedArgs args, Dictionary<string, object?> changes)
  305. {
  306. base.OnAfterEditorValueChanged(grid, items, args, changes);
  307. if (args.ColumnName.Equals("Product.ID") || args.ColumnName.Equals("Dimensions") || args.ColumnName.StartsWith("Dimensions.") || args.ColumnName.Equals("Style.ID") || args.ColumnName.Equals("Supplier.ID"))
  308. {
  309. _jriCostData ??= new();
  310. JobRequisitionItem.UpdateCosts(
  311. items,
  312. changes,
  313. data: _jriCostData
  314. );
  315. }
  316. }
  317. public override DynamicGridColumns GenerateColumns()
  318. {
  319. var columns = new DynamicGridColumns();
  320. columns.Add<JobRequisitionItem, DateTime>(x => x.Created, 80, "Date", "", Alignment.MiddleLeft);
  321. columns.Add<JobRequisitionItem, string>(x => x.Requisition.Job.JobNumber, 70, "Job", "", Alignment.MiddleLeft);
  322. columns.Add<JobRequisitionItem, int>(x => x.Requisition.Number, 50, "NO.", "", Alignment.MiddleLeft);
  323. columns.Add<JobRequisitionItem, string>(x => x.Product.Code, 70, "Code", "", Alignment.MiddleLeft);
  324. columns.Add<JobRequisitionItem, string>(x => x.Product.Name, 200, "Product Name", "", Alignment.MiddleLeft);
  325. columns.Add<JobRequisitionItem, string>(x => x.Style.Description, 150, "Style", "", Alignment.MiddleLeft);
  326. columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleLeft);
  327. columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 50, "Size", "", Alignment.MiddleLeft);
  328. columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderNumbers, 80, "PO Numbers", "", Alignment.MiddleLeft);
  329. columns.Add<JobRequisitionItem, string>(x => x.Notes, 300, "Notes", "", Alignment.MiddleLeft);
  330. columns.AddRange(base.GenerateColumns());
  331. return columns;
  332. }
  333. }