SupplierBillLineGrid.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Data;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Media.Imaging;
  10. using Comal.Classes;
  11. using InABox.Clients;
  12. using InABox.Configuration;
  13. using InABox.Core;
  14. using InABox.DynamicGrid;
  15. using InABox.Wpf;
  16. using InABox.WPF;
  17. namespace PRSDesktop;
  18. public class SupplierBillLineGrid : DynamicOneToManyGrid<Bill, BillLine>
  19. {
  20. private static readonly BitmapImage pencil = InABox.Wpf.Resources.pencil.AsBitmapImage();
  21. public SupplierBillLineGrid()
  22. {
  23. AddButton("Import", PRSDesktop.Resources.purchase.AsBitmapImage(), ImportLines);
  24. HiddenColumns.Add(x => x.TaxCode.ID);
  25. HiddenColumns.Add(x => x.TaxCode.Code);
  26. HiddenColumns.Add(x => x.TaxCode.Description);
  27. HiddenColumns.Add(x => x.TaxCode.Rate);
  28. HiddenColumns.Add(x => x.TaxRate);
  29. HiddenColumns.Add(x => x.ExTax);
  30. HiddenColumns.Add(x => x.Tax);
  31. HiddenColumns.Add(x => x.IncTax);
  32. HiddenColumns.Add(x => x.Description);
  33. HiddenColumns.Add(x=>x.Product.ID);
  34. HiddenColumns.Add(x=>x.Product.Code);
  35. HiddenColumns.Add(x=>x.Product.Name);
  36. HiddenColumns.Add(x=>x.Product.TaxCode.ID);
  37. HiddenColumns.Add(x=>x.Product.PurchaseGL.ID);
  38. HiddenColumns.Add(x=>x.Product.SellGL.ID);
  39. HiddenColumns.Add(x=>x.Product.CostCentre.ID);
  40. HiddenColumns.Add(x=>x.Consignment.ID);
  41. HiddenColumns.Add(x=>x.Consignment.Number);
  42. HiddenColumns.Add(x=>x.OrderItem.ID);
  43. HiddenColumns.Add(x=>x.OrderItem.PurchaseOrderLink.ID);
  44. HiddenColumns.Add(x=>x.OrderItem.PurchaseOrderLink.PONumber);
  45. HiddenColumns.Add(x=>x.OrderItem.Product.Code);
  46. HiddenColumns.Add(x=>x.OrderItem.Description);
  47. HiddenColumns.Add(x=>x.OrderItem.Qty);
  48. HiddenColumns.Add(x=>x.OrderItem.ExTax);
  49. HiddenColumns.Add(x=>x.OrderItem.TaxCode.ID);
  50. HiddenColumns.Add(x=>x.OrderItem.Tax);
  51. HiddenColumns.Add(x=>x.OrderItem.IncTax);
  52. ActionColumns.Add(
  53. new DynamicTextColumn(DisplayLinkText,DisplayLinkClick)
  54. {
  55. Position = DynamicActionColumnPosition.Start,
  56. Width = 30,
  57. HeaderText = "?",
  58. ToolTip = DisplayLinkToolTip,
  59. Alignment = Alignment.MiddleCenter
  60. }
  61. );
  62. ActionColumns.Add(new DynamicImageColumn(pencil, BillLineEdit_Click));
  63. }
  64. private object DisplayLinkText(CoreRow? row)
  65. {
  66. if (row == null)
  67. return "";
  68. var prodid = row.Get<BillLine, Guid>(x => x.Product.ID);
  69. var poid = row.Get<BillLine, Guid>(x => x.OrderItem.PurchaseOrderLink.ID);
  70. var conid = row.Get<BillLine, Guid>(x => x.Consignment.ID);
  71. return !Guid.Equals(poid,Guid.Empty)
  72. ? "O"
  73. : !Guid.Equals(conid,Guid.Empty)
  74. ? "C"
  75. : !Guid.Equals(prodid,Guid.Empty)
  76. ? "P"
  77. : "--";
  78. }
  79. private bool DisplayLinkClick(CoreRow? row)
  80. {
  81. return false;
  82. }
  83. private FrameworkElement? DisplayLinkToolTip(DynamicActionColumn column, CoreRow? row)
  84. {
  85. var text = !Guid.Equals(Guid.Empty, row?.Get<BillLine, Guid>(x => x.OrderItem.PurchaseOrderLink.ID) ?? Guid.Empty)
  86. ? String.Format("Purchase Order: {0}: {1:F2} x {2}",
  87. row?.Get<BillLine, String>(x => x.OrderItem.PurchaseOrderLink.PONumber),
  88. row?.Get<BillLine, double>(x => x.OrderItem.Qty),
  89. row?.Get<BillLine, String>(x => x.OrderItem.Description)
  90. )
  91. : !Guid.Equals(Guid.Empty, row?.Get<BillLine, Guid>(x => x.Consignment.ID) ?? Guid.Empty)
  92. ? String.Format("Consignment: {0}: {1}",
  93. row?.Get<BillLine, String>(x => x.Consignment.Number),
  94. row?.Get<BillLine, String>(x => x.Consignment.Description)
  95. )
  96. : !Guid.Equals(Guid.Empty, row?.Get<BillLine, Guid>(x => x.Product.ID) ?? Guid.Empty)
  97. ? String.Format("Product: {0}: {1}",
  98. row?.Get<BillLine, String>(x => x.Product.Code),
  99. row?.Get<BillLine, String>(x => x.Product.Name))
  100. : "";
  101. return String.IsNullOrWhiteSpace(text)
  102. ? column.TextToolTip(text)
  103. : null;
  104. }
  105. // private class BillLineConverter : IValueConverter
  106. // {
  107. // public Func<CoreTable> Data { get; set; }
  108. //
  109. // public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  110. // {
  111. // if (value is null)
  112. // return value;
  113. //
  114. // var datarow = (value as DataRowView).Row;
  115. // var index = datarow.Table.Rows.IndexOf(datarow);
  116. // var row = Data().Rows[index];
  117. //
  118. // }
  119. //
  120. // public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  121. // {
  122. // throw new NotImplementedException();
  123. // }
  124. // }
  125. //
  126. // private FrameworkElement DisplayLink()
  127. // {
  128. // var button = new Button();
  129. // button.SetBinding(Button.ContentProperty, new Binding(".") { Converter = new BillLineConverter() { Data = () => Data} });
  130. // button.SetBinding(Button.DataContextProperty, new Binding("."));
  131. // button.Click += (sender, args) =>
  132. // {
  133. // var datarow = ((sender as Button)?.DataContext as DataRowView)?.Row;
  134. // if (datarow != null)
  135. // {
  136. // var index = datarow.Table.Rows.IndexOf(datarow);
  137. // var row = Data.Rows[index];
  138. //
  139. // ContextMenu menu = new ContextMenu();
  140. //
  141. // var cons = new MenuItem() { Header = "Consignment" };
  142. // cons.Click += (o,e) => SelectConsignment(row);
  143. // menu.Items.Add(cons);
  144. //
  145. // var po = new MenuItem() { Header = "PO Item" };
  146. // po.Click += (o,e) => SelectPOItem(row);
  147. // menu.Items.Add(po);
  148. //
  149. // menu.IsOpen = true;
  150. // }
  151. // };
  152. //
  153. // return button;
  154. // }
  155. //
  156. // private void SelectPOItem(CoreRow row)
  157. // {
  158. // if (ImportPOLines(row))
  159. // InvalidateRow(row);
  160. // }
  161. //
  162. // private void SelectConsignment(CoreRow row)
  163. // {
  164. // throw new NotImplementedException();
  165. // }
  166. public override DynamicGridColumns GenerateColumns()
  167. {
  168. if (IsDirectEditMode())
  169. {
  170. var columns = new DynamicGridColumns();
  171. columns.Add<BillLine, string>(x => x.Description, 0, "Description", "", Alignment.MiddleLeft);
  172. columns.Add<BillLine, Guid>(x => x.OrderItem.ID, 100, "POItem", "", Alignment.MiddleLeft);
  173. columns.Add<BillLine, Guid>(x => x.PurchaseGL.ID, 100, "Purchase GL", "", Alignment.MiddleLeft);
  174. columns.Add<BillLine, double>(x => x.ExTax, 70, "Ex. Tax", "", Alignment.MiddleLeft);
  175. columns.Add<BillLine, Guid>(x => x.TaxCode.ID, 70, "Tax Code", "", Alignment.MiddleLeft);
  176. columns.Add<BillLine, double>(x => x.Tax, 70, "Tax", "", Alignment.MiddleLeft);
  177. columns.Add<BillLine, double>(x => x.IncTax, 70, "Inc. Tax", "", Alignment.MiddleLeft);
  178. return columns;
  179. }
  180. else
  181. {
  182. return base.GenerateColumns();
  183. }
  184. }
  185. protected override void CustomiseEditor(BillLine[] items, DynamicGridColumn column, BaseEditor editor)
  186. {
  187. base.CustomiseEditor(items, column, editor);
  188. if(editor is CurrencyEditor curr)
  189. {
  190. var settings = new GlobalConfiguration<SupplierBillPanelProperties>().Load();
  191. curr.Digits = settings.CurrencyDecimalPlaces;
  192. }
  193. }
  194. protected override void DoReconfigure(DynamicGridOptions options)
  195. {
  196. base.DoReconfigure(options);
  197. options.AddRows = true;
  198. options.DeleteRows = true;
  199. options.SelectColumns = true;
  200. options.DirectEdit = true;
  201. options.DragTarget = true;
  202. }
  203. private bool BillLineEdit_Click(CoreRow? row)
  204. {
  205. if(row is null)
  206. {
  207. return false;
  208. }
  209. var item = LoadItem(row);
  210. if (EditItems(new BillLine[] { item }))
  211. {
  212. SaveItem(item);
  213. DoChanged();
  214. return true;
  215. }
  216. return false;
  217. }
  218. private bool ImportLines(Button button, CoreRow[] rows)
  219. {
  220. ContextMenu menu = new ContextMenu();
  221. var cons = new MenuItem() { Header = "Consignment" };
  222. cons.Click += (o,e) => ImportConsignments();
  223. menu.Items.Add(cons);
  224. var po = new MenuItem() { Header = "PO Item" };
  225. po.Click += (o, e) => ImportPOLines();
  226. menu.Items.Add(po);
  227. menu.IsOpen = true;
  228. return false;
  229. }
  230. private void ImportConsignments()
  231. {
  232. var consignments = ExtractValues(x => x.Consignment.ID, Selection.All).ToArray();
  233. var dlg = new MultiSelectDialog<Consignment>(
  234. new Filter<Consignment>(x => x.Supplier.ID).IsEqualTo(Item.SupplierLink.ID)
  235. .And(x => x.BillLine.ID).IsEqualTo(Guid.Empty)
  236. .And(x => x.ID).NotInList(consignments),
  237. Columns.None<Consignment>().Add(
  238. x => x.ID));
  239. if (dlg.ShowDialog() == true)
  240. {
  241. var imports = dlg.Data();
  242. var consids = imports.ExtractValues<PurchaseOrderItem, Guid>(x => x.Consignment.ID).Distinct().ToArray();
  243. var results = Client.QueryMultiple(
  244. new KeyedQueryDef<Consignment>(
  245. new Filter<Consignment>(x => x.ID).InList(dlg.IDs()),
  246. Columns.None<Consignment>().Add(x => x.ID)
  247. .Add(x => x.Number)
  248. .Add(x => x.Description)
  249. .Add(x => x.TaxCode.ID)
  250. .Add(x => x.TaxCode.Code)
  251. .Add(x => x.TaxCode.Description)
  252. .Add(x => x.TaxCode.Rate)
  253. .Add(x => x.TaxRate)
  254. .Add(x => x.ExTax)
  255. .Add(x => x.Tax)
  256. .Add(x => x.IncTax)
  257. .Add(x => x.Created)),
  258. new KeyedQueryDef<ConsignmentDocument>(
  259. new Filter<ConsignmentDocument>(x => x.EntityLink.ID).InList(consids),
  260. Columns.None<ConsignmentDocument>().Add(x => x.DocumentLink.ID)
  261. .Add(x => x.DocumentLink.FileName)
  262. .Add(x => x.Thumbnail)));
  263. var items = results.Get<Consignment>();
  264. CreateItems(() =>
  265. {
  266. List<BillLine> lines = new List<BillLine>();
  267. foreach (var row in items.Rows)
  268. {
  269. var line = CreateItem();
  270. line.Consignment.ID = row.Get<Consignment, Guid>(x => x.ID);
  271. line.Consignment.Number = row.Get<Consignment, String>(x => x.Number);
  272. line.Consignment.Description = row.Get<Consignment, string>(x => x.Description);
  273. line.ExTax = row.Get<Consignment, double>(x => x.ExTax);
  274. line.TaxCode.ID = row.Get<Consignment, Guid>(x => x.TaxCode.ID);
  275. line.TaxCode.Code = row.Get<Consignment, string>(x => x.TaxCode.Code);
  276. line.TaxCode.Description = row.Get<Consignment, string>(x => x.TaxCode.Description);
  277. line.TaxCode.Rate = row.Get<Consignment, double>(x => x.TaxCode.Rate);
  278. line.TaxRate = row.Get<Consignment, double>(x => x.TaxRate);
  279. line.Tax = row.Get<Consignment, double>(x => x.Tax);
  280. line.IncTax = row.Get<Consignment, double>(x => x.IncTax);
  281. line.Description =
  282. $"{row.Get<Consignment, string>(x => x.Number)} : {row.Get<Consignment, String>(x => x.Description)}";
  283. lines.Add(line);
  284. }
  285. return lines;
  286. });
  287. var docpage = EditorGrid.Pages.FirstOrDefault(x=>x is BillDocumentGrid) as BillDocumentGrid;
  288. if (!docpage.Ready)
  289. docpage.Load(Item,null);
  290. if (docpage != null)
  291. {
  292. var docIDs = docpage.Data.ExtractValues<BillDocument, Guid>(x => x.DocumentLink.ID).ToHashSet();
  293. foreach(var eDoc in results.GetObjects<ConsignmentDocument>())
  294. {
  295. if (!docIDs.Contains(eDoc.DocumentLink.ID))
  296. {
  297. var doc = new BillDocument();
  298. doc.EntityLink.ID = Item.ID;
  299. doc.DocumentLink.ID = eDoc.DocumentLink.ID;
  300. doc.DocumentLink.FileName = eDoc.DocumentLink.FileName;
  301. doc.Thumbnail = eDoc.Thumbnail;
  302. docpage.SaveItem(doc);
  303. docIDs.Add(eDoc.DocumentLink.ID);
  304. }
  305. }
  306. docpage.Refresh(false,true);
  307. }
  308. DoChanged();
  309. Refresh(false,false);
  310. }
  311. }
  312. private void ImportPOLines()
  313. {
  314. var poItems = ExtractValues(x => x.OrderItem.ID, Selection.All).ToArray();
  315. var dlg = new MultiSelectDialog<PurchaseOrderItem>(
  316. new Filter<PurchaseOrderItem>(x => x.PurchaseOrderLink.SupplierLink.ID).IsEqualTo(Item.SupplierLink.ID)
  317. .And(x => x.BillLine.ID).IsEqualTo(Guid.Empty)
  318. .And(x => x.ID).NotInList(poItems),
  319. Columns.None<PurchaseOrderItem>().Add(
  320. x => x.ID,
  321. x => x.Consignment.ID,
  322. x => x.PurchaseOrderLink.ID));
  323. if (dlg.ShowDialog() == true)
  324. {
  325. var imports = dlg.Data();
  326. var poids = imports.ExtractValues<PurchaseOrderItem, Guid>(x => x.PurchaseOrderLink.ID).Distinct().ToArray();
  327. var consids = imports.ExtractValues<PurchaseOrderItem, Guid>(x => x.Consignment.ID).Distinct().ToArray();
  328. var results = Client.QueryMultiple(
  329. new KeyedQueryDef<PurchaseOrderItem>(
  330. new Filter<PurchaseOrderItem>(x => x.ID).InList(dlg.IDs()),
  331. Columns.None<PurchaseOrderItem>().Add(x => x.ID)
  332. .Add(x => x.Description)
  333. .Add(x => x.TaxCode.ID)
  334. .Add(x => x.TaxCode.Code)
  335. .Add(x => x.TaxCode.Description)
  336. .Add(x => x.TaxCode.Rate)
  337. .Add(x => x.Qty)
  338. .Add(x => x.TaxRate)
  339. .Add(x => x.ExTax)
  340. .Add(x => x.Tax)
  341. .Add(x => x.IncTax)
  342. .Add(x => x.Created)
  343. .Add(x => x.PurchaseOrderLink.ID)
  344. .Add(x => x.PurchaseOrderLink.PONumber)
  345. .Add(x => x.Consignment.ID)
  346. .Add(x => x.Product.ID)
  347. .Add(x => x.Product.Code)
  348. .Add(x => x.Product.Name)
  349. .Add(x => x.PurchaseGL.ID)
  350. .Add(x => x.CostCentre.ID)),
  351. new KeyedQueryDef<PurchaseOrderDocument>(
  352. new Filter<PurchaseOrderDocument>(x => x.EntityLink.ID).InList(poids),
  353. Columns.None<PurchaseOrderDocument>().Add(x => x.DocumentLink.ID)
  354. .Add(x => x.DocumentLink.FileName)
  355. .Add(x => x.Thumbnail)),
  356. new KeyedQueryDef<ConsignmentDocument>(
  357. new Filter<ConsignmentDocument>(x => x.EntityLink.ID).InList(consids),
  358. Columns.None<ConsignmentDocument>().Add(x => x.DocumentLink.ID)
  359. .Add(x => x.DocumentLink.FileName)
  360. .Add(x => x.Thumbnail)));
  361. var items = results.Get<PurchaseOrderItem>();
  362. CreateItems(() =>
  363. {
  364. List<BillLine> lines = new List<BillLine>();
  365. foreach (var row in items.Rows)
  366. {
  367. var line = CreateItem();
  368. line.OrderItem.ID = row.Get<PurchaseOrderItem, Guid>(x => x.ID);
  369. line.OrderItem.PurchaseOrderLink.ID = row.Get<PurchaseOrderItem, Guid>(x => x.PurchaseOrderLink.ID);
  370. line.OrderItem.PurchaseOrderLink.PONumber =
  371. row.Get<PurchaseOrderItem, String>(x => x.PurchaseOrderLink.PONumber);
  372. line.OrderItem.Product.ID = row.Get<PurchaseOrderItem, Guid>(x => x.Product.ID);
  373. line.OrderItem.Product.Code = row.Get<PurchaseOrderItem, string>(x => x.Product.Code);
  374. line.OrderItem.Product.Name = row.Get<PurchaseOrderItem, string>(x => x.Product.Name);
  375. line.OrderItem.Description = row.Get<PurchaseOrderItem, string>(x => x.Description);
  376. line.OrderItem.Qty = row.Get<PurchaseOrderItem, double>(x => x.Qty);
  377. line.OrderItem.ExTax = row.Get<PurchaseOrderItem, double>(x => x.ExTax);
  378. line.OrderItem.TaxCode.ID = row.Get<PurchaseOrderItem, Guid>(x => x.TaxCode.ID);
  379. line.OrderItem.TaxCode.Code = row.Get<PurchaseOrderItem, string>(x => x.TaxCode.Code);
  380. line.OrderItem.TaxCode.Description = row.Get<PurchaseOrderItem, string>(x => x.TaxCode.Description);
  381. line.OrderItem.TaxCode.Rate = row.Get<PurchaseOrderItem, double>(x => x.TaxCode.Rate);
  382. line.OrderItem.PurchaseGL.ID = row.Get<PurchaseOrderItem, Guid>(x => x.PurchaseGL.ID);
  383. line.OrderItem.CostCentre.ID = row.Get<PurchaseOrderItem, Guid>(x => x.CostCentre.ID);
  384. line.ExTax = row.Get<PurchaseOrderItem, double>(x => x.ExTax);
  385. line.TaxCode.ID = row.Get<PurchaseOrderItem, Guid>(x => x.TaxCode.ID);
  386. line.TaxCode.Code = row.Get<PurchaseOrderItem, string>(x => x.TaxCode.Code);
  387. line.TaxCode.Description = row.Get<PurchaseOrderItem, string>(x => x.TaxCode.Description);
  388. line.TaxCode.Rate = row.Get<PurchaseOrderItem, double>(x => x.TaxCode.Rate);
  389. line.TaxRate = row.Get<PurchaseOrderItem, double>(x => x.TaxRate);
  390. line.Tax = row.Get<PurchaseOrderItem, double>(x => x.Tax);
  391. line.IncTax = row.Get<PurchaseOrderItem, double>(x => x.IncTax);
  392. line.PurchaseGL.ID = row.Get<PurchaseOrderItem, Guid>(x => x.PurchaseGL.ID);
  393. line.CostCentre.ID = row.Get<PurchaseOrderItem, Guid>(x => x.CostCentre.ID);
  394. var description = row.Get<PurchaseOrderItem, String>(x => x.Description);
  395. if (String.IsNullOrWhiteSpace(description))
  396. description = row.Get<PurchaseOrderItem, String>(x => x.Product.Name);
  397. line.Description = $"{row.Get<PurchaseOrderItem, double>(x => x.Qty):F2} x {description}";
  398. lines.Add(line);
  399. }
  400. return lines;
  401. });
  402. var docpage = EditorGrid.Pages.FirstOrDefault(x=>x is BillDocumentGrid) as BillDocumentGrid;
  403. if (!docpage.Ready)
  404. docpage.Load(Item,null);
  405. if (docpage != null)
  406. {
  407. var docIDs = docpage.Data.ExtractValues<BillDocument, Guid>(x => x.DocumentLink.ID).ToHashSet();
  408. foreach(var eDoc in (results.GetObjects<PurchaseOrderDocument>() as IEnumerable<IEntityDocument>)
  409. .Concat(results.GetObjects<ConsignmentDocument>()))
  410. {
  411. if (!docIDs.Contains(eDoc.DocumentLink.ID))
  412. {
  413. var doc = new BillDocument();
  414. doc.EntityLink.ID = Item.ID;
  415. doc.DocumentLink.ID = eDoc.DocumentLink.ID;
  416. doc.DocumentLink.FileName = eDoc.DocumentLink.FileName;
  417. doc.Thumbnail = eDoc.Thumbnail;
  418. docpage.SaveItem(doc);
  419. docIDs.Add(eDoc.DocumentLink.ID);
  420. }
  421. }
  422. docpage.Refresh(false,true);
  423. }
  424. DoChanged();
  425. Refresh(false,false);
  426. }
  427. }
  428. protected override void HandleDragOver(object sender, DragEventArgs e)
  429. {
  430. base.HandleDragOver(sender, e);
  431. if (e.Data.GetDataPresent(typeof(Product)))
  432. {
  433. if (e.Data.GetData(typeof(Product)) is Product product)
  434. {
  435. if (!Security.CanEdit<Bill>() || !Security.CanEdit<BillLine>())
  436. {
  437. e.Effects = DragDropEffects.None;
  438. }
  439. }
  440. }
  441. }
  442. protected override void HandleDragDrop(object sender, DragEventArgs e)
  443. {
  444. base.HandleDragDrop(sender, e);
  445. if (e.Data.GetDataPresent(typeof(Product)))
  446. {
  447. if (e.Data.GetData(typeof(Product)) is Product product)
  448. {
  449. if (Security.CanEdit<Bill>() && Security.CanEdit<BillLine>())
  450. {
  451. var item = CreateItem();
  452. item.Product.ID = product.ID;
  453. item.Product.Synchronise(product);
  454. item.Description = product.Name;
  455. SaveItem(item);
  456. DoChanged();
  457. Refresh(false, true);
  458. }
  459. }
  460. }
  461. }
  462. }