QADashboard.xaml.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.Diagnostics;
  6. using System.Globalization;
  7. using System.Linq;
  8. using System.Linq.Expressions;
  9. using System.Reflection;
  10. using System.Text.RegularExpressions;
  11. using System.Threading;
  12. using System.Windows;
  13. using System.Windows.Controls;
  14. using System.Windows.Data;
  15. using System.Windows.Input;
  16. using Comal.Classes;
  17. using InABox.Clients;
  18. using InABox.Core;
  19. using InABox.DynamicGrid;
  20. using InABox.Reports;
  21. using InABox.Core.Reports;
  22. using InABox.WPF;
  23. using PRSDesktop.Forms;
  24. using PRSDesktop.WidgetGroups;
  25. using Syncfusion.UI.Xaml.Grid;
  26. using Syncfusion.UI.Xaml.Grid.Converter;
  27. using Syncfusion.Windows.Shared;
  28. using Syncfusion.XlsIO;
  29. using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
  30. using System.ComponentModel;
  31. namespace PRSDesktop
  32. {
  33. internal class MileStoneImageConverter : IValueConverter
  34. {
  35. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  36. {
  37. return Equals(value, DateTime.MinValue) ? null : Resources.milestone.AsBitmapImage();
  38. }
  39. public object ConvertBack(object value, Type targetType,
  40. object parameter, CultureInfo culture)
  41. {
  42. return null;
  43. }
  44. }
  45. /// <summary>
  46. /// Interaction logic for QADashboard.xaml
  47. /// </summary>
  48. public partial class QADashboard : UserControl, IPanel<DigitalForm>
  49. {
  50. private bool _changing;
  51. private DateTime _from;
  52. private string _search = "";
  53. private DateTime _to;
  54. private CoreTable allforms;
  55. private readonly Dictionary<string, string> QuestionCodes = new();
  56. public bool IsReady { get; set; }
  57. public event DataModelUpdateEvent OnUpdateDataModel;
  58. private static readonly Dictionary<Type, List<Tuple<string, string>>> parentColumns = new()
  59. {
  60. { typeof(Kanban), new() { new("Parent.Number", "Task No") } },
  61. { typeof(Job), new() { new("Parent.JobNumber", "Job No") } },
  62. { typeof(JobITP), new() { new("Parent.Code", "Code") } },
  63. { typeof(Assignment), new() { new("Parent.Number", "Ass. No") } },
  64. { typeof(TimeSheet), new() { } },
  65. { typeof(LeaveRequest), new() { } },
  66. { typeof(Employee), new() { new("Parent.Code", "Employee") } },
  67. { typeof(PurchaseOrderItem), new() { new("Parent.PONumber", "PO No") } },
  68. };
  69. private Type? parentType;
  70. private Type? formType;
  71. #region DataGrid Configuration
  72. private void DataGrid_AutoGeneratingColumn(object sender, AutoGeneratingColumnArgs e)
  73. {
  74. e.Column.TextAlignment = TextAlignment.Center;
  75. e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center;
  76. e.Column.ColumnSizer = GridLengthUnitType.None;
  77. var value = e.Column.ValueBinding as Binding;
  78. if (value.Path.Path.Equals("ID") || value.Path.Path.Equals("Form_ID") || value.Path.Path.Equals("Parent_ID") ||
  79. value.Path.Path.Equals("FormData") || value.Path.Path.Equals("Location_Latitude") || value.Path.Path.Equals("Location_Longitude"))
  80. {
  81. e.Cancel = true;
  82. }
  83. else if (value.Path.Path.Equals("Number"))
  84. {
  85. e.Column.Width = 80;
  86. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  87. }
  88. else if (value.Path.Path.Equals("Location_Timestamp"))
  89. {
  90. e.Column = new GridImageColumn();
  91. e.Column.Width = dataGrid.RowHeight;
  92. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  93. e.Column.HeaderText = "";
  94. e.Column.Padding = new Thickness(4);
  95. e.Column.ValueBinding = new Binding
  96. {
  97. Path = new PropertyPath(value.Path.Path),
  98. Converter = new MileStoneImageConverter()
  99. };
  100. e.Column.MappingName = "Location.Timestamp";
  101. }
  102. else if (parentColumns.TryGetValue(parentType, out var pColumns) && pColumns.Any(x => x.Item2.Equals(value.Path.Path)))
  103. {
  104. e.Column.ColumnSizer = GridLengthUnitType.Auto;
  105. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  106. }
  107. else if (value.Path.Path.Equals("Job No"))
  108. {
  109. e.Column.Width = 60;
  110. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  111. }
  112. else if (value.Path.Path.Equals("Description"))
  113. {
  114. e.Column.TextAlignment = TextAlignment.Left;
  115. e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Left;
  116. e.Column.Width = 450;
  117. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  118. }
  119. else if (value.Path.Path.Equals("Completed"))
  120. {
  121. e.Column.Width = 100;
  122. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  123. (e.Column as GridDateTimeColumn).Pattern = DateTimePattern.CustomPattern;
  124. (e.Column as GridDateTimeColumn).CustomPattern = "dd MMM yy hh:mm";
  125. }
  126. else if (value.Path.Path.Equals("Completed By"))
  127. {
  128. e.Column.Width = 100;
  129. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  130. }
  131. else if (value.Path.Path.Equals("Processed"))
  132. {
  133. e.Column.Width = 100;
  134. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  135. }
  136. else if (value.Path.Path.Equals("Created By"))
  137. {
  138. e.Column.Width = 100;
  139. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  140. }
  141. else if (value.Path.Path.Equals("Created"))
  142. {
  143. e.Column.Width = 100;
  144. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  145. (e.Column as GridDateTimeColumn).Pattern = DateTimePattern.CustomPattern;
  146. (e.Column as GridDateTimeColumn).CustomPattern = "dd MMM yy hh:mm";
  147. }
  148. else
  149. {
  150. var data = dataGrid.ItemsSource as DataTable;
  151. //int index = data.Columns.IndexOf(e.Column.MappingName) - 2;
  152. //Style style = new Style(typeof(GridCell));
  153. //e.Column.CellStyle = style;
  154. e.Column.Width = 100;
  155. e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style;
  156. e.Column.HeaderText = QuestionCodes[e.Column.MappingName];
  157. }
  158. }
  159. #endregion
  160. private Entity? GetEntityForm<T>(Guid id) where T : Entity, IDigitalFormInstance, IRemotable, IPersistent, new()
  161. {
  162. var columns = DynamicFormEditWindow.FormColumns<T>();
  163. return new Client<T>().Query(
  164. new Filter<T>(x => x.ID).IsEqualTo(id),
  165. columns).Rows.FirstOrDefault()?.ToObject<T>();
  166. }
  167. private void SaveEntityForm<T>(T entityForm) where T : Entity, IDigitalFormInstance, IRemotable, IPersistent, new()
  168. {
  169. new Client<T>().Save(entityForm, "Edited by user");
  170. }
  171. private void DataGrid_CellDoubleTapped(object sender, GridCellDoubleTappedEventArgs e)
  172. {
  173. if (e.RowColumnIndex.RowIndex == 0)
  174. return;
  175. var table = dataGrid.ItemsSource as DataTable;
  176. var formid = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["Form_ID"];
  177. var formdata = (string)table.Rows[e.RowColumnIndex.RowIndex - 1]["FormData"];
  178. var id = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["ID"];
  179. if (formType == null) return;
  180. IDigitalFormInstance? entityForm = null;
  181. Progress.ShowModal("Loading Form", (s) =>
  182. {
  183. entityForm = typeof(QADashboard)
  184. .GetMethod(nameof(GetEntityForm), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
  185. .MakeGenericMethod(formType)
  186. .Invoke(this, new object[] { id }) as IDigitalFormInstance;
  187. });
  188. if (entityForm != null)
  189. {
  190. if (DynamicFormEditWindow.EditDigitalForm(entityForm, out var dataModel))
  191. {
  192. dataModel.Update(null);
  193. /*typeof(QADashboard)
  194. .GetMethod(nameof(SaveEntityForm), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
  195. .MakeGenericMethod(formType)
  196. .Invoke(this, new object[] { entityForm });*/
  197. Refresh();
  198. }
  199. }
  200. /*
  201. var query = new MultiQuery();
  202. query.Add(
  203. new QueryDef<DigitalFormVariable>(
  204. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(formid),
  205. null,
  206. null
  207. ),
  208. typeof(DigitalFormVariable)
  209. );
  210. query.Add(
  211. new QueryDef<DigitalFormLayout>(
  212. new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(formid).And(x => x.Active).IsEqualTo(true),
  213. null,
  214. null
  215. ),
  216. typeof(DigitalFormLayout)
  217. );
  218. query.Query();
  219. var variables = query.Get(typeof(DigitalFormVariable)).Rows.Select(x => x.ToObject<DigitalFormVariable>());
  220. var layout = query.Get(typeof(DigitalFormLayout)).Rows.FirstOrDefault()?.ToObject<DigitalFormLayout>();
  221. if (layout == null)
  222. {
  223. MessageBox.Show("No Active Layouts Found!");
  224. return;
  225. }
  226. var form = new DynamicFormWindow();
  227. form.Designing = false;
  228. form.HideViewButton = true;
  229. form.ReadOnly = true;
  230. form.Variables = variables.ToArray();
  231. form.Type = layout.Type;
  232. var f = new DFLayout();
  233. if (!string.IsNullOrWhiteSpace(layout.Layout))
  234. {
  235. f.LoadLayout(layout.Layout);
  236. }
  237. else
  238. {
  239. f = new DFLayout();
  240. f.RowHeights.Add("Auto");
  241. f.ColumnWidths.AddRange(new[] { "*", "Auto" });
  242. }
  243. f.LoadVariables(variables);
  244. form.Form = f;
  245. if (!string.IsNullOrWhiteSpace(formdata))
  246. form.Values = Serialization.Deserialize<Dictionary<string, object>>(formdata);
  247. form.ShowDialog();*/
  248. }
  249. private void DataGrid_CellTapped(object sender, GridCellTappedEventArgs e)
  250. {
  251. if (e.RowColumnIndex.ColumnIndex == 0)
  252. {
  253. var timestamp = (DateTime)(e.Record as DataRowView).Row["Location_Timestamp"];
  254. var latitude = (double)(e.Record as DataRowView).Row["Location_Latitude"];
  255. var longitude = (double)(e.Record as DataRowView).Row["Location_Longitude"];
  256. var form = new MapForm(latitude, longitude, timestamp);
  257. form.ShowDialog();
  258. }
  259. }
  260. #region IPanel Interface
  261. public QADashboard()
  262. {
  263. _from = DateTime.Today;
  264. _to = DateTime.Today;
  265. InitializeComponent();
  266. SetDates(_from, _to, false);
  267. }
  268. public void CreateToolbarButtons(IPanelHost host)
  269. {
  270. }
  271. public void Setup()
  272. {
  273. var query = new MultiQuery();
  274. query.Add(
  275. new QueryDef<DigitalForm>(
  276. new Filter<DigitalForm>(x => x.Active).IsEqualTo(true),
  277. null,
  278. null
  279. ),
  280. typeof(DigitalForm)
  281. );
  282. query.Add(
  283. new QueryDef<Job>(
  284. LookupFactory.DefineFilter<Job>(),
  285. new Columns<Job>(x => x.ID, x => x.JobNumber, x => x.Name),
  286. null
  287. ),
  288. typeof(Job)
  289. );
  290. query.Query();
  291. allforms = query.Get(typeof(DigitalForm));
  292. var cats = new DigitalFormCategoryLookups(null);
  293. cats.OnAfterGenerateLookups += (sender, entries) => { entries.Insert(0, new LookupEntry("", "Select Category")); };
  294. Category.ItemsSource = cats.AsTable("AppliesTo").ToDictionary("AppliesTo", "Display");
  295. var jobs = query.Get(typeof(Job));
  296. var alljobs = jobs.NewRow();
  297. alljobs.Set<Job, Guid>(x => x.ID, Guid.Empty);
  298. alljobs.Set<Job, string>(x => x.JobNumber, "ALL");
  299. alljobs.Set<Job, string>(x => x.Name, "All Jobs");
  300. jobs.Rows.Insert(0, alljobs);
  301. Jobs.ItemsSource = jobs.ToDictionary(x => x.ID, new Expression<Func<Job, object>>[] { x => x.JobNumber, x => x.Name }, x => x.JobNumber);
  302. //Dictionary<Guid, String> joblist = new Dictionary<Guid, string>() { { Guid.Empty, "All Jobs" } };
  303. //CoreTable jobs = new Client<Job>().Query(
  304. // LookupFactory.DefineFilter<Job>(),
  305. // LookupFactory.DefineColumns<Job>(),
  306. // LookupFactory.DefineSort<Job>()
  307. //);
  308. //foreach (var row in jobs.Rows)
  309. //{
  310. // //if (row.Get<Employee, String>(x => x.Group.Description).Equals("FACTORY"))
  311. // joblist[row.Get<Job, Guid>(x => x.ID)] = String.Format("{0} - {1}", row.Get<Job, String>(x => x.JobNumber), row.Get<Job, String>(x => x.Name));
  312. //}
  313. //Jobs.ItemsSource = joblist;
  314. }
  315. public void Shutdown(CancelEventArgs? cancel)
  316. {
  317. }
  318. public string GetJobLink(string prefix, Type type)
  319. {
  320. var props = type.GetProperties().Where(x =>
  321. x.PropertyType.BaseType != null && x.PropertyType.BaseType.IsGenericType &&
  322. x.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(EntityLink<>));
  323. foreach (var prop in props)
  324. {
  325. if (prop.PropertyType == typeof(JobLink))
  326. return (string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name;
  327. var result = GetJobLink((string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name, prop.PropertyType);
  328. if (!string.IsNullOrEmpty(result))
  329. return result;
  330. }
  331. return "";
  332. }
  333. public Type CategoryToType(string category)
  334. {
  335. var instances = CoreUtils.TypeList(
  336. AppDomain.CurrentDomain.GetAssemblies(),
  337. x => !x.IsAbstract && x.GetInterfaces().Contains(typeof(IDigitalFormInstance))
  338. ).ToArray();
  339. foreach (var instance in instances)
  340. {
  341. var interfaces = instance.GetInterfaces()
  342. .Where(x => x.IsGenericType && x.GetGenericTypeDefinition().Equals(typeof(IDigitalFormInstance<>)));
  343. var links = interfaces.Select(x => x.GenericTypeArguments.First());
  344. var link = links.FirstOrDefault(l => l.GetInheritedGenericTypeArguments().Any(i => string.Equals(i.Name, category)));
  345. if (link != null)
  346. {
  347. return instance;
  348. }
  349. }
  350. return null;
  351. }
  352. public void Refresh()
  353. {
  354. Progress.Show("Refreshing");
  355. try
  356. {
  357. qaGrid.Clear();
  358. qaGrid.LoadChecks("", new QAQuestion[] { }, new Dictionary<Guid, object>());
  359. dataGrid.ItemsSource = null;
  360. var category = Category.SelectedValue as string;
  361. if (string.IsNullOrWhiteSpace(category))
  362. {
  363. DigitalFormsDock.Visibility = Visibility.Collapsed;
  364. qaGrid.Visibility = Visibility.Collapsed;
  365. dataGrid.Visibility = Visibility.Collapsed;
  366. return;
  367. }
  368. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  369. if (form.Key == Guid.Empty)
  370. {
  371. DigitalFormsDock.Visibility = Visibility.Collapsed;
  372. qaGrid.Visibility = Visibility.Collapsed;
  373. dataGrid.Visibility = Visibility.Collapsed;
  374. return;
  375. }
  376. var type = CategoryToType(category);
  377. if (type == null)
  378. return;
  379. formType = type;
  380. parentType = CoreUtils.TypeList(
  381. AppDomain.CurrentDomain.GetAssemblies(),
  382. x => !x.IsAbstract && string.Equals(x.Name, category)
  383. ).FirstOrDefault();
  384. var parentcols = LookupFactory.DefineColumns(parentType);
  385. Progress.SetMessage("Loading Data");
  386. var jobid = Jobs.SelectedValue != null ? (Guid)Jobs.SelectedValue : Guid.Empty;
  387. var isEntityForm = type.IsSubclassOfRawGeneric(typeof(EntityForm<,,>));
  388. var query = new MultiQuery();
  389. query.Add(
  390. new QueryDef<QAQuestion>(
  391. new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(form.Key),
  392. null,
  393. null
  394. ),
  395. typeof(QAQuestion)
  396. );
  397. query.Add(
  398. new QueryDef<DigitalFormVariable>(
  399. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(form.Key),
  400. null,
  401. new SortOrder<DigitalFormVariable>(x => x.Sequence)
  402. ),
  403. typeof(DigitalFormVariable)
  404. );
  405. var columns = LookupFactory.DefineColumns(type);
  406. var sort = LookupFactory.DefineSort(type);
  407. var JobLink = GetJobLink("", type);
  408. var filtertype = typeof(Filter<>).MakeGenericType(type);
  409. var filter = Activator.CreateInstance(typeof(Filter<>).MakeGenericType(type));
  410. CoreUtils.SetPropertyValue(filter, "Expression", CoreUtils.GetMemberExpression(type, "FormCompleted"));
  411. CoreUtils.SetPropertyValue(filter, "Operator", Operator.IsGreaterThanOrEqualTo);
  412. CoreUtils.SetPropertyValue(filter, "Value", _from);
  413. var ands = filtertype.GetProperty("Ands").GetValue(filter) as IList;
  414. var to = Activator.CreateInstance(filtertype);
  415. CoreUtils.SetPropertyValue(to, "Expression", CoreUtils.GetMemberExpression(type, "FormCompleted"));
  416. CoreUtils.SetPropertyValue(to, "Operator", Operator.IsLessThan);
  417. CoreUtils.SetPropertyValue(to, "Value", _to.AddDays(1));
  418. ands.Add(to);
  419. var formid = Activator.CreateInstance(filtertype);
  420. CoreUtils.SetPropertyValue(formid, "Expression", CoreUtils.GetMemberExpression(type, "Form.ID"));
  421. CoreUtils.SetPropertyValue(formid, "Operator", Operator.IsEqualTo);
  422. CoreUtils.SetPropertyValue(formid, "Value", form.Key);
  423. ands.Add(formid);
  424. if (jobid != Guid.Empty)
  425. {
  426. var job = Activator.CreateInstance(filtertype);
  427. CoreUtils.SetPropertyValue(job, "Expression", CoreUtils.GetMemberExpression(type, JobLink + ".ID"));
  428. CoreUtils.SetPropertyValue(job, "Operator", Operator.IsEqualTo);
  429. CoreUtils.SetPropertyValue(job, "Value", jobid);
  430. ands.Add(job);
  431. }
  432. var colstype = typeof(Columns<>).MakeGenericType(type);
  433. var cols = Activator.CreateInstance(colstype) as IColumns;
  434. cols.Add("ID");
  435. cols.Add("Number");
  436. cols.Add("CreatedBy");
  437. cols.Add("Created");
  438. foreach (var col in parentcols.ColumnNames())
  439. cols.Add("Parent." + col);
  440. if(parentColumns.TryGetValue(parentType, out var pColumns))
  441. {
  442. foreach(var (field, name) in pColumns)
  443. {
  444. cols.Add(field);
  445. }
  446. }
  447. cols.Add("Form.ID");
  448. cols.Add("FormData");
  449. cols.Add("FormCompleted");
  450. cols.Add("FormCompletedBy.UserID");
  451. if(isEntityForm)
  452. cols.Add("Processed");
  453. cols.Add("Location.Timestamp");
  454. cols.Add("Location.Latitude");
  455. cols.Add("Location.Longitude");
  456. if (!string.IsNullOrWhiteSpace(JobLink))
  457. cols.Add(JobLink + ".JobNumber");
  458. var querytype = typeof(QueryDef<>).MakeGenericType(type);
  459. query.Add(Activator.CreateInstance(querytype, filter, cols, sort) as IQueryDef, type);
  460. if(parentType == typeof(JobITP))
  461. {
  462. query.Add(
  463. new Filter<JobITP>(x => x.ID).InQuery(filter as Filter<JobITPForm>, x => x.Parent.ID),
  464. new Columns<JobITP>(x => x.ID, x => x.Job.JobNumber));
  465. }
  466. query.Query();
  467. var questions =
  468. query.Get(typeof(QAQuestion)); // new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.QAForm.ID).IsEqualTo(form.Key));
  469. var variables = query.Get(typeof(DigitalFormVariable)).Rows.Select(x => x.ToObject<DigitalFormVariable>()).ToArray();
  470. var formdata = query.Get(type);
  471. var data = new DataTable();
  472. data.Columns.Add("ID", typeof(Guid));
  473. data.Columns.Add("Form_ID", typeof(Guid));
  474. data.Columns.Add("Parent_ID", typeof(Guid));
  475. data.Columns.Add("Location_Timestamp", typeof(DateTime));
  476. data.Columns.Add("Location_Latitude", typeof(double));
  477. data.Columns.Add("Location_Longitude", typeof(double));
  478. data.Columns.Add("FormData", typeof(string));
  479. data.Columns.Add("Number", typeof(String));
  480. if (parentType == typeof(JobITP))
  481. {
  482. data.Columns.Add("Job No", typeof(string));
  483. }
  484. if (pColumns != null)
  485. {
  486. foreach (var (field, name) in pColumns)
  487. {
  488. data.Columns.Add(name, typeof(string));
  489. }
  490. }
  491. data.Columns.Add("Description", typeof(string));
  492. data.Columns.Add("Created", typeof(DateTime));
  493. data.Columns.Add("Created By", typeof(string));
  494. data.Columns.Add("Completed", typeof(DateTime));
  495. data.Columns.Add("Completed By", typeof(string));
  496. if (isEntityForm)
  497. data.Columns.Add("Processed", typeof(bool));
  498. if (variables.Any())
  499. {
  500. foreach (var variable in variables)
  501. {
  502. var code = variable.Code.Replace("/", " ");
  503. QuestionCodes[code] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(code.ToLower());
  504. data.Columns.Add(code, typeof(string));
  505. }
  506. }
  507. else if (questions.Rows.Any())
  508. {
  509. Progress.SetMessage("Loading Checks");
  510. qaGrid.Clear();
  511. qaGrid.LoadChecks(form.Value, questions.Rows.Select(x => x.ToObject<QAQuestion>()), new Dictionary<Guid, object>());
  512. qaGrid.CollapseMargins();
  513. var i = 1;
  514. foreach (var row in questions.Rows)
  515. {
  516. var id = row.Get<QAQuestion, Guid>(x => x.ID).ToString();
  517. if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
  518. {
  519. data.Columns.Add(id, typeof(string));
  520. var code = row.Get<QAQuestion, string>(x => x.Code);
  521. QuestionCodes[id] = string.IsNullOrEmpty(code) ? string.Format("{0}.", i) : code;
  522. i++;
  523. }
  524. }
  525. }
  526. foreach (var row in formdata.Rows)
  527. {
  528. var qadata = row["FormData"] != null ? row["FormData"].ToString() : "";
  529. if (!string.IsNullOrWhiteSpace(qadata))
  530. {
  531. var datarow = data.NewRow();
  532. datarow["ID"] = (Guid)row["ID"];
  533. datarow["Form_ID"] = (Guid)row["Form.ID"];
  534. datarow["Parent_ID"] = (Guid)row["Parent.ID"];
  535. datarow["Location_Timestamp"] = (DateTime)row["Location.Timestamp"];
  536. datarow["Location_Latitude"] = (double)row["Location.Latitude"];
  537. datarow["Location_Longitude"] = (double)row["Location.Longitude"];
  538. datarow["FormData"] = (string)row["FormData"];
  539. datarow["Number"] = (string)row["Number"];
  540. var desc = new List<string>();
  541. foreach (var col in parentcols.ColumnNames().Where(x => x != "ID"))
  542. {
  543. var val = row["Parent." + col];
  544. if (val != null && val.GetType() != typeof(Guid))
  545. desc.Add(val.ToString());
  546. }
  547. datarow["Description"] = string.Join(" : ", desc);
  548. datarow["Created By"] = (string)row["CreatedBy"];
  549. datarow["Created"] = (DateTime)row["Created"];
  550. datarow["Completed"] = (DateTime)row["FormCompleted"];
  551. datarow["Completed By"] = (string)row["FormCompletedBy.UserID"];
  552. if (isEntityForm)
  553. datarow["Processed"] = (bool)row["Processed"];
  554. if(parentType == typeof(JobITP))
  555. {
  556. var jobITP = query.Get<JobITP>().Rows.FirstOrDefault(x => (Guid)x["ID"] == (Guid)row["Parent.ID"]);
  557. datarow["Job No"] = jobITP?["Job.JobNumber"];
  558. }
  559. if (pColumns != null)
  560. {
  561. foreach (var (field, name) in pColumns)
  562. {
  563. datarow[name] = row[field].ToString();
  564. }
  565. }
  566. //datarow["Job No"] = (String)row[JobLink + ".JobNumber"];
  567. var bHasData = false;
  568. if (variables.Any())
  569. {
  570. var dict = Serialization.Deserialize<Dictionary<string, object?>>(qadata);
  571. if (dict is not null)
  572. {
  573. var storage = new DFLoadStorage(dict, null);
  574. foreach(var variable in variables)
  575. {
  576. var value = variable.Deserialize(storage.GetEntry(variable.Code));
  577. var format = variable.FormatValue(value);
  578. var sKey = variable.Code.Replace("/", " ");
  579. if (data.Columns.Contains(sKey))
  580. {
  581. datarow[sKey] = format;
  582. bHasData = true;
  583. }
  584. }
  585. }
  586. }
  587. else
  588. {
  589. var dict = Serialization.Deserialize<Dictionary<Guid, object>>(qadata);
  590. foreach (var key in dict.Keys)
  591. if (data.Columns.Contains(key.ToString()))
  592. {
  593. datarow[key.ToString()] = dict[key];
  594. bHasData = true;
  595. }
  596. }
  597. if (bHasData)
  598. data.Rows.Add(datarow);
  599. }
  600. }
  601. dataGrid.ItemsSource = data;
  602. qaGrid.Visibility = !variables.Any() && questions.Rows.Any() ? Visibility.Visible : Visibility.Collapsed;
  603. dataGrid.Visibility = Visibility.Visible;
  604. }
  605. finally
  606. {
  607. Progress.Close();
  608. }
  609. }
  610. public string? SectionName
  611. {
  612. get {
  613. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  614. if (Category.SelectedValue != null && form.Key != Guid.Empty)
  615. {
  616. return form.Key.ToString();
  617. }
  618. return "Digital Forms";
  619. }
  620. }
  621. public DataModel DataModel(Selection selection)
  622. {
  623. if ((Form.SelectedItem == null) || (String.IsNullOrWhiteSpace(Category.SelectedValue as String)))
  624. return new AutoDataModel<DigitalForm>(new Filter<DigitalForm>().None());
  625. Type formtype = CategoryToType(Category.SelectedValue as String);
  626. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  627. if (formtype != null && (form.Key != Guid.Empty))
  628. {
  629. IFilter filter;
  630. switch (selection)
  631. {
  632. case Selection.Selected:
  633. var formids = dataGrid.SelectedItems.Select(x => (Guid)(x as DataRowView).Row["ID"]).ToArray();
  634. filter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(formtype)) as IFilter)!;
  635. filter.Expression = CoreUtils.CreateMemberExpression(formtype, "ID");
  636. filter.Operator = Operator.InList;
  637. filter.Value = formids;
  638. break;
  639. case Selection.All:
  640. filter = Filter.Create(formtype).All();
  641. break;
  642. case Selection.None:
  643. default:
  644. filter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(formtype)) as IFilter)!.None();
  645. break;
  646. }
  647. return (Activator.CreateInstance(typeof(DigitalFormReportDataModel<>)!
  648. .MakeGenericType(formtype), new object?[] { filter, form.Key }) as DataModel)!;
  649. }
  650. return new AutoDataModel<DigitalForm>(new Filter<DigitalForm>().None());
  651. }
  652. public Dictionary<string, object[]> Selected()
  653. {
  654. return new Dictionary<string, object[]>();
  655. }
  656. public void Heartbeat(TimeSpan time)
  657. {
  658. }
  659. #endregion
  660. #region Toolbar Handling
  661. private void Category_SelectionChanged(object sender, SelectionChangedEventArgs e)
  662. {
  663. _changing = true;
  664. var category = Category.SelectedValue as string;
  665. var type = CategoryToType(category);
  666. var JobLink = type != null ? GetJobLink("", type) : "";
  667. if (string.IsNullOrWhiteSpace(JobLink))
  668. {
  669. Jobs.SelectedValue = Guid.Empty;
  670. Jobs.IsEnabled = false;
  671. }
  672. else
  673. {
  674. Jobs.IsEnabled = true;
  675. }
  676. var forms = new Dictionary<Guid, string> { { Guid.Empty, "" } };
  677. if (!string.IsNullOrWhiteSpace(category))
  678. {
  679. forms[Guid.Empty] = "Select Form";
  680. var rows = allforms.Rows.Where(r => string.Equals(r.Get<DigitalForm, string>(c => c.AppliesTo), category));
  681. foreach (var row in rows)
  682. forms[row.Get<DigitalForm, Guid>(x => x.ID)] = row.Get<DigitalForm, string>(x => x.Description);
  683. }
  684. Form.ItemsSource = forms;
  685. _changing = false;
  686. Form.SelectedIndex = 0;
  687. Form.IsEnabled = !string.IsNullOrWhiteSpace(category);
  688. OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
  689. }
  690. private void Form_SelectionChanged(object sender, SelectionChangedEventArgs e)
  691. {
  692. if (IsReady && !_changing)
  693. {
  694. Refresh();
  695. OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
  696. }
  697. }
  698. private void Jobs_SelectionChanged(object sender, SelectionChangedEventArgs e)
  699. {
  700. if (IsReady && !_changing)
  701. Refresh();
  702. }
  703. private int WeekDay(DateTime date)
  704. {
  705. if (date.DayOfWeek == DayOfWeek.Sunday)
  706. return 7;
  707. return (int)date.DayOfWeek - 1;
  708. }
  709. private void SetDates(DateTime? from, DateTime? to, bool enable)
  710. {
  711. if (_changing)
  712. return;
  713. _changing = true;
  714. _from = from.HasValue ? from.Value : DateTime.Today;
  715. FromDate.SelectedDate = from;
  716. FromDate.IsEnabled = enable;
  717. _to = to.HasValue ? to.Value : DateTime.Today;
  718. ToDate.SelectedDate = to;
  719. ToDate.IsEnabled = enable;
  720. _changing = false;
  721. if (!enable)
  722. Refresh();
  723. }
  724. private void DateRange_SelectionChanged(object sender, SelectionChangedEventArgs e)
  725. {
  726. if (!IsReady)
  727. return;
  728. if (DateRange.SelectedIndex == 0) // Week To Date
  729. SetDates(DateTime.Today, DateTime.Today, false);
  730. else if (DateRange.SelectedIndex == 1) // Week To Date
  731. SetDates(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(-1), false);
  732. else if (DateRange.SelectedIndex == 2) // Week To Date
  733. SetDates(DateTime.Today.AddDays(0 - WeekDay(DateTime.Today)), DateTime.Today, false);
  734. else if (DateRange.SelectedIndex == 3) // Last 7 Days
  735. SetDates(DateTime.Today.AddDays(-6), DateTime.Today, false);
  736. else if (DateRange.SelectedIndex == 4) // Month To Date
  737. SetDates(new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1), DateTime.Today, false);
  738. else if (DateRange.SelectedIndex == 5) // Last 30 days
  739. SetDates(DateTime.Today.AddDays(-29), DateTime.Today, false);
  740. else if (DateRange.SelectedIndex == 6) // Year To Date
  741. SetDates(new DateTime(DateTime.Today.Year, 1, 1), DateTime.Today, false);
  742. else if (DateRange.SelectedIndex == 7) // Last 12 Months
  743. SetDates(DateTime.Today.AddYears(-1).AddDays(1), DateTime.Today, false);
  744. else if (DateRange.SelectedIndex == 8) // Custom
  745. SetDates(FromDate.SelectedDate.Value, ToDate.SelectedDate.Value, true);
  746. }
  747. private void FromDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  748. {
  749. if (IsReady && !_changing)
  750. {
  751. _from = FromDate.SelectedDate.Value.Date;
  752. Refresh();
  753. }
  754. }
  755. private void ToDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  756. {
  757. if (IsReady && !_changing)
  758. {
  759. _to = ToDate.SelectedDate.Value.Date;
  760. Refresh();
  761. }
  762. }
  763. private void Search_KeyUp(object sender, KeyEventArgs e)
  764. {
  765. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return)
  766. {
  767. _search = Search.Text;
  768. Refresh();
  769. }
  770. }
  771. private void Export_Click(object sender, RoutedEventArgs e)
  772. {
  773. var cat = Category.SelectedValue as string;
  774. //KeyValuePair<Type, String> cat = (KeyValuePair<Type, String>)Category.SelectedItem;
  775. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  776. var formname = Regex.Replace(form.Value, "[^ a-zA-Z0-9]", string.Empty);
  777. var filename = string.Format("{0} - {1} - {2:yyyy-MM-dd} - {3:yyyy-MM-dd}.xlsx", cat, formname, FromDate.SelectedDate,
  778. ToDate.SelectedDate);
  779. var options = new ExcelExportingOptions();
  780. options.ExcelVersion = ExcelVersion.Excel2013;
  781. options.ExportStackedHeaders = true;
  782. var excelEngine = dataGrid.ExportToExcel(dataGrid.View, options);
  783. var workBook = excelEngine.Excel.Workbooks[0];
  784. var sheet = workBook.Worksheets[0];
  785. sheet.Name = "Summary";
  786. sheet.UsedRange.AutofitRows();
  787. sheet.UsedRange.AutofitColumns();
  788. sheet = workBook.Worksheets.Create("Questions");
  789. sheet.Move(0);
  790. var questions = new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(form.Key));
  791. sheet.Range[1, 1].Text = form.Value;
  792. sheet.Range[1, 1, 1, 3].Merge();
  793. var i = 1;
  794. foreach (var row in questions.Rows)
  795. if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
  796. {
  797. sheet.Range[i + 2, 1].Text = string.Format("{0}.", i);
  798. sheet.Range[i + 2, 2].Text = string.Format("{0}", row.Get<QAQuestion, string>(x => x.Question));
  799. sheet.Range[i + 2, 3].Text = string.Format("[{0}]", row.Get<QAQuestion, string>(x => x.Code));
  800. i++;
  801. }
  802. sheet.UsedRange.AutofitRows();
  803. sheet.UsedRange.AutofitColumns();
  804. try
  805. {
  806. workBook.SaveAs(filename);
  807. var startInfo = new ProcessStartInfo(filename);
  808. startInfo.Verb = "open";
  809. startInfo.UseShellExecute = true;
  810. Process.Start(startInfo);
  811. }
  812. catch
  813. {
  814. MessageBox.Show(string.Format("Unable to Save/Launch [{0}]!\n\nIs the file already open?", filename));
  815. }
  816. }
  817. #endregion
  818. }
  819. }