123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299 |
- 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);
-
- }
- 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.AddSeparatorIfNeeded();
- menu.AddItem("Assign To...", null, (control, models), SetAssignee_Click);
- menu.AddItem("Set Manager...", null, (control, models), SetManager_Click);
-
- if (models.Length == 1)
- menu.AddItem("Manage Subscribers", null, models.First(), Subscribers_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
- }
|