TaskPanel.xaml.cs 51 KB

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