TaskPanel.xaml.cs 48 KB

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