RequisitionItemGrid.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media.Imaging;
  7. using Comal.Classes;
  8. using InABox.Clients;
  9. using InABox.Core;
  10. using InABox.DynamicGrid;
  11. using InABox.Wpf;
  12. using InABox.WPF;
  13. using Microsoft.Office.Interop.Outlook;
  14. using Syncfusion.Windows.Tools.Controls;
  15. using Exception = System.Exception;
  16. namespace PRSDesktop
  17. {
  18. public class RequisitionItemGrid : DynamicDataGrid<RequisitionItem>
  19. {
  20. //public int Boxes { get; set; }
  21. private static readonly BitmapImage tick = PRSDesktop.Resources.tick.AsBitmapImage();
  22. public RequisitionItemGrid()
  23. {
  24. HiddenColumns.Add(x => x.Code);
  25. HiddenColumns.Add(x => x.BarCode);
  26. HiddenColumns.Add(x => x.RequisitionLink.ID);
  27. HiddenColumns.Add(x => x.RequisitionLink.JobLink.ID);
  28. HiddenColumns.Add(x => x.RequisitionLink.JobScope.ID);
  29. HiddenColumns.Add(x => x.RequisitionLink.Filled);
  30. HiddenColumns.Add(x => x.RequisitionLink.Archived);
  31. HiddenColumns.Add(x => x.Product.ID);
  32. HiddenColumns.Add(x => x.Product.Deleted);
  33. HiddenColumns.Add(x => x.Product.DefaultInstance.Style.ID);
  34. foreach(var column in new Columns<RequisitionItem>()
  35. .AddDimensionsColumns(x => x.Product.DefaultInstance.Dimensions, Dimensions.ColumnsType.Data)
  36. .GetColumns())
  37. {
  38. HiddenColumns.Add(column);
  39. }
  40. //HiddenColumns.Add(x => x.Product.Units.ID);
  41. HiddenColumns.Add(x => x.Product.NonStock);
  42. HiddenColumns.Add(x => x.Location.ID);
  43. HiddenColumns.Add(x => x.Location.Code);
  44. HiddenColumns.Add(x => x.Location.Description);
  45. HiddenColumns.Add(x => x.Location.Deleted);
  46. HiddenColumns.Add(x => x.Style.ID);
  47. HiddenColumns.Add(x => x.Style.Code);
  48. HiddenColumns.Add(x => x.Picked);
  49. HiddenColumns.Add(x => x.Image.ID);
  50. HiddenColumns.Add(x => x.Image.FileName);
  51. ActionColumns.Add(new DynamicImageManagerColumn<RequisitionItem>(this, x => x.Image, true) { Position = DynamicActionColumnPosition.Start });
  52. ActionColumns.Add(new DynamicImageColumn(Pick_Image, Pick_Click)
  53. {
  54. ToolTip = Pick_ToolTip
  55. });
  56. ActionColumns.Add(new DynamicMenuColumn(SelectHolding,
  57. (row) => (row.Get<RequisitionItem, Guid>(c => c.Product.ID) == Guid.Empty) || row.Get<RequisitionItem, bool>(c => c.Product.NonStock) == true
  58. ? DynamicMenuStatus.Hidden
  59. : DynamicMenuStatus.Enabled)
  60. );
  61. }
  62. private FrameworkElement? Pick_ToolTip(DynamicActionColumn column, CoreRow? row)
  63. {
  64. string content;
  65. if (row is null)
  66. {
  67. content = "Has this item been picked?";
  68. }
  69. else
  70. {
  71. if(!row.Get<RequisitionItem, DateTime>(x => x.Picked).IsEmpty())
  72. {
  73. content = "This item has been picked";
  74. }
  75. else
  76. {
  77. content = "This item has not been picked";
  78. }
  79. }
  80. return column.TextToolTip(content);
  81. }
  82. private BitmapImage? Pick_Image(CoreRow? row)
  83. {
  84. return row is null
  85. ? tick
  86. : (row.Get<RequisitionItem, DateTime>(x => x.Picked).IsEmpty()
  87. ? null
  88. : tick);
  89. }
  90. private bool Pick_Click(CoreRow? row)
  91. {
  92. if(row is null)
  93. {
  94. return false;
  95. }
  96. var reqItem = row.ToObject<RequisitionItem>();
  97. return ProcessItems(reqItem.Picked.IsEmpty() ? DateTime.Now : DateTime.MinValue, CoreUtils.One(reqItem));
  98. }
  99. private static bool ProcessItems(DateTime picked, IEnumerable<RequisitionItem> items)
  100. {
  101. var list = new List<RequisitionItem>();
  102. foreach (var item in items)
  103. {
  104. item.Picked = picked;
  105. if (!picked.IsEmpty())
  106. {
  107. var quantity = item.Quantity;
  108. if (!DoubleEdit.Execute("Enter actual quantity picked:", 0, double.MaxValue, ref quantity))
  109. {
  110. continue;
  111. }
  112. item.ActualQuantity = quantity;
  113. }
  114. else
  115. item.ActualQuantity = 0;
  116. list.Add(item);
  117. }
  118. if(list.Count > 0)
  119. {
  120. string audittrail;
  121. if (picked == DateTime.MinValue)
  122. audittrail = "Item unpicked";
  123. else
  124. audittrail = "Item picked " + picked.ToString("dd MMM yy");
  125. Client.Save(list, audittrail);
  126. return true;
  127. }
  128. else
  129. {
  130. return false;
  131. }
  132. }
  133. protected override void DoReconfigure(FluentList<DynamicGridOption> options)
  134. {
  135. base.DoReconfigure(options);
  136. options.BeginUpdate()
  137. .Add(DynamicGridOption.RecordCount)
  138. .Add(DynamicGridOption.SelectColumns)
  139. .Add(DynamicGridOption.AddRows)
  140. .Add(DynamicGridOption.EditRows)
  141. .Add(DynamicGridOption.DeleteRows)
  142. .Add(DynamicGridOption.FilterRows)
  143. .Add(DynamicGridOption.MultiSelect)
  144. .Add(DynamicGridOption.DirectEdit)
  145. .Add(DynamicGridOption.DragTarget)
  146. .EndUpdate();
  147. }
  148. private bool CanAddItems() =>
  149. Requisition is not null && Requisition.ID != Guid.Empty && Requisition.Filled.IsEmpty() && Security.CanEdit<Requisition>() && Security.CanEdit<RequisitionItem>();
  150. protected override void HandleDragOver(object sender, DragEventArgs e)
  151. {
  152. base.HandleDragOver(sender, e);
  153. if (e.Data.GetDataPresent(typeof(Product)))
  154. {
  155. if (e.Data.GetData(typeof(Product)) is Product product)
  156. {
  157. if (!CanAddItems())
  158. {
  159. e.Effects = DragDropEffects.None;
  160. }
  161. }
  162. }
  163. }
  164. protected override void HandleDragDrop(object sender, DragEventArgs e)
  165. {
  166. base.HandleDragDrop(sender, e);
  167. if (e.Data.GetDataPresent(typeof(Product)))
  168. {
  169. if(e.Data.GetData(typeof(Product)) is Product product)
  170. {
  171. if(CanAddItems())
  172. {
  173. int quantity = 1;
  174. if (NumberEdit.Execute("Enter Quantity:", 1, int.MaxValue, ref quantity))
  175. {
  176. var item = CreateItem();
  177. item.Product.ID = product.ID;
  178. item.Product.Synchronise(product);
  179. item.Quantity = quantity;
  180. item.Picked = DateTime.MinValue;
  181. SaveItem(item);
  182. Refresh(false, true);
  183. }
  184. }
  185. }
  186. }
  187. }
  188. private void SelectHolding(DynamicMenuColumn column, CoreRow? row)
  189. {
  190. if(row is null)
  191. {
  192. return;
  193. }
  194. var locations = new List<Guid>();
  195. var holdings = Client.Query(
  196. new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(row.Get<RequisitionItem, Guid>(c => c.Product.ID)),
  197. new Columns<StockHolding>(x => x.Location.ID)
  198. .Add(x => x.Units));
  199. foreach (var holding in holdings.Rows)
  200. {
  201. var qty = holding.Get<StockHolding, double>(c => c.Units);
  202. if (!CoreUtils.IsEffectivelyEqual(qty, 0.0F) && qty > 0)
  203. locations.Add(holding.Get<StockHolding, Guid>(x => x.Location.ID));
  204. }
  205. if (locations.Count == 0)
  206. {
  207. MessageWindow.ShowMessage("No valid holdings found for product", "No holdings");
  208. return;
  209. }
  210. var selection = new MultiSelectDialog<StockHolding>
  211. (
  212. new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(row.Get<RequisitionItem, Guid>(c => c.Product.ID))
  213. .And(x => x.Location.ID).InList(locations.ToArray())
  214. ,
  215. new Columns<StockHolding>(
  216. x => x.Job.Name,
  217. x => x.Job.JobNumber,
  218. x => x.Units,
  219. x => x.Dimensions.UnitSize,
  220. x => x.Dimensions.Height,
  221. x => x.Dimensions.Width,
  222. x => x.Dimensions.Weight,
  223. x => x.Dimensions.Quantity,
  224. x => x.Dimensions.Length,
  225. x => x.Dimensions.Unit.ID,
  226. x => x.Dimensions.Unit.Format,
  227. x => x.Dimensions.Unit.Formula,
  228. x => x.Dimensions.Unit.HasHeight,
  229. x => x.Dimensions.Unit.HasWeight,
  230. x => x.Dimensions.Unit.HasWidth,
  231. x => x.Dimensions.Unit.HasQuantity,
  232. x => x.Dimensions.Unit.HasLength,
  233. x => x.Style.ID,
  234. x => x.Style.Code,
  235. x => x.Style.Description,
  236. x => x.Location.ID,
  237. x => x.Location.Code,
  238. x => x.Location.Description,
  239. x => x.Location.Area.Code,
  240. x => x.Location.Area.Description
  241. ), false);
  242. if (selection.ShowDialog("Units", "0", Syncfusion.Data.FilterType.GreaterThan) == true)
  243. SelectLocation(selection.Data().Rows.FirstOrDefault(), row);
  244. }
  245. private void SelectLocation(CoreRow holdingrow, CoreRow itemrow)
  246. {
  247. var item = itemrow.ToObject<RequisitionItem>();
  248. var holding = holdingrow.ToObject<StockHolding>();
  249. item.Location.ID = holding.Location.ID;
  250. item.Location.Code = holding.Location.Code;
  251. item.Dimensions.CopyFrom(holding.Dimensions, true);
  252. item.Style.ID = holding.Style.ID;
  253. item.Style.Code = holding.Style.Code;
  254. new Client<RequisitionItem>().Save(item, "Changed due to stock holding selection");
  255. Data.LoadRow(itemrow, item);
  256. InvalidateRow(itemrow);
  257. }
  258. public Requisition? Requisition { get; set; }
  259. protected override void Reload(Filters<RequisitionItem> criteria, Columns<RequisitionItem> columns, ref SortOrder<RequisitionItem>? sort,
  260. Action<CoreTable?, Exception?> action)
  261. {
  262. criteria.Add(
  263. new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(Requisition != null ? Requisition.ID : CoreUtils.FullGuid));
  264. sort = new SortOrder<RequisitionItem>(x => x.Created);
  265. base.Reload(
  266. criteria,
  267. columns,
  268. ref sort,
  269. action
  270. );
  271. }
  272. protected override bool CanDeleteItems(CoreRow[] rows)
  273. {
  274. if (Requisition == null || Requisition.ID.Equals(Guid.Empty))
  275. {
  276. MessageBox.Show("Please select a Requisition first!");
  277. return false;
  278. }
  279. if (!Requisition.Filled.IsEmpty())
  280. {
  281. MessageBox.Show("Cannot Modify a Completed Requisition");
  282. return false;
  283. }
  284. return base.CanDeleteItems(rows);
  285. }
  286. public override bool EditItems(RequisitionItem[] items, Func<Type, CoreTable?>? PageDataHandler, bool PreloadPages = false)
  287. {
  288. if (Requisition == null || Requisition.ID.Equals(Guid.Empty))
  289. {
  290. MessageBox.Show("Please select a Requisition first!");
  291. return false;
  292. }
  293. if (!Requisition.StockUpdated.IsEmpty())
  294. {
  295. MessageBox.Show("Cannot Edit Items after Stock Holdings have been updated!");
  296. return false;
  297. }
  298. return base.EditItems(items, PageDataHandler, PreloadPages);
  299. }
  300. public override RequisitionItem CreateItem()
  301. {
  302. var item = base.CreateItem();
  303. item.RequisitionLink.ID = Requisition?.ID ?? Guid.Empty;
  304. item.RequisitionLink.Synchronise(Requisition);
  305. item.Quantity = 1;
  306. return item;
  307. }
  308. protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
  309. {
  310. if (Requisition == null || Requisition.ID.Equals(Guid.Empty))
  311. {
  312. MessageBox.Show("Please select a Requisition first!");
  313. return;
  314. }
  315. if (!Requisition.Filled.IsEmpty())
  316. {
  317. MessageBox.Show("Cannot Add Items to a Completed Requisition");
  318. return;
  319. }
  320. base.DoAdd();
  321. }
  322. }
  323. }