QADashboard.xaml.cs 37 KB

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