StagingPanel.xaml.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308
  1. using Comal.Classes;
  2. using InABox.Core;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using InABox.Clients;
  9. using InABox.Configuration;
  10. using InABox.DynamicGrid;
  11. using System.Diagnostics;
  12. using System.IO;
  13. using InABox.WPF;
  14. using InABox.Wpf;
  15. using System.ComponentModel;
  16. using InABox.Scripting;
  17. using System.Reflection;
  18. using System.Collections.Immutable;
  19. using StagingManufacturingPacketComponent = Comal.Classes.StagingManufacturingPacketComponent;
  20. using System.Threading.Tasks;
  21. using System.Windows.Media.Imaging;
  22. using Columns = InABox.Core.Columns;
  23. using MemoryStream = System.IO.MemoryStream;
  24. namespace PRSDesktop;
  25. public class CustomiseSetoutsArgs
  26. {
  27. public IReadOnlyList<Tuple<StagingSetout, Document>> Setouts;
  28. public CustomiseSetoutsArgs(IReadOnlyList<Tuple<StagingSetout, Document>> setouts)
  29. {
  30. Setouts = setouts;
  31. }
  32. }
  33. /// <summary>
  34. /// Interaction logic for StagingPanel.xaml
  35. /// </summary>
  36. public partial class StagingPanel : UserControl, IPanel<StagingSetout>
  37. {
  38. private StagingPanellSettings _settings = new StagingPanellSettings();
  39. private Job? _job;
  40. public Job? Job
  41. {
  42. get => _job;
  43. set
  44. {
  45. _job = value;
  46. stagingSetoutGrid.Job = value;
  47. stagingSetoutGrid.Refresh(false,true);
  48. }
  49. }
  50. /// <summary>
  51. /// The currently selected setout.
  52. /// </summary>
  53. private StagingSetout? selectedSetout;
  54. /// <summary>
  55. /// All currently selected setouts; <see cref="selectedSetout"/> will be a member of this list.
  56. /// </summary>
  57. private List<StagingSetout> selectedSetouts = new();
  58. private CoreTable _templateGroups = null!;
  59. #region Script Stuff
  60. private MethodInfo? _customiseSetoutsMethod;
  61. private MethodInfo? CustomiseSetoutsMethod
  62. {
  63. get
  64. {
  65. EnsureScript();
  66. return _customiseSetoutsMethod;
  67. }
  68. }
  69. private object? _scriptObject;
  70. private object? ScriptObject
  71. {
  72. get
  73. {
  74. EnsureScript();
  75. return _scriptObject;
  76. }
  77. }
  78. private ScriptDocument? _script;
  79. private ScriptDocument? Script
  80. {
  81. get
  82. {
  83. EnsureScript();
  84. return _script;
  85. }
  86. }
  87. private void EnsureScript()
  88. {
  89. if(_script is not null && _script.Text != _settings.Script)
  90. {
  91. _script = null;
  92. }
  93. if (_script is null && !_settings.Script.IsNullOrWhiteSpace())
  94. {
  95. _script = new ScriptDocument(_settings.Script);
  96. if (!_script.Compile())
  97. {
  98. throw new Exception("Script in Staging Panel Settings failed to compile!");
  99. }
  100. _scriptObject = _script?.GetObject();
  101. _customiseSetoutsMethod = _script?.GetMethod(methodName: "CustomiseSetouts");
  102. }
  103. }
  104. #endregion
  105. public StagingPanel()
  106. {
  107. InitializeComponent();
  108. SectionName = nameof(StagingPanel);
  109. }
  110. public void Setup()
  111. {
  112. _settings = new GlobalConfiguration<StagingPanellSettings>().Load();
  113. _templateGroups = new Client<ManufacturingTemplateGroup>().Query();
  114. MarkUpButton.Visibility = Security.IsAllowed<CanMarkUpSetouts>() ? Visibility.Visible : Visibility.Hidden;
  115. RejectButton.Visibility = Security.IsAllowed<CanApproveSetouts>() ? Visibility.Visible : Visibility.Hidden;
  116. ApproveButton.Visibility = Security.IsAllowed<CanApproveSetouts>() ? Visibility.Visible : Visibility.Hidden;
  117. ProcessButton.Visibility = Security.IsAllowed<CanApproveSetouts>() ? Visibility.Visible : Visibility.Hidden;
  118. //stagingSetoutGrid.ScanFiles(_settings.SetoutsFolder);
  119. stagingSetoutGrid.PanelSettings = _settings;
  120. stagingSetoutGrid.Refresh(true, false);
  121. SetoutComponentGrid.Refresh(true, false);
  122. }
  123. private bool CanViewPackets() => MainPanel.View != DynamicSplitPanelView.Master && NestedPanel.View != DynamicSplitPanelView.Master;
  124. private void NestedPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
  125. {
  126. if(CanViewPackets())
  127. {
  128. ManufacturingPacketList.Setout = selectedSetout;
  129. SetoutComponentGrid.StagingSetout = selectedSetout;
  130. }
  131. }
  132. #region Document Viewer
  133. public enum DocumentMode
  134. {
  135. Markup,
  136. Complete,
  137. Locked
  138. }
  139. private DocumentMode _mode;
  140. private DocumentMode Mode
  141. {
  142. get => _mode;
  143. set => SetMode(value);
  144. }
  145. private void SetMode(DocumentMode mode)
  146. {
  147. _mode = mode;
  148. if (_mode == DocumentMode.Markup)
  149. {
  150. MarkUpButton.Content = "Mark Up";
  151. MarkUpButton.IsEnabled = Document != null && !Document.Approved;
  152. UpdateOriginalButton.Visibility =
  153. Document != null && !String.Equals(Document.DocumentLink.CRC, selectedSetout?.OriginalCRC)
  154. ? Visibility.Visible
  155. : Visibility.Collapsed;
  156. ProcessButton.IsEnabled = Document != null && Document.Approved;
  157. RejectButton.IsEnabled = Document != null && !Document.Approved;
  158. ApproveButton.IsEnabled = Document != null;
  159. }
  160. else if (_mode == DocumentMode.Complete)
  161. {
  162. MarkUpButton.Content = "Complete";
  163. MarkUpButton.IsEnabled = Document != null;
  164. UpdateOriginalButton.Visibility = Visibility.Collapsed;
  165. ProcessButton.IsEnabled = false;
  166. RejectButton.IsEnabled = false;
  167. ApproveButton.IsEnabled = false;
  168. }
  169. else if (_mode == DocumentMode.Locked)
  170. {
  171. MarkUpButton.Content = "Locked";
  172. MarkUpButton.IsEnabled = false;
  173. UpdateOriginalButton.Visibility = Visibility.Collapsed;
  174. ProcessButton.IsEnabled = false;
  175. RejectButton.IsEnabled = false;
  176. ApproveButton.IsEnabled = false;
  177. }
  178. }
  179. private StagingSetoutDocument? _document;
  180. private StagingSetoutDocument? Document
  181. {
  182. get => _document;
  183. set
  184. {
  185. _document = value;
  186. if(_document is not null)
  187. {
  188. ApproveButton.Content = _document.Approved ? "Unapprove" : "Approve";
  189. }
  190. }
  191. }
  192. private byte[]? _documentdata = null;
  193. private void ClearDocuments()
  194. {
  195. Document = null;
  196. RenderDocuments(null);
  197. }
  198. private List<byte[]> GetDocuments(StagingSetoutDocument? document)
  199. {
  200. try
  201. {
  202. if(document is null)
  203. return new List<byte[]>();
  204. var table = new Client<Document>().Query(
  205. Filter<Document>.Where(x => x.ID).IsEqualTo(document.DocumentLink.ID),
  206. Columns.None<Document>().Add(x => x.Data));
  207. var first = table.Rows.FirstOrDefault();
  208. if (first is null)
  209. return new List<byte[]>();
  210. _documentdata = first.Get<Document, byte[]>(x => x.Data);
  211. return ImageUtils.RenderPDFToImageBytes(_documentdata);
  212. }
  213. catch (Exception e)
  214. {
  215. Logger.Send(LogType.Error, "", $"{e.Message}\n{e.StackTrace}");
  216. return new List<byte[]>();
  217. }
  218. }
  219. private void RenderDocuments(List<byte[]>? documents)
  220. {
  221. List<BitmapImage> _images = new List<BitmapImage>();
  222. //DocumentViewer.Children.Clear();
  223. if(documents is not null)
  224. {
  225. foreach (var document in documents)
  226. {
  227. var image = ImageUtils.LoadImage(document);
  228. if (image is not null)
  229. _images.Add(image);
  230. }
  231. }
  232. DocumentViewer.ItemsSource = _images;
  233. }
  234. private void ProcessButton_Click(object sender, RoutedEventArgs e)
  235. {
  236. bool bulkApprove = false;
  237. if (selectedSetouts.Count > 1)
  238. {
  239. if (MessageBox.Show("Bulk approve? (Skip individual setout approval)", "Continue?", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
  240. {
  241. bulkApprove = true;
  242. Progress.Show("Approving Setouts..");
  243. }
  244. }
  245. if (selectedSetouts.Any(x => x.UnapprovedDocuments > 0))
  246. {
  247. MessageBox.Show("Cannot process setouts with unapproved documents.");
  248. Progress.Close();
  249. return;
  250. }
  251. if (selectedSetouts.Any(x => x.JobLink.ID == Guid.Empty))
  252. {
  253. MessageBox.Show("Cannot process setout without a linked job.");
  254. Progress.Close();
  255. return;
  256. }
  257. if (ManufacturingPacketList.Packets.Any(x => x.Template.ID == Guid.Empty))
  258. {
  259. MessageBox.Show("Cannot process manufacturing packets without templates.");
  260. Progress.Close();
  261. return;
  262. }
  263. if (selectedSetouts.Any(x => x.Packets == 0))
  264. {
  265. if (MessageBox.Show("Warning: some setouts do not have any manufacturing packets: are you sure you wish to proceed?", "Warning", MessageBoxButton.YesNoCancel) != MessageBoxResult.Yes)
  266. {
  267. Progress.Close();
  268. return;
  269. }
  270. }
  271. string message = "";
  272. foreach (var item in selectedSetouts)
  273. {
  274. if (bulkApprove)
  275. Progress.Show("Working on " + item.Number);
  276. var returnstring = ApproveSetout(item, bulkApprove);
  277. if (!string.IsNullOrWhiteSpace(returnstring))
  278. message = message + returnstring + Environment.NewLine;
  279. }
  280. if (bulkApprove)
  281. Progress.Close();
  282. new Client<StagingSetout>().Save(selectedSetouts, "Updated from staging screen");
  283. selectedSetout = null;
  284. Refresh();
  285. if (!message.IsNullOrWhiteSpace())
  286. {
  287. MessageBox.Show($"Result:\n{message}");
  288. }
  289. MainPanel.View = DynamicSplitPanelView.Combined;
  290. NestedPanel.View = DynamicSplitPanelView.Master;
  291. }
  292. private string ApproveSetout(StagingSetout item, bool bulkapprove)
  293. {
  294. if (item.Group.ID == Guid.Empty)
  295. {
  296. var message = "Setout has no group assigned";
  297. if (Security.IsAllowed<CanApproveSetoutsWithoutGroup>())
  298. {
  299. if (MessageBox.Show(message + ", continue?", "Continue?", MessageBoxButton.OKCancel) != MessageBoxResult.OK)
  300. return "";
  301. }
  302. else
  303. {
  304. MessageBox.Show(message + ", please assign a group!");
  305. return "";
  306. }
  307. }
  308. var setoutDocument = new Client<StagingSetoutDocument>()
  309. .Query(
  310. Filter<StagingSetoutDocument>.Where(x => x.EntityLink.ID).IsEqualTo(item.ID),
  311. Columns.None<StagingSetoutDocument>().Add(x => x.ID, x => x.DocumentLink.ID, x => x.DocumentLink.FileName))
  312. .ToObjects<StagingSetoutDocument>().FirstOrDefault();
  313. if (setoutDocument is null)
  314. return "";
  315. var setout = new Client<Setout>()
  316. .Query(
  317. Filter<Setout>.Where(x => x.Number).IsEqualTo(item.Number),
  318. Columns.Required<Setout>().Add(x => x.ID))
  319. .ToObjects<Setout>().FirstOrDefault();
  320. string result;
  321. //setout already exists - create new setoutdoc and supercede old ones
  322. if (setout is not null)
  323. {
  324. if (!bulkapprove)
  325. if (MessageBox.Show("Supercede existing documents?", "Proceed?", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  326. return "";
  327. setout.Group.ID = item.Group.ID;
  328. item.Setout.ID = setout.ID;
  329. var setoutdoc = new SetoutDocument();
  330. setoutdoc.EntityLink.ID = setout.ID;
  331. setoutdoc.DocumentLink.ID = setoutDocument.DocumentLink.ID;
  332. var setoutdocs = new List<SetoutDocument>
  333. {
  334. setoutdoc
  335. };
  336. CoreTable oldDocsTable = new Client<SetoutDocument>().Query(
  337. Filter<SetoutDocument>.Where(x => x.EntityLink.ID).IsEqualTo((Guid)setout.ID)
  338. .And(x => x.DocumentLink.ID).IsNotEqualTo(item.Group.OptimizationDocument.ID)
  339. );
  340. foreach (var row in oldDocsTable.Rows)
  341. {
  342. var oldDoc = row.ToObject<SetoutDocument>();
  343. if (oldDoc.Superceded == DateTime.MinValue)
  344. {
  345. oldDoc.Superceded = DateTime.Now;
  346. setoutdocs.Add(oldDoc);
  347. }
  348. }
  349. new Client<SetoutDocument>().Save(setoutdocs, "Updated from Staging Screen");
  350. new Client<Setout>().Save((Setout)setout, "Updated from Staging Screen");
  351. result = item.Number + " Superceded";
  352. }
  353. //no setout for this pdf - create new
  354. else
  355. {
  356. setout = new Setout
  357. {
  358. Number = item.Number
  359. };
  360. setout.JobLink.ID = item.JobLink.ID;
  361. setout.Group.ID = item.Group.ID;
  362. var editor = new DynamicDataGrid<Setout>();
  363. editor.OnAfterSave += (editor, items) =>
  364. {
  365. CreateSetoutDocument(setout, item, setoutDocument);
  366. };
  367. if (!bulkapprove)
  368. {
  369. if (!editor.EditItems(new[] { setout }))
  370. {
  371. MessageBox.Show("Setout Creation Cancelled");
  372. return "";
  373. }
  374. else
  375. result = item.Number + " Created";
  376. }
  377. else
  378. {
  379. new Client<Setout>().Save(setout, "Added from staging screen");
  380. CreateSetoutDocument(setout, item, setoutDocument);
  381. result = item.Number + " Created";
  382. }
  383. }
  384. var tuples = new List<Tuple<ManufacturingPacket, StagingManufacturingPacket>>();
  385. var stagingPackets = new Client<StagingManufacturingPacket>()
  386. .Query(
  387. Filter<StagingManufacturingPacket>.Where(x => x.StagingSetout.ID).IsEqualTo(item.ID),
  388. Columns.Required<StagingManufacturingPacket>().Add(x => x.ID)
  389. .Add(x => x.Serial)
  390. .Add(x => x.Title)
  391. .Add(x => x.Quantity)
  392. .Add(x => x.BarcodeQuantity)
  393. .Add(x => x.Watermark)
  394. .Add(x => x.Group.Watermark)
  395. .Add(x => x.Location)
  396. .Add(x => x.ITP.ID)
  397. .Add(x => x.Job.ID)
  398. .Add(x => x.Template.ID));
  399. foreach(var stagingPacket in stagingPackets.ToObjects<StagingManufacturingPacket>())
  400. {
  401. if(stagingPacket.ManufacturingPacket.ID != Guid.Empty)
  402. {
  403. MessageBox.Show($"A manufacturing packet already exists for {stagingPacket.Serial}; skipping packet.");
  404. continue;
  405. }
  406. var packet = new ManufacturingPacket
  407. {
  408. Serial = stagingPacket.Serial,
  409. Title = stagingPacket.Title,
  410. Quantity = stagingPacket.Quantity,
  411. BarcodeQty = string.IsNullOrWhiteSpace(stagingPacket.BarcodeQuantity)
  412. ? stagingPacket.Quantity
  413. : int.Parse(stagingPacket.BarcodeQuantity),
  414. WaterMark = string.IsNullOrWhiteSpace(stagingPacket.Watermark)
  415. ? stagingPacket.Group.Watermark
  416. : stagingPacket.Watermark,
  417. Location = stagingPacket.Location
  418. };
  419. packet.SetoutLink.ID = setout.ID;
  420. packet.ITP.ID = stagingPacket.ITP.ID;
  421. packet.JobLink.ID = stagingPacket.Job.ID;
  422. packet.ManufacturingTemplateLink.ID = stagingPacket.Template.ID;
  423. tuples.Add(new(packet, stagingPacket));
  424. }
  425. new Client<ManufacturingPacket>().Save(tuples.Select(x => x.Item1), "Created from Design Management Panel");
  426. var newStages = new List<ManufacturingPacketStage>();
  427. var newComponents = new List<ManufacturingPacketComponent>();
  428. var newTreatments = new List<ManufacturingTreatment>();
  429. foreach(var (packet, stagingPacket) in tuples)
  430. {
  431. stagingPacket.ManufacturingPacket.ID = packet.ID;
  432. var stages = new Client<StagingManufacturingPacketStage>()
  433. .Query(
  434. Filter<StagingManufacturingPacketStage>.Where(x => x.Packet.ID).IsEqualTo(stagingPacket.ID),
  435. IManufacturingPacketGeneratorExtensions.GetPacketGeneratorRequiredColumns<StagingManufacturingPacketStage>());
  436. newStages.AddRange(stages.ToObjects<StagingManufacturingPacketStage>()
  437. .Select(x =>
  438. {
  439. var stage = x.CreateManufacturingPacketStage();
  440. stage.Parent.ID = packet.ID;
  441. return stage;
  442. }));
  443. var components = new Client<StagingManufacturingPacketComponent>()
  444. .Query(
  445. Filter<StagingManufacturingPacketComponent>.Where(x => x.Packet.ID).IsEqualTo(stagingPacket.ID),
  446. Columns.None<StagingManufacturingPacketComponent>().Add(x=>x.Packet.ID)
  447. .Add(x => x.Product.ID)
  448. .Add(x => x.Quantity)
  449. .Add(x => x.Dimensions.Unit.ID)
  450. .Add(x => x.Dimensions.Quantity)
  451. .Add(x => x.Dimensions.Length)
  452. .Add(x => x.Dimensions.Width)
  453. .Add(x => x.Dimensions.Height)
  454. .Add(x => x.Dimensions.Weight)
  455. .Add(x => x.Dimensions.Value)
  456. .Add(x => x.Dimensions.UnitSize)
  457. );
  458. newComponents.AddRange(components.ToObjects<StagingManufacturingPacketComponent>()
  459. .Select(x => x.CreateComponent(packet.ID)));
  460. var treatments = new Client<StagingManufacturingPacketTreatment>()
  461. .Query(
  462. Filter<StagingManufacturingPacketTreatment>.Where(x => x.Packet.ID).IsEqualTo(stagingPacket.ID),
  463. Columns.None<StagingManufacturingPacketTreatment>().Add(x=>x.Packet.ID)
  464. .Add(x=>x.Product.ID)
  465. .Add(x=>x.Parameter)
  466. );
  467. newTreatments.AddRange(treatments.ToObjects<StagingManufacturingPacketTreatment>()
  468. .Select(x => x.CreateTreatment(packet.ID)));
  469. }
  470. new Client<ManufacturingPacketStage>().Save(newStages, "Created from Design Management");
  471. new Client<ManufacturingPacketComponent>().Save(newComponents, "Created from Design Management");
  472. new Client<ManufacturingTreatment>().Save(newTreatments, "Created from Design Management");
  473. new Client<StagingManufacturingPacket>().Save(tuples.Select(x => x.Item2), "Created from Design Management");
  474. //currently not creating packets due to temporary change in requirements - to uncomment and check for validity when required
  475. //CreatePackets(setout);
  476. return result;
  477. }
  478. private static void CreateSetoutDocument(Setout setout, StagingSetout item, StagingSetoutDocument stagingsetoutdocument)
  479. {
  480. item.Setout.ID = setout.ID;
  481. var setoutdoc = new SetoutDocument();
  482. setoutdoc.EntityLink.ID = setout.ID;
  483. setoutdoc.DocumentLink.ID = stagingsetoutdocument.DocumentLink.ID;
  484. new Client<SetoutDocument>().Save(setoutdoc, "Added from staging screen");
  485. }
  486. private void RejectButton_Click(object sender, RoutedEventArgs e)
  487. {
  488. if (selectedSetout is null || Document is null)
  489. {
  490. MessageBox.Show("Please select a setout");
  491. return;
  492. }
  493. //dont create setout - setout.id remains blank
  494. //create kanban and populate task.id - this prevents it from appearing on the stagingsetout grid, and allows a new staging setout to be created when the file is saved to the folder again
  495. //attach the document to the task for reference
  496. var task = new Kanban
  497. {
  498. Title = "Setout Review Task (setout rejected)",
  499. Description = "Please review the attached document for setout " + selectedSetout.Number
  500. };
  501. task.ManagerLink.ID = App.EmployeeID;
  502. if (DynamicGridUtils.EditEntity(task))
  503. {
  504. var doc = new KanbanDocument();
  505. doc.EntityLink.ID = task.ID;
  506. doc.DocumentLink.ID = Document.DocumentLink.ID;
  507. new Client<KanbanDocument>().Save(doc, "Created from staging screen");
  508. selectedSetout.Task.ID = task.ID;
  509. new Client<StagingSetout>().Save(selectedSetout, "Updated from staging screen");
  510. MessageBox.Show("Success - Task Created for Document " + selectedSetout.Number + " (Task no. " + task.Number + " assigned to " + task.EmployeeLink.Name + ")");
  511. selectedSetout = null;
  512. ClearDocuments();
  513. refreshing = true;
  514. stagingSetoutGrid.Refresh(false, true);
  515. }
  516. else
  517. {
  518. MessageWindow.ShowMessage("Task creation cancelled - setout not rejected", "Action cancelled");
  519. }
  520. }
  521. private void MarkUpButton_Click(object sender, RoutedEventArgs e)
  522. {
  523. if (Mode == DocumentMode.Markup)
  524. {
  525. Mode = DocumentMode.Complete;
  526. MessageBox.Show("IMPORTANT - press save in your document editor, then press the Complete Button in PRS");
  527. OnMarkupSelected();
  528. }
  529. else
  530. {
  531. OnMarkupComplete();
  532. Mode = DocumentMode.Markup;
  533. }
  534. }
  535. private void UpdateOriginalButton_Click(object sender, RoutedEventArgs e)
  536. {
  537. if ((_documentdata?.Any() == true) && !String.IsNullOrWhiteSpace(selectedSetout?.OriginalPath))
  538. {
  539. try
  540. {
  541. File.WriteAllBytes(selectedSetout.OriginalPath, _documentdata);
  542. selectedSetout.OriginalCRC = CoreUtils.CalculateCRC(_documentdata);
  543. new Client<StagingSetout>().Save(selectedSetout,"Updated Source File with markups");
  544. UpdateOriginalButton.Visibility = Visibility.Collapsed;
  545. }
  546. catch (Exception _exception)
  547. {
  548. MessageBox.Show($"Unable to update {selectedSetout?.OriginalPath}!\n\n{_exception.Message}");
  549. }
  550. return;
  551. }
  552. MessageBox.Show("Please select a design first!");
  553. }
  554. private void ApproveButton_Click(object sender, RoutedEventArgs e)
  555. {
  556. if (Document is null || selectedSetout is null)
  557. {
  558. MessageBox.Show("Please select a setout first.");
  559. return;
  560. }
  561. if (selectedSetouts.Count > 1)
  562. {
  563. var msg = Document.Approved
  564. ? "Bulk unapprove?"
  565. : "Bulk approve? (Skip individual setout approval)";
  566. if (MessageBox.Show(msg, "Continue?", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
  567. {
  568. Progress.Show("Approving Setouts..");
  569. var documents = Client.Query(
  570. Filter<StagingSetoutDocument>.Where(x => x.EntityLink.ID).InList(selectedSetouts.Select(x => x.ID).ToArray()),
  571. Columns.Required<StagingSetoutDocument>().Add(x => x.ID, x => x.Approved)
  572. ).ToObjects<StagingSetoutDocument>().ToList();
  573. foreach(var document in documents)
  574. {
  575. document.Approved = !Document.Approved;
  576. }
  577. Client.Save(documents, "Approved by user.");
  578. Progress.Close();
  579. refreshing = true;
  580. stagingSetoutGrid.Refresh(false, true);
  581. }
  582. }
  583. else
  584. {
  585. Document.Approved = !Document.Approved;
  586. new Client<StagingSetoutDocument>().Save(Document, "");
  587. refreshing = true;
  588. stagingSetoutGrid.Refresh(false, true);
  589. }
  590. }
  591. private void OnMarkupSelected()
  592. {
  593. if (Document is null || selectedSetout is null)
  594. {
  595. MessageBox.Show("Please select a setout first.");
  596. return;
  597. }
  598. var doc = new Client<Document>()
  599. .Query(
  600. Filter<Document>.Where(x => x.ID).IsEqualTo(Document.DocumentLink.ID))
  601. .ToObjects<Document>().FirstOrDefault();
  602. if (doc is null)
  603. {
  604. Logger.Send(LogType.Error, "", $"Document with ID {Document.DocumentLink.ID} could not be found.");
  605. MessageBox.Show("Error: the selected document could not be found in the database.");
  606. return;
  607. }
  608. var tempdocpath = Path.Combine(Path.GetTempPath(), doc.FileName);
  609. selectedSetout.SavePath = tempdocpath;
  610. selectedSetout.LockedBy.ID = App.EmployeeID;
  611. selectedSetout.LockedBy.Name = App.EmployeeName;
  612. new Client<StagingSetout>().Save(selectedSetout, "Locked from Staging Screen");
  613. File.WriteAllBytes(tempdocpath, doc.Data);
  614. using (var p = new Process())
  615. {
  616. p.StartInfo = new ProcessStartInfo()
  617. {
  618. UseShellExecute = true,
  619. FileName = tempdocpath
  620. };
  621. p.Start();
  622. }
  623. refreshing = true;
  624. stagingSetoutGrid.Refresh(false, true);
  625. }
  626. private void OnMarkupComplete()
  627. {
  628. if (selectedSetout is null)
  629. {
  630. MessageBox.Show("Please select a setout first.");
  631. return;
  632. }
  633. StagingSetoutGrid.ReloadFile(selectedSetout);
  634. refreshing = true;
  635. stagingSetoutGrid.Refresh(false, true);
  636. }
  637. #endregion
  638. private bool refreshing = false;
  639. private void stagingSetoutGrid_AfterRefresh(object sender, AfterRefreshEventArgs args)
  640. {
  641. refreshing = false;
  642. }
  643. private void StagingSetoutGrid_OnSelectItem(object sender, InABox.DynamicGrid.DynamicGridSelectionEventArgs e)
  644. {
  645. var newSetouts = new List<StagingSetout>();
  646. foreach (var row in e.Rows ?? Enumerable.Empty<CoreRow>())
  647. newSetouts.Add(row.ToObject<StagingSetout>());
  648. if(!refreshing && (selectedSetouts.Count == newSetouts.Count
  649. && !selectedSetouts.Any(x => !newSetouts.Any(y => x.ID == y.ID))))
  650. {
  651. selectedSetouts = newSetouts;
  652. selectedSetout = selectedSetouts.FirstOrDefault();
  653. return;
  654. }
  655. selectedSetouts = newSetouts;
  656. selectedSetout = selectedSetouts.FirstOrDefault();
  657. AddPacketButton.IsEnabled = selectedSetout is not null;
  658. if(selectedSetout is null)
  659. {
  660. ClearDocuments();
  661. ManufacturingPacketList.Setout = null;
  662. CollapsePacketsButton.IsEnabled = false;
  663. SetoutComponentGrid.StagingSetout = null;
  664. SetMode(DocumentMode.Markup);
  665. return;
  666. }
  667. var doc = new Client<StagingSetoutDocument>()
  668. .Query(
  669. Filter<StagingSetoutDocument>.Where(x => x.EntityLink.ID).IsEqualTo(selectedSetout.ID),
  670. Columns.None<StagingSetoutDocument>().Add(x => x.ID)
  671. .Add(x => x.DocumentLink.ID)
  672. .Add(x => x.DocumentLink.FileName)
  673. .Add(x => x.Approved)
  674. .Add(x=>x.DocumentLink.CRC)
  675. ).ToObjects<StagingSetoutDocument>().FirstOrDefault();
  676. if(doc is null)
  677. {
  678. MessageBox.Show("No document found for this setout.");
  679. ClearDocuments();
  680. ManufacturingPacketList.Setout = null;
  681. CollapsePacketsButton.IsEnabled = false;
  682. SetoutComponentGrid.StagingSetout = null;
  683. return;
  684. }
  685. Document = doc;
  686. var docTask = Task.Run(() => GetDocuments(doc));
  687. if(CanViewPackets())
  688. {
  689. ManufacturingPacketList.Setout = selectedSetout;
  690. SetoutComponentGrid.StagingSetout = selectedSetout;
  691. }
  692. CollapsePacketsButton.IsEnabled = true;
  693. var mode =
  694. selectedSetout.LockedBy.ID == Guid.Empty ?
  695. DocumentMode.Markup :
  696. selectedSetout.LockedBy.ID == App.EmployeeID ?
  697. DocumentMode.Complete :
  698. DocumentMode.Locked;
  699. docTask.Wait();
  700. RenderDocuments(docTask.Result);
  701. SetMode(mode);
  702. }
  703. public bool IsReady { get; set; }
  704. public string SectionName { get; }
  705. public event DataModelUpdateEvent? OnUpdateDataModel;
  706. #region Settings
  707. public void CreateToolbarButtons(IPanelHost host)
  708. {
  709. ProjectSetupActions.JobStatuses(host);
  710. ProjectSetupActions.DrawingTemplates(host);
  711. host.CreateSetupSeparator();
  712. ProjectSetupActions.JobSpreadsheetTemplates(host);
  713. host.CreateSetupSeparator();
  714. ProjectSetupActions.SetoutGroups(host);
  715. host.CreateSetupSeparator();
  716. SetoutsConfigurationSettings(host, () => _settings);
  717. host.CreateSetupAction(
  718. new PanelAction()
  719. {
  720. Caption = "Component Import Profiles",
  721. Image = PRSDesktop.Resources.doc_xls,
  722. OnExecute = ConfigComponentProfiles
  723. });
  724. host.CreateSetupAction(
  725. new PanelAction()
  726. {
  727. Caption = "Template Products",
  728. Image = PRSDesktop.Resources.specifications,
  729. OnExecute =
  730. action =>
  731. {
  732. var list = new MasterList(typeof(ManufacturingTemplateGroupProducts));
  733. list.ShowDialog();
  734. }
  735. }
  736. );
  737. SystemSetupActions.ERPStatuses(host);
  738. }
  739. private void ConfigComponentProfiles(PanelAction obj)
  740. {
  741. var list = new DynamicImportList(
  742. typeof(StagingSetoutComponent),
  743. Guid.Empty,
  744. canImport: false
  745. );
  746. list.ShowDialog();
  747. }
  748. public static void SetoutsConfigurationSettings(IPanelHost host, Func<StagingPanellSettings> getSettings)
  749. {
  750. host.CreateSetupAction(
  751. new PanelAction()
  752. {
  753. Caption = "Setouts Configuration",
  754. Image = PRSDesktop.Resources.specifications,
  755. OnExecute = action => ConfigSettingsClick(getSettings())
  756. });
  757. }
  758. private static void ConfigSettingsClick(StagingPanellSettings settings)
  759. {
  760. var grid = new DynamicItemsListGrid<StagingPanellSettings>();
  761. grid.OnCustomiseEditor += Grid_OnCustomiseEditor;
  762. if(grid.EditItems(new[] { settings }))
  763. {
  764. new GlobalConfiguration<StagingPanellSettings>().Save(settings);
  765. }
  766. }
  767. private static void Grid_OnCustomiseEditor(IDynamicEditorForm sender, StagingPanellSettings[]? items, DynamicGridColumn column, BaseEditor editor)
  768. {
  769. if (items?.FirstOrDefault() is not StagingPanellSettings settings) return;
  770. if (column.ColumnName == nameof(StagingPanellSettings.Script) && editor is ScriptEditor scriptEditor)
  771. {
  772. scriptEditor.Type = ScriptEditorType.TemplateEditor;
  773. scriptEditor.OnEditorClicked += () =>
  774. {
  775. var script = settings.Script.NotWhiteSpaceOr()
  776. ?? StagingPanellSettings.DefaultScript();
  777. var editor = new ScriptEditorWindow(script, SyntaxLanguage.CSharp);
  778. if (editor.ShowDialog() == true)
  779. {
  780. sender.SetEditorValue(column.ColumnName, editor.Script);
  781. settings.Script = editor.Script;
  782. }
  783. };
  784. }
  785. }
  786. #endregion
  787. public void Heartbeat(TimeSpan time)
  788. {
  789. }
  790. public void Refresh()
  791. {
  792. //stagingSetoutGrid.ScanFiles(_settings.SetoutsFolder);
  793. refreshing = true;
  794. stagingSetoutGrid.Refresh(false, true);
  795. /*Document = null;
  796. selectedSetout = null;
  797. ManufacturingPacketList.Setout = null;
  798. SetoutComponentGrid.StagingSetout = null;*/
  799. CalculateTime();
  800. }
  801. private void stagingSetoutGrid_OnRefreshPackets()
  802. {
  803. if (CanViewPackets())
  804. {
  805. ManufacturingPacketList.Refresh();
  806. }
  807. }
  808. public Dictionary<string, object[]> Selected()
  809. {
  810. return new();
  811. }
  812. public void Shutdown(CancelEventArgs? cancel)
  813. {
  814. }
  815. public DataModel DataModel(Selection selection)
  816. {
  817. return new AutoDataModel<StagingSetout>(new Filter<StagingSetout>().All());
  818. }
  819. private void AddPacketButton_Click(object sender, RoutedEventArgs e)
  820. {
  821. if (_templateGroups.Rows.Any() == true)
  822. {
  823. ContextMenu menu = new ContextMenu();
  824. if (ManufacturingPacketList.Packets.Any())
  825. {
  826. menu.AddItem("Duplicate Last Item",null, () =>
  827. {
  828. ManufacturingPacketList.Add(
  829. selectedSetout?.JobLink.ID ?? Guid.Empty,
  830. ManufacturingPacketList.Packets.Last().Group
  831. );
  832. UpdateStagingSetoutGrid();
  833. });
  834. menu.AddSeparator();
  835. }
  836. foreach (var row in _templateGroups.Rows)
  837. {
  838. menu.AddItem(
  839. $"{row.Get<ManufacturingTemplateGroup, String>(x => x.Code)}: {row.Get<ManufacturingTemplateGroup, String>(x => x.Description)}",
  840. null,
  841. () =>
  842. {
  843. ManufacturingPacketList.Add(
  844. selectedSetout?.JobLink.ID ?? Guid.Empty,
  845. row.ToObject<ManufacturingTemplateGroup>()
  846. );
  847. UpdateStagingSetoutGrid();
  848. });
  849. }
  850. menu.AddSeparator();
  851. menu.AddItem("Miscellaneous Item", null, () =>
  852. {
  853. ManufacturingPacketList.Add(
  854. selectedSetout?.JobLink.ID ?? Guid.Empty,
  855. null
  856. );
  857. UpdateStagingSetoutGrid();
  858. });
  859. menu.IsOpen = true;
  860. }
  861. else
  862. {
  863. ManufacturingPacketList.Add(
  864. selectedSetout?.JobLink.ID ?? Guid.Empty,
  865. null
  866. );
  867. UpdateStagingSetoutGrid();
  868. }
  869. }
  870. private void UpdateStagingSetoutGrid()
  871. {
  872. var selected = stagingSetoutGrid.SelectedRows.FirstOrDefault();
  873. if (selected != null)
  874. {
  875. var packets = ManufacturingPacketList.Packets;
  876. selected.Set<StagingSetout, int>(x => x.Packets, packets.Length);
  877. selected.Set<StagingSetout, int>(x => x.UnprocessedPackets, packets.Count(x => x.ManufacturingPacket.ID == Guid.Empty));
  878. stagingSetoutGrid.InvalidateRow(selected);
  879. }
  880. }
  881. private void CollapsePacketsButton_Click(object sender, RoutedEventArgs e)
  882. {
  883. if (ManufacturingPacketList.Collapsed())
  884. {
  885. ManufacturingPacketList.Uncollapse();
  886. }
  887. else
  888. {
  889. ManufacturingPacketList.Collapse();
  890. }
  891. }
  892. private void ManufacturingPacketList_OnCollapsed(bool collapsed)
  893. {
  894. if (collapsed)
  895. {
  896. CollapsePacketsButton.Content = "Expand";
  897. }
  898. else
  899. {
  900. CollapsePacketsButton.Content = "Collapse";
  901. }
  902. }
  903. private void stagingSetoutGrid_OnCustomiseSetouts(IReadOnlyList<StagingSetoutGrid.SetoutDocument> setouts)
  904. {
  905. if(CustomiseSetoutsMethod != null && ScriptObject != null)
  906. {
  907. CustomiseSetoutsMethod?.Invoke(ScriptObject, new object?[]
  908. {
  909. new CustomiseSetoutsArgs(setouts.Select(x => new Tuple<StagingSetout, Document>(x.Setout, x.Document)).ToImmutableList())
  910. });
  911. }
  912. }
  913. private void StagingSetoutGrid_OnOnDoubleClick(object sender, HandledEventArgs args)
  914. {
  915. ManufacturingPacketList.Setout = selectedSetout;
  916. SetoutComponentGrid.StagingSetout = selectedSetout;
  917. MainPanel.View = DynamicSplitPanelView.Detail;
  918. NestedPanel.View = DynamicSplitPanelView.Combined;
  919. args.Handled = true;
  920. }
  921. private void CalculateTime()
  922. {
  923. if (selectedSetout != null)
  924. {
  925. var time = ManufacturingPacketList.TimeRequired();
  926. TimeRequired.Content = $"{time.TotalHours:F2} hours";
  927. }
  928. else
  929. TimeRequired.Content = "N/A";
  930. }
  931. private void ManufacturingPacketList_OnChanged(object? sender, EventArgs e)
  932. {
  933. CalculateTime();
  934. UpdateStagingSetoutGrid();
  935. SetoutComponentGrid.StagingSetout = selectedSetout;
  936. //SetoutComponentGrid.Refresh(false, true);
  937. }
  938. private void DoImport(Importer importer, string? componentFileName, Guid setoutID)
  939. {
  940. var success = DynamicImportGrid.CreateImporter(importer, ref componentFileName, out var iimporter);
  941. if (!success)
  942. {
  943. return;
  944. }
  945. var errors = new List<string>();
  946. var stagingSetoutComponents = new List<StagingSetoutComponent>();
  947. iimporter.OnLoad += Iimporter_OnLoad;
  948. iimporter.OnSave += (_, entity) => stagingSetoutComponents.Add((entity as StagingSetoutComponent)!);
  949. iimporter.OnError += (_, error) => errors.Add(error);
  950. using var stream = new FileStream(componentFileName!, FileMode.Open, FileAccess.Read);
  951. if (iimporter.Open(stream))
  952. {
  953. if (iimporter.ReadHeader())
  954. {
  955. var mismatches = iimporter.Mappings.Where(x =>
  956. !string.IsNullOrWhiteSpace(x.Field) &&
  957. !iimporter.Fields.Contains(x.Field)
  958. ).Select(x => x.Field).ToArray();
  959. if (!mismatches.Any())
  960. {
  961. var imported = iimporter.Import();
  962. if (errors.Any())
  963. {
  964. MessageBox.Show($"Import for component file {componentFileName} failed:\nSome errors occurred: {string.Join('\n', errors)}", "Import failed");
  965. }
  966. else
  967. {
  968. var valid = true;
  969. var conflicts = false;
  970. if (setoutID != Guid.Empty)
  971. {
  972. var newComponents = new List<StagingSetoutComponent>();
  973. foreach (var component in stagingSetoutComponents)
  974. {
  975. if (component.StagingSetout.ID == Guid.Empty)
  976. {
  977. component.StagingSetout.ID = setoutID;
  978. newComponents.Add(component);
  979. }
  980. else if (component.StagingSetout.ID != setoutID)
  981. {
  982. conflicts = true;
  983. // Ignoring this item.
  984. }
  985. else
  986. {
  987. newComponents.Add(component);
  988. }
  989. }
  990. stagingSetoutComponents = newComponents;
  991. if (conflicts)
  992. {
  993. MessageBox.Show($"Warning: the lines in this file have conflicting setout numbers.", "Warning");
  994. }
  995. }
  996. if (valid)
  997. {
  998. foreach (var component in stagingSetoutComponents)
  999. {
  1000. if (component.StagingSetout.ID == Guid.Empty)
  1001. {
  1002. MessageBox.Show($"Component with no related setout cannot be imported.");
  1003. valid = false;
  1004. break;
  1005. }
  1006. else if (component.Description.IsNullOrWhiteSpace())
  1007. {
  1008. MessageBox.Show($"Component with no description cannot be imported.");
  1009. valid = false;
  1010. break;
  1011. }
  1012. else if (component.Dimensions.Unit.ID == Guid.Empty)
  1013. {
  1014. MessageBox.Show($"Component with no dimensions unit cannot be imported.");
  1015. valid = false;
  1016. break;
  1017. }
  1018. }
  1019. }
  1020. if (valid)
  1021. {
  1022. new Client<StagingSetoutComponent>().Save(stagingSetoutComponents, $"Imported from {componentFileName}");
  1023. SetoutComponentGrid.Refresh(false, true);
  1024. }
  1025. else
  1026. {
  1027. MessageBox.Show($"Import for component file {componentFileName} failed.", "Import failed");
  1028. }
  1029. }
  1030. }
  1031. else
  1032. {
  1033. MessageBox.Show("Import Mappings do not match file headers!\n\n- " + string.Join("\n- ", mismatches),
  1034. "Import Failed");
  1035. }
  1036. }
  1037. else
  1038. {
  1039. MessageBox.Show("Unable to Read Headers from {0}", Path.GetFileName(componentFileName));
  1040. }
  1041. }
  1042. else
  1043. {
  1044. MessageBox.Show("Unable to Open {0}", Path.GetFileName(componentFileName));
  1045. }
  1046. iimporter.Close();
  1047. }
  1048. private CoreTable Iimporter_OnLoad(object sender, Type type, string[] fields, string ID)
  1049. {
  1050. var result = new CoreTable();
  1051. result.LoadColumns(Columns.None<StagingSetoutComponent>().Add(fields));
  1052. return result;
  1053. }
  1054. private void stagingSetoutGrid_OnParseComponentFile(string componentFileName, Guid setoutID)
  1055. {
  1056. try
  1057. {
  1058. var entityName = typeof(StagingSetoutComponent).EntityName();
  1059. var importers = new Client<Importer>()
  1060. .Query(
  1061. Filter<Importer>.Where(x => x.EntityName).IsEqualTo(entityName),
  1062. Columns.None<Importer>().Add(x => x.ID));
  1063. if (importers.Rows.Count == 0)
  1064. {
  1065. var importer = new Importer
  1066. {
  1067. EntityName = entityName,
  1068. FileName = componentFileName
  1069. };
  1070. var form = new DynamicImportForm(importer);
  1071. if (form.ShowDialog() == true)
  1072. {
  1073. new Client<Importer>().Save(importer, "");
  1074. DoImport(importer, componentFileName, setoutID);
  1075. return;
  1076. }
  1077. }
  1078. else if (importers.Rows.Count == 1)
  1079. {
  1080. var importer = new Client<Importer>().Load(Filter<Importer>.Where(x => x.ID).IsEqualTo(importers.Rows[0].Get<Importer, Guid>(x => x.ID))).First();
  1081. DoImport(importer, componentFileName, setoutID);
  1082. }
  1083. else
  1084. {
  1085. var list = new PopupList(
  1086. typeof(Importer),
  1087. Guid.Empty,
  1088. Array.Empty<string>());
  1089. list.OnDefineFilter += t => Filter<Importer>.Where(x => x.EntityName).IsEqualTo(entityName);
  1090. if (list.ShowDialog() == true)
  1091. {
  1092. var importer = new Client<Importer>().Load(Filter<Importer>.Where(x => x.ID).IsEqualTo(list.ID)).First();
  1093. DoImport(importer, componentFileName, setoutID);
  1094. }
  1095. }
  1096. }
  1097. catch(Exception e)
  1098. {
  1099. Logger.Send(LogType.Error, "", $"Error in file {componentFileName}: {CoreUtils.FormatException(e)}");
  1100. MessageBox.Show($"Error opening {componentFileName}: {e.Message}");
  1101. }
  1102. }
  1103. private void DistributeProducts_Click(object sender, RoutedEventArgs e)
  1104. {
  1105. var updates = new Dictionary<StagingManufacturingPacketComponent, StagingSetoutComponent>();
  1106. var components = SetoutComponentGrid.SelectedRows.ToObjects<StagingSetoutComponent>().ToArray();
  1107. var productids = components.Select(x=>x.Product.ID).Distinct().ToArray();
  1108. var packets = ManufacturingPacketList.Packets.ToArray();
  1109. var groupids = packets.Select(x => x.Group.ID).Distinct().ToArray();
  1110. Progress.ShowModal("Checking Mappings", progress =>
  1111. {
  1112. var mappings = Client.Query(
  1113. Filter<ManufacturingTemplateGroupProducts>.Where(x => x.TemplateGroup.ID).InList(groupids)
  1114. .And(x=>x.Product.ID).InList(productids),
  1115. Columns.None<ManufacturingTemplateGroupProducts>().Add(x=>x.ID).Add(x=>x.Product.ID).Add(x=>x.TemplateGroup.ID)
  1116. ).ToObjects<ManufacturingTemplateGroupProducts>().ToArray();
  1117. foreach (var component in components)
  1118. {
  1119. var mapping = mappings.FirstOrDefault(x => x.Product.ID == component.Product.ID);
  1120. if (mapping != null)
  1121. {
  1122. var packet =
  1123. packets.FirstOrDefault(x => x.Group.ID == mapping.TemplateGroup.ID);
  1124. if (packet != null)
  1125. {
  1126. var mfgcomp = new StagingManufacturingPacketComponent();
  1127. mfgcomp.Packet.ID = packet.ID;
  1128. mfgcomp.Dimensions.CopyFrom(component.Dimensions);
  1129. mfgcomp.Product.CopyFrom(component.Product);
  1130. mfgcomp.Quantity = component.Quantity;
  1131. mfgcomp.Description = component.Description;
  1132. updates[mfgcomp] = component;
  1133. }
  1134. }
  1135. }
  1136. progress.Report("Saving Manufacturing Packets");
  1137. if (updates.Keys.Any())
  1138. {
  1139. Client.Save(updates.Keys, "Distributed from Staging Components Grid");
  1140. progress.Report("Updating Setout Components");
  1141. foreach (var key in updates.Keys)
  1142. updates[key].StagingManufacturingPacketComponent.ID = key.ID;
  1143. Client.Save(updates.Values,"Distributed to Staging Manufacturing Packet");
  1144. }
  1145. });
  1146. SetoutComponentGrid.Refresh(false, true);
  1147. ManufacturingPacketList.Refresh();
  1148. }
  1149. private void SetoutComponentGrid_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
  1150. {
  1151. Distribute.IsEnabled = e.Rows?.Any() == true;
  1152. }
  1153. }