| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294 | 
							- using System;
 
- using System.Collections.Generic;
 
- using System.IO;
 
- using System.Linq;
 
- using System.Threading.Tasks;
 
- using System.Windows;
 
- using System.Windows.Controls;
 
- using Comal.Classes;
 
- using InABox.Clients;
 
- using InABox.Configuration;
 
- using InABox.Core;
 
- using InABox.DynamicGrid;
 
- using InABox.WPF;
 
- using Syncfusion.Pdf.Graphics;
 
- using Syncfusion.Pdf;
 
- using System.Drawing;
 
- using System.ComponentModel;
 
- using InABox.Wpf;
 
- namespace PRSDesktop;
 
- public class TaskPanelProperties : BaseObject, IGlobalConfigurationSettings
 
- {
 
-     [Comment("Require that all tasks are given a task type.")]
 
-     public bool RequireTaskTypes { get; set; } = false;
 
- }
 
- public class TaskPanelFilterButton : FilterButton<Kanban>
 
- {
 
-     public TaskPanelFilterButton() : base(
 
-         new GlobalConfiguration<CoreFilterDefinitions>(nameof(Kanban)),
 
-         new UserConfiguration<CoreFilterDefinitions>(nameof(Kanban)))
 
-     {
 
-     }
 
-     public static Filter<Kanban> ConvertFilterToKanbanFilter(Filter<Kanban>? kanbanFilter)
 
-     {
 
-         if (kanbanFilter is null)
 
-         {
 
-             return new Filter<Kanban>().All();
 
-         }
 
-         else if (!kanbanFilter.Property.IsNullOrWhiteSpace())
 
-         {
 
-             var filter = new Filter<Kanban>(kanbanFilter.Property)
 
-             {
 
-                 Operator = kanbanFilter.Operator,
 
-                 Value = kanbanFilter.Value
 
-             };
 
-             filter.Ands.AddRange(kanbanFilter.Ands.Select(ConvertFilterToKanbanFilter));
 
-             filter.Ors.AddRange(kanbanFilter.Ors.Select(ConvertFilterToKanbanFilter));
 
-             return filter;
 
-         }
 
-         else
 
-         {
 
-             return new Filter<Kanban>().None();
 
-         }
 
-     }
 
-     public static Filter<KanbanSubscriber> ConvertFilterToSubscriberFilter(Filter<IKanban>? kanbanFilter)
 
-     {
 
-         if (kanbanFilter is null)
 
-         {
 
-             return new Filter<KanbanSubscriber>().All();
 
-         }
 
-         else if (!kanbanFilter.Property.IsNullOrWhiteSpace())
 
-         {
 
-             var filter = new Filter<KanbanSubscriber>(nameof(KanbanSubscriber.Kanban) + "." + kanbanFilter.Property)
 
-             {
 
-                 Operator = kanbanFilter.Operator,
 
-                 Value = kanbanFilter.Value
 
-             };
 
-             filter.Ands.AddRange(kanbanFilter.Ands.Select(ConvertFilterToSubscriberFilter));
 
-             filter.Ors.AddRange(kanbanFilter.Ors.Select(ConvertFilterToSubscriberFilter));
 
-             return filter;
 
-         }
 
-         else
 
-         {
 
-             return new Filter<KanbanSubscriber>().None();
 
-         }
 
-     }
 
- }
 
- /// <summary>
 
- ///     Interaction logic for TaskPanel.xaml
 
- /// </summary>
 
- public partial class TaskPanel : UserControl, IPanel<Kanban>, ITaskHost, IMasterDetailControl<Job>, IPropertiesPanel<TaskPanelProperties, CanConfigureTasksPanel>
 
- {
 
-     private bool _bTabChanging;
 
-     private KanbanType[] kanbanTypes = null!; // Initialized in Setup()
 
-     
 
-     public IList<KanbanType> KanbanTypes => kanbanTypes;
 
-     
 
-     public Job? Master { get; set; }
 
-     
 
-     public TaskPanel()
 
-     {
 
-         InitializeComponent();
 
-         
 
-         foreach (TabItem tab in TaskPanels.Items)
 
-         {
 
-             var panel = (tab.Content as ITaskControl)!;
 
-             _viewmap[panel.KanbanViewType] = tab;
 
-             panel.Host = this;
 
-         }
 
-     }
 
-     #region Menu
 
-     private void CompleteTask(ITaskControl control, IEnumerable<TaskModel> tasks, DateTime completed)
 
-     {
 
-         if (!MessageWindow.ShowYesNo("Are you sure you want to complete the selected tasks?", "Confirm Completion"))
 
-             return;
 
-         Progress.ShowModal("Completing Tasks", progress =>
 
-         {
 
-             var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.Completed, x => x.Status));
 
-             foreach (var kanban in kanbans)
 
-             {
 
-                 kanban.Completed = completed;
 
-                 kanban.Status = KanbanStatus.Complete;
 
-             }
 
-             Client.Save(kanbans, $"Kanban Marked as Complete");
 
-         });
 
-         control.Refresh();
 
-     }
 
-     private void AddChangeStatusButton(ITaskControl control, TaskModel[] models, MenuItem menu, string header, KanbanStatus status)
 
-     {
 
-         menu.AddItem(header, null, Tuple.Create(control, models, status), ChangeStatus_Click);
 
-     }
 
-     private void ChangeStatus_Click(Tuple<ITaskControl, TaskModel[], KanbanStatus> obj)
 
-     {
 
-         var (control, tasks, status) = obj;
 
-         if (!MessageWindow.ShowYesNo($"Are you sure you want to mark the selected tasks as {status}?", "Confirm Change Status"))
 
-             return;
 
-         Progress.ShowModal("Changing Status", progress =>
 
-         {
 
-             var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.Completed, x => x.Status));
 
-             foreach (var kanban in kanbans)
 
-             {
 
-                 if (status == KanbanStatus.Complete)
 
-                 {
 
-                     kanban.Completed = DateTime.Now;
 
-                 }
 
-                 kanban.Status = status;
 
-             }
 
-             new Client<Kanban>().Save(kanbans, $"Kanban Marked as {status}");
 
-         });
 
-         control.Refresh();
 
-     }
 
-     public bool CanChangeTasks(IEnumerable<TaskModel> models)
 
-     {
 
-         foreach (var task in models)
 
-         {
 
-             if (!App.EmployeeID.Equals(task.ManagerID) && !App.EmployeeID.Equals(task.EmployeeID))
 
-             {
 
-                 // If you can change others tasks, IsFullControl is true - but we don't check at the beginning of the function
 
-                 // to save checking security tokens every time.
 
-                 return Security.IsAllowed<CanChangeOthersTasks>();
 
-             }
 
-         }
 
-         return true;
 
-     }
 
-     public void PopulateMenu(ITaskControl control, TaskModel task, ContextMenu menu)
 
