JobSummaryGrid.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. using com.sun.corba.se.spi.orbutil.threadpool;
  2. using Comal.Classes;
  3. using InABox.Clients;
  4. using InABox.Core;
  5. using InABox.DynamicGrid;
  6. using InABox.WPF;
  7. using InABox.Wpf;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Diagnostics.CodeAnalysis;
  11. using System.Linq;
  12. using System.Linq.Expressions;
  13. using System.Windows;
  14. using System.Windows.Media;
  15. namespace PRSDesktop
  16. {
  17. internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailControl<Job,JobMaterial>, IDataModelSource
  18. {
  19. Guid empID = Guid.Empty;
  20. string empName = "";
  21. public Job? Master { get; set; }
  22. public Filter<JobMaterial> MasterDetailFilter => (Master?.ID ?? Guid.Empty) != Guid.Empty
  23. ? new Filter<JobMaterial>(x => x.Job.ID).IsEqualTo(Master.ID)
  24. .And(x => x.Product.ID).IsNotEqualTo(Guid.Empty)
  25. : new Filter<JobMaterial>().None();
  26. public bool IncludeReserves { get; set; }
  27. public bool ShowIssues { get; set; }
  28. public JobSummaryGrid() : base()
  29. {
  30. ColumnsTag = nameof(JobSummaryGrid);
  31. OnCellDoubleClick += JobSummaryGrid_OnCellDoubleClick;
  32. SetupDetailsColumns();
  33. }
  34. protected override void Init()
  35. {
  36. base.Init();
  37. HiddenColumns.Add(x => x.Product.ID);
  38. HiddenColumns.Add(x => x.Style.ID);
  39. HiddenColumns.Add(x => x.Dimensions.UnitSize);
  40. HiddenColumns.Add(x => x.BillOfMaterials);
  41. HiddenColumns.Add(x => x.Requisitions);
  42. HiddenColumns.Add(x => x.PickingLists);
  43. HiddenColumns.Add(x => x.Issued);
  44. HiddenColumns.Add(x => x.ReservedStock);
  45. HiddenColumns.Add(x => x.OnOrder);
  46. HiddenColumns.Add(x => x.JobShortage);
  47. HiddenColumns.Add(x => x.FreeOnHand);
  48. HiddenColumns.Add(x => x.FreeOnOrder);
  49. HiddenColumns.Add(x => x.FreeStockTotal);
  50. HiddenColumns.Add(x => x.FreeStockShortage);
  51. HiddenColumns.Add(x => x.Product.Image.ID);
  52. HiddenColumns.Add(x => x.Product.Image.FileName);
  53. ActionColumns.Add(new DynamicImageManagerColumn<JobMaterial>(this, x => x.Product.Image, false)
  54. { Position = DynamicActionColumnPosition.Start });
  55. ActionColumns.Add(new DynamicMenuColumn(BuildMenu));
  56. AddButton("Create PO", null, CreatePO);
  57. }
  58. protected override void DoReconfigure(FluentList<DynamicGridOption> options)
  59. {
  60. base.DoReconfigure(options);
  61. options.AddRange(
  62. DynamicGridOption.RecordCount,
  63. DynamicGridOption.SelectColumns,
  64. DynamicGridOption.FilterRows,
  65. DynamicGridOption.ExportData,
  66. DynamicGridOption.MultiSelect
  67. );
  68. }
  69. private bool StyleColumnVisible()
  70. {
  71. var styleColumn = CoreUtils.GetFullPropertyName<JobMaterial, ProductStyleLink>(x => x.Style, ".");
  72. return VisibleColumns.Any(x => x.ColumnName.StartsWith(styleColumn));
  73. }
  74. public override DynamicGridColumns GenerateColumns()
  75. {
  76. var columns = new DynamicGridColumns();
  77. columns.Add<JobMaterial, string>(x => x.Product.Group.Code, 120, "Group Code", "", Alignment.MiddleCenter);
  78. columns.Add<JobMaterial, string>(x => x.Product.Code, 200, "Product Code", "", Alignment.MiddleCenter);
  79. columns.Add<JobMaterial, string>(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleCenter);
  80. columns.Add<JobMaterial, string>(x => x.Dimensions.UnitSize, 120, "UOM", "", Alignment.MiddleCenter);
  81. columns.Add<JobMaterial, double>(x => x.BillOfMaterials, 80, "BOM", "", Alignment.MiddleCenter);
  82. columns.Add<JobMaterial, double>(x => x.Requisitions, 80, "Req.", "", Alignment.MiddleCenter);
  83. columns.Add<JobMaterial, double>(x => x.PickingLists, 80, "P/L", "", Alignment.MiddleCenter);
  84. columns.Add<JobMaterial, double>(x => x.Issued, 80, "Issued", "", Alignment.MiddleCenter);
  85. columns.Add<JobMaterial, double>(x => x.ReservedStock, 80, "Reserved", "", Alignment.MiddleCenter);
  86. columns.Add<JobMaterial, double>(x => x.OnOrder, 80, "Ordered", "", Alignment.MiddleCenter);
  87. columns.Add<JobMaterial, double>(x => x.JobShortage, 80, "Job Short", "", Alignment.MiddleCenter);
  88. columns.Add<JobMaterial, double>(x => x.FreeStockTotal, 80, "Free Stock", "", Alignment.MiddleCenter);
  89. columns.Add<JobMaterial, double>(x => x.FreeStockShortage, 80, "Stk Short", "", Alignment.MiddleCenter);
  90. return columns;
  91. }
  92. private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
  93. {
  94. if (row is null) return;
  95. var menu = column.GetMenu();
  96. menu.AddItem("View Stock Movements", PRSDesktop.Resources.forklift, row, ViewStockMovements_Click);
  97. foreach(var col in DetailsColumns)
  98. {
  99. menu.AddItem(col.MenuText, null, row, col.Action);
  100. }
  101. }
  102. private void ViewStockMovements_Click(CoreRow row)
  103. {
  104. var productID = row.Get<StockSummary, Guid>(c => c.Product.ID);
  105. Guid? styleID = StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null;
  106. var unitSize = row.Get<StockSummary, String>(c => c.Dimensions.UnitSize);
  107. /*ShowDetailGrid<StockMovement>(
  108. args.Column.ColumnName,
  109. x => x.Product.ID,
  110. productid,
  111. x => x.Style.ID,
  112. styleid,
  113. x => x.Dimensions.UnitSize,
  114. unitsize,
  115. x => x.Job.ID,
  116. new Filter<StockMovement>(x => x.IsTransfer).IsEqualTo(false).And(x => x.Issued).IsNotEqualTo(0.0F),
  117. null
  118. );
  119. var movements = Client.Query<StockMovement>(
  120. );*/
  121. var grid = (Activator.CreateInstance(typeof(DynamicDataGrid<>).MakeGenericType(typeof(StockMovement))) as DynamicDataGrid<StockMovement>);
  122. if (grid == null)
  123. {
  124. MessageBox.Show($"Cannot create Grid for [{typeof(StockMovement).Name}]");
  125. return;
  126. }
  127. grid.ColumnsTag = $"{ColumnsTag}.Transactions";
  128. grid.Reconfigure(options =>
  129. {
  130. options.BeginUpdate().Clear().AddRange(DynamicGridOption.FilterRows, DynamicGridOption.SelectColumns).EndUpdate();
  131. });
  132. grid.OnReload += (object sender, Filters<StockMovement> criteria, Columns<StockMovement> columns, ref SortOrder<StockMovement>? sortby) =>
  133. {
  134. var filter = criteria.Combine();
  135. criteria.Clear();
  136. criteria.Add(new Filter<StockMovement>(x => x.Transaction).InQuery(filter, x => x.Transaction));
  137. };
  138. grid.OnDefineFilter += t =>
  139. {
  140. var filter = new Filter<StockMovement>(x => x.Product.ID).IsEqualTo(productID)
  141. .And(x => x.Dimensions.UnitSize).IsEqualTo(unitSize);
  142. if (styleID.HasValue)
  143. filter = filter.And(x => x.Style.ID).IsEqualTo(styleID);
  144. filter = filter.And(x => x.Job.ID).IsEqualTo(Master?.ID ?? Guid.Empty);
  145. return filter;
  146. };
  147. var window = DynamicGridUtils.CreateGridWindow($"Stock Movements", grid);
  148. window.ShowDialog();
  149. }
  150. private void ShowDetailGrid<TEntity>(
  151. String columnname,
  152. Expression<Func<TEntity, object?>> productcol,
  153. Guid productid,
  154. Expression<Func<TEntity, object?>> stylecol,
  155. Guid? styleid,
  156. Expression<Func<TEntity, object?>> unitcol,
  157. String unitsize,
  158. Expression<Func<TEntity, object?>>? jobcol,
  159. Filter<TEntity>? extrafilter,
  160. Func<CoreRow, bool>? rowfilter
  161. )
  162. {
  163. var grid = (Activator.CreateInstance(typeof(DynamicDataGrid<>).MakeGenericType(typeof(TEntity))) as IDynamicDataGrid);
  164. if (grid == null)
  165. {
  166. MessageBox.Show($"Cannot create Grid for [{typeof(TEntity).Name}]");
  167. return;
  168. }
  169. grid.ColumnsTag = $"{ColumnsTag}.{columnname}";
  170. grid.Reconfigure(options =>
  171. {
  172. options.BeginUpdate().Clear().AddRange(DynamicGridOption.FilterRows, DynamicGridOption.SelectColumns).EndUpdate();
  173. });
  174. grid.OnDefineFilter += t =>
  175. {
  176. var filter = new Filter<TEntity>(productcol).IsEqualTo(productid)
  177. .And(unitcol).IsEqualTo(unitsize);
  178. if (styleid.HasValue)
  179. filter = filter.And(stylecol).IsEqualTo(styleid);
  180. if (jobcol != null)
  181. filter = filter.And(jobcol).IsEqualTo(Master?.ID ?? Guid.Empty);
  182. if (extrafilter != null)
  183. filter = filter.And(extrafilter);
  184. return filter;
  185. };
  186. grid.OnFilterRecord += row => rowfilter?.Invoke(row) ?? true;
  187. var window = DynamicGridUtils.CreateGridWindow($"Viewing {CoreUtils.Neatify(columnname)} Calculation", grid);
  188. window.ShowDialog();
  189. }
  190. private static readonly Column<JobMaterial> BOMColumn = new Column<JobMaterial>(x => x.BillOfMaterials);
  191. private static readonly Column<JobMaterial> RequisitionsColumn = new Column<JobMaterial>(x => x.Requisitions);
  192. private static readonly Column<JobMaterial> PickingListsColumn = new Column<JobMaterial>(x => x.PickingLists);
  193. private static readonly Column<JobMaterial> IssuedColumn = new Column<JobMaterial>(x => x.Issued);
  194. private static readonly Column<JobMaterial> ReservedStockColumn = new Column<JobMaterial>(x => x.ReservedStock);
  195. private static readonly Column<JobMaterial> OnOrderColumn = new Column<JobMaterial>(x => x.OnOrder);
  196. private static readonly Column<JobMaterial> FreeOnHandColumn = new Column<JobMaterial>(x => x.FreeOnHand);
  197. private static readonly Column<JobMaterial> FreeOnOrderColumn = new Column<JobMaterial>(x => x.FreeOnOrder);
  198. private void ViewBillOfMaterials(CoreRow row)
  199. {
  200. ShowDetailGrid<JobBillOfMaterialsItem>(
  201. BOMColumn.Property,
  202. x => x.Product.ID,
  203. row.Get<StockSummary, Guid>(c => c.Product.ID),
  204. x => x.Style.ID,
  205. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  206. x => x.Dimensions.UnitSize,
  207. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  208. x => x.Job.ID,
  209. new Filter<JobBillOfMaterialsItem>(x => x.BillOfMaterials.Approved).IsNotEqualTo(DateTime.MinValue),
  210. null
  211. );
  212. }
  213. private void ViewRequisitions(CoreRow row)
  214. {
  215. ShowDetailGrid<JobRequisitionItem>(
  216. RequisitionsColumn.Property,
  217. x => x.Product.ID,
  218. row.Get<StockSummary, Guid>(c => c.Product.ID),
  219. x => x.Style.ID,
  220. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  221. x => x.Dimensions.UnitSize,
  222. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  223. x => x.Job.ID,
  224. new Filter<JobRequisitionItem>(x => x.Requisition.Approved).IsNotEqualTo(DateTime.MinValue),
  225. null
  226. );
  227. }
  228. private void ViewPickingLists(CoreRow row)
  229. {
  230. ShowDetailGrid<RequisitionItem>(
  231. PickingListsColumn.Property,
  232. x => x.Product.ID,
  233. row.Get<StockSummary, Guid>(c => c.Product.ID),
  234. x => x.Style.ID,
  235. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  236. x => x.Dimensions.UnitSize,
  237. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  238. x => x.JobLink.ID,
  239. new Filter<RequisitionItem>(x => x.RequisitionLink.Filled).IsEqualTo(DateTime.MinValue),
  240. null
  241. );
  242. }
  243. private void ViewIssued(CoreRow row)
  244. {
  245. ShowDetailGrid<StockMovement>(
  246. IssuedColumn.Property,
  247. x => x.Product.ID,
  248. row.Get<StockSummary, Guid>(c => c.Product.ID),
  249. x => x.Style.ID,
  250. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  251. x => x.Dimensions.UnitSize,
  252. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  253. x => x.Job.ID,
  254. new Filter<StockMovement>(x => x.Type).IsEqualTo(StockMovementType.Issue),
  255. null
  256. );
  257. }
  258. private void ViewReservedStock(CoreRow row)
  259. {
  260. ShowDetailGrid<StockHolding>(
  261. ReservedStockColumn.Property,
  262. x => x.Product.ID,
  263. row.Get<StockSummary, Guid>(c => c.Product.ID),
  264. x => x.Style.ID,
  265. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  266. x => x.Dimensions.UnitSize,
  267. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  268. x => x.Job.ID,
  269. new Filter<StockHolding>(x => x.Units).IsGreaterThan(0.1),
  270. null
  271. );
  272. }
  273. private void ViewOnOrder(CoreRow row)
  274. {
  275. ShowDetailGrid<PurchaseOrderItem>(
  276. OnOrderColumn.Property,
  277. x => x.Product.ID,
  278. row.Get<StockSummary, Guid>(c => c.Product.ID),
  279. x => x.Style.ID,
  280. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  281. x => x.Dimensions.UnitSize,
  282. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  283. x => x.Job.ID,
  284. null,
  285. null
  286. );
  287. }
  288. private void ViewFreeOnHand(CoreRow row)
  289. {
  290. ShowDetailGrid<StockHolding>(
  291. FreeOnHandColumn.Property,
  292. x => x.Product.ID,
  293. row.Get<StockSummary, Guid>(c => c.Product.ID),
  294. x => x.Style.ID,
  295. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  296. x => x.Dimensions.UnitSize,
  297. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  298. null,
  299. new Filter<StockHolding>(x => x.Units).IsNotEqualTo(0.0F)
  300. .And(
  301. IncludeReserves
  302. ? new Filter<StockHolding>(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)
  303. : new Filter<StockHolding>(x => x.Job.JobStatus.Active).IsEqualTo(false)
  304. ),
  305. null
  306. );
  307. }
  308. private void ViewFreeOnOrder(CoreRow row)
  309. {
  310. ShowDetailGrid<PurchaseOrderItem>(
  311. FreeOnOrderColumn.Property,
  312. x => x.Product.ID,
  313. row.Get<StockSummary, Guid>(c => c.Product.ID),
  314. x => x.Style.ID,
  315. StyleColumnVisible() ? row.Get<StockSummary, Guid>(c => c.Style.ID) : null,
  316. x => x.Dimensions.UnitSize,
  317. row.Get<StockSummary, String>(c => c.Dimensions.UnitSize),
  318. null,
  319. IncludeReserves
  320. ? new Filter<PurchaseOrderItem>(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)
  321. : new Filter<PurchaseOrderItem>(x => x.Job.JobStatus.Active).IsEqualTo(false),
  322. null
  323. );
  324. }
  325. private List<DetailsColumn> DetailsColumns;
  326. [MemberNotNull(nameof(DetailsColumns))]
  327. private void SetupDetailsColumns()
  328. {
  329. DetailsColumns = new List<DetailsColumn>
  330. {
  331. new(BOMColumn, ViewBillOfMaterials, "View bill of materials"),
  332. new(RequisitionsColumn, ViewRequisitions, "View requisitions"),
  333. new(PickingListsColumn, ViewPickingLists, "View picking lists"),
  334. new(IssuedColumn, ViewIssued, "View issued"),
  335. new(ReservedStockColumn, ViewReservedStock, "View reserved stock"),
  336. new(OnOrderColumn, ViewOnOrder, "View on order"),
  337. new(FreeOnHandColumn, ViewFreeOnHand, "View free on hand"),
  338. new(FreeOnOrderColumn, ViewFreeOnOrder, "View free on order"),
  339. };
  340. }
  341. private class DetailsColumn
  342. {
  343. public Column<JobMaterial> Column { get; set; }
  344. public Action<CoreRow> Action { get; set; }
  345. public string MenuText { get; set; }
  346. public DetailsColumn(Column<JobMaterial> column, Action<CoreRow> action, string menuText)
  347. {
  348. Column = column;
  349. Action = action;
  350. MenuText = menuText;
  351. }
  352. }
  353. private void JobSummaryGrid_OnCellDoubleClick(object sender, DynamicGridCellClickEventArgs args)
  354. {
  355. foreach(var column in DetailsColumns)
  356. {
  357. if (column.Column.IsEqualTo(args.Column.ColumnName))
  358. {
  359. column.Action(args.Row);
  360. break;
  361. }
  362. }
  363. }
  364. public event DataModelUpdateEvent? OnUpdateDataModel;
  365. public string SectionName => "Job Summary";
  366. public DataModel DataModel(Selection selection)
  367. {
  368. return new AutoDataModel<JobMaterial>(MasterDetailFilter);
  369. }
  370. protected override JobMaterial CreateItem()
  371. {
  372. var result = base.CreateItem();
  373. result.Job.ID = Master?.ID ?? Guid.Empty;
  374. result.Job.Synchronise(Master ?? new Job());
  375. return result;
  376. }
  377. private Tuple<Guid, Guid, Guid?, String>[] GetKeys(IEnumerable<CoreRow> rows, Columns<JobMaterial> columns, bool hasstyle)
  378. {
  379. int jobcol = columns.IndexOf(x => x.Job.ID);
  380. int productcol = columns.IndexOf(x => x.Product.ID);
  381. int stylecol = hasstyle ? columns.IndexOf(x => x.Style.ID) : -1;
  382. int unitcol = columns.IndexOf(x => x.Dimensions.UnitSize);
  383. var result = rows.Select(r => new Tuple<Guid, Guid, Guid?, String>(
  384. (Guid)(r.Values[jobcol] ?? Guid.Empty),
  385. (Guid)(r.Values[productcol] ?? Guid.Empty),
  386. (stylecol != -1) ? (Guid)(r.Values[stylecol] ?? Guid.Empty) : null,
  387. (String)(r.Values[unitcol] ?? ""))
  388. ).Distinct().ToArray();
  389. return result;
  390. }
  391. private CoreRow[] GetRows<TSource>(IEnumerable<CoreRow> rows, Columns<TSource> columns, Guid? jobid, Guid productid, Guid? styleid, String unitsize, Func<CoreRow, bool>? extrafilter = null) where TSource : IJobMaterial
  392. {
  393. int jobcol = columns.IndexOf(x => x.Job.ID);
  394. int productcol = columns.IndexOf(x => x.Product.ID);
  395. int stylecol = styleid.HasValue ? columns.IndexOf(x => x.Style.ID) : -1;
  396. int unitcol = columns.IndexOf(x => x.Dimensions.UnitSize);
  397. var subset = rows
  398. .Where(r =>
  399. (!jobid.HasValue || Guid.Equals(r.Values[jobcol], jobid))
  400. && Guid.Equals(r.Values[productcol], productid)
  401. && (!styleid.HasValue || Guid.Equals(r.Values[stylecol], styleid))
  402. && String.Equals(r.Values[unitcol], unitsize)
  403. && ((extrafilter == null) || extrafilter(r))
  404. );
  405. return subset.ToArray();
  406. }
  407. private double Aggregate<TSource>(IEnumerable<CoreRow> rows, Columns<TSource> columns, bool hasstyle, bool hasjob, Expression<Func<TSource, object>> source, CoreRow target, Expression<Func<JobMaterial, object>> aggregate)
  408. {
  409. int srcol = columns.IndexOf(source);
  410. if (srcol == -1)
  411. return 0.00;
  412. var total = rows.Aggregate(0d, (value, row) => value + (double)(row.Values[srcol] ?? 0.0d));
  413. target.Set(aggregate, total);
  414. return total;
  415. }
  416. protected override void Reload(Filters<JobMaterial> criteria, Columns<JobMaterial> columns, ref SortOrder<JobMaterial>? sort,
  417. Action<CoreTable?, Exception?> action)
  418. {
  419. var filter = MasterDetailFilter;
  420. var orderby = sort;
  421. Progress.ShowModal("Loading Data",
  422. (progress) =>
  423. {
  424. var table = new CoreTable();
  425. table.LoadColumns(columns);
  426. var data = new Client<JobMaterial>().Query(filter, columns, orderby);
  427. var pids = data.ExtractValues<JobMaterial, Guid>(x => x.Product.ID).ToArray();
  428. if (pids.Any())
  429. {
  430. var results = Client.QueryMultiple(
  431. new KeyedQueryDef<StockHolding>(
  432. new Filter<StockHolding>(x => x.Product.ID).InList(pids)
  433. .And(x => x.Units).IsNotEqualTo(0.0F)
  434. .And(new Filter<StockHolding>(x => x.Job.ID).IsEqualTo(Guid.Empty).Or(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)),
  435. new Columns<StockHolding>(x => x.Product.ID)
  436. .Add(x => x.Style.ID)
  437. .Add(x => x.Dimensions.UnitSize)
  438. .Add(x => x.Units)
  439. .Add(x => x.Job.ID)
  440. .Add(x => x.Job.JobStatus.Active)),
  441. new KeyedQueryDef<PurchaseOrderItem>(
  442. new Filter<PurchaseOrderItem>(x => x.ReceivedDate).IsEqualTo(DateTime.MinValue)
  443. .And(x => x.Product.ID).InList(pids)
  444. .And(new Filter<PurchaseOrderItem>(x => x.Job.ID).IsEqualTo(Guid.Empty).Or(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)),
  445. new Columns<PurchaseOrderItem>(x => x.Product.ID)
  446. .Add(x => x.Style.ID)
  447. .Add(x => x.Dimensions.UnitSize)
  448. .Add(x => x.Qty)
  449. .Add(x => x.Job.ID)
  450. .Add(x => x.Job.JobStatus.Active)));
  451. var freestock = results.Get<StockHolding>();
  452. var freestockcolumns = new Columns<StockHolding>(freestock.Columns.Select(x => x.ColumnName));
  453. var freeorders = results.Get<PurchaseOrderItem>();
  454. var freeordercolumns = new Columns<PurchaseOrderItem>(freeorders.Columns.Select(x => x.ColumnName));
  455. var hasStyle = StyleColumnVisible();
  456. var keys = GetKeys(data.Rows, columns, hasStyle);
  457. foreach (var key in keys)
  458. {
  459. var rows = GetRows(data.Rows, columns, key.Item1, key.Item2, key.Item3, key.Item4);
  460. if (rows.Any())
  461. {
  462. CoreRow newrow = table.NewRow();
  463. newrow.LoadValues(rows.First().Values);
  464. var bom = Aggregate(rows, columns, hasStyle, true, x => x.BillOfMaterials, newrow,
  465. x => x.BillOfMaterials);
  466. var requi = Aggregate(rows, columns, hasStyle, true, x => x.Requisitions, newrow, x => x.Requisitions);
  467. var picklist = Aggregate(rows, columns, hasStyle, true, x => x.PickingLists, newrow,
  468. x => x.PickingLists);
  469. var issued = Aggregate(rows, columns, hasStyle, true, x => x.Issued, newrow, x => x.Issued);
  470. var reserved = Aggregate(rows, columns, hasStyle, true, x => x.ReservedStock, newrow,
  471. x => x.ReservedStock);
  472. var ordered = Aggregate(rows, columns, hasStyle, true, x => x.OnOrder, newrow, x => x.OnOrder);
  473. var shortage = Math.Max(0, Math.Max(0, (requi - issued)) - (reserved + ordered));
  474. newrow.Set<JobMaterial, double>(x => x.JobShortage, shortage);
  475. var freestockrows = GetRows(freestock.Rows, freestockcolumns, null, key.Item2, key.Item3, key.Item4,
  476. IncludeReserves ? null : (r) => !r.Get<StockHolding, bool>(x => x.Job.JobStatus.Active));
  477. var freeonhand = Aggregate(freestockrows, freestockcolumns, hasStyle, false, x => x.Units, newrow,
  478. x => x.FreeOnHand);
  479. newrow.Set<JobMaterial, double>(x => x.FreeOnHand, freeonhand);
  480. var freeorderrows = GetRows(freeorders.Rows, freeordercolumns, null, key.Item2, key.Item3, key.Item4,
  481. IncludeReserves ? null : (r) => !r.Get<PurchaseOrderItem, bool>(x => x.Job.JobStatus.Active));
  482. var freeonorder = Aggregate(freeorderrows, freeordercolumns, hasStyle, false, x => x.Qty, newrow,
  483. x => x.FreeOnOrder);
  484. newrow.Set<JobMaterial, double>(x => x.FreeOnOrder, freeonorder);
  485. newrow.Set<JobMaterial, double>(x => x.FreeStockTotal, freeonhand + freeonorder);
  486. newrow.Set<JobMaterial, double>(x => x.FreeStockShortage, Math.Max(0, shortage - (freeonhand + freeonorder)));
  487. table.Rows.Add(newrow);
  488. }
  489. }
  490. }
  491. action?.Invoke(table, null);
  492. }
  493. );
  494. }
  495. protected override bool FilterRecord(CoreRow row)
  496. {
  497. var result = base.FilterRecord(row)
  498. && (
  499. row.Get<JobMaterial, double>(x => x.BillOfMaterials) != 0.0F ||
  500. row.Get<JobMaterial, double>(x => x.Requisitions) != 0.0F ||
  501. row.Get<JobMaterial, double>(x => x.PickingLists) != 0.0F ||
  502. row.Get<JobMaterial, double>(x => x.Issued) != 0.0F ||
  503. row.Get<JobMaterial, double>(x => x.ReservedStock) != 0.0F ||
  504. row.Get<JobMaterial, double>(x => x.OnOrder) != 0.0F
  505. );
  506. if (ShowIssues)
  507. {
  508. result = result && (
  509. row.Get<JobMaterial, double>(x => x.JobShortage) > 0.0F ||
  510. row.Get<JobMaterial, double>(x => x.FreeStockShortage) > 0.0F);
  511. }
  512. return result;
  513. }
  514. private Column<JobMaterial> _jobshortage = new Column<JobMaterial>(x => x.JobShortage);
  515. private Column<JobMaterial> _stockshortage = new Column<JobMaterial>(x => x.FreeStockShortage);
  516. protected override Brush? GetCellBackground(CoreRow row, string columnname)
  517. {
  518. if (_jobshortage.IsEqualTo(columnname))
  519. return row.Get<JobMaterial, double>(x => x.JobShortage) > 0.0F ? new SolidColorBrush(Colors.LightSalmon) { Opacity = 0.5 } : null;
  520. if (_stockshortage.IsEqualTo(columnname))
  521. return row.Get<JobMaterial, double>(x => x.FreeStockShortage) > 0.0F ? new SolidColorBrush(Colors.LightSalmon) { Opacity = 0.5 } : null;
  522. return null;
  523. }
  524. #region Create PO
  525. private void GetEmpID()
  526. {
  527. CoreTable table = new Client<Employee>().Query(new Filter<Employee>(x => x.UserLink.UserID).IsEqualTo(ClientFactory.UserID), new Columns<Employee>(x => x.ID, x => x.Name));
  528. if (table.Rows.Any())
  529. {
  530. empID = Guid.Parse(table.Rows.FirstOrDefault().Values[0].ToString());
  531. empName = table.Rows.FirstOrDefault().Values[1].ToString();
  532. }
  533. }
  534. private bool CreatePO(System.Windows.Controls.Button btn, CoreRow[] rows)
  535. {
  536. if (!rows.Any())
  537. {
  538. MessageBox.Show("Please select at least one row to add to PO");
  539. return false;
  540. }
  541. PurchaseOrder purchaseOrder = new PurchaseOrder();
  542. purchaseOrder.Description = "Created from Job Summary Screen" + System.Environment.NewLine;
  543. purchaseOrder.RaisedBy.ID = empID;
  544. var page = new SupplierPurchaseOrders();
  545. page.OnAfterSave += (form, items) =>
  546. {
  547. MessageBox.Show("Success - New Purchase Order Created (" + purchaseOrder.PONumber + ")");
  548. };
  549. return page.EditItems(new[] { purchaseOrder }, LoadPurchaseOrderItems, true);
  550. }
  551. private CoreTable LoadPurchaseOrderItems(Type arg)
  552. {
  553. Progress.Show("Working");
  554. var result = new CoreTable();
  555. result.LoadColumns(typeof(PurchaseOrderItem));
  556. List<PurchaseOrderItem> items = new List<PurchaseOrderItem>();
  557. foreach (CoreRow row in SelectedRows)
  558. {
  559. JobMaterial material = row.ToObject<JobMaterial>();
  560. PurchaseOrderItem POItem = new PurchaseOrderItem();
  561. POItem.Product.ID = material.Product.ID;
  562. POItem.Product.Code = material.Product.Code;
  563. POItem.Product.Name = material.Product.Name;
  564. POItem.Description = material.Product.Name;
  565. POItem.Qty = 0;
  566. POItem.Dimensions.CopyFrom(material.Dimensions);
  567. POItem.Style.ID = material.Style.ID;
  568. POItem.Style.Code = material.Style.Code;
  569. POItem.Style.Description = material.Style.Description;
  570. POItem.Job.ID = material.Job.ID;
  571. POItem.Dimensions.UnitSize = material.Dimensions.UnitSize;
  572. items.Add(POItem);
  573. }
  574. result.LoadRows(items);
  575. Progress.Close();
  576. return result;
  577. }
  578. #endregion
  579. }
  580. }