TaskPanel.xaml.cs 51 KB

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