-     {
 
-         menu.Items.Clear();
 
-         
 
-         var models = control.SelectedModels(task).ToArray();
 
-         var references = GetReferences(models);
 
-         var bLinks = references.Any(x => x.ReferenceType() != null);
 
-         var referencetypes = references.Select(x => x.ReferenceType()).Distinct().ToArray();
 
-         var bSingle = models.Length == 1;
 
-         var canChange = CanChangeTasks(models);
 
-         menu.AddItem(referencetypes.SingleOrDefault() == typeof(Requisition)
 
-             ? "Edit Requisition Details"
 
-             : referencetypes.SingleOrDefault() == typeof(Setout)
 
-                 ? "Edit Setout Details"
 
-                 : referencetypes.SingleOrDefault() == typeof(Delivery)
 
-                     ? "Edit Delivery Details"
 
-                     : referencetypes.SingleOrDefault() == typeof(PurchaseOrder)
 
-                         ? "Edit Order Details"
 
-                         : "Edit Task" + (bSingle ? "" : "s"),
 
-             null,
 
-             () =>
 
-             {
 
-                 if (EditReferences(models))
 
-                 {
 
-                     control.Refresh();
 
-                 }
 
-             },
 
-             enabled: referencetypes.Length == 1);
 
-         if (!bLinks && models.Length == 1)
 
-         {
 
-             var digitalForms = menu.AddItem("Digital Forms", null, null);
 
-             var model = models.First();
 
-             DynamicGridUtils.PopulateFormMenu<KanbanForm, Kanban, KanbanLink>(
 
-                 digitalForms,
 
-                 model.ID,
 
-                 () => new Client<Kanban>().Load(new Filter<Kanban>(x => x.ID).IsEqualTo(model.ID)).First(),
 
-                 model.EmployeeID == App.EmployeeID);
 
-             menu.AddItem("Manage Subscribers", null, model, Subscribers_Click);
 
-         }
 
-         if (!models.Any(x => !x.CompletedDate.IsEmpty()) && !bLinks)
 
-         {
 
-             menu.AddSeparatorIfNeeded();
 
-             var job = menu.AddItem("Link to Job", null, null);
 
-             job.SubmenuOpened += (o, e) => CreateJobSubMenu(control, job, models);
 
-             if (bSingle)
 
-             {
 
-                 menu.AddItem("Create Setout from Task", null, models.First(), task =>
 
-                 {
 
-                     if (!MessageWindow.ShowYesNo("This will convert this task into a Setout.\n\nDo you wish to continue?", "Confirmation"))
 
-                         return;
 
-                     ManufacturingTemplate? template = new Client<ManufacturingTemplate>()
 
-                         .Load(new Filter<ManufacturingTemplate>(x => x.Code).IsEqualTo("PRS")).FirstOrDefault();
 
-                     if (template == null)
 
-                     {
 
-                         MessageWindow.ShowMessage("[Pressing] Template does not exist!", "No template");
 
-                         return;
 
-                     }
 
-                     string? setoutNumber = null;
 
-                     Kanban? kanban = null;
 
-                     ManufacturingTemplateStage[] tstages = Array.Empty<ManufacturingTemplateStage>();
 
-                     Progress.ShowModal("Creating Setout", (progress) =>
 
-                     {
 
-                         var kanbanFilter = new Filter<Kanban>(x => x.ID).IsEqualTo(task.ID);
 
-                         var tables = Client.QueryMultiple(new Dictionary<string, IQueryDef>
 
-                         {
 
-                             { "ManufacturingTemplateStage", new QueryDef<ManufacturingTemplateStage>(
 
-                                 new Filter<ManufacturingTemplateStage>(x => x.Template.ID).IsEqualTo(template.ID),
 
-                                 null,
 
-                                 new SortOrder<ManufacturingTemplateStage>(x => x.Sequence)) },
 
-                             { "Kanban", new QueryDef<Kanban>(
 
-                                 kanbanFilter,
 
-                                 null,
 
-                                 null) },
 
-                             { "Setout", new QueryDef<Setout>(
 
-                                 new Filter<Setout>(x => x.JobLink.ID)
 
-                                     .InQuery(new SubQuery<Kanban>(kanbanFilter, new Column<Kanban>(x => x.JobLink.ID))),
 
-                                 Columns.None<Setout>().Add(x => x.JobLink.JobNumber, x => x.Number),
 
-                                 null) }
 
-                         });
 
-                         tstages = tables["ManufacturingTemplateStage"].Rows
 
-                            .Select(x => x.ToObject<ManufacturingTemplateStage>()).ToArray();
 
-                         kanban = tables["Kanban"].Rows.FirstOrDefault()?.ToObject<Kanban>();
 
-                         if (kanban == null)
 
-                         {
 
-                             MessageWindow.ShowMessage("Task does not exist!", "No task");
 
-                             return;
 
-                         }
 
-                         progress.Report("Creating Setouts");
 
-                         CoreTable setouts = tables["Setout"];
 
-                         int ireq = 0;
 
-                         string sreq = "";
 
-                         while (true)
 
-                         {
 
-                             ireq++;
 
-                             sreq = string.Format("{0}-{1:yyMMdd}-{2}", kanban.JobLink.JobNumber, DateTime.Now, ireq);
 
-                             if (!setouts.Rows.Any(r => sreq.Equals(r.Get<Setout, String>(c => c.Number))))
 
-                                 break;
 
-                         }
 
-                         setoutNumber = sreq;
 
-                     });
 
-                     if (setoutNumber == null || kanban == null)
 
-                     {
 
-                         return;
 
-                     }
 
-                     var result = CreateSetout(
 
-                         task,
 
-                         s =>
 
-                         {
 
-                             s.Number = setoutNumber;
 
-                             s.JobLink.ID = task.JobID;
 
-                             var notes = kanban.Notes.ToList();
 
-                             var description = kanban.Summary;
 
-                             if (string.IsNullOrWhiteSpace(description))
 
-                             {
 
-                                 description = CoreUtils.StripHTML(kanban.Description);
 
-                             }
 
-                             if (!string.IsNullOrWhiteSpace(description))
 
-                             {
 
-                                 notes.Insert(0, description);
 
-                             }
 
-                             s.Description = string.Join("\n==========================================\n", notes);
 
-                         }
 
-                     );
 
-                     if (result != null)
 
-                     {
 
-                         Progress.ShowModal("Creating Manufacturing Packet", progress =>
 
-                         {
 
-                             ManufacturingPacket packet = new ManufacturingPacket()
 
-                             {
 
-                                 Serial = template.Code,
 
-                                 Title = kanban.Title,
 
-                                 Quantity = 1,
 
-                                 BarcodeQty = 1,
 
-                                 DueDate = kanban.DueDate
 
-                             };
 
-                             packet.ManufacturingTemplateLink.ID = template.ID;
 
-                             packet.ManufacturingTemplateLink.Code = template.Code;
 
-                             packet.ManufacturingTemplateLink.Factory.ID = template.Factory.ID;
 
-                             packet.SetoutLink.ID = result.ID;
 
-                             new Client<ManufacturingPacket>().Save(packet, "Created from Task");
 
-                             DoLink<ManufacturingPacketKanban, ManufacturingPacket, ManufacturingPacketLink>(task, packet.ID);
 
-                             List<ManufacturingPacketStage> pstages = new List<ManufacturingPacketStage>();
 
-                             foreach (var tstage in tstages)
 
-                             {
 
-                                 var pstage = new ManufacturingPacketStage()
 
-                                 {
 
-                                     Time = tstage.Time,
 
-                                     Sequence = tstage.Sequence,
 
-                                     SequenceType = tstage.SequenceType,
 
-                                     Started = DateTime.MinValue,
 
-                                     PercentageComplete = 0.0F,
 
-                                     Completed = DateTime.MinValue,
 
-                                     QualityChecks = tstage.QualityChecks,
 
-                                     QualityStatus = QualityStatus.NotChecked,
 
-                                     QualityNotes = "",
 
-                                 };
 
-                                 pstage.Parent.ID = packet.ID;
 
-                                 pstage.ManufacturingSectionLink.ID = tstage.Section.ID;
 
-                                 pstage.ManufacturingSectionLink.Name = tstage.Section.Name;
 
-                                 pstages.Add(pstage);
 
-                             }
 
-                             new Client<ManufacturingPacketStage>().Save(pstages, "Created from Task", (_, __) => { });
 
-                             progress.Report("Processing Documents");
 
-                             List<SetoutDocument> _setoutdocuments = new List<SetoutDocument>();
 
-                             List<KanbanDocument> _kanbandocuments = new List<KanbanDocument>();
 
-                             KanbanDocument[] docrefs = new Client<KanbanDocument>()
 
-                                 .Load(new Filter<KanbanDocument>(x => x.EntityLink.ID).IsEqualTo(kanban.ID));
 
-                             foreach (var docref in docrefs)
 
-                             {
 
-                                 // Convert the document to a PDF
 
-                                 var docid = ProcessKanbanDocument(docref);
 
-                                 var newdoc = new SetoutDocument();
 
-                                 newdoc.EntityLink.ID = result.ID;
 
-                                 newdoc.DocumentLink.ID = docid;
 
-                                 _setoutdocuments.Add(newdoc);
 
-                                 if (docid != docref.DocumentLink.ID)
 
-                                 {
 
-                                     docref.DocumentLink.ID = docid;
 
-                                     _kanbandocuments.Add(docref);
 
-                                 }
 
-                             }
 
-                             new Client<SetoutDocument>().Save(_setoutdocuments, "Converted from Task", (_, __) => { });
 
-                             new Client<KanbanDocument>().Save(_kanbandocuments, "Converted to PDF", (_, __) => { });
 
-                             progress.Report("Updating Task");
 
-                             kanban.Title = kanban.Title + " (" + result.Number + ")";
 
-                             new Client<Kanban>().Save(kanban, "Converting Kanban to Setout");
 
-                         });
 
-                         control.Refresh();
 
-                     }
 
-                 });
 
-                 menu.AddItem("Create Requisition from Task", null, models, tasks =>
 
-                 {
 
-                     var taskModel = tasks.First();
 
-                     
 
-                     var kanbanTable = new Client<Kanban>().Query(new Filter<Kanban>(x => x.ID).IsEqualTo(taskModel.ID));
 
-                     var kanban = kanbanTable.Rows.First().ToObject<Kanban>();
 
-                     var result = CreateRequisition(
 
-                         taskModel,
 
-                         r =>
 
-                         {
 
-                             r.RequestedBy.ID = kanban.ManagerLink.ID;
 
-                             r.Employee.ID = Guid.Empty;
 
-                             r.Title = kanban.Title;
 
-                             r.Request = string.IsNullOrWhiteSpace(kanban.Summary)
 
-                                 ? String.IsNullOrWhiteSpace(kanban.Description)
 
-                                     ? String.Join("\n", kanban.Notes)
 
-                                     : CoreUtils.StripHTML(kanban.Description)
 
-                                 : kanban.Summary;
 
-                             r.Notes = kanban.Notes;
 
-                             r.Due = kanban.DueDate;
 
-                             r.JobLink.ID = taskModel.JobID;
 
-                         }
 
-                     );
 
-                     if (result != null)
 
-                     {
 
-                         Progress.ShowModal("Updating Documents", progress =>
 
-                         {
 
-                             progress.Report("Updating Documents");
 
-                             List<RequisitionDocument> requiDocuments = new();
 
-                             KanbanDocument[] kanbanDocuments = new Client<KanbanDocument>()
 
-                                 .Load(new Filter<KanbanDocument>(x => x.EntityLink.ID).IsEqualTo(kanban.ID));
 
-                             foreach (var document in kanbanDocuments)
 
-                             {
 
-                                 var newdoc = new RequisitionDocument();
 
-                                 newdoc.EntityLink.ID = result.ID;
 
-                                 newdoc.DocumentLink.ID = document.DocumentLink.ID;
 
-                                 requiDocuments.Add(newdoc);
 
-                             }
 
-                             new Client<RequisitionDocument>().Save(requiDocuments, "Converted from Task", (_, __) => { });
 
-                             /*RequisitionKanban link = new();
 
-                             link.Entity.ID = result.ID;
 
-                             link.Kanban.ID = kanban.ID;
 
-                             new Client<RequisitionKanban>().Save(link, "Converting Task -> Requisition", (_, __) => { });*/
 
-                             progress.Report("Updating Task");
 
-                             kanban.Status = KanbanStatus.Open;
 
-                             kanban.Completed = DateTime.MinValue;
 
-                             kanban.Title += $" (Requi #{result.Number})";
 
-                             new Client<Kanban>().Save(kanban, "Converted to Requisition", (_, __) => { });
 
-                         });
 
-                         MessageWindow.ShowMessage($"Created Requisition {result.Number}", "Success");
 
-                         control.Refresh();
 
-                     }
 
-                 });
 
-                 menu.AddItem("Create Delivery from Task", null, models, tasks =>
 
-                 {
 
-                     var result = CreateDelivery(
 
-                         tasks.First(),
 
-                         d =>
 
-                         {
 
-                             // Post-Process Requi Here
 
-                         }
 
-                     );
 
-                     if (result != null)
 
-                         control.Refresh();
 
-                 });
 
-                 menu.AddItem("Create Purchase Order from Task", null, models, tasks =>
 
-                 {
 
-                     var result = CreateOrder(
 
-                         tasks.First(),
 
-                         p =>
 
-                         {
 
-                             // Post-Process Requi Here
 
-                         }
 
-                     );
 
-                     if (result != null)
 
-                         control.Refresh();
 
-                 });
 
-             }
 
-         }
 
-         if (!bLinks && canChange)
 
-         {
 
-             menu.AddSeparatorIfNeeded();
 
-             #region Status
 
-             var changeStatus = new MenuItem { Header = "Change Status" };
 
-             AddChangeStatusButton(control, models, changeStatus, "Open", KanbanStatus.Open);
 
-             AddChangeStatusButton(control, models, changeStatus, "In Progress", KanbanStatus.InProgress);
 
-             AddChangeStatusButton(control, models, changeStatus, "Waiting", KanbanStatus.Waiting);
 
-             if (models.Any(x => x.CompletedDate.IsEmpty()))
 
-             {
 
-                 var complete = menu.AddItem(models.Length > 1 ? "Complete Tasks" : "Complete Task", null, () =>
 
-                 {
 
-                     CompleteTask(control, models, DateTime.Now);
 
-                 });
 
-                 if (Security.IsAllowed<CanSetKanbanCompletedDate>())
 
-                 {
 
-                     var completeDate = new MenuItem
 
-                     {
 
-                         Tag = models,
 
-                         Header = "Set Completed Date"
 
-                     };
 
-                     var dateItem = new MenuItem();
 
-                     var dateCalendar = new System.Windows.Controls.Calendar { SelectedDate = DateTime.MinValue };
 
-                     dateCalendar.Tag = models;
 
-                     dateCalendar.SelectedDatesChanged += (o, e) =>
 
-                     {
 
-                         if (e.Source is not System.Windows.Controls.Calendar calendar) return;
 
-                         menu.IsOpen = false;
 
-                         var selectedDate = calendar.SelectedDate ?? DateTime.Now;
 
-                         CompleteTask(control, models, selectedDate);
 
-                     };
 
-                     dateItem.Header = dateCalendar;
 
-                     dateItem.Style = Resources["calendarItem"] as Style;
 
-                     completeDate.Items.Add(dateItem);
 
-                     menu.Items.Add(completeDate);
 
-                 }
 
-             }
 
-             else
 
-             {
 
-                 menu.AddItem(models.Length > 1 ? "Archive Tasks" : "Archive Task", null, models, tasks =>
 
-                 {
 
-                     if (!MessageWindow.ShowYesNo("Are you sure you want to remove the selected tasks from the list?", "Confirm removal"))
 
-                         return;
 
-                     Progress.ShowModal("Closing Kanbans", progress =>
 
-                     {
 
-                         var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.Closed));
 
-                         foreach (var kanban in kanbans)
 
-                             kanban.Closed = DateTime.Now;
 
-                         new Client<Kanban>().Save(kanbans, "Kanban Marked as Closed");
 
-                     });
 
-                     control.Refresh();
 
-                 });
 
-             }
 
