1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246 |
- using com.sun.tools.doclets.formats.html;
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.Reports;
- using InABox.Reports.Common;
- using InABox.Scripting;
- using InABox.WPF;
- using PRSDesktop.Configuration;
- using PRSDesktop.Forms;
- using PRSDesktop.WidgetGroups;
- using Syncfusion.UI.Xaml.Grid;
- using Syncfusion.UI.Xaml.Grid.Converter;
- using Syncfusion.Windows.Shared;
- using Syncfusion.XlsIO;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Navigation;
- using System.Windows.Shapes;
- using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
- namespace PRSDesktop
- {
- public enum DateFilterType
- {
- Today,
- Yesterday,
- Week,
- SevenDays,
- Month,
- ThirtyDays,
- Year,
- TwelveMonths,
- Custom
- }
- public class DFFilter : BaseObject
- {
- [EditorSequence(1)]
- [TextBoxEditor]
- public string Name { get; set; }
- [EditorSequence(2)]
- [FilterEditor]
- public string Filter { get; set; }
- protected override void Init()
- {
- base.Init();
- Name = "";
- Filter = "";
- }
- }
- public class DigitalFormsDashboardProperties : IDashboardProperties
- {
- public bool ShowJobFilter { get; set; } = false;
- public bool ShowDateFilter { get; set; } = true;
- public Guid JobID { get; set; }
- public DateFilterType DateFilterType { get; set; } = DateFilterType.Today;
- public DateTime FromDate { get; set; }
- public DateTime ToDate { get; set; }
- public Dictionary<string, List<DFFilter>> Filters { get; set; } = new();
- }
- public class DigitalFormsDashboardElement : DashboardElement<DigitalFormsDashboard, Common, DigitalFormsDashboardProperties> { }
- /// <summary>
- /// Interaction logic for DigitalFormsDashboard.xaml
- /// </summary>
- public partial class DigitalFormsDashboard : UserControl,
- IDashboardWidget<Common, DigitalFormsDashboardProperties>,
- IRequiresSecurity<CanViewDigitalFormsDashbaord>,
- IHeaderDashboard, IActionsDashboard
- {
- public DigitalFormsDashboardProperties Properties { get; set; }
- private List<DigitalForm> DigitalForms;
- private List<Job> Jobs;
- private Dictionary<string, string> Categories;
- public DashboardHeader Header { get; set; } = new();
- private bool IsQAForm = false;
- private List<QAQuestion> Questions = new();
- public DigitalFormsDashboard()
- {
- InitializeComponent();
- }
- public void Setup()
- {
- var results = Client.QueryMultiple(
- new KeyedQueryDef<DigitalForm>(new Filter<DigitalForm>(x => x.Active).IsEqualTo(true)),
- new KeyedQueryDef<Job>(
- LookupFactory.DefineFilter<Job>(),
- new Columns<Job>(x => x.ID)
- .Add(x => x.JobNumber)
- .Add(x => x.Name)));
- DigitalForms = results.Get<DigitalForm>().ToList<DigitalForm>();
- var categories = new DigitalFormCategoryLookups(null);
- categories.OnAfterGenerateLookups += (sender, entries) => { entries.Insert(0, new LookupEntry("", "Select Category")); };
- Categories = categories.AsTable("AppliesTo")
- .ToDictionary("AppliesTo", "Display")
- .Cast<KeyValuePair<object, string>>()
- .ToDictionary(x => (x.Key as string)!, x => x.Value);
- Jobs = results.Get<Job>().ToList<Job>();
- Jobs.Insert(0, new Job { ID = Guid.Empty, JobNumber = "ALL", Name = "All Jobs" });
- SetupHeader();
- SetupFilters();
- }
- #region Header
- private ComboBox CategoryBox;
- private ComboBox FormBox;
- private ComboBox JobBox;
- private ComboBox DateTypeBox;
- private Label FromLabel;
- private DatePicker FromPicker;
- private Label ToLabel;
- private DatePicker ToPicker;
- private Button Print;
- private static Dictionary<DateFilterType, string> FilterTypes = new()
- {
- { DateFilterType.Today, "Today" },
- { DateFilterType.Yesterday, "Yesterday" },
- { DateFilterType.Week, "Week to Date" },
- { DateFilterType.SevenDays, "Last 7 Days" },
- { DateFilterType.Month, "Month to Date" },
- { DateFilterType.ThirtyDays, "Last 30 Days" },
- { DateFilterType.Year, "Year to Date" },
- { DateFilterType.TwelveMonths, "Last 12 Months" },
- { DateFilterType.Custom, "Custom" }
- };
- public void SetupHeader()
- {
- CategoryBox = new ComboBox {
- Width = 150,
- VerticalContentAlignment = VerticalAlignment.Center,
- Margin = new Thickness(0, 0, 5, 0)
- };
- CategoryBox.ItemsSource = Categories;
- CategoryBox.SelectedValuePath = "Key";
- CategoryBox.DisplayMemberPath = "Value";
- CategoryBox.SelectionChanged += Category_SelectionChanged;
- FormBox = new ComboBox
- {
- Width = 250,
- VerticalContentAlignment = VerticalAlignment.Center,
- Margin = new Thickness(0, 0, 5, 0),
- IsEnabled = false
- };
- FormBox.SelectionChanged += FormBox_SelectionChanged;
- FormBox.ItemsSource = new Dictionary<DigitalForm, string> { };
- JobBox = new ComboBox
- {
- Width = 250,
- Margin = new Thickness(0, 0, 5, 0),
- VerticalContentAlignment = VerticalAlignment.Center
- };
- JobBox.ItemsSource = Jobs.ToDictionary(x => x.ID, x => $"{x.JobNumber} : {x.Name}");
- JobBox.SelectedIndex = 0;
- JobBox.SelectedValuePath = "Key";
- JobBox.DisplayMemberPath = "Value";
- JobBox.SelectionChanged += JobBox_SelectionChanged;
- DateTypeBox = new ComboBox
- {
- Width = 120,
- VerticalContentAlignment = VerticalAlignment.Center
- };
- DateTypeBox.ItemsSource = FilterTypes;
- DateTypeBox.SelectedValuePath = "Key";
- DateTypeBox.DisplayMemberPath = "Value";
- DateTypeBox.SelectedValue = Properties.DateFilterType;
- DateTypeBox.SelectionChanged += DateTypeBox_SelectionChanged;
- FromLabel = new Label { Content = "From", VerticalContentAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 5, 0) };
- FromPicker = new DatePicker {
- Width = 100,
- Background = new SolidColorBrush(Colors.LightYellow),
- VerticalContentAlignment = VerticalAlignment.Center,
- FirstDayOfWeek = DayOfWeek.Monday,
- Margin = new Thickness(0, 0, 5, 0)
- };
- FromPicker.SelectedDateChanged += FromPicker_SelectedDateChanged;
- ToLabel = new Label { Content = "To", VerticalContentAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 5, 0) };
- ToPicker = new DatePicker
- {
- Width = 100,
- Background = new SolidColorBrush(Colors.LightYellow),
- VerticalContentAlignment = VerticalAlignment.Center,
- FirstDayOfWeek = DayOfWeek.Monday,
- Margin = new Thickness(0, 0, 5, 0)
- };
- ToPicker.SelectedDateChanged += ToPicker_SelectedDateChanged;
- Print = new Button
- {
- Width = 25,
- Height = 25,
- Content = new Image { Source = PRSDesktop.Resources.printer.AsBitmapImage() }
- };
- Print.Click += Print_Click;
- Header.BeginUpdate()
- .Clear()
- .Add(CategoryBox)
- .Add(FormBox)
- .Add(JobBox)
- .Add(DateTypeBox)
- .Add(FromLabel)
- .Add(FromPicker)
- .Add(ToLabel)
- .Add(ToPicker)
- .AddRight(Print);
- Header.EndUpdate();
- }
- private void Print_Click(object sender, RoutedEventArgs e)
- {
- var menu = new ContextMenu();
- foreach (var report in ReportUtils.LoadReports(SectionName, DataModel(Selection.None)))
- {
- menu.AddItem(report.Name, PRSDesktop.Resources.printer, report, PrintReport_Click);
- }
- if (Security.IsAllowed<CanDesignReports>())
- {
- menu.AddSeparatorIfNeeded();
- menu.AddItem("Manage Reports", PRSDesktop.Resources.printer, ManageReports_Click);
- }
- menu.IsOpen = true;
- }
- private void PrintReport_Click(ReportTemplate obj)
- {
- Selection selection;
- if (obj.SelectedRecords && obj.AllRecords)
- selection = RecordSelectionDialog.Execute();
- else if (obj.SelectedRecords)
- selection = Selection.Selected;
- else if (obj.AllRecords)
- selection = Selection.All;
- else
- selection = Selection.None;
- ReportUtils.PreviewReport(obj, DataModel(selection), false, Security.IsAllowed<CanDesignReports>());
- }
- private void ManageReports_Click()
- {
- var manager = new ReportManager()
- {
- DataModel = DataModel(Selection.None),
- Section = SectionName,
- Populate = true
- };
- manager.ShowDialog();
- }
- private void Search_KeyUp(object sender, KeyEventArgs e)
- {
- Refresh();
- }
- private void JobBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- Properties.JobID = (Guid)JobBox.SelectedValue;
- Refresh();
- }
- private void SetDateFilterVisibility(bool visible)
- {
- var visibility = visible ? Visibility.Visible : Visibility.Collapsed;
- FromLabel.Visibility = visibility;
- FromPicker.Visibility = visibility;
- ToLabel.Visibility = visibility;
- ToPicker.Visibility = visibility;
- DateTypeBox.Visibility = visibility;
- }
- private void SetJobFilterVisibility(bool visible)
- {
- var visibility = visible ? Visibility.Visible : Visibility.Collapsed;
- JobBox.Visibility = visibility;
- }
- private void DateTypeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- var filterType = (DateFilterType)DateTypeBox.SelectedValue;
- Properties.DateFilterType = filterType;
- if(filterType == DateFilterType.Custom)
- {
- if (FromPicker.SelectedDate == null || FromPicker.SelectedDate == DateTime.MinValue)
- {
- Properties.FromDate = DateTime.Today;
- }
- else
- {
- Properties.FromDate = FromPicker.SelectedDate.Value;
- }
- if (ToPicker.SelectedDate == null || ToPicker.SelectedDate == DateTime.MinValue)
- {
- Properties.ToDate = DateTime.Today;
- }
- else
- {
- Properties.ToDate = ToPicker.SelectedDate.Value;
- }
- }
- SetupDateFilters();
- Refresh();
- }
- private void FromPicker_SelectedDateChanged(object? sender, SelectionChangedEventArgs e)
- {
- Properties.FromDate = FromPicker.SelectedDate ?? DateTime.Today;
- }
- private void ToPicker_SelectedDateChanged(object? sender, SelectionChangedEventArgs e)
- {
- Properties.ToDate = ToPicker.SelectedDate ?? DateTime.Today;
- }
- private void Category_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- SetCategory((CategoryBox.SelectedValue as string)!);
- var jobLink = FormType is not null ? GetJobLink("", FormType) : "";
- if (string.IsNullOrWhiteSpace(jobLink))
- {
- var jobID = Properties.JobID;
- JobBox.SelectedValue = Guid.Empty;
- JobBox.IsEnabled = false;
- Properties.JobID = jobID;
- }
- else
- {
- JobBox.SelectedValue = Properties.JobID;
- JobBox.IsEnabled = true;
- }
- if (ParentType is null)
- {
- FormBox.IsEnabled = false;
- FormBox.ItemsSource = new Dictionary<DigitalForm, string> { };
- }
- else
- {
- var forms = DigitalForms.Where(x => x.AppliesTo == ParentType.Name).ToList();
- forms.Insert(0, new DigitalForm { ID = Guid.Empty, Description = "Select Form" });
- FormBox.ItemsSource = forms;
- FormBox.DisplayMemberPath = "Description";
- FormBox.SelectedIndex = 0;
- FormBox.IsEnabled = true;
- }
- Refresh();
- }
- private void FormBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- Form = (FormBox.SelectedValue as DigitalForm)!;
- Refresh();
- }
- #endregion
- private string SectionName
- {
- get
- {
- if (Form is null || Form.ID == Guid.Empty)
- return "Digital Forms";
- return Form.ID.ToString() ?? "Digital Forms";
- }
- }
- private DataModel DataModel(Selection selection)
- {
- if(FormType is null || Form is null || Form.ID == Guid.Empty)
- {
- return new AutoDataModel<DigitalForm>(new Filter<DigitalForm>().None());
- }
- IFilter filter;
- switch (selection)
- {
- case Selection.Selected:
- var formids = DataGrid.SelectedItems.Select(x => (x as DataRowView)!.Row["ID"]).ToArray();
- filter = Filter.Create<Entity>(FormType, x => x.ID).InList(formids);
- break;
- case Selection.All:
- filter = Filter.Create(FormType).All();
- break;
- case Selection.None:
- default:
- filter = Filter.Create(FormType).None();
- break;
- }
- return (Activator.CreateInstance(typeof(DigitalFormReportDataModel<>)!
- .MakeGenericType(FormType), new object?[] { filter, Form.ID }) as DataModel)!;
- }
- public void BuildActionsMenu(ContextMenu menu)
- {
- menu.AddCheckItem<object?>("Show Date Filter", null, ToggleDateFilter, Properties.ShowDateFilter);
- menu.AddCheckItem<object?>("Show Job Filter", null, ToggleJobFilter, Properties.ShowJobFilter);
- menu.AddSeparator();
- if (ParentType is not null)
- {
- menu.AddSeparatorIfNeeded();
- if (Properties.Filters.TryGetValue(ParentType.Name, out var filters))
- {
- var i = 0;
- var items = new List<MenuItem>();
- foreach (var filter in filters)
- {
- items.Add(menu.AddCheckItem(
- filter.Name,
- new Tuple<int, string, List<MenuItem>>(i, filter.Filter, items),
- ExecuteFilter,
- i == CustomFilterIndex));
- ++i;
- }
- }
- menu.AddSeparatorIfNeeded();
- menu.AddItem("Manage Filters", InABox.DynamicGrid.Properties.Resources.filter, ManageFilters_Click);
- }
- menu.AddSeparatorIfNeeded();
- menu.AddItem("Export", InABox.DynamicGrid.Properties.Resources.doc_xls, Export_Click, Form is not null && Form.ID != Guid.Empty);
- var loadingModules = menu.AddItem("Loading Modules...", null, null, false);
- Task.Run(() =>
- {
- return CustomModuleUtils.LoadCustomModuleThumbnails(SectionName, DataModel(Selection.None));
- }).ContinueWith((task) =>
- {
- var modules = task.Result;
- var index = menu.Items.IndexOf(loadingModules);
- menu.Items.RemoveAt(index);
- foreach (var (module, image) in modules)
- {
- menu.AddItem(module.Name, image, module, ExecuteModule_Click, index: index);
- ++index;
- }
- }, TaskScheduler.FromCurrentSynchronizationContext());
- if (Security.IsAllowed<CanCustomiseModules>())
- {
- menu.AddSeparatorIfNeeded();
- menu.AddItem("Manage Modules", PRSDesktop.Resources.script, ManageModules_Click);
- }
- }
- private void Export_Click()
- {
- var formName = Regex.Replace(Form?.Description ?? "", "[^ a-zA-Z0-9]", string.Empty);
- var filename = string.Format("{0} - {1} - {2:yyyy-MM-dd} - {3:yyyy-MM-dd}.xlsx", ParentType!.Name, formName, From, To);
- var options = new ExcelExportingOptions();
- options.ExcelVersion = ExcelVersion.Excel2013;
- options.ExportStackedHeaders = true;
- var excelEngine = DataGrid.ExportToExcel(DataGrid.View, options);
- var workBook = excelEngine.Excel.Workbooks[0];
- var sheet = workBook.Worksheets[0];
- sheet.Name = "Summary";
- sheet.UsedRange.AutofitRows();
- sheet.UsedRange.AutofitColumns();
- sheet = workBook.Worksheets.Create("Questions");
- sheet.Move(0);
- var questions = new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(Form!.ID));
- sheet.Range[1, 1].Text = Form?.Description ?? "";
- sheet.Range[1, 1, 1, 3].Merge();
- var i = 1;
- foreach (var row in questions.Rows)
- if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
- {
- sheet.Range[i + 2, 1].Text = string.Format("{0}.", i);
- sheet.Range[i + 2, 2].Text = string.Format("{0}", row.Get<QAQuestion, string>(x => x.Question));
- sheet.Range[i + 2, 3].Text = string.Format("[{0}]", row.Get<QAQuestion, string>(x => x.Code));
- i++;
- }
- sheet.UsedRange.AutofitRows();
- sheet.UsedRange.AutofitColumns();
- try
- {
- workBook.SaveAs(filename);
- var startInfo = new ProcessStartInfo(filename);
- startInfo.Verb = "open";
- startInfo.UseShellExecute = true;
- Process.Start(startInfo);
- }
- catch
- {
- MessageBox.Show(string.Format("Unable to Save/Launch [{0}]!\n\nIs the file already open?", filename));
- }
- }
- private void ManageFilters_Click()
- {
- var filters = Properties.Filters.GetValueOrDefault(ParentType!.Name) ?? new List<DFFilter>();
- var gridFilters = new DynamicGridFilters();
- gridFilters.AddRange(filters.Select(x => new DynamicGridFilter { Name = x.Name, Filter = x.Filter }));
- var grid = new DynamicGridFilterEditor(gridFilters, FormType!);
- if (grid.ShowDialog() == true)
- {
- Properties.Filters[ParentType!.Name] = grid.Filters.Select(x => new DFFilter { Name = x.Name, Filter = x.Filter }).ToList();
- if (CustomFilterIndex != null)
- {
- Refresh();
- }
- }
- }
- private void ExecuteFilter(Tuple<int, string, List<MenuItem>> tag, bool isChecked)
- {
- var (index, filter, items) = tag;
- if (isChecked)
- {
- var i = 0;
- foreach (var item in items)
- {
- item.IsChecked = i == index;
- ++i;
- }
- }
- if (isChecked)
- {
- CustomFilter = Serialization.Deserialize(typeof(Filter<>).MakeGenericType(FormType!), filter) as IFilter;
- CustomFilterIndex = index;
- Refresh();
- }
- else if (index == CustomFilterIndex)
- {
- CustomFilter = null;
- CustomFilterIndex = null;
- Refresh();
- }
- }
- private void ExecuteModule_Click(CustomModule obj)
- {
- if (!string.IsNullOrWhiteSpace(obj.Script))
- try
- {
- Selection selection;
- if (obj.SelectedRecords && obj.AllRecords)
- selection = RecordSelectionDialog.Execute();
- else if (obj.SelectedRecords)
- selection = Selection.Selected;
- else if (obj.AllRecords)
- selection = Selection.All;
- else
- selection = Selection.None;
- var result = ScriptDocument.RunCustomModule(DataModel(selection), new Dictionary<string, object[]>(), obj.Script);
- if (result)
- Refresh();
- }
- catch (CompileException c)
- {
- MessageBox.Show(c.Message);
- }
- catch (Exception err)
- {
- MessageBox.Show(CoreUtils.FormatException(err));
- }
- else
- MessageBox.Show("Unable to load " + obj.Name);
- }
- private void ManageModules_Click()
- {
- var section = SectionName;
- var dataModel = DataModel(Selection.Selected);
- var manager = new CustomModuleManager()
- {
- Section = section,
- DataModel = dataModel
- };
- manager.ShowDialog();
- }
- private void ToggleDateFilter(object? tag, bool isChecked)
- {
- Properties.ShowDateFilter = isChecked;
- SetDateFilterVisibility(Properties.ShowDateFilter);
- }
- private void ToggleJobFilter(object? tag, bool isChecked)
- {
- Properties.ShowJobFilter = isChecked;
- SetJobFilterVisibility(Properties.ShowJobFilter);
- Refresh();
- }
- #region Filtering
- private DateTime From { get; set; }
- private DateTime To { get; set; }
- private bool IsEntityForm { get; set; }
- private Type? ParentType { get; set; }
- private Type? FormType { get; set; }
- private DigitalForm? Form { get; set; }
- private IFilter? CustomFilter { get; set; }
- private int? CustomFilterIndex { get; set; }
- private readonly Dictionary<string, string> QuestionCodes = new();
- private static int WeekDay(DateTime date)
- {
- if (date.DayOfWeek == DayOfWeek.Sunday)
- return 7;
- return (int)date.DayOfWeek - 1;
- }
- private void SetupDateFilters()
- {
- switch (Properties.DateFilterType)
- {
- case DateFilterType.Today:
- From = DateTime.Today;
- To = DateTime.Today;
- break;
- case DateFilterType.Yesterday:
- From = DateTime.Today.AddDays(-1);
- To = DateTime.Today.AddDays(-1);
- break;
- case DateFilterType.Week:
- From = DateTime.Today.AddDays(-WeekDay(DateTime.Today));
- To = DateTime.Today;
- break;
- case DateFilterType.SevenDays:
- From = DateTime.Today.AddDays(-6);
- To = DateTime.Today;
- break;
- case DateFilterType.Month:
- From = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
- To = DateTime.Today;
- break;
- case DateFilterType.ThirtyDays:
- From = DateTime.Today.AddDays(-29);
- To = DateTime.Today;
- break;
- case DateFilterType.Year:
- From = new DateTime(DateTime.Today.Year, 1, 1);
- To = DateTime.Today;
- break;
- case DateFilterType.TwelveMonths:
- From = DateTime.Today.AddYears(-1).AddDays(1);
- To = DateTime.Today;
- break;
- case DateFilterType.Custom:
- From = Properties.FromDate;
- To = Properties.ToDate;
- break;
- }
- DateTypeBox.SelectedValue = Properties.DateFilterType;
- FromPicker.SelectedDate = From;
- ToPicker.SelectedDate = To;
- var enabledPicker = Properties.DateFilterType == DateFilterType.Custom;
- FromPicker.IsEnabled = enabledPicker;
- ToPicker.IsEnabled = enabledPicker;
- }
- private void SetupJobFilter()
- {
- JobBox.SelectedValue = Properties.JobID;
- }
- private void SetupFilters()
- {
- SetupDateFilters();
- SetupJobFilter();
- SetDateFilterVisibility(Properties.ShowDateFilter);
- SetJobFilterVisibility(Properties.ShowJobFilter);
- }
- #region Categories
- private static Dictionary<string, Tuple<Type, Type>>? FormInstanceTypes;
- private static readonly Dictionary<Type, List<Tuple<string, string>>> parentColumns = new()
- {
- { typeof(Kanban), new() { new("Parent.Number", "Task No") } },
- { typeof(Job), new() { new("Parent.JobNumber", "Job No") } },
- { typeof(JobITP), new() { new("Parent.Code", "Code") } },
- { typeof(Assignment), new() { new("Parent.Number", "Ass. No") } },
- { typeof(TimeSheet), new() { } },
- { typeof(LeaveRequest), new() { } },
- { typeof(Employee), new() { new("Parent.Code", "Employee") } },
- { typeof(PurchaseOrderItem), new() { new("Parent.PONumber", "PO No") } },
- };
- private static bool CategoryToType(string category, [NotNullWhen(true)] out Type? formType, [NotNullWhen(true)] out Type? parentType)
- {
- FormInstanceTypes ??= CoreUtils.TypeList(
- AppDomain.CurrentDomain.GetAssemblies(),
- x => !x.IsAbstract && x.GetInterfaces().Contains(typeof(IDigitalFormInstance))
- ).Select(x =>
- {
- var inter = x.GetInterfaces()
- .Where(x => x.IsGenericType && x.GetGenericTypeDefinition().Equals(typeof(IDigitalFormInstance<>))).FirstOrDefault();
- if (inter is not null)
- {
- var link = inter.GenericTypeArguments[0];
- var entityLinkDef = link.GetSuperclassDefinition(typeof(EntityLink<>));
- if (entityLinkDef is not null)
- {
- var entityType = entityLinkDef.GenericTypeArguments[0];
- return new Tuple<string, Type, Type>(entityType.Name, x, entityType);
- }
- }
- return null;
- }).Where(x => x is not null).ToDictionary(x => x!.Item1, x => new Tuple<Type, Type>(x!.Item2, x!.Item3));
- if (!FormInstanceTypes.TryGetValue(category, out var result))
- {
- formType = null;
- parentType = null;
- return false;
- }
- formType = result.Item1;
- parentType = result.Item2;
- return true;
- }
- private void SetCategory(string category)
- {
- CustomFilter = null;
- CustomFilterIndex = null;
- if (!CategoryToType(category, out var formType, out var parentType))
- {
- IsEntityForm = false;
- ParentType = null;
- FormType = null;
- return;
- }
- IsEntityForm = formType.IsSubclassOfRawGeneric(typeof(EntityForm<,>));
- ParentType = parentType;
- FormType = formType;
- }
- #endregion
- private string GetJobLink(string prefix, Type type)
- {
- var props = type.GetProperties().Where(x =>
- x.PropertyType.BaseType != null && x.PropertyType.BaseType.IsGenericType &&
- x.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(EntityLink<>));
- foreach (var prop in props)
- {
- if (prop.PropertyType == typeof(JobLink))
- return (string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name;
- var result = GetJobLink((string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name, prop.PropertyType);
- if (!string.IsNullOrEmpty(result))
- return result;
- }
- return "";
- }
- /// <summary>
- /// Find a link from the form type to an associated <see cref="Job"/>, allowing us to filter based on jobs.
- /// </summary>
- /// <returns>The property name of the <see cref="JobLink"/>.</returns>
- private string GetJobLink<T>() where T : IDigitalFormInstance
- => GetJobLink("", typeof(T));
- private IKeyedQueryDef GetFormQuery<T>()
- where T : Entity, IRemotable, IPersistent, IDigitalFormInstance, new()
- {
- var sort = LookupFactory.DefineSort<T>();
- var jobLink = GetJobLink<T>();
- var filter = new Filter<T>(x => x.FormCompleted).IsGreaterThanOrEqualTo(From)
- .And(x => x.FormCompleted).IsLessThan(To.AddDays(1))
- .And(x => x.Form.ID).IsEqualTo(Form!.ID);
-
- if (Properties.JobID != Guid.Empty && Properties.ShowJobFilter)
- {
- filter.And(jobLink + ".ID").IsEqualTo(Properties.JobID);
- }
- if (CustomFilter is not null)
- {
- filter.And(CustomFilter);
- }
- var columns = new Columns<T>(x => x.ID)
- .Add(x => x.Form.ID)
- .Add(x => x.FormData)
- .Add(x => x.FormCompleted)
- .Add(x => x.FormCompletedBy.UserID)
- .Add(x => x.Location.Timestamp)
- .Add(x => x.Location.Latitude)
- .Add(x => x.Location.Longitude);
- var parentcols = LookupFactory.DefineColumns(ParentType!);
- foreach (var col in parentcols.ColumnNames())
- columns.Add("Parent." + col);
- if (parentColumns.TryGetValue(ParentType!, out var pColumns))
- {
- foreach (var (field, name) in pColumns)
- {
- columns.Add(field);
- }
- }
- if (IsEntityForm)
- columns.Add("Processed");
- if (!string.IsNullOrWhiteSpace(jobLink))
- columns.Add(jobLink + ".ID");
- return new KeyedQueryDef<T>(filter, columns, sort);
- }
- #endregion
- private void LoadDataIntoGrid(List<DigitalFormVariable> variables, List<QAQuestion> questions, CoreTable formData, List<string> additionalColumns, CoreTable? jobITPs)
- {
- var data = new DataTable();
- data.Columns.Add("ID", typeof(Guid));
- data.Columns.Add("Form_ID", typeof(Guid));
- data.Columns.Add("Parent_ID", typeof(Guid));
- data.Columns.Add("Location_Timestamp", typeof(DateTime));
- data.Columns.Add("Location_Latitude", typeof(double));
- data.Columns.Add("Location_Longitude", typeof(double));
- data.Columns.Add("FormData", typeof(string));
- if (ParentType == typeof(JobITP))
- {
- data.Columns.Add("Job No", typeof(string));
- }
- if (parentColumns.TryGetValue(ParentType!, out var pColumns))
- {
- foreach (var (field, name) in pColumns)
- {
- data.Columns.Add(name, typeof(string));
- }
- }
- data.Columns.Add("Description", typeof(string));
- data.Columns.Add("Completed", typeof(DateTime));
- data.Columns.Add("Completed By", typeof(string));
- if (IsEntityForm)
- data.Columns.Add("Processed", typeof(bool));
- if (variables.Any())
- {
- foreach (var variable in variables)
- {
- var code = variable.Code.Replace("/", " ");
- QuestionCodes[code] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(code.ToLower());
- data.Columns.Add(code, typeof(string));
- }
- }
- else if (questions.Any())
- {
- Questions = questions;
- Progress.SetMessage("Loading Checks");
- QAGrid.Clear();
- QAGrid.LoadChecks(Form!.Description, Questions, new Dictionary<Guid, object>());
- QAGrid.CollapseMargins();
- var i = 1;
- foreach (var question in Questions)
- {
- var id = question.ID.ToString();
- if (!question.Answer.Equals(QAAnswer.Comment))
- {
- data.Columns.Add(id, typeof(string));
- var code = question.Code;
- QuestionCodes[id] = string.IsNullOrEmpty(code) ? string.Format("{0}.", i) : code;
- i++;
- }
- }
- }
- foreach (var row in formData.Rows)
- {
- var form = (row.ToObject(FormType!) as IDigitalFormInstance)!;
- if (!string.IsNullOrWhiteSpace(form.FormData))
- {
- var dataRow = data.NewRow();
- dataRow["ID"] = form.ID;
- dataRow["Form_ID"] = form.Form.ID;
- dataRow["Parent_ID"] = form.ParentID();
- dataRow["Location_Timestamp"] = form.Location.Timestamp;
- dataRow["Location_Latitude"] = form.Location.Latitude;
- dataRow["Location_Longitude"] = form.Location.Longitude;
- dataRow["FormData"] = form.FormData;
- var desc = new List<string>();
- foreach (var col in additionalColumns)
- {
- var val = row[col];
- if (val != null && val is not Guid)
- desc.Add(val.ToString() ?? "");
- }
- dataRow["Description"] = string.Join(" : ", desc);
- dataRow["Completed"] = form.FormCompleted;
- dataRow["Completed By"] = form.FormCompletedBy.UserID;
- if (IsEntityForm)
- dataRow["Processed"] = (bool?)row["Processed"] ?? false;
- if (ParentType == typeof(JobITP))
- {
- var jobITP = jobITPs!.Rows.FirstOrDefault(x => x.Get<JobITP, Guid>(x => x.ID) == form.ParentID());
- if(jobITP is not null)
- {
- var jobID = jobITP.Get<JobITP, Guid>(x => x.Job.ID);
- dataRow["Job No"] = Jobs.Where(x => x.ID == jobID).FirstOrDefault()?.JobNumber;
- }
- }
- if (pColumns != null)
- {
- foreach (var (field, name) in pColumns)
- {
- dataRow[name] = row[field]?.ToString();
- }
- }
- //datarow["Job No"] = (String)row[JobLink + ".JobNumber"];
- var bHasData = false;
- if (variables.Any())
- {
- var dict = Serialization.Deserialize<Dictionary<string, object>>(form.FormData);
- foreach (var key in dict.Keys)
- {
- var variable = variables.FirstOrDefault(x => string.Equals(key, x.Code));
- var type = variable?.FieldType();
- if (variable != null)
- {
- var value = variable.ParseValue(dict[key]);
- var format = variable.FormatValue(value);
- var sKey = key.Replace("/", " ");
- if (data.Columns.Contains(sKey))
- {
- dataRow[sKey] = format;
- bHasData = true;
- }
- }
- }
- }
- else
- {
- var dict = Serialization.Deserialize<Dictionary<Guid, object>>(form.FormData);
- foreach (var key in dict.Keys)
- if (data.Columns.Contains(key.ToString()))
- {
- dataRow[key.ToString()] = dict[key];
- bHasData = true;
- }
- }
- if (bHasData)
- data.Rows.Add(dataRow);
- }
- }
- DataGrid.ItemsSource = data;
- IsQAForm = !variables.Any() && questions.Any();
- QAGrid.Visibility = IsQAForm ? Visibility.Visible : Visibility.Collapsed;
- DataGrid.Visibility = Visibility.Visible;
- }
- private void RefreshData<TForm>()
- where TForm : Entity, IRemotable, IPersistent, IDigitalFormInstance, new()
- {
- var formQuery = GetFormQuery<TForm>();
- var queries = new List<IKeyedQueryDef>()
- {
- new KeyedQueryDef<QAQuestion>(new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(Form!.ID)),
- new KeyedQueryDef<DigitalFormVariable>(
- new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(Form.ID),
- null,
- new SortOrder<DigitalFormVariable>(x => x.Sequence)),
- formQuery
- };
- if (ParentType == typeof(JobITPForm))
- {
- queries.Add(new KeyedQueryDef<JobITP>(
- new Filter<JobITP>(x => x.ID).InQuery((formQuery.Filter as Filter<JobITPForm>)!, x => x.Parent.ID),
- new Columns<JobITP>(x => x.ID, x => x.Job.JobNumber)));
- }
- var results = Client.QueryMultiple(queries);
- var questions = results.Get<QAQuestion>().ToList<QAQuestion>();
- var variables = results.Get<DigitalFormVariable>().ToList<DigitalFormVariable>();
- var formData = results.Get(formQuery.Key);
- LoadDataIntoGrid(
- variables, questions,
- formData,
- formQuery.Columns!.ColumnNames().Where(x => x != "ID" && x.StartsWith("Parent.")).ToList(),
- ParentType == typeof(JobITP) ? results.Get<JobITP>() : null);
- }
- public void Refresh()
- {
- Progress.Show("Refreshing");
- try
- {
- Questions.Clear();
- QAGrid.Clear();
- QAGrid.LoadChecks("", Array.Empty<QAQuestion>(), new Dictionary<Guid, object>());
- DataGrid.ItemsSource = null;
- if (ParentType is null || FormType is null || Form is null || Form.ID == Guid.Empty)
- {
- QAGrid.Visibility = Visibility.Collapsed;
- DataGrid.Visibility = Visibility.Collapsed;
- return;
- }
- Progress.SetMessage("Loading Data");
- var refreshMethod = typeof(DigitalFormsDashboard).GetMethod(nameof(RefreshData), BindingFlags.Instance | BindingFlags.NonPublic)!.MakeGenericMethod(FormType);
- refreshMethod.Invoke(this, Array.Empty<object?>());
- }
- finally
- {
- Progress.Close();
- }
- }
- public void Shutdown()
- {
- }
- #region DataGrid Configuration
- private void DataGrid_AutoGeneratingColumn(object sender, Syncfusion.UI.Xaml.Grid.AutoGeneratingColumnArgs e)
- {
- e.Column.TextAlignment = TextAlignment.Center;
- e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center;
- e.Column.ColumnSizer = GridLengthUnitType.None;
- var value = (e.Column.ValueBinding as Binding)!;
- if (value.Path.Path.Equals("ID") || value.Path.Path.Equals("Form_ID") || value.Path.Path.Equals("Parent_ID") ||
- value.Path.Path.Equals("FormData") || value.Path.Path.Equals("Location_Latitude") || value.Path.Path.Equals("Location_Longitude"))
- {
- e.Cancel = true;
- }
- else if (value.Path.Path.Equals("Location_Timestamp"))
- {
- e.Column = new GridImageColumn();
- e.Column.Width = DataGrid.RowHeight;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- e.Column.HeaderText = "";
- e.Column.Padding = new Thickness(4);
- e.Column.ValueBinding = new Binding
- {
- Path = new PropertyPath(value.Path.Path),
- Converter = new MileStoneImageConverter()
- };
- e.Column.MappingName = "Location.Timestamp";
- }
- else if (ParentType is not null && parentColumns.TryGetValue(ParentType, out var pColumns) && pColumns.Any(x => x.Item2.Equals(value.Path.Path)))
- {
- e.Column.ColumnSizer = GridLengthUnitType.Auto;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- }
- else if (value.Path.Path.Equals("Job No"))
- {
- e.Column.Width = 60;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- }
- else if (value.Path.Path.Equals("Description"))
- {
- e.Column.TextAlignment = TextAlignment.Left;
- e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Left;
- e.Column.Width = 450;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- }
- else if (value.Path.Path.Equals("Completed"))
- {
- e.Column.Width = 100;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- (e.Column as GridDateTimeColumn)!.Pattern = DateTimePattern.CustomPattern;
- (e.Column as GridDateTimeColumn)!.CustomPattern = "dd MMM yy hh:mm";
- }
- else if (value.Path.Path.Equals("Completed By"))
- {
- e.Column.Width = 100;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- }
- else if (value.Path.Path.Equals("Processed"))
- {
- e.Column.Width = 100;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- }
- else
- {
- var data = DataGrid.ItemsSource as DataTable;
- //int index = data.Columns.IndexOf(e.Column.MappingName) - 2;
- //Style style = new Style(typeof(GridCell));
- //e.Column.CellStyle = style;
- e.Column.Width = 100;
- e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
- e.Column.HeaderText = QuestionCodes[e.Column.MappingName];
- }
- }
- private Entity? GetEntityForm<T>(Guid id) where T : Entity, IDigitalFormInstance, IRemotable, IPersistent, new()
- {
- var columns = new Columns<T>(x => x.ID)
- .Add(x => x.FormCompleted)
- .Add(x => x.FormData)
- .Add(x => x.Form.ID)
- .Add(x => x.Form.Description);
- if (typeof(T).HasInterface(typeof(IDigitalFormInstance<>)))
- {
- columns.Add("Parent.ID");
- }
- return new Client<T>().Query(
- new Filter<T>(x => x.ID).IsEqualTo(id),
- columns).Rows.FirstOrDefault()?.ToObject<T>();
- }
- private void DataGrid_CellDoubleTapped(object sender, Syncfusion.UI.Xaml.Grid.GridCellDoubleTappedEventArgs e)
- {
- if (e.RowColumnIndex.RowIndex == 0)
- return;
- var table = (DataGrid.ItemsSource as DataTable)!;
- var formid = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["Form_ID"];
- var formdata = (string)table.Rows[e.RowColumnIndex.RowIndex - 1]["FormData"];
- var id = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["ID"];
- if (FormType is null) return;
- if (IsQAForm)
- {
- var formData = Serialization.Deserialize<Dictionary<string, object>>(formdata);
- var values = new Dictionary<Guid, object>();
- foreach(var (idStr, value) in formData)
- {
- if(Guid.TryParse(idStr, out var codeID))
- {
- values[codeID] = value;
- }
- }
- QAGrid.Clear();
- QAGrid.LoadChecks(Form!.Description, Questions, values);
- QAGrid.CollapseMargins();
- return;
- }
- var entityForm = typeof(DigitalFormsDashboard)
- .GetMethod(nameof(GetEntityForm), BindingFlags.NonPublic | BindingFlags.Instance)!
- .MakeGenericMethod(FormType)
- .Invoke(this, new object[] { id }) as IDigitalFormInstance;
- if (entityForm is not null)
- {
- if (DynamicFormEditWindow.EditDigitalForm(entityForm, out var dataModel))
- {
- dataModel.Update(null);
- /*typeof(QADashboard)
- .GetMethod(nameof(SaveEntityForm), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
- .MakeGenericMethod(formType)
- .Invoke(this, new object[] { entityForm });*/
- Refresh();
- }
- }
- }
- private void DataGrid_CellTapped(object sender, Syncfusion.UI.Xaml.Grid.GridCellTappedEventArgs e)
- {
- if (e.RowColumnIndex.ColumnIndex == 0)
- {
- var timestamp = (DateTime)(e.Record as DataRowView)!.Row["Location_Timestamp"];
- var latitude = (double)(e.Record as DataRowView)!.Row["Location_Latitude"];
- var longitude = (double)(e.Record as DataRowView)!.Row["Location_Longitude"];
- var form = new MapForm(latitude, longitude, timestamp);
- form.ShowDialog();
- }
- }
- #endregion
- }
- }
|