TaskPanel.xaml.cs 48 KB

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