-             menu.Items.Add(changeStatus);
 
-             #endregion
 
-             #region Task Type
 
-             var changeType = menu.AddItem("Change Task Type", null, null);
 
-             foreach(var type in KanbanTypes)
 
-             {
 
-                 changeType.AddItem($"{type.Code}: {type.Description}", null, type, type =>
 
-                 {
 
-                     Progress.ShowModal("Changing Task Type", progress =>
 
-                     {
 
-                         var kanbans = LoadKanbans(models, Columns.Required<Kanban>().Add(x => x.ID, x => x.Type.ID));
 
-                         foreach (var kanban in kanbans)
 
-                         {
 
-                             kanban.Type.ID = type.ID;
 
-                         }
 
-                         new Client<Kanban>().Save(kanbans, $"Kanban Task Type changed to {type}");
 
-                     });
 
-                     control.Refresh();
 
-                 });
 
-             }
 
-             #endregion
 
-             #region Due Date
 
-             var changeDueDate = menu.AddItem("Change Due Date", null, null);
 
-             var calendarItem = new MenuItem();
 
-             var calendar = new System.Windows.Controls.Calendar { SelectedDate = models.Length == 1 ? models[0].DueDate : DateTime.Today };
 
-             calendar.Tag = models;
 
-             calendar.SelectedDatesChanged += (o, e) =>
 
