123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.Scripting;
- using InABox.Wpf.Reports;
- using InABox.WPF;
- using PRSDesktop.Configuration;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- namespace PRSDesktop;
- public class DigitalFormDockGrid : DynamicGrid<DigitalFormDockModel>
- {
- private static readonly CoreFieldMap<IDigitalFormInstance, DigitalFormDockModel> _mappings =
- new CoreFieldMap<IDigitalFormInstance, DigitalFormDockModel>()
- .Add(x => x.ID, x => x.ID)
- .Add(x => x.Form.ID, x => x.FormID)
- .Add(x => x.Number, x => x.Number)
- .Add(x => x.Description, x => x.FormName)
- .Add(x => x.FormCompleted, x => x.Completed)
- .Add(x => x.FormCompletedBy.UserID, x => x.CompletedBy)
- .Add(x => x.FormProcessed, x => x.Processed)
- .Add(x => x.Parent.ID, x => x.ParentID);
- public static readonly Dictionary<Type, System.Drawing.Bitmap> Images = new()
- {
- { typeof(AssignmentForm), PRSDesktop.Resources.assignments },
- { typeof(KanbanForm), PRSDesktop.Resources.kanban },
- { typeof(JobForm), PRSDesktop.Resources.project },
- { typeof(JobITPForm), PRSDesktop.Resources.checklist },
- { typeof(EmployeeForm), PRSDesktop.Resources.employees },
- { typeof(LeaveRequestForm), PRSDesktop.Resources.leave },
- { typeof(ManufacturingPacketStage), PRSDesktop.Resources.factory },
- { typeof(TimeSheetForm), PRSDesktop.Resources.time },
- { typeof(PurchaseOrderItemForm), PRSDesktop.Resources.purchase },
- { typeof(DeliveryForm), PRSDesktop.Resources.truck },
- };
- public List<Type> ExcludedTypes { get; private set; }
- public DateTime StartDate { get; set; }
- public DigitalFormDockGrid()
- {
- StartDate = DateTime.Today;
- ExcludedTypes = new List<Type>();
- ActionColumns.Add(new DynamicImageColumn(TypeImage)
- {
- Position = DynamicActionColumnPosition.Start,
- GetFilter = () => new StaticColumnFilter<Type>(
- FormType,
- Images.Keys.Select(x => new Tuple<string, Type>(x.EntityName().Split('.').Last().SplitCamelCase(), x)).ToArray())
- });
- ActionColumns.Add(new DynamicMenuColumn(MenuBuild, MenuStatus) { Position = DynamicActionColumnPosition.End });
- }
- protected override void DoReconfigure(DynamicGridOptions options)
- {
- options.Clear();
- options.FilterRows = true;
- }
- protected override DynamicGridStyle GetRowStyle(CoreRow row, DynamicGridStyle style)
- {
- var result = base.GetRowStyle(row, style);
- if (!row.Get<DigitalFormDockModel, DateTime>(x => x.Processed).IsEmpty())
- result = new DynamicGridRowStyle(result)
- {
- Background = new SolidColorBrush(Colors.LightGray),
- };
- return result;
- }
- private Type FormType(CoreRow row)
- {
- return row.Get<DigitalFormDockModel, Type>(x => x.FormType);
- }
- private BitmapImage? TypeImage(CoreRow? arg)
- {
- if (arg is null)
- return null;
- var type = arg.Get<DigitalFormDockModel, Type>(x => x.FormType);
- return Images.GetValueOrDefault(type)?.AsBitmapImage();
- }
- private static readonly MethodInfo MenuBuildGenericMethod = typeof(DigitalFormDockGrid)
- .GetMethod(nameof(MenuBuildGeneric), BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)!;
- private void MenuBuildGeneric<TEntityForm, TEntity, TEntityLink>(ContextMenu menu, DigitalFormDockModel formModel)
- where TEntityForm : Entity, IDigitalFormInstance<TEntityLink>, IRemotable, IPersistent, new()
- where TEntity : Entity, IRemotable, IPersistent, new()
- where TEntityLink : IEntityLink<TEntity>, new()
- {
- var filter = new Filter<TEntityForm>(x => x.ID).IsEqualTo(formModel.ID);
- var model = new DigitalFormReportDataModel<TEntityForm>(filter, formModel.FormID);
- if (Security.CanView<TEntity>())
- {
- menu.AddItem($"View {typeof(TEntity).Name}", Images.GetValueOrDefault(typeof(TEntityForm)), formModel, ViewEntity_Click<TEntity>);
- }
- var moduleTask = Task.Run(() =>
- {
- return new Client<CustomModule>().Query(
- new Filter<CustomModule>(x => x.DataModel).IsEqualTo(model.Name)
- .And(x => x.Section).IsEqualTo(formModel.FormID.ToString())
- .And(x => x.Visible).IsEqualTo(true)
- ).ToObjects<CustomModule>();
- });
- var modulesSeparator = menu.AddSeparatorIfNeeded();
- var modulesItem = menu.AddItem("Loading...", null, null, enabled: false);
- moduleTask.ContinueWith((task) =>
- {
- try
- {
- var index = menu.Items.IndexOf(modulesItem);
- menu.Items.Remove(modulesItem);
- var any = false;
- foreach (var module in task.Result)
- {
- any = true;
- menu.AddItem(
- module.Name,
- PRSDesktop.Resources.edit,
- () =>
- {
- try
- {
- if (ScriptDocument.RunCustomModule(model, new Dictionary<string, object[]>(), module.Script))
- {
- Refresh(false, true);
- }
- }
- catch (CompileException c)
- {
- MessageBox.Show(c.Message);
- }
- catch (Exception e)
- {
- MessageBox.Show(CoreUtils.FormatException(e));
- }
- },
- enabled: formModel.Processed.IsEmpty(),
- index: index);
- ++index;
- }
- if (!any && modulesSeparator is not null)
- {
- menu.Items.Remove(modulesSeparator);
- }
- }
- catch (Exception ex)
- {
- Logger.Send(LogType.Error, ClientFactory.UserID, $"Error in digital form dock while loading custom modules: {CoreUtils.FormatException(ex)}");
- MessageBox.Show($"Error: {ex.Message}", "Error");
- }
- }, TaskScheduler.FromCurrentSynchronizationContext());
- menu.AddSeparator();
- if (formModel.Processed.IsEmpty())
- {
- menu.AddItem(
- "Mark as Processed",
- PRSDesktop.Resources.lock_sml,
- () =>
- {
- var form = new TEntityForm
- {
- FormProcessed = formModel.Processed
- }.SetID(formModel.ID);
- form.CommitChanges();
- form.FormProcessed = DateTime.Now;
- using (new WaitCursor())
- {
- Client.Save(form, "Marked As Processed");
- Refresh(false, true);
- }
- });
- }
- else
- {
- menu.AddItem(
- "Clear Processed Flag",
- PRSDesktop.Resources.lock_sml,
- () =>
- {
- var form = new TEntityForm
- {
- FormProcessed = formModel.Processed
- }.SetID(formModel.ID);
- form.CommitChanges();
- form.FormProcessed = DateTime.MinValue;
- using (new WaitCursor())
- {
- Client.Save(form, "Processed Flag Cleared");
- Refresh(false, true);
- }
- });
- }
- if (typeof(TEntity).HasInterface<IJobScopedItem>())
- {
- menu.AddSeparatorIfNeeded();
- menu.AddItem("Set Job", PRSDesktop.Resources.project, formModel,
- SetJob_ClickMethod.MakeGenericMethod(typeof(TEntity)).CreateDelegate<Action<DigitalFormDockModel>>());
- menu.AddItem("Set Job Scope", PRSDesktop.Resources.project, formModel,
- SetJobScope_ClickMethod.MakeGenericMethod(typeof(TEntity)).CreateDelegate<Action<DigitalFormDockModel>>());
- }
- else if (typeof(TEntity) == typeof(Job) && typeof(TEntityForm) == typeof(JobForm))
- {
- menu.AddSeparatorIfNeeded();
- var scopeheader = menu.AddItem("Set Job Scope", PRSDesktop.Resources.project, formModel, dockModel => { });
- var scopes = Client.Query<JobScope>(
- new Filter<JobScope>(x => x.Job.ID).IsEqualTo(formModel.ParentID),
- Columns.None<JobScope>()
- .Add(x => x.ID)
- .Add(x => x.Number)
- .Add(x => x.Description)
- ).ToObjects<JobScope>();
- foreach (var scope in scopes)
- {
- var existingscope = new MenuItem() { Header = $"{scope.Number}: {scope.Description}", DataContext = formModel, Tag = scope };
- existingscope.Click += SetJobScopeFromMenu_Click;
- scopeheader.Items.Add(existingscope);
- }
- if (scopes.Any())
- scopeheader.Items.Add(new Separator());
-
- var newscope = new MenuItem() { Header = $"Create New Scope", DataContext = formModel };
- newscope.Click += CreateJobScopeFromMenu_Click;
- scopeheader.Items.Add(newscope);
- }
- if (Security.IsAllowed<CanCustomiseModules>())
- {
- menu.AddSeparatorIfNeeded();
- menu.AddItem("Customise Modules", PRSDesktop.Resources.script, () =>
- {
- var manager = new CustomModuleManager
- {
- Section = formModel.FormID.ToString(),
- DataModel = model
- };
- manager.ShowDialog();
- });
- }
- if (Security.IsAllowed<CanPrintReports>())
- {
- menu.AddSeparatorIfNeeded();
- var printItem = menu.AddItem("Print", PRSDesktop.Resources.printer, null);
- ReportUtils.PopulateMenu(printItem, formModel.FormID.ToString(), model, Security.IsAllowed<CanDesignReports>(), true);
- }
- }
-
- private static void UpdateScopeID(DigitalFormDockModel formModel, Guid scopeid)
- {
- var instance = Client.Query(
- new Filter<JobForm>(x => x.ID).IsEqualTo(formModel.ID),
- Columns.Required<JobForm>()
- ).ToObjects<JobForm>().First();
-
- instance.JobScope.ID = scopeid;
- Client.Save(instance, "Linked scope set by user from Digital forms dock.");
- }
- private void CreateJobScopeFromMenu_Click(object sender, RoutedEventArgs e)
- {
- if ((sender as MenuItem)?.DataContext is DigitalFormDockModel model)
- {
- var scope = new JobScope();
- scope.Job.ID = model.ParentID;
- scope.Description = model.FormName;
- if (new DynamicDataGrid<JobScope>().EditItems(new[] { scope }))
- {
- UpdateScopeID(model, scope.ID);
- MessageBox.Show($"Form has been assigned to scope {scope.Number}.");
- // Update the form scope here (from the SetScope) stuff
- }
- }
-
- }
- private void SetJobScopeFromMenu_Click(object sender, RoutedEventArgs e)
- {
- if (sender is MenuItem mi && mi.DataContext is DigitalFormDockModel model && mi.Tag is JobScope scope)
- {
- UpdateScopeID(model, scope.ID);
- MessageBox.Show($"Form has been assigned to scope {scope.Number}.");
- // Update the form scope here (from the SetScope) stuff
- }
- }
- private static void ViewEntity_Click<TEntity>(DigitalFormDockModel model)
- where TEntity : Entity, IRemotable, IPersistent, new()
- {
- var entity = Client.Query(
- new Filter<TEntity>(x => x.ID).IsEqualTo(model.ParentID),
- DynamicGridUtils.LoadEditorColumns<TEntity>(Columns.None<TEntity>()))
- .ToObjects<TEntity>().First();
- var grid = (DynamicGridUtils.CreateDynamicGrid(typeof(DynamicGrid<>), typeof(TEntity)) as DynamicGrid<TEntity>)!;
- grid.EditItems(new TEntity[] { entity });
- }
- private static void SetJobScopeFromJob_Click(DigitalFormDockModel formModel)
- {
- var instance = Client.Query(
- new Filter<JobForm>(x => x.ID).IsEqualTo(formModel.ID),
- LookupFactory.DefineLookupFilterColumns<JobForm, JobScope, JobScopeLink>(x => x.JobScope)
- .Add(x => x.ID)
- .Add(x => x.Parent.ID))
- .ToObjects<JobForm>().First();
- var job = Client.Query(
- new Filter<Job>(x => x.ID).IsEqualTo(instance.Parent.ID),
- LookupFactory.DefineChildFilterColumns<Job, JobScope>()).ToObjects<Job>().First();
- var window = new MultiSelectDialog<JobScope>(
- new Filters<JobScope>()
- .Add(LookupFactory.DefineChildFilter<Job, JobScope>(new Job[] { job }))
- .Add(new Filter<JobScope>(x => x.Job.ID).IsEqualTo(instance.Parent.ID))
- .Combine(),
- Columns.None<JobScope>().Add(x => x.ID).Add(x => x.Number), multiselect: false);
- if (!window.ShowDialog())
- {
- return;
- }
- var scope = window.Data().ToObjects<JobScope>().First();
- instance.JobScope.ID = scope.ID;
- Client.Save(instance, "Linked scope set by user from Digital forms dock.");
- MessageBox.Show($"Form has been assigned to scope {scope.Number}.");
- }
- private static readonly MethodInfo SetJobScope_ClickMethod = typeof(DigitalFormDockGrid).GetMethod(nameof(SetJobScope_Click), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)!;
- private static void SetJobScope_Click<TEntity>(DigitalFormDockModel formModel)
- where TEntity : Entity, IJobScopedItem, IRemotable, IPersistent, new()
- {
- var entity = Client.Query(
- new Filter<TEntity>(x => x.ID).IsEqualTo(formModel.ParentID),
- LookupFactory.DefineLookupFilterColumns<TEntity, JobScope, JobScopeLink>(x => x.JobScope)
- .Add(x => x.ID)
- .Add(x => x.JobLink.ID)
- .Add(x => x.JobScope.ID)
- .Add(x => x.JobScope.Number))
- .ToObjects<TEntity>().First();
- if (entity.JobLink.ID == Guid.Empty)
- {
- MessageBox.Show($"{typeof(TEntity).Name} is not linked to a job. Please select a job first.");
- return;
- }
- var window = new MultiSelectDialog<JobScope>(
- new Filters<JobScope>()
- .Add(LookupFactory.DefineLookupFilter<TEntity, JobScope, JobScopeLink>(x => x.JobScope, new TEntity[] { entity }))
- .Add(new Filter<JobScope>(x => x.Job.ID).IsEqualTo(entity.JobLink.ID))
- .Combine(),
- Columns.None<JobScope>().Add(x => x.ID).Add(x => x.Number),
- multiselect: false);
- if (!window.ShowDialog(nameof(JobScope.Number), entity.JobScope.Number, Syncfusion.Data.FilterType.Equals))
- {
- return;
- }
- var scope = window.Data().ToObjects<JobScope>().First();
- entity.JobScope.ID = scope.ID;
- Client.Save(entity, "Linked scope set by user from Digital forms dock.");
- MessageBox.Show($"{typeof(TEntity).Name} has been assigned to scope {scope.Number}.");
- }
- private static readonly MethodInfo SetJob_ClickMethod = typeof(DigitalFormDockGrid).GetMethod(nameof(SetJob_Click), BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)!;
- private static void SetJob_Click<TEntity>(DigitalFormDockModel formModel)
- where TEntity: Entity, IJobScopedItem, IRemotable, IPersistent, new()
- {
- var entity = Client.Query(
- new Filter<TEntity>(x => x.ID).IsEqualTo(formModel.ParentID),
- LookupFactory.DefineLookupFilterColumns<TEntity, Job, JobLink>(x => x.JobLink)
- .Add(x => x.ID)
- .Add(x => x.JobLink.ID)
- .Add(x => x.JobLink.JobNumber))
- .ToObjects<TEntity>().First();
- var window = new MultiSelectDialog<Job>(
- LookupFactory.DefineLookupFilter<TEntity, Job, JobLink>(x => x.JobLink, new TEntity[] { entity }),
- Columns.None<Job>().Add(x => x.DefaultScope.ID).Add(x => x.JobNumber),
- multiselect: false);
- if (!window.ShowDialog(nameof(Job.JobNumber), entity.JobLink.JobNumber, Syncfusion.Data.FilterType.Equals))
- {
- return;
- }
- var job = window.Data().ToObjects<Job>().First();
- entity.JobLink.ID = job.ID;
- entity.JobLink.Synchronise(job);
- Client.Save(entity, "Linked job set by user from Digital forms dock.");
- MessageBox.Show($"{typeof(TEntity).Name} has been assigned to job {job.JobNumber}.");
- }
- private void MenuBuild(DynamicMenuColumn column, CoreRow? row)
- {
- if (row is null) return;
- var form = row.ToObject<DigitalFormDockModel>();
- var linkType = DFUtils.FormEntityLinkType(form.FormType);
- var entityType = DFUtils.FormEntityType(form.FormType);
- MenuBuildGenericMethod.MakeGenericMethod(form.FormType, entityType, linkType).Invoke(this, new object?[] { column.GetMenu(), form });
- }
- private DynamicMenuStatus MenuStatus(CoreRow row)
- {
- if (row == null) return DynamicMenuStatus.Hidden;
- return DynamicMenuStatus.Enabled;
- }
- protected override void Reload(
- Filters<DigitalFormDockModel> criteria, Columns<DigitalFormDockModel> columns, ref SortOrder<DigitalFormDockModel>? sort,
- CancellationToken token, Action<CoreTable?, Exception?> action)
- {
- var queryDefs = new Dictionary<string, IQueryDef>();
- var types = DFUtils.GetFormInstanceTypes().Except(ExcludedTypes).ToList();
- foreach (var type in types)
- {
- var filter = Filter.Create<IDigitalFormInstance>(type, x => x.FormCompleted).IsGreaterThanOrEqualTo(StartDate)
- .And<IDigitalFormInstance>(x => x.FormCancelled).IsEqualTo(DateTime.MinValue);
- var cols = Columns.Create<IDigitalFormInstance>(type, ColumnTypeFlags.None)
- .Add<IDigitalFormInstance>(c => c.ID)
- .Add<IDigitalFormInstance>(c => c.Parent.ID)
- .Add<IDigitalFormInstance>(c => c.Form.ID)
- .Add<IDigitalFormInstance>(c => c.Number)
- .Add<IDigitalFormInstance>(c => c.Description)
- .Add<IDigitalFormInstance>(c => c.FormCompleted)
- .Add<IDigitalFormInstance>(c => c.FormCompletedBy.UserID)
- .Add<IDigitalFormInstance>(c => c.FormProcessed);
- var sorts = SortOrder.Create<IDigitalFormInstance>(type, x => x.FormCompleted, SortDirection.Descending);
- queryDefs.Add(
- type.ToString(),
- new QueryDef(type)
- {
- Filter = filter,
- Columns = cols,
- SortOrder = sorts
- });
- }
- Client.QueryMultiple(
- (results, e) =>
- {
- if(results is not null)
- {
- var data = new CoreTable();
- data.LoadColumns(typeof(DigitalFormDockModel));
- foreach (var type in types)
- data.LoadFrom(
- results[type.ToString()],
- _mappings,
- (r) => r.Set<DigitalFormDockModel, Type>(x => x.FormType, type)
- );
- action.Invoke(data, null);
- }
- else if(e is not null)
- {
- Logger.Send(LogType.Error, ClientFactory.UserID, CoreUtils.FormatException(e));
- MessageBox.Show($"Error: {e.Message}");
- }
- },
- queryDefs);
- }
- public override DigitalFormDockModel LoadItem(CoreRow row)
- {
- return row.ToObject<DigitalFormDockModel>();
- }
- public override void SaveItem(DigitalFormDockModel item)
- {
- }
- public override void DeleteItems(params CoreRow[] rows)
- {
- }
- protected override void DoDoubleClick(object sender, DynamicGridCellClickEventArgs args)
- {
- base.DoDoubleClick(sender, args);
- var row = SelectedRows.FirstOrDefault();
- if (row is null)
- return;
- var instanceID = row.Get<DigitalFormDockModel, Guid>(x => x.ID);
- var formID = row.Get<DigitalFormDockModel, Guid>(x => x.FormID);
- var formType = row.Get<DigitalFormDockModel, Type>(x => x.FormType);
- var formInstance = Client.Create(formType)
- .Query(
- Filter.Create<IDigitalFormInstance>(formType, x => x.ID).IsEqualTo(instanceID),
- DynamicFormEditWindow.FormColumns(formType))
- .Rows.FirstOrDefault()
- ?.ToObject(formType) as IDigitalFormInstance;
- if (formInstance is null)
- {
- return;
- }
- if (formID == Guid.Empty)
- {
- var window = new DeletedFormWindow();
- window.FormData = formInstance?.FormData ?? "";
- window.ShowDialog();
- return;
- }
- if (DynamicFormEditWindow.EditDigitalForm(formInstance, out var model))
- {
- model.Update(null);
- }
- }
- }
|