TaskPanel.xaml.cs 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using Comal.Classes;
  9. using InABox.Clients;
  10. using InABox.Configuration;
  11. using InABox.Core;
  12. using InABox.DynamicGrid;
  13. using InABox.WPF;
  14. using Syncfusion.Pdf.Graphics;
  15. using Syncfusion.Pdf;
  16. using System.Drawing;
  17. using System.ComponentModel;
  18. using InABox.Wpf;
  19. namespace PRSDesktop
  20. {
  21. public class TaskPanelProperties : BaseObject, IGlobalConfigurationSettings
  22. {
  23. [CheckBoxEditor(ToolTip = "Require that all tasks are given a task type.")]
  24. public bool RequireTaskTypes { get; set; } = false;
  25. }
  26. public class TaskPanelFilterButton : FilterButton<Kanban>
  27. {
  28. public TaskPanelFilterButton() : base(
  29. new GlobalConfiguration<CoreFilterDefinitions>(nameof(Kanban)),
  30. new UserConfiguration<CoreFilterDefinitions>(nameof(Kanban)))
  31. {
  32. }
  33. public static Filter<Kanban> ConvertFilterToKanbanFilter(Filter<Kanban>? kanbanFilter)
  34. {
  35. if (kanbanFilter is null)
  36. {
  37. return new Filter<Kanban>().All();
  38. }
  39. else if (CoreUtils.TryFindMemberExpression(kanbanFilter.Expression, out var mexp))
  40. {
  41. var prop = CoreUtils.GetFullPropertyName(mexp, ".");
  42. var filter = new Filter<Kanban>(prop)
  43. {
  44. Operator = kanbanFilter.Operator,
  45. Value = kanbanFilter.Value
  46. };
  47. filter.Ands.AddRange(kanbanFilter.Ands.Select(ConvertFilterToKanbanFilter));
  48. filter.Ors.AddRange(kanbanFilter.Ors.Select(ConvertFilterToKanbanFilter));
  49. return filter;
  50. }
  51. else
  52. {
  53. return new Filter<Kanban>().None();
  54. }
  55. }
  56. public static Filter<KanbanSubscriber> ConvertFilterToSubscriberFilter(Filter<IKanban>? kanbanFilter)
  57. {
  58. if (kanbanFilter is null)
  59. {
  60. return new Filter<KanbanSubscriber>().All();
  61. }
  62. else if (CoreUtils.TryFindMemberExpression(kanbanFilter.Expression, out var mexp))
  63. {
  64. var prop = CoreUtils.GetFullPropertyName(mexp, ".");
  65. var filter = new Filter<KanbanSubscriber>(nameof(KanbanSubscriber.Kanban) + "." + prop)
  66. {
  67. Operator = kanbanFilter.Operator,
  68. Value = kanbanFilter.Value
  69. };
  70. filter.Ands.AddRange(kanbanFilter.Ands.Select(ConvertFilterToSubscriberFilter));
  71. filter.Ors.AddRange(kanbanFilter.Ors.Select(ConvertFilterToSubscriberFilter));
  72. return filter;
  73. }
  74. else
  75. {
  76. return new Filter<KanbanSubscriber>().None();
  77. }
  78. }
  79. }
  80. /// <summary>
  81. /// Interaction logic for TaskPanel.xaml
  82. /// </summary>
  83. public partial class TaskPanel : UserControl, IPanel<Kanban>, ITaskHost, IMasterDetailControl<Job>, IPropertiesPanel<TaskPanelProperties, CanConfigureTasksPanel>
  84. {
  85. private bool _bTabChanging;
  86. private KanbanType[] kanbanTypes = null!; // Initialized in Setup()
  87. public IList<KanbanType> KanbanTypes => kanbanTypes;
  88. public Job? Master { get; set; }
  89. public TaskPanel()
  90. {
  91. InitializeComponent();
  92. foreach (TabItem tab in TaskPanels.Items)
  93. {
  94. var panel = (tab.Content as ITaskControl)!;
  95. _viewmap[panel.KanbanViewType] = tab;
  96. panel.Host = this;
  97. }
  98. }
  99. #region Menu
  100. private void CompleteTask(ITaskControl control, RoutedEventArgs e, DateTime completed)
  101. {
  102. if (MessageBox.Show($"Are you sure you want to complete the selected tasks?", "Confirm Completion",
  103. MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  104. return;
  105. var tasks = (((FrameworkElement)e.Source).Tag as IEnumerable<TaskModel>)!;
  106. Progress.ShowModal("Completing Tasks", progress =>
  107. {
  108. var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.Completed, x => x.Status));
  109. foreach (var kanban in kanbans)
  110. {
  111. kanban.Completed = completed;
  112. kanban.Status = KanbanStatus.Complete;
  113. }
  114. Client.Save(kanbans, $"Kanban Marked as Complete");
  115. });
  116. control.Refresh();
  117. }
  118. private void AddChangeStatusButton(ITaskControl control, TaskModel[] models, MenuItem menu, string header, KanbanStatus status)
  119. {
  120. menu.AddItem(header, null, Tuple.Create(control, models, status), ChangeStatus_Click);
  121. }
  122. private void ChangeStatus_Click(Tuple<ITaskControl, TaskModel[], KanbanStatus> obj)
  123. {
  124. var (control, tasks, status) = obj;
  125. if (MessageBox.Show($"Are you sure you want to mark the selected tasks as {status}?", "Confirm Change Status",
  126. MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  127. return;
  128. Progress.ShowModal("Changing Status", progress =>
  129. {
  130. var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.Completed, x => x.Status));
  131. foreach (var kanban in kanbans)
  132. {
  133. if (status == KanbanStatus.Complete)
  134. {
  135. kanban.Completed = DateTime.Now;
  136. }
  137. kanban.Status = status;
  138. }
  139. new Client<Kanban>().Save(kanbans, $"Kanban Marked as {status}");
  140. });
  141. control.Refresh();
  142. }
  143. public bool CanChangeTasks(IEnumerable<TaskModel> models)
  144. {
  145. foreach (var task in models)
  146. {
  147. if (!App.EmployeeID.Equals(task.ManagerID) && !App.EmployeeID.Equals(task.EmployeeID))
  148. {
  149. // If you can change others tasks, IsFullControl is true - but we don't check at the beginning of the function
  150. // to save checking security tokens every time.
  151. return Security.IsAllowed<CanChangeOthersTasks>();
  152. }
  153. }
  154. return true;
  155. }
  156. public void PopulateMenu(ITaskControl control, TaskModel task, ContextMenu menu)
  157. {
  158. menu.Items.Clear();
  159. var models = control.SelectedModels(task).ToArray();
  160. var references = GetReferences(models);
  161. var bLinks = references.Any(x => x.ReferenceType() != null);
  162. var referencetypes = references.Select(x => x.ReferenceType()).Distinct().ToArray();
  163. var bSingle = models.Length == 1;
  164. var canChange = CanChangeTasks(models);
  165. var edit = new MenuItem
  166. {
  167. Tag = models,
  168. Header = referencetypes.SingleOrDefault() == typeof(Requisition)
  169. ? "Edit Requisition Details"
  170. : referencetypes.SingleOrDefault() == typeof(Setout)
  171. ? "Edit Setout Details"
  172. : referencetypes.SingleOrDefault() == typeof(Delivery)
  173. ? "Edit Delivery Details"
  174. : referencetypes.SingleOrDefault() == typeof(PurchaseOrder)
  175. ? "Edit Order Details"
  176. : "Edit Task" + (bSingle ? "" : "s")
  177. };
  178. edit.Click += (o, e) =>
  179. {
  180. var tasks = (((MenuItem)e.Source).Tag as IEnumerable<TaskModel>)!;
  181. if (EditReferences(tasks))
  182. control.Refresh();
  183. e.Handled = true;
  184. };
  185. edit.IsEnabled = referencetypes.Length == 1;
  186. menu.Items.Add(edit);
  187. if (!bLinks && models.Length == 1)
  188. {
  189. var digitalForms = new MenuItem { Header = "Digital Forms" };
  190. var model = models.First();
  191. DynamicGridUtils.PopulateFormMenu<KanbanForm, Kanban, KanbanLink>(
  192. digitalForms,
  193. model.ID,
  194. () => new Client<Kanban>().Load(new Filter<Kanban>(x => x.ID).IsEqualTo(model.ID)).First(),
  195. model.EmployeeID == App.EmployeeID);
  196. menu.Items.Add(digitalForms);
  197. }
  198. if (!models.Any(x => !x.CompletedDate.IsEmpty()) && !bLinks)
  199. {
  200. menu.Items.Add(new Separator());
  201. var job = new MenuItem
  202. {
  203. Tag = models,
  204. Header = "Link to Job"
  205. };
  206. job.SubmenuOpened += (o, e) => CreateJobSubMenu(control, job, models);
  207. menu.Items.Add(job);
  208. if (bSingle)
  209. {
  210. menu.AddItem("Create Setout from Task", null, models.First(), task =>
  211. {
  212. if (MessageBox.Show("This will convert this task into a Setout.\n\nDo you wish to continue?", "Confirmation", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  213. return;
  214. ManufacturingTemplate? template = new Client<ManufacturingTemplate>()
  215. .Load(new Filter<ManufacturingTemplate>(x => x.Code).IsEqualTo("PRS")).FirstOrDefault();
  216. if (template == null)
  217. {
  218. MessageBox.Show("[Pressing] Template does not exist!");
  219. return;
  220. }
  221. string? setoutNumber = null;
  222. Kanban? kanban = null;
  223. ManufacturingTemplateStage[] tstages = Array.Empty<ManufacturingTemplateStage>();
  224. Progress.ShowModal("Creating Setout", (progress) =>
  225. {
  226. var kanbanFilter = new Filter<Kanban>(x => x.ID).IsEqualTo(task.ID);
  227. var tables = Client.QueryMultiple(new Dictionary<string, IQueryDef>
  228. {
  229. { "ManufacturingTemplateStage", new QueryDef<ManufacturingTemplateStage>(
  230. new Filter<ManufacturingTemplateStage>(x => x.Template.ID).IsEqualTo(template.ID),
  231. null,
  232. new SortOrder<ManufacturingTemplateStage>(x => x.Sequence)) },
  233. { "Kanban", new QueryDef<Kanban>(
  234. kanbanFilter,
  235. null,
  236. null) },
  237. { "Setout", new QueryDef<Setout>(
  238. new Filter<Setout>(x => x.JobLink.ID)
  239. .InQuery(new SubQuery<Kanban>(kanbanFilter, new Column<Kanban>(x => x.JobLink.ID))),
  240. Columns.None<Setout>().Add(x => x.JobLink.JobNumber, x => x.Number),
  241. null) }
  242. });
  243. tstages = tables["ManufacturingTemplateStage"].Rows
  244. .Select(x => x.ToObject<ManufacturingTemplateStage>()).ToArray();
  245. kanban = tables["Kanban"].Rows.FirstOrDefault()?.ToObject<Kanban>();
  246. if (kanban == null)
  247. {
  248. MessageBox.Show("Task does not exist!");
  249. return;
  250. }
  251. progress.Report("Creating Setouts");
  252. CoreTable setouts = tables["Setout"];
  253. int ireq = 0;
  254. string sreq = "";
  255. while (true)
  256. {
  257. ireq++;
  258. sreq = string.Format("{0}-{1:yyMMdd}-{2}", kanban.JobLink.JobNumber, DateTime.Now, ireq);
  259. if (!setouts.Rows.Any(r => sreq.Equals(r.Get<Setout, String>(c => c.Number))))
  260. break;
  261. }
  262. setoutNumber = sreq;
  263. });
  264. if (setoutNumber == null || kanban == null)
  265. {
  266. return;
  267. }
  268. var result = CreateSetout(
  269. task,
  270. s =>
  271. {
  272. s.Number = setoutNumber;
  273. s.JobLink.ID = task.JobID;
  274. var notes = kanban.Notes.ToList();
  275. var description = kanban.Summary;
  276. if (string.IsNullOrWhiteSpace(description))
  277. {
  278. description = CoreUtils.StripHTML(kanban.Description);
  279. }
  280. if (!string.IsNullOrWhiteSpace(description))
  281. {
  282. notes.Insert(0, description);
  283. }
  284. s.Description = string.Join("\n==========================================\n", notes);
  285. }
  286. );
  287. if (result != null)
  288. {
  289. Progress.ShowModal("Creating Manufacturing Packet", progress =>
  290. {
  291. ManufacturingPacket packet = new ManufacturingPacket()
  292. {
  293. Serial = template.Code,
  294. Title = kanban.Title,
  295. Quantity = 1,
  296. BarcodeQty = 1,
  297. DueDate = kanban.DueDate
  298. };
  299. packet.ManufacturingTemplateLink.ID = template.ID;
  300. packet.ManufacturingTemplateLink.Code = template.Code;
  301. packet.ManufacturingTemplateLink.Factory.ID = template.Factory.ID;
  302. packet.SetoutLink.ID = result.ID;
  303. new Client<ManufacturingPacket>().Save(packet, "Created from Task");
  304. DoLink<ManufacturingPacketKanban, ManufacturingPacket, ManufacturingPacketLink>(task, packet.ID);
  305. List<ManufacturingPacketStage> pstages = new List<ManufacturingPacketStage>();
  306. foreach (var tstage in tstages)
  307. {
  308. var pstage = new ManufacturingPacketStage()
  309. {
  310. Time = tstage.Time,
  311. Sequence = tstage.Sequence,
  312. SequenceType = tstage.SequenceType,
  313. Started = DateTime.MinValue,
  314. PercentageComplete = 0.0F,
  315. Completed = DateTime.MinValue,
  316. QualityChecks = tstage.QualityChecks,
  317. QualityStatus = QualityStatus.NotChecked,
  318. QualityNotes = "",
  319. };
  320. pstage.Parent.ID = packet.ID;
  321. pstage.ManufacturingSectionLink.ID = tstage.Section.ID;
  322. pstage.ManufacturingSectionLink.Name = tstage.Section.Name;
  323. pstages.Add(pstage);
  324. }
  325. new Client<ManufacturingPacketStage>().Save(pstages, "Created from Task", (_, __) => { });
  326. progress.Report("Processing Documents");
  327. List<SetoutDocument> _setoutdocuments = new List<SetoutDocument>();
  328. List<KanbanDocument> _kanbandocuments = new List<KanbanDocument>();
  329. KanbanDocument[] docrefs = new Client<KanbanDocument>()
  330. .Load(new Filter<KanbanDocument>(x => x.EntityLink.ID).IsEqualTo(kanban.ID));
  331. foreach (var docref in docrefs)
  332. {
  333. // Convert the document to a PDF
  334. var docid = ProcessKanbanDocument(docref);
  335. var newdoc = new SetoutDocument();
  336. newdoc.EntityLink.ID = result.ID;
  337. newdoc.DocumentLink.ID = docid;
  338. _setoutdocuments.Add(newdoc);
  339. if (docid != docref.DocumentLink.ID)
  340. {
  341. docref.DocumentLink.ID = docid;
  342. _kanbandocuments.Add(docref);
  343. }
  344. }
  345. new Client<SetoutDocument>().Save(_setoutdocuments, "Converted from Task", (_, __) => { });
  346. new Client<KanbanDocument>().Save(_kanbandocuments, "Converted to PDF", (_, __) => { });
  347. progress.Report("Updating Task");
  348. kanban.Title = kanban.Title + " (" + result.Number + ")";
  349. new Client<Kanban>().Save(kanban, "Converting Kanban to Setout");
  350. });
  351. control.Refresh();
  352. }
  353. });
  354. menu.AddItem("Create Requisition from Task", null, models, tasks =>
  355. {
  356. var taskModel = tasks.First();
  357. var kanbanTable = new Client<Kanban>().Query(new Filter<Kanban>(x => x.ID).IsEqualTo(taskModel.ID));
  358. var kanban = kanbanTable.Rows.First().ToObject<Kanban>();
  359. var result = CreateRequisition(
  360. taskModel,
  361. r =>
  362. {
  363. r.RequestedBy.ID = kanban.ManagerLink.ID;
  364. r.Employee.ID = Guid.Empty;
  365. r.Title = kanban.Title;
  366. r.Request = string.IsNullOrWhiteSpace(kanban.Summary)
  367. ? String.IsNullOrWhiteSpace(kanban.Description)
  368. ? String.Join("\n", kanban.Notes)
  369. : CoreUtils.StripHTML(kanban.Description)
  370. : kanban.Summary;
  371. r.Notes = kanban.Notes;
  372. r.Due = kanban.DueDate;
  373. r.JobLink.ID = taskModel.JobID;
  374. }
  375. );
  376. if (result != null)
  377. {
  378. Progress.ShowModal("Updating Documents", progress =>
  379. {
  380. progress.Report("Updating Documents");
  381. List<RequisitionDocument> requiDocuments = new();
  382. KanbanDocument[] kanbanDocuments = new Client<KanbanDocument>()
  383. .Load(new Filter<KanbanDocument>(x => x.EntityLink.ID).IsEqualTo(kanban.ID));
  384. foreach (var document in kanbanDocuments)
  385. {
  386. var newdoc = new RequisitionDocument();
  387. newdoc.EntityLink.ID = result.ID;
  388. newdoc.DocumentLink.ID = document.DocumentLink.ID;
  389. requiDocuments.Add(newdoc);
  390. }
  391. new Client<RequisitionDocument>().Save(requiDocuments, "Converted from Task", (_, __) => { });
  392. /*RequisitionKanban link = new();
  393. link.Entity.ID = result.ID;
  394. link.Kanban.ID = kanban.ID;
  395. new Client<RequisitionKanban>().Save(link, "Converting Task -> Requisition", (_, __) => { });*/
  396. progress.Report("Updating Task");
  397. kanban.Status = KanbanStatus.Open;
  398. kanban.Completed = DateTime.MinValue;
  399. kanban.Title += $" (Requi #{result.Number})";
  400. new Client<Kanban>().Save(kanban, "Converted to Requisition", (_, __) => { });
  401. });
  402. MessageBox.Show(String.Format("Created Requisition {0}", result.Number));
  403. control.Refresh();
  404. }
  405. });
  406. menu.AddItem("Create Delivery from Task", null, models, tasks =>
  407. {
  408. var result = CreateDelivery(
  409. tasks.First(),
  410. d =>
  411. {
  412. // Post-Process Requi Here
  413. }
  414. );
  415. if (result != null)
  416. control.Refresh();
  417. });
  418. menu.AddItem("Create Purchase Order from Task", null, models, tasks =>
  419. {
  420. var result = CreateOrder(
  421. tasks.First(),
  422. p =>
  423. {
  424. // Post-Process Requi Here
  425. }
  426. );
  427. if (result != null)
  428. control.Refresh();
  429. });
  430. }
  431. }
  432. if (!bLinks && canChange)
  433. {
  434. menu.Items.Add(new Separator());
  435. var changeStatus = new MenuItem { Header = "Change Status" };
  436. AddChangeStatusButton(control, models, changeStatus, "Open", KanbanStatus.Open);
  437. AddChangeStatusButton(control, models, changeStatus, "In Progress", KanbanStatus.InProgress);
  438. AddChangeStatusButton(control, models, changeStatus, "Waiting", KanbanStatus.Waiting);
  439. if (models.Any(x => x.CompletedDate.IsEmpty()))
  440. {
  441. var complete = new MenuItem
  442. {
  443. Tag = models,
  444. Header = models.Length > 1 ? "Complete Tasks" : "Complete Task"
  445. };
  446. complete.Click += (o, e) =>
  447. {
  448. CompleteTask(control, e, DateTime.Now);
  449. };
  450. menu.Items.Add(complete);
  451. if (Security.IsAllowed<CanSetKanbanCompletedDate>())
  452. {
  453. var completeDate = new MenuItem
  454. {
  455. Tag = models,
  456. Header = "Set Completed Date"
  457. };
  458. var dateItem = new MenuItem();
  459. var dateCalendar = new System.Windows.Controls.Calendar { SelectedDate = DateTime.MinValue };
  460. dateCalendar.Tag = models;
  461. dateCalendar.SelectedDatesChanged += (o, e) =>
  462. {
  463. if (e.Source is not System.Windows.Controls.Calendar calendar) return;
  464. menu.IsOpen = false;
  465. var selectedDate = calendar.SelectedDate ?? DateTime.Now;
  466. CompleteTask(control, e, selectedDate);
  467. };
  468. dateItem.Header = dateCalendar;
  469. dateItem.Style = Resources["calendarItem"] as Style;
  470. completeDate.Items.Add(dateItem);
  471. menu.Items.Add(completeDate);
  472. }
  473. }
  474. else
  475. {
  476. menu.AddItem(models.Length > 1 ? "Archive Tasks" : "Archive Task", null, models, tasks =>
  477. {
  478. if (MessageBox.Show("Are you sure you want to remove the selected tasks from the list?", "Confirm removal",
  479. MessageBoxButton.YesNo) != MessageBoxResult.Yes)
  480. return;
  481. Progress.ShowModal("Closing Kanbans", progress =>
  482. {
  483. var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.Closed));
  484. foreach (var kanban in kanbans)
  485. kanban.Closed = DateTime.Now;
  486. new Client<Kanban>().Save(kanbans, "Kanban Marked as Closed");
  487. });
  488. control.Refresh();
  489. });
  490. }
  491. menu.Items.Add(changeStatus);
  492. var changeType = new MenuItem { Header = "Change Task Type", Tag = models };
  493. foreach(var type in KanbanTypes)
  494. {
  495. changeType.AddItem($"{type.Code}: {type.Description}", null, type, type =>
  496. {
  497. Progress.ShowModal("Changing Task Type", progress =>
  498. {
  499. var kanbans = LoadKanbans(models, Columns.Required<Kanban>().Add(x => x.ID, x => x.Type.ID));
  500. foreach (var kanban in kanbans)
  501. {
  502. kanban.Type.ID = type.ID;
  503. }
  504. new Client<Kanban>().Save(kanbans, $"Kanban Task Type changed to {type}");
  505. });
  506. control.Refresh();
  507. });
  508. }
  509. menu.Items.Add(changeType);
  510. var changeDueDate = new MenuItem { Header = "Change Due Date" };
  511. var calendarItem = new MenuItem();
  512. var calendar = new System.Windows.Controls.Calendar { SelectedDate = models.Length == 1 ? models[0].DueDate : DateTime.Today };
  513. calendar.Tag = models;
  514. calendar.SelectedDatesChanged += (o, e) =>
  515. {
  516. if (e.Source is not System.Windows.Controls.Calendar calendar) return;
  517. var selectedDate = calendar.SelectedDate ?? DateTime.Now;
  518. var models = (calendar.Tag as IList<TaskModel>)!;
  519. Progress.ShowModal("Changing Due Date", progress =>
  520. {
  521. var kanbans = LoadKanbans(models, Columns.Required<Kanban>().Add(x => x.ID, x => x.DueDate));
  522. foreach (var kanban in kanbans)
  523. {
  524. kanban.DueDate = selectedDate;
  525. }
  526. new Client<Kanban>().Save(kanbans, $"Kanban Due Date changed to {selectedDate:dd MMM yyyy}");
  527. });
  528. control.Refresh();
  529. menu.IsOpen = false;
  530. };
  531. calendarItem.Header = calendar;
  532. calendarItem.Style = Resources["calendarItem"] as Style;
  533. changeDueDate.Items.Add(calendarItem);
  534. menu.Items.Add(changeDueDate);
  535. }
  536. }
  537. /// <summary>
  538. /// Takes a <see cref="KanbanDocument"/>, and if it is a .txt or an image (".png", ".jpg", ".jpeg" or ".bmp"), converts to a PDF
  539. /// with the content of the document, saving a new document with extension changed to ".pdf".
  540. /// </summary>
  541. /// <param name="docref">The original document.</param>
  542. /// <returns>
  543. /// The ID of the new <see cref="Document"/> or,
  544. /// if not one of the given types, the original document ID.
  545. /// </returns>
  546. private static Guid ProcessKanbanDocument(KanbanDocument docref)
  547. {
  548. var result = docref.DocumentLink.ID;
  549. var ext = System.IO.Path.GetExtension(docref.DocumentLink.FileName).ToLower();
  550. if (ext.EndsWith("txt"))
  551. {
  552. var doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(docref.DocumentLink.ID)).FirstOrDefault();
  553. if (doc is null)
  554. {
  555. Logger.Send(LogType.Error, "", $"Document {docref.DocumentLink.ID} does not exist!");
  556. return docref.DocumentLink.ID;
  557. }
  558. PdfDocument pdf = new PdfDocument();
  559. PdfPage page = pdf.Pages.Add();
  560. PdfGraphics graphics = page.Graphics;
  561. PdfFont font = new PdfStandardFont(PdfFontFamily.Courier, 12);
  562. String text = System.Text.Encoding.UTF8.GetString(doc.Data);
  563. graphics.DrawString(text, font, PdfBrushes.Black, new PointF(0, 0));
  564. MemoryStream ms = new MemoryStream();
  565. pdf.Save(ms);
  566. pdf.Close(true);
  567. byte[] data = ms.ToArray();
  568. var newdoc = new Document()
  569. {
  570. Data = data,
  571. FileName = System.IO.Path.ChangeExtension(docref.DocumentLink.FileName, "pdf"),
  572. CRC = CoreUtils.CalculateCRC(data),
  573. TimeStamp = DateTime.Now,
  574. };
  575. new Client<Document>().Save(newdoc, "Converted from Text");
  576. return newdoc.ID;
  577. }
  578. else if (ext.EndsWith("png") || ext.EndsWith("bmp") || ext.EndsWith("jpg") || ext.EndsWith("jpeg"))
  579. {
  580. var doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(docref.DocumentLink.ID)).FirstOrDefault();
  581. if (doc is null)
  582. {
  583. Logger.Send(LogType.Error, "", $"Document {docref.DocumentLink.ID} does not exist!");
  584. return docref.DocumentLink.ID;
  585. }
  586. PdfBitmap image = new PdfBitmap(new MemoryStream(doc.Data));
  587. PdfDocument pdf = new PdfDocument();
  588. pdf.PageSettings.Orientation = image.Height > image.Width ? PdfPageOrientation.Portrait : PdfPageOrientation.Landscape;
  589. pdf.PageSettings.Size = new SizeF(image.Width, image.Height);
  590. PdfPage page = pdf.Pages.Add();
  591. PdfGraphics graphics = page.Graphics;
  592. graphics.DrawImage(image, 0.0F, 0.0F);
  593. MemoryStream ms = new MemoryStream();
  594. pdf.Save(ms);
  595. pdf.Close(true);
  596. byte[] data = ms.ToArray();
  597. var newdoc = new Document()
  598. {
  599. Data = data,
  600. FileName = System.IO.Path.ChangeExtension(docref.DocumentLink.FileName, "pdf"),
  601. CRC = CoreUtils.CalculateCRC(data),
  602. TimeStamp = DateTime.Now,
  603. };
  604. new Client<Document>().Save(newdoc, "Converted from Image");
  605. return newdoc.ID;
  606. }
  607. return result;
  608. }
  609. private void CreateJobSubMenu(ITaskControl control, MenuItem job, IEnumerable<TaskModel> tasks)
  610. {
  611. job.Items.Clear();
  612. job.Items.Add(new MenuItem { Header = "Loading...", IsEnabled = false });
  613. using (new WaitCursor())
  614. {
  615. job.Items.Clear();
  616. var jobs = new Client<Job>().Query(
  617. LookupFactory.DefineFilter<Job>(),
  618. LookupFactory.DefineColumns<Job>(),
  619. LookupFactory.DefineSort<Job>()
  620. );
  621. foreach (var row in jobs.Rows)
  622. {
  623. var jobNumber = row.Get<Job, string>(x => x.JobNumber);
  624. var jobName = row.Get<Job, string>(x => x.Name);
  625. job.AddItem($"{jobNumber}: {jobName}", null, tasks, tasks =>
  626. {
  627. using (new WaitCursor())
  628. {
  629. var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.JobLink.ID));
  630. foreach (var kanban in kanbans)
  631. kanban.JobLink.ID = row.Get<Job, Guid>(x => x.ID);
  632. new Client<Kanban>().Save(kanbans, "Updated Job Number");
  633. control.Refresh();
  634. }
  635. });
  636. }
  637. }
  638. }
  639. #endregion
  640. private void TaskPanels_SelectionChanged(object sender, SelectionChangedEventArgs e)
  641. {
  642. if (!IsReady)
  643. return;
  644. if (e.Source is not TabControl)
  645. return;
  646. if (_bTabChanging)
  647. return;
  648. try
  649. {
  650. _bTabChanging = true;
  651. var panel = GetCurrentPanel();
  652. if(panel is not null)
  653. {
  654. KanbanSettings.ViewType = panel.KanbanViewType;
  655. new UserConfiguration<KanbanSettings>().Save(KanbanSettings);
  656. panel.Refresh();
  657. }
  658. }
  659. finally
  660. {
  661. _bTabChanging = false;
  662. }
  663. }
  664. #region Get/Save Settings
  665. private KanbanSettings? _settings;
  666. public KanbanSettings KanbanSettings
  667. {
  668. get
  669. {
  670. _settings ??= new UserConfiguration<KanbanSettings>().Load();
  671. return _settings;
  672. }
  673. }
  674. public void SaveSettings()
  675. {
  676. if(_settings != null)
  677. new UserConfiguration<KanbanSettings>().Save(_settings);
  678. }
  679. #endregion
  680. #region IPanel Stuff
  681. public event DataModelUpdateEvent? OnUpdateDataModel;
  682. public bool IsReady { get; set; }
  683. public void CreateToolbarButtons(IPanelHost host)
  684. {
  685. host.CreatePanelAction(
  686. new PanelAction
  687. {
  688. Caption = "New Task",
  689. OnExecute = a => {
  690. if(CreateKanban(k => { }) != null)
  691. {
  692. Refresh();
  693. }
  694. },
  695. Image = PRSDesktop.Resources.add
  696. }
  697. );
  698. if (Security.CanView<KanbanType>())
  699. {
  700. host.CreateSetupAction(
  701. new PanelAction
  702. {
  703. Caption = "Task Types",
  704. Image = PRSDesktop.Resources.kanbantype,
  705. OnExecute = a =>
  706. {
  707. var list = new MasterList(typeof(KanbanType));
  708. list.ShowDialog();
  709. }
  710. });
  711. }
  712. }
  713. public Dictionary<string, object[]> Selected()
  714. {
  715. return new Dictionary<string, object[]>();
  716. }
  717. public void Heartbeat(TimeSpan time)
  718. {
  719. }
  720. private readonly Dictionary<KanbanViewType, TabItem> _viewmap = new();
  721. private readonly List<ITaskControl> _initialized = new();
  722. private ITaskControl GetCurrentPanel()
  723. {
  724. var result = (TaskPanels.SelectedContent as ITaskControl)!;
  725. if (result == null)
  726. result = (TaskPanels.Items[0] as DynamicTabItem)?.Content as ITaskControl;
  727. try
  728. {
  729. //if (result != null)
  730. if (!_initialized.Contains(result))
  731. {
  732. result.Setup();
  733. result.IsReady = true;
  734. _initialized.Add(result);
  735. }
  736. }
  737. catch (Exception e)
  738. {
  739. Logger.Send(LogType.Error, "", $"Error in TaskPanel.GetCurrentPanel: {CoreUtils.FormatException(e)}");
  740. }
  741. return result;
  742. }
  743. public void Setup()
  744. {
  745. _settings = new UserConfiguration<KanbanSettings>().Load();
  746. TaskPanels.SelectedItem = _viewmap[_settings.ViewType];
  747. kanbanTypes = new Client<KanbanType>()
  748. .Query(
  749. new Filter<KanbanType>(x => x.Hidden).IsEqualTo(false),
  750. Columns.None<KanbanType>().Add(x => x.ID, x => x.Code, x => x.Description))
  751. .Rows.Select(x => x.ToObject<KanbanType>()).ToArray();
  752. }
  753. public void Shutdown(CancelEventArgs? cancel)
  754. {
  755. }
  756. public void Refresh()
  757. {
  758. if (Master == null)
  759. {
  760. if (Equals(TaskPanels.SelectedItem, TasksPlannerTabItem))
  761. TaskPanels.SelectedItem = _viewmap[KanbanViewType.Status];
  762. TasksPlannerTabItem.Visibility = Visibility.Collapsed;
  763. }
  764. else
  765. TasksPlannerTabItem.Visibility = Visibility.Visible;
  766. GetCurrentPanel()?.Refresh();
  767. }
  768. public string SectionName => GetCurrentPanel().SectionName;
  769. public TaskPanelProperties Properties { get; set; }
  770. public DataModel DataModel(Selection selection)
  771. {
  772. return GetCurrentPanel().DataModel(selection);
  773. //return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).IsEqualTo(Guid.Empty));
  774. }
  775. #endregion
  776. #region CRUD Functionality
  777. private TEntity? DoCreate<TEntity>(Action<TEntity> customise)
  778. where TEntity : Entity, IRemotable, IPersistent, new()
  779. {
  780. var result = new TEntity();
  781. customise?.Invoke(result);
  782. if (DoEdit(new[] { result }, null))
  783. return result;
  784. return null;
  785. }
  786. private readonly Dictionary<Type, IDynamicGrid> _grids = new();
  787. private readonly List<Tuple<Guid, Entity>> _entitycache = new();
  788. private DynamicDataGrid<TEntity> GetGrid<TEntity>() where TEntity : Entity, IRemotable, IPersistent, new()
  789. {
  790. if(!_grids.TryGetValue(typeof(TEntity), out var grid))
  791. {
  792. grid = (DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(TEntity)) as DynamicDataGrid<TEntity>)!;
  793. _grids[typeof(TEntity)] = grid;
  794. if (typeof(TEntity) == typeof(Kanban))
  795. {
  796. CustomiseKanbanGrid((grid as DynamicDataGrid<Kanban>)!);
  797. }
  798. }
  799. return (grid as DynamicDataGrid<TEntity>)!;
  800. }
  801. private IEnumerable<TEntity> DoLoad<TEntity>(IEnumerable<TaskModel> models, Columns<TEntity> columns)
  802. where TEntity : Entity, IRemotable, IPersistent, new()
  803. {
  804. var result = new List<TEntity>();
  805. var load = new List<Guid>();
  806. foreach (var model in models)
  807. {
  808. var entity = _entitycache.FirstOrDefault(x => Equals(x.Item1, model.ID) && x.Item2 is TEntity) as TEntity;
  809. if (entity is not null)
  810. result.Add(entity);
  811. else
  812. load.Add(model.ID);
  813. }
  814. if (load.Any())
  815. {
  816. var entities = new Client<TEntity>()
  817. .Query(new Filter<TEntity>(x => x.ID).InList(load.ToArray()), columns)
  818. .Rows.Select(x => x.ToObject<TEntity>()).ToList();
  819. foreach (var entity in entities)
  820. _entitycache.Add(new Tuple<Guid, Entity>(entity.ID, entity));
  821. result.AddRange(entities);
  822. }
  823. return result;
  824. }
  825. private IEnumerable<TEntity> DoLoad<TEntityKanban, TEntity, TLink>(IEnumerable<TaskModel> models, Columns<TEntity> columns)
  826. where TEntityKanban : EntityKanban<TEntity, TLink>, new()
  827. where TEntity : Entity, IRemotable, IPersistent, new()
  828. where TLink : IEntityLink<TEntity>, new()
  829. {
  830. var result = DoLoad(models, columns);
  831. if (!result.Any())
  832. foreach (var model in models)
  833. {
  834. result = new Client<TEntity>().Load(
  835. new Filter<TEntity>(x => x.ID).InQuery(new Filter<TEntityKanban>(x => x.Kanban.ID).IsEqualTo(model.ID),
  836. x => x.Entity.ID));
  837. foreach (var r in result)
  838. _entitycache.Add(new Tuple<Guid, Entity>(model.ID, r));
  839. }
  840. return result;
  841. }
  842. private void DoCache<TEntity>(Guid kanbanid, TEntity entity) where TEntity : Entity
  843. {
  844. if (!_entitycache.Any(x => Equals(x.Item1, kanbanid) && x.Item2 is TEntity && Equals(x.Item2.ID, entity.ID)))
  845. _entitycache.Add(new Tuple<Guid, Entity>(kanbanid, entity));
  846. }
  847. private bool DoEdit<TEntity>(IEnumerable<TEntity> entities, Action<TEntity>? action = null)
  848. where TEntity : Entity, IRemotable, IPersistent, new()
  849. {
  850. if (entities == null || !entities.Any())
  851. return false;
  852. foreach (var entity in entities)
  853. action?.Invoke(entity);
  854. return GetGrid<TEntity>().EditItems(entities.ToArray());
  855. }
  856. private void DoLink<TEntityKanban, TEntity, TLink>(TaskModel model, Guid entityid)
  857. where TEntityKanban : EntityKanban<TEntity, TLink>, new()
  858. where TEntity : Entity, IRemotable, IPersistent, new()
  859. where TLink : IEntityLink<TEntity>, new()
  860. {
  861. var linktask = Task.Run(() =>
  862. {
  863. var link = new TEntityKanban();
  864. link.Kanban.ID = model.ID;
  865. link.Entity.ID = entityid;
  866. new Client<TEntityKanban>().Save(link, "");
  867. });
  868. var kanbantask = Task.Run(() =>
  869. {
  870. var kanban = LoadKanbans(
  871. new[] { model },
  872. Columns.Required<Kanban>().Add(x => x.ID, x => x.Locked)).FirstOrDefault();
  873. if (kanban is not null)
  874. {
  875. kanban.Locked = true;
  876. new Client<Kanban>().Save(kanban, "Locked because of linked " + typeof(TEntity).EntityName().Split('.').Last());
  877. }
  878. });
  879. Task.WaitAll(linktask, kanbantask);
  880. }
  881. private static void DoDelete<TEntity>(IList<TEntity> entities, string auditnote)
  882. where TEntity : Entity, IRemotable, IPersistent, new()
  883. {
  884. new Client<TEntity>().Delete(entities, auditnote);
  885. }
  886. public Kanban? CreateKanban(Action<Kanban> customise)
  887. {
  888. var result = DoCreate<Kanban>(
  889. kanban =>
  890. {
  891. kanban.Title = "New Task";
  892. kanban.Description = "";
  893. kanban.Status = KanbanStatus.Open;
  894. kanban.DueDate = DateTime.Today;
  895. kanban.Private = false;
  896. kanban.JobLink.ID = Master?.ID ?? Guid.Empty;
  897. kanban.JobLink.Synchronise(Master ?? new Job());
  898. kanban.EmployeeLink.ID = App.EmployeeID;
  899. kanban.ManagerLink.ID = App.EmployeeID;
  900. customise?.Invoke(kanban);
  901. });
  902. if (result != null)
  903. DoCache(result.ID, result);
  904. return result;
  905. }
  906. public IEnumerable<Kanban> LoadKanbans(IEnumerable<TaskModel> models, Columns<Kanban> columns)
  907. {
  908. columns.Add(x => x.ID);
  909. columns.Add(x => x.Number);
  910. columns.Add(x => x.Title);
  911. columns.Add(x => x.Notes);
  912. columns.Add(x => x.Summary);
  913. columns.Add(x => x.Completed);
  914. columns.Add(x => x.DueDate);
  915. columns.Add(x => x.ManagerLink.ID);
  916. columns.Add(x => x.EmployeeLink.ID);
  917. return DoLoad(models, columns);
  918. }
  919. public void OnValidateKanban(object sender, Kanban[] items, List<string> errors)
  920. {
  921. if (Properties.RequireTaskTypes && items.Any(x => x.Type.ID == Guid.Empty))
  922. {
  923. errors.Add("[Task Type] may not be blank!");
  924. }
  925. }
  926. public void CustomiseKanbanGrid(DynamicDataGrid<Kanban> grid)
  927. {
  928. grid.OnValidate += OnValidateKanban;
  929. }
  930. public bool EditKanbans(IEnumerable<TaskModel> models, Action<Kanban>? customise = null)
  931. {
  932. var entities = LoadKanbans(models, GetGrid<Kanban>().LoadEditorColumns());
  933. return DoEdit(entities, customise);
  934. }
  935. public void DeleteKanbans(IEnumerable<TaskModel> models, string auditnote)
  936. {
  937. var kanbans = models.Select(x => new Kanban { ID = x.ID }).ToList();
  938. DoDelete(kanbans, auditnote);
  939. }
  940. public Requisition? CreateRequisition(TaskModel model, Action<Requisition>? customise)
  941. {
  942. var result = DoCreate<Requisition>(
  943. requi =>
  944. {
  945. requi.JobLink.ID = Master?.ID ?? Guid.Empty;
  946. requi.JobLink.Synchronise(Master ?? new Job());
  947. customise?.Invoke(requi);
  948. });
  949. if (result != null)
  950. {
  951. DoCache(model.ID, result);
  952. DoLink<RequisitionKanban, Requisition, RequisitionLink>(model, result.ID);
  953. }
  954. return result;
  955. }
  956. public bool EditRequisitions(IEnumerable<TaskModel> models, Action<Requisition>? customise = null)
  957. {
  958. var requis = DoLoad<RequisitionKanban, Requisition, RequisitionLink>(models, GetGrid<Requisition>().LoadEditorColumns());
  959. if (requis.Any())
  960. return DoEdit(requis, customise);
  961. return false;
  962. }
  963. public Setout? CreateSetout(TaskModel model, Action<Setout> customise)
  964. {
  965. var result = DoCreate<Setout>(
  966. setout =>
  967. {
  968. setout.JobLink.ID = Master?.ID ?? Guid.Empty;
  969. setout.JobLink.Synchronise(Master ?? new Job());
  970. customise?.Invoke(setout);
  971. });
  972. if (result != null)
  973. {
  974. DoCache(model.ID, result);
  975. //DoLink<SetoutKanban, Setout, SetoutLink>(model, result.ID);
  976. }
  977. return result;
  978. }
  979. public bool EditSetouts(IEnumerable<TaskModel> models, Action<Setout>? customise = null)
  980. {
  981. var setouts = DoLoad<SetoutKanban, Setout, SetoutLink>(models, GetGrid<Setout>().LoadEditorColumns());
  982. if (setouts.Any())
  983. return DoEdit(setouts, customise);
  984. return false;
  985. }
  986. public Delivery? CreateDelivery(TaskModel model, Action<Delivery> customise)
  987. {
  988. var result = DoCreate<Delivery>(
  989. delivery =>
  990. {
  991. delivery.Job.ID = Master?.ID ?? Guid.Empty;
  992. delivery.Job.Synchronise(Master ?? new Job());
  993. customise?.Invoke(delivery);
  994. });
  995. if (result != null)
  996. {
  997. DoCache(model.ID, result);
  998. DoLink<DeliveryKanban, Delivery, DeliveryLink>(model, result.ID);
  999. }
  1000. return result;
  1001. }
  1002. public bool EditDeliveries(IEnumerable<TaskModel> models, Action<Delivery>? customise = null)
  1003. {
  1004. var deliveries = DoLoad<DeliveryKanban, Delivery, DeliveryLink>(models, GetGrid<Delivery>().LoadEditorColumns());
  1005. if (deliveries.Any())
  1006. return DoEdit(deliveries, customise);
  1007. return false;
  1008. }
  1009. public PurchaseOrder? CreateOrder(TaskModel model, Action<PurchaseOrder> customise)
  1010. {
  1011. var result = DoCreate<PurchaseOrder>(
  1012. order => { customise?.Invoke(order); });
  1013. if (result != null)
  1014. {
  1015. DoCache(model.ID, result);
  1016. DoLink<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(model, result.ID);
  1017. }
  1018. return result;
  1019. }
  1020. public bool EditPurchaseOrders(IEnumerable<TaskModel> models, Action<PurchaseOrder>? customise = null)
  1021. {
  1022. var orders = DoLoad<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(models, GetGrid<PurchaseOrder>().LoadEditorColumns());
  1023. if (orders.Any())
  1024. return DoEdit(orders, customise);
  1025. return false;
  1026. }
  1027. #endregion
  1028. #region EntityReferences
  1029. private static void AddQuery<TEntityKanban, TEntity, TLink>(MultiQuery query, Guid[] taskids)
  1030. where TEntityKanban : EntityKanban<TEntity, TLink>, new()
  1031. where TEntity : Entity
  1032. where TLink : IEntityLink<TEntity>, new()
  1033. {
  1034. query.Add(
  1035. new Filter<TEntityKanban>(x => x.Kanban.ID).InList(taskids),
  1036. Columns.None<TEntityKanban>().Add(x => x.Entity.ID).Add(x => x.Kanban.ID)
  1037. );
  1038. }
  1039. private static Guid[] ExtractIDs<TEntityKanban, TEntity, TLink>(MultiQuery query)
  1040. where TEntityKanban : EntityKanban<TEntity, TLink>, new()
  1041. where TEntity : Entity
  1042. where TLink : IEntityLink<TEntity>, new()
  1043. {
  1044. var lookup = query.Get<TEntityKanban>().ToLookup<TEntityKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
  1045. return query.Get<TEntityKanban>().ExtractValues<TEntityKanban, Guid>(x => x.Entity.ID).ToArray();
  1046. }
  1047. public KanbanReferences[] GetReferences(IEnumerable<TaskModel> models)
  1048. {
  1049. var result = new List<KanbanReferences>();
  1050. var ids = models.Select(x => x.ID).ToArray();
  1051. var query = new MultiQuery();
  1052. AddQuery<RequisitionKanban, Requisition, RequisitionLink>(query, ids);
  1053. AddQuery<SetoutKanban, Setout, SetoutLink>(query, ids);
  1054. AddQuery<DeliveryKanban, Delivery, DeliveryLink>(query, ids);
  1055. AddQuery<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(query, ids);
  1056. query.Query();
  1057. var requis = query.Get<RequisitionKanban>().ToLookup<RequisitionKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
  1058. var setouts = query.Get<SetoutKanban>().ToLookup<SetoutKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
  1059. var deliveries = query.Get<DeliveryKanban>().ToLookup<DeliveryKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
  1060. var orders = query.Get<PurchaseOrderKanban>().ToLookup<PurchaseOrderKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
  1061. foreach (var id in ids)
  1062. {
  1063. var references = new KanbanReferences
  1064. {
  1065. Kanban = id,
  1066. Requisitions = requis.Contains(id) ? requis[id].ToArray() : Array.Empty<Guid>(),
  1067. Setouts = setouts.Contains(id) ? setouts[id].ToArray() : Array.Empty<Guid>(),
  1068. Deliveries = deliveries.Contains(id) ? deliveries[id].ToArray() : Array.Empty<Guid>(),
  1069. Orders = orders.Contains(id) ? orders[id].ToArray() : Array.Empty<Guid>()
  1070. };
  1071. result.Add(references);
  1072. }
  1073. return result.ToArray();
  1074. }
  1075. public bool EditReferences(IEnumerable<TaskModel> models)
  1076. {
  1077. var result = false;
  1078. var refs = GetReferences(models).First();
  1079. if (refs.ReferenceType() == typeof(Requisition))
  1080. result = EditRequisitions(
  1081. models,
  1082. requi =>
  1083. {
  1084. requi.Notes = Utility.ProcessNotes(requi.Notes, requi.Request);
  1085. requi.Request = "";
  1086. }
  1087. );
  1088. else if (refs.ReferenceType() == typeof(Setout))
  1089. result = EditSetouts(models);
  1090. else if (refs.ReferenceType() == typeof(Delivery))
  1091. result = EditDeliveries(models);
  1092. else if (refs.ReferenceType() == typeof(PurchaseOrder))
  1093. result = EditPurchaseOrders(models);
  1094. else
  1095. result = EditKanbans(models);
  1096. return result;
  1097. }
  1098. #endregion
  1099. }
  1100. }