-             {
 
-                 if (e.Source is not System.Windows.Controls.Calendar calendar) return;
 
-                 var selectedDate = calendar.SelectedDate ?? DateTime.Now;
 
-                 var models = (calendar.Tag as IList<TaskModel>)!;
 
-                 Progress.ShowModal("Changing Due Date", progress =>
 
-                 {
 
-                     var kanbans = LoadKanbans(models, Columns.Required<Kanban>().Add(x => x.ID, x => x.DueDate));
 
-                     foreach (var kanban in kanbans)
 
-                     {
 
-                         kanban.DueDate = selectedDate;
 
-                     }
 
-                     new Client<Kanban>().Save(kanbans, $"Kanban Due Date changed to {selectedDate:dd MMM yyyy}");
 
-                 });
 
-                 control.Refresh();
 
-                 menu.IsOpen = false;
 
-             };
 
-             calendarItem.Header = calendar;
 
-             calendarItem.Style = Resources["calendarItem"] as Style;
 
-             changeDueDate.Items.Add(calendarItem);
 
-             #endregion
 
-             #region Employees
 
-             menu.AddItem("Assign To...", null, (control, models), SetAssignee_Click);
 
-             menu.AddItem("Set Manager...", null, (control, models), SetManager_Click);
 
-             #endregion
 
-         }
 
-     }
 
-     private void SetAssignee_Click((ITaskControl control, TaskModel[] models) tuple)
 
-     {
 
-         var tasks = LoadKanbans(tuple.models, Columns.Required<Kanban>().Add(x => x.ID).Add(x => x.EmployeeLink.ID))
 
-             .ToArray();
 
-         if (MultiSelectDialog.SelectItem<Employee>(out var employee,
 
-             filter: LookupFactory.DefineLookupFilter<Kanban, Employee, EmployeeLink>(x => x.EmployeeLink, tasks),
 
-             columns: LookupFactory.DefineLookupColumns<Kanban, Employee, EmployeeLink>(x => x.EmployeeLink),
 
-             title: "Select Assignee for Task"))
 
-         {
 
-             foreach (var task in tasks)
 
-             {
 
-                 task.EmployeeLink.CopyFrom(employee);
 
-             }
 
-             Client.Save(tasks, "Set Assignee");
 
-             tuple.control.Refresh();
 
-         }
 
-     }
 
-     private void SetManager_Click((ITaskControl control, TaskModel[] models) tuple)
 
