QADashboard.xaml.cs 37 KB

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