TaskPanel.xaml.cs 52 KB

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