-     {
 
-         var tasks = LoadKanbans(tuple.models, Columns.Required<Kanban>().Add(x => x.ID).Add(x => x.ManagerLink.ID))
 
-             .ToArray();
 
-         if (MultiSelectDialog.SelectItem<Employee>(out var employee,
 
-             filter: LookupFactory.DefineLookupFilter<Kanban, Employee, EmployeeLink>(x => x.ManagerLink, tasks),
 
-             columns: LookupFactory.DefineLookupColumns<Kanban, Employee, EmployeeLink>(x => x.ManagerLink),
 
-             title: "Select Manager for Task"))
 
-         {
 
-             foreach (var task in tasks)
 
-             {
 
-                 task.ManagerLink.CopyFrom(employee);
 
-             }
 
-             Client.Save(tasks, "Set Manager");
 
-             tuple.control.Refresh();
 
-         }
 
-     }
 
-     private void Subscribers_Click(TaskModel model)
 
-     {
 
-         var kanban = LoadKanbans([model], Columns.Required<Kanban>().Add(x => x.ID).Add(x => x.Number)).First();
 
-         ManageSubscribers(kanban);
 
-     }
 
-     public static void ManageSubscribers(Kanban kanban)
 
-     {
 
-         var grid = new KanbanSubscriberGrid(kanban);
 
-         var window = DynamicGridUtils.CreateGridWindow($"Manage subscribers for Task #{kanban.Number}", grid);
 
-         window.Width = 400;
 
-         window.Height = 400;
 
-         window.ShowDialog();
 
-     }
 
-     /// <summary>
 
-     /// Takes a <see cref="KanbanDocument"/>, and if it is a .txt or an image (".png", ".jpg", ".jpeg" or ".bmp"), converts to a PDF
 
-     /// with the content of the document, saving a new document with extension changed to ".pdf".
 
-     /// </summary>
 
-     /// <param name="docref">The original document.</param>
 
-     /// <returns>
 
-     /// The ID of the new <see cref="Document"/> or,
 
-     /// if not one of the given types, the original document ID.
 
-     /// </returns>
 
-     private static Guid ProcessKanbanDocument(KanbanDocument docref)
 
-     {
 
-         var result = docref.DocumentLink.ID;
 
-         var ext = System.IO.Path.GetExtension(docref.DocumentLink.FileName).ToLower();
 
-         if (ext.EndsWith("txt"))
 
-         {
 
-             var doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(docref.DocumentLink.ID)).FirstOrDefault();
 
-             if (doc is null)
 
-             {
 
-                 Logger.Send(LogType.Error, "", $"Document {docref.DocumentLink.ID} does not exist!");
 
-                 return docref.DocumentLink.ID;
 
-             }
 
-             PdfDocument pdf = new PdfDocument();
 
-             PdfPage page = pdf.Pages.Add();
 
-             PdfGraphics graphics = page.Graphics;
 
-             PdfFont font = new PdfStandardFont(PdfFontFamily.Courier, 12);
 
-             String text = System.Text.Encoding.UTF8.GetString(doc.Data);
 
-             graphics.DrawString(text, font, PdfBrushes.Black, new PointF(0, 0));
 
-             MemoryStream ms = new MemoryStream();
 
-             pdf.Save(ms);
 
-             pdf.Close(true);
 
-             byte[] data = ms.ToArray();
 
-             var newdoc = new Document()
 
-             {
 
-                 Data = data,
 
-                 FileName = System.IO.Path.ChangeExtension(docref.DocumentLink.FileName, "pdf"),
 
-                 CRC = CoreUtils.CalculateCRC(data),
 
-                 TimeStamp = DateTime.Now,
 
-             };
 
-             new Client<Document>().Save(newdoc, "Converted from Text");
 
-             return newdoc.ID;
 
-         }
 
-         else if (ext.EndsWith("png") || ext.EndsWith("bmp") || ext.EndsWith("jpg") || ext.EndsWith("jpeg"))
 
-         {
 
-             var doc = new Client<Document>().Load(new Filter<Document>(x => x.ID).IsEqualTo(docref.DocumentLink.ID)).FirstOrDefault();
 
-             if (doc is null)
 
-             {
 
-                 Logger.Send(LogType.Error, "", $"Document {docref.DocumentLink.ID} does not exist!");
 
-                 return docref.DocumentLink.ID;
 
-             }
 
-             PdfBitmap image = new PdfBitmap(new MemoryStream(doc.Data));
 
-             PdfDocument pdf = new PdfDocument();
 
-             pdf.PageSettings.Orientation = image.Height > image.Width ? PdfPageOrientation.Portrait : PdfPageOrientation.Landscape;
 
-             pdf.PageSettings.Size = new SizeF(image.Width, image.Height);
 
-             PdfPage page = pdf.Pages.Add();
 
-             PdfGraphics graphics = page.Graphics;
 
-             graphics.DrawImage(image, 0.0F, 0.0F);
 
-             MemoryStream ms = new MemoryStream();
 
-             pdf.Save(ms);
 
-             pdf.Close(true);
 
-             byte[] data = ms.ToArray();
 
-             var newdoc = new Document()
 
-             {
 
-                 Data = data,
 
-                 FileName = System.IO.Path.ChangeExtension(docref.DocumentLink.FileName, "pdf"),
 
-                 CRC = CoreUtils.CalculateCRC(data),
 
-                 TimeStamp = DateTime.Now,
 
-             };
 
-             new Client<Document>().Save(newdoc, "Converted from Image");
 
-             return newdoc.ID;
 
-         }
 
-         return result;
 
-     }
 
-     private void CreateJobSubMenu(ITaskControl control, MenuItem job, IEnumerable<TaskModel> tasks)
 
-     {
 
-         job.Items.Clear();
 
-         job.Items.Add(new MenuItem { Header = "Loading...", IsEnabled = false });
 
-         using (new WaitCursor())
 
-         {
 
-             job.Items.Clear();
 
-             var jobs = new Client<Job>().Query(
 
-                 LookupFactory.DefineFilter<Job>(),
 
-                 LookupFactory.DefineColumns<Job>(),
 
-                 LookupFactory.DefineSort<Job>()
 
-             );
 
-             foreach (var row in jobs.Rows)
 
-             {
 
-                 var jobNumber = row.Get<Job, string>(x => x.JobNumber);
 
-                 var jobName = row.Get<Job, string>(x => x.Name);
 
-                 job.AddItem($"{jobNumber}: {jobName}", null, tasks, tasks =>
 
-                 {
 
-                     using (new WaitCursor())
 
-                     {
 
-                         var kanbans = LoadKanbans(tasks, Columns.Required<Kanban>().Add(x => x.ID, x => x.JobLink.ID));
 
-                         foreach (var kanban in kanbans)
 
-                             kanban.JobLink.ID = row.Get<Job, Guid>(x => x.ID);
 
-                         new Client<Kanban>().Save(kanbans, "Updated Job Number");
 
-                         control.Refresh();
 
-                     }
 
-                 });
 
-             }
 
-         }
 
-     }
 
-     #endregion
 
-     private void TaskPanels_SelectionChanged(object sender, SelectionChangedEventArgs e)
 
