SupplierPurchaseOrderItemOneToMany.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. namespace PRSDesktop;
  13. public class SupplierPurchaseOrderItemOneToMany : DynamicOneToManyGrid<PurchaseOrder,PurchaseOrderItem>
  14. {
  15. private Button bill;
  16. private Button? createConsignment;
  17. //private Button? viewconsign;
  18. private Button receive;
  19. private Button assignLocation;
  20. private List<Tuple<PurchaseOrderItem, JobRequisitionItemPurchaseOrderItem>> JobRequisitionItems = new();
  21. public SupplierPurchaseOrderItemOneToMany() : base()
  22. {
  23. HiddenColumns.Add(x => x.ID);
  24. HiddenColumns.Add(x => x.Description);
  25. HiddenColumns.Add(x => x.TaxRate);
  26. HiddenColumns.Add(x => x.ExTax);
  27. HiddenColumns.Add(x => x.Tax);
  28. HiddenColumns.Add(x => x.IncTax);
  29. HiddenColumns.Add(x => x.ReceivedDate);
  30. HiddenColumns.Add(x => x.Qty);
  31. HiddenColumns.Add(x => x.Balance);
  32. HiddenColumns.Add(x => x.PORevision);
  33. HiddenColumns.Add(x => x.DueDate);
  34. HiddenColumns.Add(x => x.SupplierCode);
  35. HiddenColumns.Add(x => x.BillLine.ID);
  36. HiddenColumns.Add(x => x.Consignment.ID);
  37. HiddenColumns.Add(x => x.Job.ID);
  38. HiddenColumns.Add(x => x.StockLocation.ID);
  39. HiddenColumns.Add(x => x.PurchaseGL.ID);
  40. HiddenColumns.Add(x => x.CostCentre.ID);
  41. HiddenColumns.Add(x => x.Product.ID);
  42. HiddenColumns.Add(x => x.Product.Code);
  43. HiddenColumns.Add(x => x.Product.Name);
  44. HiddenColumns.Add(x => x.Style.ID);
  45. HiddenColumns.Add(x => x.TaxCode.ID);
  46. HiddenColumns.Add(x => x.TaxCode.Code);
  47. HiddenColumns.Add(x => x.TaxCode.Description);
  48. HiddenColumns.Add(x => x.TaxCode.Rate);
  49. HiddenColumns.Add(x => x.PostedReference);
  50. foreach (var column in Columns.None<PurchaseOrderItem>()
  51. .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local))
  52. {
  53. HiddenColumns.Add(column);
  54. }
  55. HiddenColumns.Add(x => x.PurchaseOrderLink.SupplierLink.ID);
  56. HiddenColumns.Add(x => x.PurchaseOrderLink.Category.ID);
  57. HiddenColumns.Add(x => x.Product.DigitalForm.ID);
  58. HiddenColumns.Add(x => x.Product.DigitalForm.Description);
  59. HiddenColumns.Add(x => x.Product.Image.ID);
  60. HiddenColumns.Add(x => x.Product.Image.FileName);
  61. ActionColumns.Add(new DynamicImageManagerColumn<PurchaseOrderItem>(this, x => x.Product.Image, true)
  62. { Position = DynamicActionColumnPosition.Start });
  63. HiddenColumns.Add(x => x.FormCount);
  64. HiddenColumns.Add(x => x.OpenForms);
  65. ActionColumns.Add(new DynamicMenuColumn(BuildFormsMenu) { Position = DynamicActionColumnPosition.End });
  66. ActionColumns.Add(new DynamicImageColumn(FormsImage) { Position = DynamicActionColumnPosition.Start, ToolTip = FormsToolTip });
  67. }
  68. protected override void Init()
  69. {
  70. base.Init();
  71. AddButton("Catalog", PRSDesktop.Resources.product.AsBitmapImage(), SearchProducts);
  72. if (Security.IsAllowed<CanViewConsignmentModule>())
  73. {
  74. createConsignment = AddButton("Add to Consignment", null, AddToConsignment);
  75. createConsignment.IsEnabled = false;
  76. }
  77. receive = AddButton("Receive Items", null, ReceiveItems);
  78. receive.IsEnabled = false;
  79. bill = AddButton("Enter Bill", null, EnterBill);
  80. bill.IsEnabled = false;
  81. assignLocation = AddButton("Assign Location", null, AssignLocation);
  82. }
  83. protected override void DoReconfigure(DynamicGridOptions options)
  84. {
  85. base.DoReconfigure(options);
  86. if (!ReadOnly && Security.CanEdit<PurchaseOrderItem>())
  87. {
  88. options.DirectEdit = true;
  89. options.DragTarget = true;
  90. }
  91. //if (!IsDirectEditMode(options))
  92. //{
  93. options.FilterRows = true;
  94. //}
  95. }
  96. protected override void OnAfterRefresh()
  97. {
  98. base.OnAfterRefresh();
  99. JobRequisitionItems.RemoveAll(x => !Items.Contains(x.Item1));
  100. }
  101. public override void AfterSave(object item)
  102. {
  103. base.AfterSave(item);
  104. var toSave = new List<JobRequisitionItemPurchaseOrderItem>();
  105. foreach (var poItem in Items)
  106. {
  107. var jriPois = JobRequisitionItems.Where(x => x.Item1 == poItem).Select(x => x.Item2);
  108. foreach (var jriPoi in jriPois)
  109. {
  110. jriPoi.PurchaseOrderItem.ID = poItem.ID;
  111. }
  112. toSave.AddRange(jriPois);
  113. }
  114. Client.Save(toSave, "");
  115. }
  116. private void BuildFormsMenu(DynamicMenuColumn column, CoreRow? row)
  117. {
  118. if (row == null) return;
  119. if (Security.CanEdit<PurchaseOrderItem>())
  120. {
  121. column.AddItem("Split Line", PRSDesktop.Resources.split, SplitLine, enabled: row.Get<PurchaseOrderItem, DateTime>(x => x.ReceivedDate).IsEmpty());
  122. }
  123. if(row.Get<PurchaseOrderItem, Guid>(x => x.Consignment.ID) != Guid.Empty)
  124. {
  125. column.AddItem("View Consignment", null, ViewConsignment);
  126. }
  127. var formsItem = column.AddItem("Digital Forms", PRSDesktop.Resources.kanban, null);
  128. DynamicGridUtils.PopulateFormMenu<PurchaseOrderItemForm, PurchaseOrderItem, PurchaseOrderItemLink>(
  129. formsItem,
  130. row.Get<PurchaseOrderItem, Guid>(x => x.ID),
  131. row.ToObject<PurchaseOrderItem>);
  132. }
  133. private void SplitLine(CoreRow? row)
  134. {
  135. if (row is null)
  136. return;
  137. var qty = row.Get<PurchaseOrderItem, double>(x => x.Qty);
  138. var value = qty / 2;
  139. if(DoubleEdit.Execute("Enter quantity to split on:", 0.0, qty, ref value))
  140. {
  141. var poi = LoadItem(row);
  142. IEnumerable<Guid> jobRequiItemIDs;
  143. if(poi.ID == Guid.Empty)
  144. {
  145. // If not saved yet, we will have any jriPOIs in the transient list.
  146. jobRequiItemIDs = JobRequisitionItems.Where(x => x.Item1 == poi).Select(x => x.Item2.JobRequisitionItem.ID).ToList();
  147. }
  148. else
  149. {
  150. // Otherwise, they'll all be in the database.
  151. jobRequiItemIDs = Client.Query(
  152. new Filter<JobRequisitionItemPurchaseOrderItem>(x => x.PurchaseOrderItem.ID).IsEqualTo(poi.ID),
  153. Columns.None<JobRequisitionItemPurchaseOrderItem>().Add(x => x.JobRequisitionItem.ID))
  154. .ExtractValues<JobRequisitionItemPurchaseOrderItem, Guid>(x => x.JobRequisitionItem.ID);
  155. }
  156. var newLine = new PurchaseOrderItem
  157. {
  158. };
  159. newLine.BillLine.ID = poi.BillLine.ID;
  160. newLine.BillLine.Synchronise(poi.BillLine);
  161. newLine.StockLocation.ID = poi.StockLocation.ID;
  162. newLine.StockLocation.Synchronise(poi.StockLocation);
  163. newLine.Consignment.ID = poi.Consignment.ID;
  164. newLine.Consignment.Synchronise(poi.Consignment);
  165. newLine.PurchaseGL.ID = poi.PurchaseGL.ID;
  166. newLine.PurchaseGL.Synchronise(poi.PurchaseGL);
  167. newLine.CostCentre.ID = poi.CostCentre.ID;
  168. newLine.CostCentre.Synchronise(poi.CostCentre);
  169. newLine.Product.ID = poi.Product.ID;
  170. newLine.Product.Synchronise(poi.Product);
  171. newLine.Style.ID = poi.Style.ID;
  172. newLine.Style.Synchronise(poi.Style);
  173. newLine.TaxCode.ID = poi.TaxCode.ID;
  174. newLine.TaxCode.Synchronise(poi.TaxCode);
  175. newLine.PurchaseOrderLink.ID = poi.PurchaseOrderLink.ID;
  176. newLine.PurchaseOrderLink.Synchronise(poi.PurchaseOrderLink);
  177. newLine.Job.ID = poi.Job.ID;
  178. newLine.Job.Synchronise(poi.Job);
  179. newLine.Dimensions.CopyFrom(poi.Dimensions);
  180. // Copying across the posted reference; this would be a problem if we were to try to sync via a Poster two purchase order items with the
  181. // original posted single line; however, after discussing with Frank, we can't imagine a place where we would do this; we would generally replace
  182. // the posted lines. Hence, we can copy the posted reference.
  183. newLine.PostedReference = poi.PostedReference;
  184. newLine.Description = poi.Description;
  185. newLine.TaxRate = poi.TaxRate;
  186. newLine.ExTax = poi.ExTax;
  187. newLine.Tax = poi.Tax;
  188. newLine.IncTax = poi.IncTax;
  189. newLine.Cost = poi.Cost;
  190. newLine.Balance = poi.Balance;
  191. newLine.PORevision = poi.PORevision;
  192. newLine.DueDate = poi.DueDate;
  193. newLine.SupplierCode = poi.SupplierCode;
  194. poi.Qty = value;
  195. newLine.Qty = qty - value;
  196. foreach(var jriID in jobRequiItemIDs)
  197. {
  198. // Add to a list to be saved later.
  199. var jriPoi = new JobRequisitionItemPurchaseOrderItem();
  200. jriPoi.JobRequisitionItem.ID = jriID;
  201. JobRequisitionItems.Add(new(newLine, jriPoi));
  202. }
  203. SaveItem(poi);
  204. SaveItem(newLine);
  205. Refresh(false, true);
  206. DoChanged();
  207. }
  208. }
  209. private void ViewConsignment(CoreRow? row)
  210. {
  211. if (row is null) return;
  212. var consignmentID = row.Get<PurchaseOrderItem, Guid>(x => x.Consignment.ID);
  213. var consignments = Client.Query(
  214. new Filter<Consignment>(x => x.ID).IsEqualTo(consignmentID),
  215. DynamicGridUtils.LoadEditorColumns(Columns.None<Consignment>()))
  216. .ToObjects<Consignment>().ToArray();
  217. DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(Consignment)).EditItems(consignments);
  218. }
  219. private FrameworkElement? FormsToolTip(DynamicActionColumn arg1, CoreRow? arg2)
  220. {
  221. var text = arg2 == null || arg2.Get<PurchaseOrderItem, Guid>(x => x.Product.DigitalForm.ID) == Guid.Empty
  222. ? ""
  223. : arg2.Get<PurchaseOrderItem, int>(c => c.FormCount) == 0
  224. ? "No forms found for this item"
  225. : arg2.Get<PurchaseOrderItem, int>(c => c.OpenForms) > 0
  226. ? "Incomplete forms found"
  227. : "All forms completed";
  228. return string.IsNullOrWhiteSpace(text) ? null : arg1.TextToolTip(text);
  229. }
  230. private BitmapImage? FormsImage(CoreRow? arg)
  231. {
  232. if (arg == null)
  233. return PRSDesktop.Resources.quality.AsBitmapImage();
  234. return arg.Get<PurchaseOrderItem, Guid>(x => x.Product.DigitalForm.ID) == Guid.Empty
  235. ? null
  236. : arg.Get<PurchaseOrderItem, int>(c => c.FormCount) == 0
  237. ? PRSDesktop.Resources.warning.AsBitmapImage()
  238. : arg.Get<PurchaseOrderItem, int>(c => c.OpenForms) > 0
  239. ? PRSDesktop.Resources.warning.AsBitmapImage()
  240. : PRSDesktop.Resources.quality.AsBitmapImage();
  241. }
  242. private bool AddToConsignment(Button sender, CoreRow[] rows)
  243. {
  244. if (!rows.Any())
  245. {
  246. MessageBox.Show("Please select a row first");
  247. return false;
  248. }
  249. var poItems = LoadItems(rows);
  250. if(poItems.Any(x => x.ID == Guid.Empty))
  251. {
  252. MessageBox.Show("Please save this purchase order first.");
  253. return false;
  254. }
  255. var menu = new ContextMenu();
  256. menu.AddItem("New Consignment", null, () =>
  257. {
  258. var consign = new Consignment();
  259. consign.Supplier.ID = rows.First().Get<PurchaseOrderItem, Guid>(x => x.PurchaseOrderLink.SupplierLink.ID);
  260. consign.Category.ID = rows.First().Get<PurchaseOrderItem, Guid>(x => x.PurchaseOrderLink.Category.ID);
  261. if (new DynamicDataGrid<Consignment>().EditItems(new[] { consign }, LoadConsignmentLines, true))
  262. {
  263. foreach (var item in poItems)
  264. {
  265. item.Consignment.ID = consign.ID;
  266. }
  267. new Client<PurchaseOrderItem>().Save(poItems, "Added to new consignment");
  268. Refresh(false, true);
  269. }
  270. });
  271. menu.AddItem("Existing Consignment", null, () =>
  272. {
  273. var popupList = new PopupList(typeof(Consignment), Guid.Empty, Array.Empty<string>());
  274. popupList.OnDefineFilter += type =>
  275. {
  276. return new Filter<Consignment>(x => x.Closed).IsNotEqualTo(DateTime.MinValue);
  277. };
  278. if (popupList.ShowDialog() == true)
  279. {
  280. foreach (var item in poItems)
  281. {
  282. item.Consignment.ID = popupList.ID;
  283. }
  284. new Client<PurchaseOrderItem>().Save(poItems, "Added to existing consignment");
  285. Refresh(false, true);
  286. }
  287. });
  288. menu.IsOpen = true;
  289. return false;
  290. }
  291. private CoreTable? LoadConsignmentLines(Type type)
  292. {
  293. if (type == typeof(PurchaseOrderItem))
  294. {
  295. var result = new CoreTable();
  296. result.LoadColumns(typeof(PurchaseOrderItem));
  297. result.LoadRows(SelectedRows);
  298. return result;
  299. }
  300. else
  301. {
  302. return null;
  303. }
  304. }
  305. private static bool EnterBill(Button sender, CoreRow[] rows)
  306. {
  307. if (!rows.Any())
  308. {
  309. MessageBox.Show("Please select a row first");
  310. return false;
  311. }
  312. var bill = new Bill();
  313. bill.SupplierLink.ID = rows.First()
  314. .Get<PurchaseOrderItem, Guid>(x => x.PurchaseOrderLink.SupplierLink.ID);
  315. bill.BillDate = DateTime.Today;
  316. return new DynamicDataGrid<Bill>().EditItems(new[] { bill }, (type) =>
  317. {
  318. return LoadBillLines(type, rows);
  319. }, true);
  320. }
  321. private static CoreTable LoadBillLines(Type type, CoreRow[] rows)
  322. {
  323. var result = new CoreTable();
  324. result.LoadColumns(typeof(BillLine));
  325. foreach (var row in rows)
  326. {
  327. var billrow = result.NewRow();
  328. billrow.Set<BillLine, Guid>(x => x.OrderItem.ID, row.Get<PurchaseOrderItem, Guid>(x => x.ID));
  329. var description = new List<string>();
  330. if (row.Get<PurchaseOrderItem, Guid>(x => x.Product.ID) != Guid.Empty)
  331. description.Add(string.Format("{0} : {1}", row.Get<PurchaseOrderItem, string>(x => x.Product.Code),
  332. row.Get<PurchaseOrderItem, string>(x => x.Product.Name)));
  333. var Description = row.Get<PurchaseOrderItem, string>(x => x.Description);
  334. if (!string.IsNullOrEmpty(Description))
  335. description.Add(Description);
  336. billrow.Set<BillLine, string>(x => x.Description, string.Join("\n", description));
  337. billrow.Set<BillLine, Guid>(x => x.TaxCode.ID, row.Get<PurchaseOrderItem, Guid>(x => x.TaxCode.ID));
  338. billrow.Set<BillLine, string>(x => x.TaxCode.Code, row.Get<PurchaseOrderItem, string>(x => x.TaxCode.Code));
  339. billrow.Set<BillLine, string>(x => x.TaxCode.Description, row.Get<PurchaseOrderItem, string>(x => x.TaxCode.Description));
  340. billrow.Set<BillLine, double>(x => x.TaxCode.Rate, row.Get<PurchaseOrderItem, double>(x => x.TaxCode.Rate));
  341. billrow.Set<BillLine, double>(x => x.TaxRate, row.Get<PurchaseOrderItem, double>(x => x.TaxRate));
  342. billrow.Set<BillLine, double>(x => x.ExTax, row.Get<PurchaseOrderItem, double>(x => x.ExTax));
  343. billrow.Set<BillLine, double>(x => x.Tax, row.Get<PurchaseOrderItem, double>(x => x.Tax));
  344. billrow.Set<BillLine, double>(x => x.IncTax, row.Get<PurchaseOrderItem, double>(x => x.IncTax));
  345. result.Rows.Add(billrow);
  346. }
  347. return result;
  348. }
  349. private bool ReceiveItems(Button sender, CoreRow[] rows)
  350. {
  351. if (!rows.Any())
  352. {
  353. MessageBox.Show("Please select a row first");
  354. return false;
  355. }
  356. var now = DateTime.Now;
  357. using (new WaitCursor())
  358. {
  359. var items = LoadItems(rows);
  360. foreach (var item in items)
  361. item.ReceivedDate = now;
  362. new Client<PurchaseOrderItem>().Save(items, "Consignment Items Received");
  363. }
  364. return true;
  365. }
  366. public static bool AssignLocation(Button btn, CoreRow[] rows)
  367. {
  368. if (!rows.Any())
  369. {
  370. MessageBox.Show("Please select at least one row to assign");
  371. return false;
  372. }
  373. var menu = new ContextMenu();
  374. menu.AddItem("Create New Location", null, () =>
  375. {
  376. var grid = new StockLocationGrid();
  377. var location = new StockLocation();
  378. if (grid.EditItems(new StockLocation[] { location }))
  379. AssignLocationToItems(location.ID, rows);
  380. });
  381. menu.AddItem("Choose Existing", null, () =>
  382. {
  383. var popup = new PopupList(typeof(StockLocation), Guid.Empty, new string[] { });
  384. if (popup.ShowDialog() == true)
  385. AssignLocationToItems(popup.ID, rows);
  386. });
  387. menu.IsOpen = true;
  388. return true;
  389. }
  390. private static void AssignLocationToItems(Guid locationID, CoreRow[] rows)
  391. {
  392. var items = new List<PurchaseOrderItem>();
  393. foreach (CoreRow row in rows)
  394. {
  395. var item = row.ToObject<PurchaseOrderItem>();
  396. item.StockLocation.ID = locationID;
  397. items.Add(item);
  398. }
  399. Client.Save(items, "Added stock location from PurchaseOrderItem Grid");
  400. }
  401. /*private StockLocation[] QueryLocations()
  402. {
  403. CoreTable table = new Client<StockLocation>().Query(new Filter<StockLocation>(x => x.Active).IsEqualTo(true), new Columns<StockLocation>(x => x.ID));
  404. List<StockLocation> locations = new List<StockLocation>();
  405. foreach (CoreRow row in table.Rows)
  406. locations.Add(row.ToObject<StockLocation>());
  407. return locations.ToArray();
  408. }*/
  409. protected override void SelectItems(CoreRow[]? rows)
  410. {
  411. if (createConsignment != null)
  412. {
  413. createConsignment.IsEnabled =
  414. rows != null
  415. && !rows.Any(r => Entity.IsEntityLinkValid<PurchaseOrderItem, ConsignmentLink>(x => x.Consignment, r))
  416. && !rows.Any(r => !r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty())
  417. && !ReadOnly && Security.CanEdit<Consignment>();
  418. }
  419. receive.IsEnabled =
  420. rows != null
  421. && !rows.Any(r => Entity.IsEntityLinkValid<PurchaseOrderItem, ConsignmentLink>(x => x.Consignment, r))
  422. && !rows.Any(r => r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty() == false)
  423. && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();
  424. bill.IsEnabled =
  425. rows != null
  426. && !rows.Any(r => r.IsEntityLinkValid<PurchaseOrderItem, BillLineLink>(x => x.BillLine))
  427. && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();
  428. assignLocation.IsEnabled =
  429. rows != null && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();
  430. base.SelectItems(rows);
  431. }
  432. private bool SearchProducts(Button button, CoreRow[] rows)
  433. {
  434. var dlg = new MultiSelectDialog<ProductInstance>(
  435. new Filter<ProductInstance>().All(),
  436. Columns.None<ProductInstance>()
  437. .Add(x => x.ID)
  438. .Add(x => x.Product.ID)
  439. .Add(x => x.Product.Code)
  440. .Add(x => x.Product.Name)
  441. .Add(x => x.Product.TaxCode.ID)
  442. .Add(x => x.Product.TaxCode.Code)
  443. .Add(x => x.Product.TaxCode.Description)
  444. .Add(x => x.Product.TaxCode.Rate)
  445. .Add(x => x.Product.PurchaseGL.ID)
  446. .Add(x => x.Product.PurchaseGL.Code)
  447. .Add(x => x.Product.PurchaseGL.Description)
  448. .Add(x => x.Product.CostCentre.ID)
  449. .Add(x => x.Product.CostCentre.Code)
  450. .Add(x => x.Product.CostCentre.Description)
  451. .Add(x => x.Style.ID)
  452. .Add(x => x.Style.Code)
  453. .Add(x => x.Style.Description)
  454. .AddDimensionsColumns(x => x.Dimensions)
  455. .Add(x => x.NettCost),
  456. false
  457. );
  458. if (dlg.ShowDialog() == true)
  459. {
  460. CreateItems(() =>
  461. {
  462. var result = new List<PurchaseOrderItem>();
  463. var pi = dlg.Data().Rows.FirstOrDefault()?.ToObject<ProductInstance>();
  464. if (pi == null)
  465. return result;
  466. var sp = new Client<SupplierProduct>().Query(
  467. new Filter<SupplierProduct>(x => x.Product.ID).IsEqualTo(pi.Product.ID)
  468. .And(x=>x.Style.ID).IsEqualTo(pi.Style.ID)
  469. .And(x=>x.Dimensions).DimensionEquals(pi.Dimensions),
  470. Columns.None<SupplierProduct>().Add(x => x.ID)
  471. .Add(x => x.Product.ID)
  472. .Add(x => x.Product.Code)
  473. .Add(x => x.Product.Name)
  474. .Add(x => x.Product.TaxCode.ID)
  475. .Add(x => x.Product.TaxCode.Code)
  476. .Add(x => x.Product.TaxCode.Description)
  477. .Add(x => x.Product.TaxCode.Rate)
  478. .Add(x => x.Product.PurchaseGL.ID)
  479. .Add(x => x.Product.PurchaseGL.Code)
  480. .Add(x => x.Product.PurchaseGL.Description)
  481. .Add(x => x.Product.CostCentre.ID)
  482. .Add(x => x.Product.CostCentre.Code)
  483. .Add(x => x.Product.CostCentre.Description)
  484. .Add(x => x.Style.ID)
  485. .Add(x => x.Style.Code)
  486. .Add(x => x.Style.Description)
  487. .Add(x=>x.Job.ID)
  488. .Add(x=>x.Job.JobNumber)
  489. .Add(x=>x.Job.Name)
  490. .AddDimensionsColumns(x => x.Dimensions)
  491. .Add(x => x.CostPrice)
  492. .Add(x => x.ForeignCurrencyPrice)
  493. ).Rows.FirstOrDefault()?.ToObject<SupplierProduct>();
  494. if (sp != null)
  495. {
  496. var poi = CreateItem();
  497. poi.Product.ID = sp.Product.ID;
  498. poi.Product.Synchronise(sp.Product);
  499. poi.Style.ID = sp.Style.ID;
  500. poi.Style.Synchronise(sp.Style);
  501. poi.Dimensions.CopyFrom(sp.Dimensions);
  502. poi.Job.ID = sp.Job.ID;
  503. poi.Job.Synchronise(sp.Job);
  504. poi.ForeignCurrencyCost = sp.ForeignCurrencyPrice;
  505. poi.Cost = sp.CostPrice;
  506. result.Add(poi);
  507. }
  508. else if (pi != null)
  509. {
  510. var poi = CreateItem();
  511. poi.Product.ID = pi.Product.ID;
  512. poi.Product.Synchronise(pi.Product);
  513. poi.Style.ID = pi.Style.ID;
  514. poi.Style.Synchronise(pi.Style);
  515. poi.Dimensions.CopyFrom(pi.Dimensions);
  516. poi.Cost = pi.NettCost;
  517. result.Add(poi);
  518. }
  519. return result;
  520. });
  521. }
  522. return false;
  523. }
  524. protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
  525. {
  526. var dlg = new MultiSelectDialog<SupplierProduct>(
  527. new Filter<SupplierProduct>(x => x.SupplierLink.ID).IsEqualTo(Item.SupplierLink.ID),
  528. Columns.None<SupplierProduct>().Add(x => x.ID)
  529. .Add(x => x.Product.ID)
  530. .Add(x => x.Product.Code)
  531. .Add(x => x.Product.Name)
  532. .Add(x => x.Product.TaxCode.ID)
  533. .Add(x => x.Product.TaxCode.Code)
  534. .Add(x => x.Product.TaxCode.Description)
  535. .Add(x => x.Product.TaxCode.Rate)
  536. .Add(x => x.Product.PurchaseGL.ID)
  537. .Add(x => x.Product.PurchaseGL.Code)
  538. .Add(x => x.Product.PurchaseGL.Description)
  539. .Add(x => x.Product.CostCentre.ID)
  540. .Add(x => x.Product.CostCentre.Code)
  541. .Add(x => x.Product.CostCentre.Description)
  542. .Add(x => x.Style.ID)
  543. .Add(x => x.Style.Code)
  544. .Add(x => x.Style.Description)
  545. .Add(x=>x.Job.ID)
  546. .Add(x=>x.Job.JobNumber)
  547. .Add(x=>x.Job.Name)
  548. .AddDimensionsColumns(x => x.Dimensions)
  549. .Add(x => x.CostPrice)
  550. .Add(x => x.ForeignCurrencyPrice),
  551. false
  552. );
  553. if (dlg.ShowDialog() == true)
  554. {
  555. CreateItems(() =>
  556. {
  557. var result = new List<PurchaseOrderItem>();
  558. var sp = dlg.Data().Rows.FirstOrDefault()?.ToObject<SupplierProduct>();
  559. if (sp != null)
  560. {
  561. var poi = CreateItem();
  562. poi.Product.ID = sp.Product.ID;
  563. poi.Product.Synchronise(sp.Product);
  564. poi.Style.ID = sp.Style.ID;
  565. poi.Style.Synchronise(sp.Style);
  566. poi.Dimensions.CopyFrom(sp.Dimensions);
  567. poi.Job.ID = sp.Job.ID;
  568. poi.Job.Synchronise(sp.Job);
  569. poi.ForeignCurrencyCost = sp.ForeignCurrencyPrice;
  570. poi.Cost = sp.CostPrice;
  571. result.Add(poi);
  572. }
  573. return result;
  574. });
  575. }
  576. }
  577. protected override void CustomiseEditor(PurchaseOrderItem[] items, DynamicGridColumn column, BaseEditor editor)
  578. {
  579. base.CustomiseEditor(items, column, editor);
  580. if(items.Any(x => x.ReceivedDate != DateTime.MinValue) && !new Column<PurchaseOrderItem>(x => x.ReceivedDate).IsEqualTo(column.ColumnName) && editor.Editable == Editable.Enabled)
  581. {
  582. editor.Editable = editor.Editable.Combine(Editable.Disabled);
  583. }
  584. }
  585. protected override void OnAfterEditorValueChanged(DynamicEditorGrid? grid, PurchaseOrderItem[] items, AfterEditorValueChangedArgs args, Dictionary<string, object?> changes)
  586. {
  587. base.OnAfterEditorValueChanged(grid, items, args, changes);
  588. if (args.ColumnName.Equals("Product.ID") || args.ColumnName.Equals("Job.ID") || args.ColumnName.Equals("Dimensions") || args.ColumnName.StartsWith("Dimensions.") || args.ColumnName.Equals("Style.ID"))
  589. {
  590. PurchaseOrder.UpdateCosts(
  591. items,
  592. Item.SupplierLink.ID,
  593. changes
  594. );
  595. }
  596. }
  597. protected override Dictionary<string, object?> EditorValueChanged(IDynamicEditorForm editor, PurchaseOrderItem[] items, string name,
  598. object value)
  599. {
  600. var results = base.EditorValueChanged(editor, items, name, value);
  601. if (name.Equals("ProductLink.TaxCode.ID"))
  602. DynamicGridUtils.UpdateEditorValue(items, "TaxCode.ID", (Guid)value, results);
  603. return results;
  604. }
  605. }