JobRequisitionItemGrid.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. _pois[_jri] = _poi;
  110. }
  111. Client.Save(_pois.Values, "Created From Requisition Screen");
  112. var poias = new List<PurchaseOrderItemAllocation>();
  113. foreach (var _jri in _pois.Keys)
  114. {
  115. var poia = new PurchaseOrderItemAllocation();
  116. poia.Job.ID = _jri.Job.ID;
  117. poia.JobRequisitionItem.ID = _jri.ID;
  118. poia.Quantity = _pois[_jri].Qty;
  119. poia.Item.ID = _pois[_jri].ID;
  120. }
  121. Client.Save(poias,"Created From Requisition Screen");
  122. });
  123. }
  124. new SupplierPurchaseOrders().EditItems(new[] { _po });
  125. return true;
  126. }
  127. #endregion
  128. #region CreatePickingList
  129. private bool DoCreatePickingList(Button button, CoreRow[]? rows)
  130. {
  131. if (rows?.Any() != true)
  132. return false;
  133. if (rows.All(r =>
  134. r.Get<JobRequisitionItem, double>(x => x.PickRequested)
  135. .IsEffectivelyEqual(r.Get<JobRequisitionItem, double>(x => x.Qty))))
  136. {
  137. MessageWindow.ShowMessage("All Items have been picked!","Error");
  138. return false;
  139. }
  140. var picklist = new Requisition();
  141. if (Job != null)
  142. picklist.JobLink.CopyFrom(Job);
  143. else
  144. picklist.JobLink.CopyFrom(Master?.Job ?? new JobLink());
  145. if (new RequisitionGrid().EditItems(new Requisition[] { picklist }))
  146. {
  147. Progress.ShowModal("Creating Picking List", (progress) =>
  148. {
  149. List<RequisitionItem> pickitems = new();
  150. foreach (var item in rows.Select(x => x.ToObject<JobRequisitionItem>()))
  151. {
  152. if (!item.PickRequested.IsEffectivelyEqual(item.Qty))
  153. {
  154. var pickitem = new RequisitionItem();
  155. pickitem.RequisitionLink.ID = picklist.ID;
  156. pickitem.RequisitionLink.Synchronise(picklist);
  157. pickitem.SourceJRI.ID = item.ID;
  158. pickitem.SourceJRI.Synchronise(item);
  159. pickitem.Product.ID = item.Product.ID;
  160. pickitem.Product.Synchronise(item.Product);
  161. pickitem.Style.ID = item.Style.ID;
  162. pickitem.Style.Synchronise(item.Style);
  163. pickitem.Dimensions.CopyFrom(item.Dimensions);
  164. pickitem.Quantity = item.Qty - item.PickRequested;
  165. pickitems.Add(pickitem);
  166. }
  167. }
  168. Client.Save(pickitems, "Created from Job Requisition");
  169. });
  170. }
  171. return true;
  172. }
  173. #endregion
  174. // private void CheckVisibility()
  175. // {
  176. // CancelItemsButton.Visibility = Master is not null && Security.CanEdit<JobRequisition>() && Security.CanEdit<JobRequisitionItem>()
  177. // ? System.Windows.Visibility.Visible
  178. // : System.Windows.Visibility.Hidden;
  179. // }
  180. // protected override void SelectItems(CoreRow[]? rows)
  181. // {
  182. // base.SelectItems(rows);
  183. // CancelItemsButton.IsEnabled = rows is not null && rows.Length > 0;
  184. // }
  185. //private bool CancelItems(Button button, CoreRow[] rows)
  186. //{
  187. // if (Master is null) return false;
  188. // if(rows.Length == 0)
  189. // {
  190. // MessageWindow.ShowMessage("Please select at least one item to cancel.", "Select items");
  191. // return false;
  192. // }
  193. // // Reloading so I can ensure the correct columns without having to add hidden columns to JobRequisitionGrid.
  194. // var oldRequi = Client.Query(
  195. // new Filter<JobRequisition>(x => x.ID).IsEqualTo(Master?.ID ?? Guid.Empty),
  196. // Columns.None<JobRequisition>().Add(x => x.Description)
  197. // .Add(x => x.Number)
  198. // .Add(x => x.DueDate))
  199. // .ToObjects<JobRequisition>()
  200. // .First();
  201. // var oldRequiItems = Client.Query(
  202. // new Filter<JobRequisitionItem>(x => x.ID).InList(rows.Select(x => x.Get<JobRequisitionItem, Guid>(x => x.ID)).ToArray()),
  203. // Columns.None<JobRequisitionItem>().Add(x => x.Qty)
  204. // .Add(x => x.Sequence)
  205. // .Add(x => x.Job.ID)
  206. // .Add(x => x.Product.ID)
  207. // .Add(x => x.Product.Code)
  208. // .Add(x => x.Style.ID)
  209. // .Add(x => x.Style.Code)
  210. // .Add(x => x.Style.Description)
  211. // .Add(x => x.Dimensions.Unit.ID)
  212. // .Add(x => x.Dimensions.Quantity)
  213. // .Add(x => x.Dimensions.Length)
  214. // .Add(x => x.Dimensions.Width)
  215. // .Add(x => x.Dimensions.Height)
  216. // .Add(x => x.Dimensions.Weight)
  217. // .Add(x => x.Dimensions.UnitSize)
  218. // .Add(x => x.Supplier.ID));
  219. // var requisition = new JobRequisition
  220. // {
  221. // Description = $"Adjustment Requisition for Requisition {oldRequi.Number}",
  222. // DueDate = oldRequi.DueDate
  223. // };
  224. // requisition.Job.ID = Master.Job.ID;
  225. // requisition.Job.Synchronise(Master.Job);
  226. // var requiItems = new List<JobRequisitionItem>();
  227. // foreach(var oldItem in oldRequiItems.ToObjects<JobRequisitionItem>())
  228. // {
  229. // var newItem = new JobRequisitionItem
  230. // {
  231. // Notes = "Adjustment Requisition item",
  232. // Qty = -oldItem.Qty,
  233. // Sequence = oldItem.Sequence
  234. // };
  235. // newItem.Job.ID = requisition.Job.ID;
  236. // newItem.Product.ID = oldItem.Product.ID;
  237. // newItem.Style.ID = oldItem.Style.ID;
  238. // newItem.Supplier.ID = oldItem.Supplier.ID;
  239. // requiItems.Add(newItem);
  240. // }
  241. // var grid = DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(JobRequisition));
  242. // if (grid.EditItems(new JobRequisition[] { requisition }, t =>
  243. // {
  244. // if (t == typeof(JobRequisitionItem))
  245. // {
  246. // var table = new CoreTable();
  247. // table.LoadColumns(new Columns<JobRequisitionItem>(ColumnTypeFlags.Local | ColumnTypeFlags.IncludeAggregates | ColumnTypeFlags.IncludeFormulae | ColumnTypeFlags.Required));
  248. // table.LoadRows(requiItems);
  249. // return table;
  250. // }
  251. // return null;
  252. // }))
  253. // {
  254. // MessageWindow.ShowMessage($"Created requisition {requisition.Number}", "Created Requisition");
  255. // return true;
  256. // }
  257. // else
  258. // {
  259. // return false;
  260. // }
  261. //}
  262. protected override void DoReconfigure(DynamicGridOptions options)
  263. {
  264. base.DoReconfigure(options);
  265. options.RecordCount = true;
  266. options.SelectColumns = true;
  267. options.FilterRows = true;
  268. options.MultiSelect = true;
  269. if(Master is not null)
  270. {
  271. options.AddRows = true;
  272. }
  273. else
  274. {
  275. options.AddRows = false;
  276. }
  277. }
  278. protected override void Reload(
  279. Filters<JobRequisitionItem> criteria, Columns<JobRequisitionItem> columns, ref SortOrder<JobRequisitionItem>? sort,
  280. CancellationToken token, Action<CoreTable?, Exception?> action)
  281. {
  282. criteria.Add(MasterDetailFilter);
  283. base.Reload(criteria, columns, ref sort, token, action);
  284. }
  285. protected override bool CanCreateItems()
  286. {
  287. return base.CanCreateItems() && (Master?.ID ?? Guid.Empty) != Guid.Empty;
  288. }
  289. public override JobRequisitionItem CreateItem()
  290. {
  291. var result = base.CreateItem();
  292. if(Master is not null)
  293. {
  294. result.Requisition.ID = Master.ID;
  295. result.Requisition.Synchronise(Master);
  296. result.Job.ID = Master.Job.ID;
  297. result.Job.Synchronise(Master.Job);
  298. }
  299. result.Qty = 1;
  300. return result;
  301. }
  302. protected override void OnAfterEditorValueChanged(DynamicEditorGrid? grid, JobRequisitionItem[] items, AfterEditorValueChangedArgs args, Dictionary<string, object?> changes)
  303. {
  304. base.OnAfterEditorValueChanged(grid, items, args, changes);
  305. if (args.ColumnName.Equals("Product.ID") || args.ColumnName.Equals("Dimensions") || args.ColumnName.StartsWith("Dimensions.") || args.ColumnName.Equals("Style.ID") || args.ColumnName.Equals("Supplier.ID"))
  306. {
  307. JobRequisitionItem.UpdateCosts(
  308. items,
  309. changes
  310. );
  311. }
  312. }
  313. public override DynamicGridColumns GenerateColumns()
  314. {
  315. var columns = new DynamicGridColumns();
  316. columns.Add<JobRequisitionItem, DateTime>(x => x.Created, 80, "Date", "", Alignment.MiddleLeft);
  317. columns.Add<JobRequisitionItem, string>(x => x.Requisition.Job.JobNumber, 70, "Job", "", Alignment.MiddleLeft);
  318. columns.Add<JobRequisitionItem, int>(x => x.Requisition.Number, 50, "NO.", "", Alignment.MiddleLeft);
  319. columns.Add<JobRequisitionItem, string>(x => x.Product.Code, 70, "Code", "", Alignment.MiddleLeft);
  320. columns.Add<JobRequisitionItem, string>(x => x.Product.Name, 200, "Product Name", "", Alignment.MiddleLeft);
  321. columns.Add<JobRequisitionItem, string>(x => x.Style.Description, 150, "Style", "", Alignment.MiddleLeft);
  322. columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleLeft);
  323. columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 50, "Size", "", Alignment.MiddleLeft);
  324. columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderNumbers, 80, "PO Numbers", "", Alignment.MiddleLeft);
  325. columns.Add<JobRequisitionItem, string>(x => x.Notes, 300, "Notes", "", Alignment.MiddleLeft);
  326. columns.AddRange(base.GenerateColumns());
  327. return columns;
  328. }
  329. }