-     {
 
-         if (!IsReady)
 
-             return;
 
-         if (e.Source is not TabControl)
 
-             return;
 
-         if (_bTabChanging)
 
-             return;
 
-         try
 
-         {
 
-             _bTabChanging = true;
 
-             var panel = GetCurrentPanel();
 
-             if(panel is not null)
 
-             {
 
-                 KanbanSettings.ViewType = panel.KanbanViewType;
 
-                 new UserConfiguration<KanbanSettings>().Save(KanbanSettings);
 
-                 panel.Refresh();
 
-                 OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
 
-             }
 
-         }
 
-         finally
 
-         {
 
-             _bTabChanging = false;
 
-         }
 
-     }
 
-     #region Get/Save Settings
 
-     private KanbanSettings? _settings;
 
-     public KanbanSettings KanbanSettings
 
-     {
 
-         get
 
-         {
 
-             _settings ??= new UserConfiguration<KanbanSettings>().Load();
 
-             return _settings;
 
-         }
 
-     }
 
-     public void SaveSettings()
 
-     {
 
-         if(_settings != null)
 
-             new UserConfiguration<KanbanSettings>().Save(_settings);
 
-     }
 
-     #endregion
 
-     #region IPanel Stuff
 
-     public event DataModelUpdateEvent? OnUpdateDataModel;
 
-     public bool IsReady { get; set; }
 
-     public void CreateToolbarButtons(IPanelHost host)
 
-     {
 
-         host.CreatePanelAction(
 
-             new PanelAction
 
-             {
 
-                 Caption = "New Task",
 
-                 OnExecute = a => {
 
-                     if(CreateKanban(k => { }) != null)
 
-                     {
 
-                         Refresh();
 
-                     }
 
-                 },
 
-                 Image = InABox.Wpf.Resources.add
 
-             }
 
-         );
 
-         if (Security.CanView<KanbanType>())
 
-         {
 
-             host.CreateSetupAction(
 
-                 new PanelAction
 
-                 {
 
-                     Caption = "Task Types",
 
-                     Image = PRSDesktop.Resources.kanbantype,
 
-                     OnExecute = a =>
 
-                     {
 
-                         var list = new MasterList(typeof(KanbanType));
 
-                         list.ShowDialog();
 
-                     }
 
-                 });
 
-         }
 
-     }
 
-     public Dictionary<string, object[]> Selected()
 
-     {
 
-         return new Dictionary<string, object[]>();
 
-     }
 
-     public void Heartbeat(TimeSpan time)
 
-     {
 
-     }
 
-     private readonly Dictionary<KanbanViewType, TabItem> _viewmap = new();
 
-     private readonly List<ITaskControl> _initialized = new();
 
-     private ITaskControl GetCurrentPanel()
 
-     {
 
-         var result = (TaskPanels.SelectedContent as ITaskControl)!;
 
-         if (result == null)
 
-             result = (TaskPanels.Items[0] as DynamicTabItem)?.Content as ITaskControl;
 
-         try
 
-         {
 
-             //if (result != null)
 
-             if (!_initialized.Contains(result))
 
-             {
 
-                 result.Setup();
 
-                 result.IsReady = true;
 
-                 _initialized.Add(result);
 
-             }
 
-         }
 
-         catch (Exception e)
 
-         {
 
-             Logger.Send(LogType.Error, "", $"Error in TaskPanel.GetCurrentPanel: {CoreUtils.FormatException(e)}");
 
-         }
 
-         return result;
 
-     }
 
-     public void Setup()
 
-     {
 
-         _settings = new UserConfiguration<KanbanSettings>().Load();
 
-         TaskPanels.SelectedItem = _viewmap[_settings.ViewType];
 
-         kanbanTypes = new Client<KanbanType>()
 
-             .Query(
 
-                 new Filter<KanbanType>(x => x.Hidden).IsEqualTo(false),
 
-                 Columns.None<KanbanType>().Add(x => x.ID, x => x.Code, x => x.Description))
 
-             .Rows.Select(x => x.ToObject<KanbanType>()).ToArray();
 
-     }
 
-     public void Shutdown(CancelEventArgs? cancel)
 
-     {
 
-     }
 
-     public void Refresh()
 
-     {
 
-         if (Master == null)
 
-         {
 
-             if (Equals(TaskPanels.SelectedItem, TasksPlannerTabItem))
 
-                 TaskPanels.SelectedItem = _viewmap[KanbanViewType.Status];
 
-             TasksPlannerTabItem.Visibility = Visibility.Collapsed;
 
-         }
 
-         else
 
-             TasksPlannerTabItem.Visibility = Visibility.Visible;
 
-         
 
-         GetCurrentPanel()?.Refresh();
 
-     }
 
-     public string SectionName => GetCurrentPanel().SectionName;
 
-     public TaskPanelProperties Properties { get; set; }
 
-     public DataModel DataModel(Selection selection)
 
-     {
 
-         return GetCurrentPanel().DataModel(selection);
 
-         //return new AutoDataModel<Kanban>(new Filter<Kanban>(x => x.ID).IsEqualTo(Guid.Empty));
 
-     }
 
-     #endregion
 
-     #region CRUD Functionality
 
-     private TEntity? DoCreate<TEntity>(Action<TEntity> customise)
 
-         where TEntity : Entity, IRemotable, IPersistent, new()
 
-     {
 
-         var result = new TEntity();
 
-         customise?.Invoke(result);
 
-         if (DoEdit(new[] { result }, null))
 
-             return result;
 
-         return null;
 
-     }
 
-     private readonly Dictionary<Type, IDynamicGrid> _grids = new();
 
-     private readonly List<Tuple<Guid, Entity>> _entitycache = new();
 
-     private DynamicDataGrid<TEntity> GetGrid<TEntity>() where TEntity : Entity, IRemotable, IPersistent, new()
 
-     {
 
-         if(!_grids.TryGetValue(typeof(TEntity), out var grid))
 
-         {
 
-             grid = (DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(TEntity)) as DynamicDataGrid<TEntity>)!;
 
-             _grids[typeof(TEntity)] = grid;
 
-             if(grid is ITaskControl ctl)
 
-             {
 
-                 ctl.Host = this;
 
-             }
 
-         }
 
-         return (grid as DynamicDataGrid<TEntity>)!;
 
-     }
 
-     private IEnumerable<TEntity> DoLoad<TEntity>(IEnumerable<TaskModel> models, Columns<TEntity> columns)
 
-         where TEntity : Entity, IRemotable, IPersistent, new()
 
-     {
 
-         var result = new List<TEntity>();
 
-         var load = new List<Guid>();
 
-         foreach (var model in models)
 
-         {
 
-             var entity = _entitycache.FirstOrDefault(x => Equals(x.Item1, model.ID) && x.Item2 is TEntity) as TEntity;
 
-             if (entity is not null)
 
-                 result.Add(entity);
 
-             else
 
-                 load.Add(model.ID);
 
-         }
 
-         if (load.Any())
 
-         {
 
-             var entities = new Client<TEntity>()
 
-                 .Query(new Filter<TEntity>(x => x.ID).InList(load.ToArray()), columns)
 
-                 .Rows.Select(x => x.ToObject<TEntity>()).ToList();
 
-             foreach (var entity in entities)
 
-                 _entitycache.Add(new Tuple<Guid, Entity>(entity.ID, entity));
 
-             result.AddRange(entities);
 
-         }
 
-         return result;
 
-     }
 
