QADashboard.xaml.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  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 = new Columns<T>(x => x.ID)
  145. .Add(x => x.FormCompleted)
  146. .Add(x => x.FormData)
  147. .Add(x => x.Form.ID)
  148. .Add(x => x.Form.Description);
  149. if (typeof(T).HasInterface(typeof(IDigitalFormInstance<>)))
  150. {
  151. columns.Add("Parent.ID");
  152. }
  153. return new Client<T>().Query(
  154. new Filter<T>(x => x.ID).IsEqualTo(id),
  155. columns).Rows.FirstOrDefault()?.ToObject<T>();
  156. }
  157. private void SaveEntityForm<T>(T entityForm) where T : Entity, IDigitalFormInstance, IRemotable, IPersistent, new()
  158. {
  159. new Client<T>().Save(entityForm, "Edited by user");
  160. }
  161. private void DataGrid_CellDoubleTapped(object sender, GridCellDoubleTappedEventArgs e)
  162. {
  163. if (e.RowColumnIndex.RowIndex == 0)
  164. return;
  165. var table = dataGrid.ItemsSource as DataTable;
  166. var formid = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["Form_ID"];
  167. var formdata = (string)table.Rows[e.RowColumnIndex.RowIndex - 1]["FormData"];
  168. var id = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["ID"];
  169. if (formType == null) return;
  170. var entityForm = typeof(QADashboard)
  171. .GetMethod(nameof(GetEntityForm), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
  172. .MakeGenericMethod(formType)
  173. .Invoke(this, new object[] { id }) as IDigitalFormInstance;
  174. if (entityForm != null)
  175. {
  176. if (DynamicFormEditWindow.EditDigitalForm(entityForm, out var dataModel))
  177. {
  178. dataModel.Update(null);
  179. /*typeof(QADashboard)
  180. .GetMethod(nameof(SaveEntityForm), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!
  181. .MakeGenericMethod(formType)
  182. .Invoke(this, new object[] { entityForm });*/
  183. Refresh();
  184. }
  185. }
  186. /*
  187. var query = new MultiQuery();
  188. query.Add(
  189. new QueryDef<DigitalFormVariable>(
  190. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(formid),
  191. null,
  192. null
  193. ),
  194. typeof(DigitalFormVariable)
  195. );
  196. query.Add(
  197. new QueryDef<DigitalFormLayout>(
  198. new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(formid).And(x => x.Active).IsEqualTo(true),
  199. null,
  200. null
  201. ),
  202. typeof(DigitalFormLayout)
  203. );
  204. query.Query();
  205. var variables = query.Get(typeof(DigitalFormVariable)).Rows.Select(x => x.ToObject<DigitalFormVariable>());
  206. var layout = query.Get(typeof(DigitalFormLayout)).Rows.FirstOrDefault()?.ToObject<DigitalFormLayout>();
  207. if (layout == null)
  208. {
  209. MessageBox.Show("No Active Layouts Found!");
  210. return;
  211. }
  212. var form = new DynamicFormWindow();
  213. form.Designing = false;
  214. form.HideViewButton = true;
  215. form.ReadOnly = true;
  216. form.Variables = variables.ToArray();
  217. form.Type = layout.Type;
  218. var f = new DFLayout();
  219. if (!string.IsNullOrWhiteSpace(layout.Layout))
  220. {
  221. f.LoadLayout(layout.Layout);
  222. }
  223. else
  224. {
  225. f = new DFLayout();
  226. f.RowHeights.Add("Auto");
  227. f.ColumnWidths.AddRange(new[] { "*", "Auto" });
  228. }
  229. f.LoadVariables(variables);
  230. form.Form = f;
  231. if (!string.IsNullOrWhiteSpace(formdata))
  232. form.Values = Serialization.Deserialize<Dictionary<string, object>>(formdata);
  233. form.ShowDialog();*/
  234. }
  235. private void DataGrid_CellTapped(object sender, GridCellTappedEventArgs e)
  236. {
  237. if (e.RowColumnIndex.ColumnIndex == 0)
  238. {
  239. var timestamp = (DateTime)(e.Record as DataRowView).Row["Location_Timestamp"];
  240. var latitude = (double)(e.Record as DataRowView).Row["Location_Latitude"];
  241. var longitude = (double)(e.Record as DataRowView).Row["Location_Longitude"];
  242. var form = new MapForm(latitude, longitude, timestamp);
  243. form.ShowDialog();
  244. }
  245. }
  246. #region IPanel Interface
  247. public QADashboard()
  248. {
  249. _from = DateTime.Today;
  250. _to = DateTime.Today;
  251. InitializeComponent();
  252. SetDates(_from, _to, false);
  253. }
  254. public void CreateToolbarButtons(IPanelHost host)
  255. {
  256. }
  257. public void Setup()
  258. {
  259. var query = new MultiQuery();
  260. query.Add(
  261. new QueryDef<DigitalForm>(
  262. new Filter<DigitalForm>(x => x.Active).IsEqualTo(true),
  263. null,
  264. null
  265. ),
  266. typeof(DigitalForm)
  267. );
  268. query.Add(
  269. new QueryDef<Job>(
  270. LookupFactory.DefineFilter<Job>(),
  271. new Columns<Job>(x => x.ID, x => x.JobNumber, x => x.Name),
  272. null
  273. ),
  274. typeof(Job)
  275. );
  276. query.Query();
  277. allforms = query.Get(typeof(DigitalForm));
  278. var cats = new DigitalFormCategoryLookups(null);
  279. cats.OnAfterGenerateLookups += (sender, entries) => { entries.Insert(0, new LookupEntry("", "Select Category")); };
  280. Category.ItemsSource = cats.AsTable("AppliesTo").ToDictionary("AppliesTo", "Display");
  281. var jobs = query.Get(typeof(Job));
  282. var alljobs = jobs.NewRow();
  283. alljobs.Set<Job, Guid>(x => x.ID, Guid.Empty);
  284. alljobs.Set<Job, string>(x => x.JobNumber, "ALL");
  285. alljobs.Set<Job, string>(x => x.Name, "All Jobs");
  286. jobs.Rows.Insert(0, alljobs);
  287. Jobs.ItemsSource = jobs.ToDictionary(x => x.ID, new Expression<Func<Job, object>>[] { x => x.JobNumber, x => x.Name }, x => x.JobNumber);
  288. //Dictionary<Guid, String> joblist = new Dictionary<Guid, string>() { { Guid.Empty, "All Jobs" } };
  289. //CoreTable jobs = new Client<Job>().Query(
  290. // LookupFactory.DefineFilter<Job>(),
  291. // LookupFactory.DefineColumns<Job>(),
  292. // LookupFactory.DefineSort<Job>()
  293. //);
  294. //foreach (var row in jobs.Rows)
  295. //{
  296. // //if (row.Get<Employee, String>(x => x.Group.Description).Equals("FACTORY"))
  297. // 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));
  298. //}
  299. //Jobs.ItemsSource = joblist;
  300. }
  301. public void Shutdown()
  302. {
  303. }
  304. public string GetJobLink(string prefix, Type type)
  305. {
  306. var props = type.GetProperties().Where(x =>
  307. x.PropertyType.BaseType != null && x.PropertyType.BaseType.IsGenericType &&
  308. x.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(EntityLink<>));
  309. foreach (var prop in props)
  310. {
  311. if (prop.PropertyType == typeof(JobLink))
  312. return (string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name;
  313. var result = GetJobLink((string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name, prop.PropertyType);
  314. if (!string.IsNullOrEmpty(result))
  315. return result;
  316. }
  317. return "";
  318. }
  319. public Type CategoryToType(string category)
  320. {
  321. var instances = CoreUtils.TypeList(
  322. AppDomain.CurrentDomain.GetAssemblies(),
  323. x => !x.IsAbstract && x.GetInterfaces().Contains(typeof(IDigitalFormInstance))
  324. ).ToArray();
  325. foreach (var instance in instances)
  326. {
  327. var interfaces = instance.GetInterfaces()
  328. .Where(x => x.IsGenericType && x.GetGenericTypeDefinition().Equals(typeof(IDigitalFormInstance<>)));
  329. var links = interfaces.Select(x => x.GenericTypeArguments.First());
  330. var link = links.FirstOrDefault(l => l.GetInheritedGenericTypeArguments().Any(i => string.Equals(i.Name, category)));
  331. if (link != null)
  332. {
  333. return instance;
  334. break;
  335. }
  336. }
  337. return null;
  338. }
  339. public void Refresh()
  340. {
  341. Progress.Show("Refreshing");
  342. try
  343. {
  344. qaGrid.Clear();
  345. qaGrid.LoadChecks("", new QAQuestion[] { }, new Dictionary<Guid, object>());
  346. dataGrid.ItemsSource = null;
  347. var category = Category.SelectedValue as string;
  348. if (string.IsNullOrWhiteSpace(category))
  349. {
  350. DigitalFormsDock.Visibility = Visibility.Collapsed;
  351. qaGrid.Visibility = Visibility.Collapsed;
  352. dataGrid.Visibility = Visibility.Collapsed;
  353. return;
  354. }
  355. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  356. if (form.Key == Guid.Empty)
  357. {
  358. DigitalFormsDock.Visibility = Visibility.Collapsed;
  359. qaGrid.Visibility = Visibility.Collapsed;
  360. dataGrid.Visibility = Visibility.Collapsed;
  361. return;
  362. }
  363. var type = CategoryToType(category);
  364. if (type == null)
  365. return;
  366. formType = type;
  367. parentType = CoreUtils.TypeList(
  368. AppDomain.CurrentDomain.GetAssemblies(),
  369. x => !x.IsAbstract && string.Equals(x.Name, category)
  370. ).FirstOrDefault();
  371. var parentcols = LookupFactory.DefineColumns(parentType);
  372. Progress.SetMessage("Loading Data");
  373. var jobid = Jobs.SelectedValue != null ? (Guid)Jobs.SelectedValue : Guid.Empty;
  374. var isEntityForm = type.IsSubclassOfRawGeneric(typeof(EntityForm<,>));
  375. var query = new MultiQuery();
  376. query.Add(
  377. new QueryDef<QAQuestion>(
  378. new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(form.Key),
  379. null,
  380. null
  381. ),
  382. typeof(QAQuestion)
  383. );
  384. query.Add(
  385. new QueryDef<DigitalFormVariable>(
  386. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(form.Key),
  387. null,
  388. new SortOrder<DigitalFormVariable>(x => x.Sequence)
  389. ),
  390. typeof(DigitalFormVariable)
  391. );
  392. var columns = LookupFactory.DefineColumns(type);
  393. var sort = LookupFactory.DefineSort(type);
  394. var JobLink = GetJobLink("", type);
  395. var filtertype = typeof(Filter<>).MakeGenericType(type);
  396. var filter = Activator.CreateInstance(typeof(Filter<>).MakeGenericType(type));
  397. CoreUtils.SetPropertyValue(filter, "Expression", CoreUtils.GetMemberExpression(type, "FormCompleted"));
  398. CoreUtils.SetPropertyValue(filter, "Operator", Operator.IsGreaterThanOrEqualTo);
  399. CoreUtils.SetPropertyValue(filter, "Value", _from);
  400. var ands = filtertype.GetProperty("Ands").GetValue(filter) as IList;
  401. var to = Activator.CreateInstance(filtertype);
  402. CoreUtils.SetPropertyValue(to, "Expression", CoreUtils.GetMemberExpression(type, "FormCompleted"));
  403. CoreUtils.SetPropertyValue(to, "Operator", Operator.IsLessThan);
  404. CoreUtils.SetPropertyValue(to, "Value", _to.AddDays(1));
  405. ands.Add(to);
  406. var formid = Activator.CreateInstance(filtertype);
  407. CoreUtils.SetPropertyValue(formid, "Expression", CoreUtils.GetMemberExpression(type, "Form.ID"));
  408. CoreUtils.SetPropertyValue(formid, "Operator", Operator.IsEqualTo);
  409. CoreUtils.SetPropertyValue(formid, "Value", form.Key);
  410. ands.Add(formid);
  411. if (jobid != Guid.Empty)
  412. {
  413. var job = Activator.CreateInstance(filtertype);
  414. CoreUtils.SetPropertyValue(job, "Expression", CoreUtils.GetMemberExpression(type, JobLink + ".ID"));
  415. CoreUtils.SetPropertyValue(job, "Operator", Operator.IsEqualTo);
  416. CoreUtils.SetPropertyValue(job, "Value", jobid);
  417. ands.Add(job);
  418. }
  419. var colstype = typeof(Columns<>).MakeGenericType(type);
  420. var cols = Activator.CreateInstance(colstype) as IColumns;
  421. cols.Add("ID");
  422. foreach (var col in parentcols.ColumnNames())
  423. cols.Add("Parent." + col);
  424. if(parentColumns.TryGetValue(parentType, out var pColumns))
  425. {
  426. foreach(var (field, name) in pColumns)
  427. {
  428. cols.Add(field);
  429. }
  430. }
  431. cols.Add("Form.ID");
  432. cols.Add("FormData");
  433. cols.Add("FormCompleted");
  434. cols.Add("FormCompletedBy.UserID");
  435. if(isEntityForm)
  436. cols.Add("Processed");
  437. cols.Add("Location.Timestamp");
  438. cols.Add("Location.Latitude");
  439. cols.Add("Location.Longitude");
  440. if (!string.IsNullOrWhiteSpace(JobLink))
  441. cols.Add(JobLink + ".JobNumber");
  442. var querytype = typeof(QueryDef<>).MakeGenericType(type);
  443. query.Add(Activator.CreateInstance(querytype, filter, cols, sort) as IQueryDef, type);
  444. if(parentType == typeof(JobITP))
  445. {
  446. query.Add(
  447. new Filter<JobITP>(x => x.ID).InQuery(filter as Filter<JobITPForm>, x => x.Parent.ID),
  448. new Columns<JobITP>(x => x.ID, x => x.Job.JobNumber));
  449. }
  450. query.Query();
  451. var questions =
  452. query.Get(typeof(QAQuestion)); // new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.QAForm.ID).IsEqualTo(form.Key));
  453. var variables = query.Get(typeof(DigitalFormVariable)).Rows.Select(x => x.ToObject<DigitalFormVariable>()).ToArray();
  454. var formdata = query.Get(type);
  455. var data = new DataTable();
  456. data.Columns.Add("ID", typeof(Guid));
  457. data.Columns.Add("Form_ID", typeof(Guid));
  458. data.Columns.Add("Parent_ID", typeof(Guid));
  459. data.Columns.Add("Location_Timestamp", typeof(DateTime));
  460. data.Columns.Add("Location_Latitude", typeof(double));
  461. data.Columns.Add("Location_Longitude", typeof(double));
  462. data.Columns.Add("FormData", typeof(string));
  463. if (parentType == typeof(JobITP))
  464. {
  465. data.Columns.Add("Job No", typeof(string));
  466. }
  467. if (pColumns != null)
  468. {
  469. foreach (var (field, name) in pColumns)
  470. {
  471. data.Columns.Add(name, typeof(string));
  472. }
  473. }
  474. data.Columns.Add("Description", typeof(string));
  475. data.Columns.Add("Completed", typeof(DateTime));
  476. data.Columns.Add("Completed By", typeof(string));
  477. if(isEntityForm)
  478. data.Columns.Add("Processed", typeof(bool));
  479. if (variables.Any())
  480. {
  481. foreach (var variable in variables)
  482. {
  483. var code = variable.Code.Replace("/", " ");
  484. QuestionCodes[code] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(code.ToLower());
  485. data.Columns.Add(code, typeof(string));
  486. }
  487. }
  488. else if (questions.Rows.Any())
  489. {
  490. Progress.SetMessage("Loading Checks");
  491. qaGrid.Clear();
  492. qaGrid.LoadChecks(form.Value, questions.Rows.Select(x => x.ToObject<QAQuestion>()), new Dictionary<Guid, object>());
  493. qaGrid.CollapseMargins();
  494. var i = 1;
  495. foreach (var row in questions.Rows)
  496. {
  497. var id = row.Get<QAQuestion, Guid>(x => x.ID).ToString();
  498. if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
  499. {
  500. data.Columns.Add(id, typeof(string));
  501. var code = row.Get<QAQuestion, string>(x => x.Code);
  502. QuestionCodes[id] = string.IsNullOrEmpty(code) ? string.Format("{0}.", i) : code;
  503. i++;
  504. }
  505. }
  506. }
  507. foreach (var row in formdata.Rows)
  508. {
  509. var qadata = row["FormData"] != null ? row["FormData"].ToString() : "";
  510. if (!string.IsNullOrWhiteSpace(qadata))
  511. {
  512. var datarow = data.NewRow();
  513. datarow["ID"] = (Guid)row["ID"];
  514. datarow["Form_ID"] = (Guid)row["Form.ID"];
  515. datarow["Parent_ID"] = (Guid)row["Parent.ID"];
  516. datarow["Location_Timestamp"] = (DateTime)row["Location.Timestamp"];
  517. datarow["Location_Latitude"] = (double)row["Location.Latitude"];
  518. datarow["Location_Longitude"] = (double)row["Location.Longitude"];
  519. datarow["FormData"] = (string)row["FormData"];
  520. var desc = new List<string>();
  521. foreach (var col in parentcols.ColumnNames().Where(x => x != "ID"))
  522. {
  523. var val = row["Parent." + col];
  524. if (val != null && val.GetType() != typeof(Guid))
  525. desc.Add(val.ToString());
  526. }
  527. datarow["Description"] = string.Join(" : ", desc);
  528. datarow["Completed"] = (DateTime)row["FormCompleted"];
  529. datarow["Completed By"] = (string)row["FormCompletedBy.UserID"];
  530. if(isEntityForm)
  531. datarow["Processed"] = (bool)row["Processed"];
  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. foreach (var key in dict.Keys)
  550. {
  551. var variable = variables.FirstOrDefault(x => string.Equals(key, x.Code));
  552. if (variable != null)
  553. {
  554. var value = variable.ParseValue(dict[key]);
  555. object format = variable.FormatValue(value);
  556. var sKey = key.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. Type formtype = CategoryToType(Category.SelectedValue as String);
  602. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  603. if (formtype != null && form.Key != Guid.Empty)
  604. {
  605. IFilter filter;
  606. switch (selection)
  607. {
  608. case Selection.Selected:
  609. var formids = dataGrid.SelectedItems.Select(x => (x as DataRowView).Row["ID"]).ToArray();
  610. filter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(formtype)) as IFilter)!;
  611. filter.Expression = CoreUtils.CreateMemberExpression(formtype, "ID");
  612. filter.Operator = Operator.InList;
  613. filter.Value = formids;
  614. break;
  615. case Selection.All:
  616. filter = Filter.Create(formtype).All();
  617. break;
  618. case Selection.None:
  619. default:
  620. filter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(formtype)) as IFilter)!.None();
  621. break;
  622. }
  623. return (Activator.CreateInstance(typeof(DigitalFormReportDataModel<>)!
  624. .MakeGenericType(formtype), new object?[] { filter, form.Key }) as DataModel)!;
  625. }
  626. return new AutoDataModel<DigitalForm>(new Filter<DigitalForm>().None());
  627. }
  628. public Dictionary<string, object[]> Selected()
  629. {
  630. return new Dictionary<string, object[]>();
  631. }
  632. public void Heartbeat(TimeSpan time)
  633. {
  634. }
  635. #endregion
  636. #region Toolbar Handling
  637. private void Category_SelectionChanged(object sender, SelectionChangedEventArgs e)
  638. {
  639. _changing = true;
  640. var category = Category.SelectedValue as string;
  641. var type = CategoryToType(category);
  642. var JobLink = type != null ? GetJobLink("", type) : "";
  643. if (string.IsNullOrWhiteSpace(JobLink))
  644. {
  645. Jobs.SelectedValue = Guid.Empty;
  646. Jobs.IsEnabled = false;
  647. }
  648. else
  649. {
  650. Jobs.IsEnabled = true;
  651. }
  652. var forms = new Dictionary<Guid, string> { { Guid.Empty, "" } };
  653. if (!string.IsNullOrWhiteSpace(category))
  654. {
  655. forms[Guid.Empty] = "Select Form";
  656. var rows = allforms.Rows.Where(r => string.Equals(r.Get<DigitalForm, string>(c => c.AppliesTo), category));
  657. foreach (var row in rows)
  658. forms[row.Get<DigitalForm, Guid>(x => x.ID)] = row.Get<DigitalForm, string>(x => x.Description);
  659. }
  660. Form.ItemsSource = forms;
  661. _changing = false;
  662. Form.SelectedIndex = 0;
  663. Form.IsEnabled = !string.IsNullOrWhiteSpace(category);
  664. OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
  665. }
  666. private void Form_SelectionChanged(object sender, SelectionChangedEventArgs e)
  667. {
  668. if (IsReady && !_changing)
  669. {
  670. Refresh();
  671. OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
  672. }
  673. }
  674. private void Jobs_SelectionChanged(object sender, SelectionChangedEventArgs e)
  675. {
  676. if (IsReady && !_changing)
  677. Refresh();
  678. }
  679. private int WeekDay(DateTime date)
  680. {
  681. if (date.DayOfWeek == DayOfWeek.Sunday)
  682. return 7;
  683. return (int)date.DayOfWeek - 1;
  684. }
  685. private void SetDates(DateTime? from, DateTime? to, bool enable)
  686. {
  687. if (_changing)
  688. return;
  689. _changing = true;
  690. _from = from.HasValue ? from.Value : DateTime.Today;
  691. FromDate.SelectedDate = from;
  692. FromDate.IsEnabled = enable;
  693. _to = to.HasValue ? to.Value : DateTime.Today;
  694. ToDate.SelectedDate = to;
  695. ToDate.IsEnabled = enable;
  696. _changing = false;
  697. if (!enable)
  698. Refresh();
  699. }
  700. private void DateRange_SelectionChanged(object sender, SelectionChangedEventArgs e)
  701. {
  702. if (!IsReady)
  703. return;
  704. if (DateRange.SelectedIndex == 0) // Week To Date
  705. SetDates(DateTime.Today, DateTime.Today, false);
  706. else if (DateRange.SelectedIndex == 1) // Week To Date
  707. SetDates(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(-1), false);
  708. else if (DateRange.SelectedIndex == 2) // Week To Date
  709. SetDates(DateTime.Today.AddDays(0 - WeekDay(DateTime.Today)), DateTime.Today, false);
  710. else if (DateRange.SelectedIndex == 3) // Last 7 Days
  711. SetDates(DateTime.Today.AddDays(-6), DateTime.Today, false);
  712. else if (DateRange.SelectedIndex == 4) // Month To Date
  713. SetDates(new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1), DateTime.Today, false);
  714. else if (DateRange.SelectedIndex == 5) // Last 30 days
  715. SetDates(DateTime.Today.AddDays(-29), DateTime.Today, false);
  716. else if (DateRange.SelectedIndex == 6) // Year To Date
  717. SetDates(new DateTime(DateTime.Today.Year, 1, 1), DateTime.Today, false);
  718. else if (DateRange.SelectedIndex == 7) // Last 12 Months
  719. SetDates(DateTime.Today.AddYears(-1).AddDays(1), DateTime.Today, false);
  720. else if (DateRange.SelectedIndex == 8) // Custom
  721. SetDates(FromDate.SelectedDate.Value, ToDate.SelectedDate.Value, true);
  722. }
  723. private void FromDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  724. {
  725. if (IsReady && !_changing)
  726. {
  727. _from = FromDate.SelectedDate.Value.Date;
  728. Refresh();
  729. }
  730. }
  731. private void ToDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  732. {
  733. if (IsReady && !_changing)
  734. {
  735. _to = ToDate.SelectedDate.Value.Date;
  736. Refresh();
  737. }
  738. }
  739. private void Search_KeyUp(object sender, KeyEventArgs e)
  740. {
  741. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return)
  742. {
  743. _search = Search.Text;
  744. Refresh();
  745. }
  746. }
  747. private void Export_Click(object sender, RoutedEventArgs e)
  748. {
  749. var cat = Category.SelectedValue as string;
  750. //KeyValuePair<Type, String> cat = (KeyValuePair<Type, String>)Category.SelectedItem;
  751. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  752. var formname = Regex.Replace(form.Value, "[^ a-zA-Z0-9]", string.Empty);
  753. var filename = string.Format("{0} - {1} - {2:yyyy-MM-dd} - {3:yyyy-MM-dd}.xlsx", cat, formname, FromDate.SelectedDate,
  754. ToDate.SelectedDate);
  755. var options = new ExcelExportingOptions();
  756. options.ExcelVersion = ExcelVersion.Excel2013;
  757. options.ExportStackedHeaders = true;
  758. var excelEngine = dataGrid.ExportToExcel(dataGrid.View, options);
  759. var workBook = excelEngine.Excel.Workbooks[0];
  760. var sheet = workBook.Worksheets[0];
  761. sheet.Name = "Summary";
  762. sheet.UsedRange.AutofitRows();
  763. sheet.UsedRange.AutofitColumns();
  764. sheet = workBook.Worksheets.Create("Questions");
  765. sheet.Move(0);
  766. var questions = new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(form.Key));
  767. sheet.Range[1, 1].Text = form.Value;
  768. sheet.Range[1, 1, 1, 3].Merge();
  769. var i = 1;
  770. foreach (var row in questions.Rows)
  771. if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
  772. {
  773. sheet.Range[i + 2, 1].Text = string.Format("{0}.", i);
  774. sheet.Range[i + 2, 2].Text = string.Format("{0}", row.Get<QAQuestion, string>(x => x.Question));
  775. sheet.Range[i + 2, 3].Text = string.Format("[{0}]", row.Get<QAQuestion, string>(x => x.Code));
  776. i++;
  777. }
  778. sheet.UsedRange.AutofitRows();
  779. sheet.UsedRange.AutofitColumns();
  780. try
  781. {
  782. workBook.SaveAs(filename);
  783. var startInfo = new ProcessStartInfo(filename);
  784. startInfo.Verb = "open";
  785. startInfo.UseShellExecute = true;
  786. Process.Start(startInfo);
  787. }
  788. catch
  789. {
  790. MessageBox.Show(string.Format("Unable to Save/Launch [{0}]!\n\nIs the file already open?", filename));
  791. }
  792. }
  793. #endregion
  794. }
  795. }