-     private IEnumerable<TEntity> DoLoad<TEntityKanban, TEntity, TLink>(IEnumerable<TaskModel> models, Columns<TEntity> columns)
 
-         where TEntityKanban : EntityKanban<TEntity, TLink>, new()
 
-         where TEntity : Entity, IRemotable, IPersistent, new()
 
-         where TLink : IEntityLink<TEntity>, new()
 
-     {
 
-         var result = DoLoad(models, columns);
 
-         if (!result.Any())
 
-             foreach (var model in models)
 
-             {
 
-                 result = new Client<TEntity>().Load(
 
-                     new Filter<TEntity>(x => x.ID).InQuery(new Filter<TEntityKanban>(x => x.Kanban.ID).IsEqualTo(model.ID),
 
-                         x => x.Entity.ID));
 
-                 foreach (var r in result)
 
-                     _entitycache.Add(new Tuple<Guid, Entity>(model.ID, r));
 
-             }
 
-         return result;
 
-     }
 
-     private void DoCache<TEntity>(Guid kanbanid, TEntity entity) where TEntity : Entity
 
-     {
 
-         if (!_entitycache.Any(x => Equals(x.Item1, kanbanid) && x.Item2 is TEntity && Equals(x.Item2.ID, entity.ID)))
 
-             _entitycache.Add(new Tuple<Guid, Entity>(kanbanid, entity));
 
-     }
 
-     private bool DoEdit<TEntity>(IEnumerable<TEntity> entities, Action<TEntity>? action = null)
 
-         where TEntity : Entity, IRemotable, IPersistent, new()
 
-     {
 
-         if (entities == null || !entities.Any())
 
-             return false;
 
-         foreach (var entity in entities)
 
-             action?.Invoke(entity);
 
-         return GetGrid<TEntity>().EditItems(entities.ToArray());
 
-     }
 
-     private void DoLink<TEntityKanban, TEntity, TLink>(TaskModel model, Guid entityid)
 
-         where TEntityKanban : EntityKanban<TEntity, TLink>, new()
 
-         where TEntity : Entity, IRemotable, IPersistent, new()
 
-         where TLink : IEntityLink<TEntity>, new()
 
-     {
 
-         var linktask = Task.Run(() =>
 
-         {
 
-             var link = new TEntityKanban();
 
-             link.Kanban.ID = model.ID;
 
-             link.Entity.ID = entityid;
 
-             new Client<TEntityKanban>().Save(link, "");
 
-         });
 
-         var kanbantask = Task.Run(() =>
 
-         {
 
-             var kanban = LoadKanbans(
 
-                 new[] { model },
 
-                 Columns.Required<Kanban>().Add(x => x.ID, x => x.Locked)).FirstOrDefault();
 
-             if (kanban is not null)
 
-             {
 
-                 kanban.Locked = true;
 
-                 new Client<Kanban>().Save(kanban, "Locked because of linked " + typeof(TEntity).EntityName().Split('.').Last());
 
-             }
 
-         });
 
-         Task.WaitAll(linktask, kanbantask);
 
-     }
 
-     private static void DoDelete<TEntity>(IList<TEntity> entities, string auditnote)
 
-         where TEntity : Entity, IRemotable, IPersistent, new()
 
-     {
 
-         new Client<TEntity>().Delete(entities, auditnote);
 
-     }
 
-     public Kanban? CreateKanban(Action<Kanban> customise)
 
-     {
 
-         var result = DoCreate<Kanban>(
 
-             kanban =>
 
-             {
 
-                 kanban.Title = "New Task";
 
-                 kanban.Description = "";
 
-                 kanban.Status = KanbanStatus.Open;
 
-                 kanban.DueDate = DateTime.Today;
 
-                 kanban.Private = false;
 
-                 kanban.JobLink.ID = Master?.ID ?? Guid.Empty;
 
-                 kanban.JobLink.Synchronise(Master ?? new Job());
 
-                 kanban.EmployeeLink.ID = App.EmployeeID;
 
-                 kanban.ManagerLink.ID = App.EmployeeID;
 
-                 customise?.Invoke(kanban);
 
-             });
 
-         if (result != null)
 
-             DoCache(result.ID, result);
 
-         return result;
 
-     }
 
-     public IEnumerable<Kanban> LoadKanbans(IEnumerable<TaskModel> models, Columns<Kanban> columns)
 
-     {
 
-         columns.Add(x => x.ID);
 
-         columns.Add(x => x.Number);
 
-         columns.Add(x => x.Title);
 
-         columns.Add(x => x.Notes);
 
-         columns.Add(x => x.Summary);
 
-         columns.Add(x => x.Completed);
 
-         columns.Add(x => x.DueDate);
 
-         columns.Add(x => x.ManagerLink.ID);
 
-         columns.Add(x => x.EmployeeLink.ID);
 
-         return DoLoad(models, columns);
 
-     }
 
-     public bool EditKanbans(IEnumerable<TaskModel> models, Action<Kanban>? customise = null)
 
-     {
 
-         var entities = LoadKanbans(models, GetGrid<Kanban>().LoadEditorColumns());
 
-         return DoEdit(entities, customise);
 
-     }
 
-     public void DeleteKanbans(IEnumerable<TaskModel> models, string auditnote)
 
-     {
 
-         var kanbans = models.Select(x => new Kanban { ID = x.ID }).ToList();
 
-         DoDelete(kanbans, auditnote);
 
-     }
 
-     public Requisition? CreateRequisition(TaskModel model, Action<Requisition>? customise)
 
-     {
 
-         var result = DoCreate<Requisition>(
 
-             requi =>
 
-             {
 
-                 requi.JobLink.ID = Master?.ID ?? Guid.Empty;
 
-                 requi.JobLink.Synchronise(Master ?? new Job());
 
-                 customise?.Invoke(requi);
 
-             });
 
-         if (result != null)
 
-         {
 
-             DoCache(model.ID, result);
 
-             DoLink<RequisitionKanban, Requisition, RequisitionLink>(model, result.ID);
 
-         }
 
-         return result;
 
-     }
 
-     public bool EditRequisitions(IEnumerable<TaskModel> models, Action<Requisition>? customise = null)
 
-     {
 
-         var requis = DoLoad<RequisitionKanban, Requisition, RequisitionLink>(models, GetGrid<Requisition>().LoadEditorColumns());
 
-         if (requis.Any())
 
-             return DoEdit(requis, customise);
 
-         return false;
 
-     }
 
-     public Setout? CreateSetout(TaskModel model, Action<Setout> customise)
 
-     {
 
-         var result = DoCreate<Setout>(
 
-             setout =>
 
-             {
 
-                 setout.JobLink.ID = Master?.ID ?? Guid.Empty;
 
-                 setout.JobLink.Synchronise(Master ?? new Job());
 
-                 customise?.Invoke(setout);
 
-             });
 
-         if (result != null)
 
-         {
 
-             DoCache(model.ID, result);
 
-             //DoLink<SetoutKanban, Setout, SetoutLink>(model, result.ID);
 
-         }
 
-         return result;
 
-     }
 
-     public bool EditSetouts(IEnumerable<TaskModel> models, Action<Setout>? customise = null)
 
-     {
 
-         var setouts = DoLoad<SetoutKanban, Setout, SetoutLink>(models, GetGrid<Setout>().LoadEditorColumns());
 
-         if (setouts.Any())
 
-             return DoEdit(setouts, customise);
 
-         return false;
 
-     }
 
-     public Delivery? CreateDelivery(TaskModel model, Action<Delivery> customise)
 
-     {
 
-         var result = DoCreate<Delivery>(
 
-             delivery =>
 
-             {
 
-                 delivery.Job.ID = Master?.ID ?? Guid.Empty;
 
-                 delivery.Job.Synchronise(Master ?? new Job());
 
-                 customise?.Invoke(delivery);
 
-             });
 
-         if (result != null)
 
-         {
 
-             DoCache(model.ID, result);
 
-             DoLink<DeliveryKanban, Delivery, DeliveryLink>(model, result.ID);
 
-         }
 
-         return result;
 
-     }
 
-     public bool EditDeliveries(IEnumerable<TaskModel> models, Action<Delivery>? customise = null)
 
-     {
 
-         var deliveries = DoLoad<DeliveryKanban, Delivery, DeliveryLink>(models, GetGrid<Delivery>().LoadEditorColumns());
 
-         if (deliveries.Any())
 
-             return DoEdit(deliveries, customise);
 
-         return false;
 
-     }
 
-     public PurchaseOrder? CreateOrder(TaskModel model, Action<PurchaseOrder> customise)
 
-     {
 
-         var result = DoCreate<PurchaseOrder>(
 
-             order => { customise?.Invoke(order); });
 
-         if (result != null)
 
-         {
 
-             DoCache(model.ID, result);
 
-             DoLink<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(model, result.ID);
 
-         }
 
-         return result;
 
-     }
 
-     public bool EditPurchaseOrders(IEnumerable<TaskModel> models, Action<PurchaseOrder>? customise = null)
 
-     {
 
-         var orders = DoLoad<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(models, GetGrid<PurchaseOrder>().LoadEditorColumns());
 
-         if (orders.Any())
 
-             return DoEdit(orders, customise);
 
-         return false;
 
-     }
 
-     #endregion
 
-     #region EntityReferences
 
-     private static void AddQuery<TEntityKanban, TEntity, TLink>(MultiQuery query, Guid[] taskids)
 
-         where TEntityKanban : EntityKanban<TEntity, TLink>, new()
 
-         where TEntity : Entity
 
-         where TLink : IEntityLink<TEntity>, new()
 
-     {
 
-         query.Add(
 
-             new Filter<TEntityKanban>(x => x.Kanban.ID).InList(taskids),
 
-             Columns.None<TEntityKanban>().Add(x => x.Entity.ID).Add(x => x.Kanban.ID)
 
-         );
 
-     }
 
-     private static Guid[] ExtractIDs<TEntityKanban, TEntity, TLink>(MultiQuery query)
 
-         where TEntityKanban : EntityKanban<TEntity, TLink>, new()
 
-         where TEntity : Entity
 
-         where TLink : IEntityLink<TEntity>, new()
 
-     {
 
-         var lookup = query.Get<TEntityKanban>().ToLookup<TEntityKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
 
-         return query.Get<TEntityKanban>().ExtractValues<TEntityKanban, Guid>(x => x.Entity.ID).ToArray();
 
-     }
 
-     public KanbanReferences[] GetReferences(IEnumerable<TaskModel> models)
 
-     {
 
-         var result = new List<KanbanReferences>();
 
-         var ids = models.Select(x => x.ID).ToArray();
 
-         var query = new MultiQuery();
 
-         AddQuery<RequisitionKanban, Requisition, RequisitionLink>(query, ids);
 
-         AddQuery<SetoutKanban, Setout, SetoutLink>(query, ids);
 
-         AddQuery<DeliveryKanban, Delivery, DeliveryLink>(query, ids);
 
-         AddQuery<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(query, ids);
 
-         query.Query();
 
-         var requis = query.Get<RequisitionKanban>().ToLookup<RequisitionKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
 
-         var setouts = query.Get<SetoutKanban>().ToLookup<SetoutKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
 
-         var deliveries = query.Get<DeliveryKanban>().ToLookup<DeliveryKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
 
-         var orders = query.Get<PurchaseOrderKanban>().ToLookup<PurchaseOrderKanban, Guid, Guid>(x => x.Kanban.ID, x => x.Entity.ID);
 
-         foreach (var id in ids)
 
-         {
 
-             var references = new KanbanReferences
 
-             {
 
-                 Kanban = id,
 
-                 Requisitions = requis.Contains(id) ? requis[id].ToArray() : Array.Empty<Guid>(),
 
-                 Setouts = setouts.Contains(id) ? setouts[id].ToArray() : Array.Empty<Guid>(),
 
-                 Deliveries = deliveries.Contains(id) ? deliveries[id].ToArray() : Array.Empty<Guid>(),
 
-                 Orders = orders.Contains(id) ? orders[id].ToArray() : Array.Empty<Guid>()
 
-             };
 
-             result.Add(references);
 
-         }
 
-         return result.ToArray();
 
-     }
 
-     public bool EditReferences(IEnumerable<TaskModel> models)
 
-     {
 
-         var result = false;
 
-         var refs = GetReferences(models).First();
 
-         if (refs.ReferenceType() == typeof(Requisition))
 
-             result = EditRequisitions(
 
-                 models,
 
-                 requi =>
 
-                 {
 
-                     requi.Notes = Utility.ProcessNotes(requi.Notes, requi.Request);
 
-                     requi.Request = "";
 
-                 }
 
-             );
 
-         else if (refs.ReferenceType() == typeof(Setout))
 
-             result = EditSetouts(models);
 
-         else if (refs.ReferenceType() == typeof(Delivery))
 
-             result = EditDeliveries(models);
 
-         else if (refs.ReferenceType() == typeof(PurchaseOrder))
 
-             result = EditPurchaseOrders(models);
 
-         else
 
-             result = EditKanbans(models);
 
-         return result;
 
-     }
 
-     #endregion
 
- }
 
 
  |