QADashboard.xaml.cs 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  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. 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. }
  327. }
  328. return null;
  329. }
  330. public void Refresh()
  331. {
  332. Progress.Show("Refreshing");
  333. try
  334. {
  335. qaGrid.Clear();
  336. qaGrid.LoadChecks("", new QAQuestion[] { }, new Dictionary<Guid, object>());
  337. dataGrid.ItemsSource = null;
  338. var category = Category.SelectedValue as string;
  339. if (string.IsNullOrWhiteSpace(category))
  340. {
  341. DigitalFormsDock.Visibility = Visibility.Collapsed;
  342. qaGrid.Visibility = Visibility.Collapsed;
  343. dataGrid.Visibility = Visibility.Collapsed;
  344. return;
  345. }
  346. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  347. if (form.Key == Guid.Empty)
  348. {
  349. DigitalFormsDock.Visibility = Visibility.Collapsed;
  350. qaGrid.Visibility = Visibility.Collapsed;
  351. dataGrid.Visibility = Visibility.Collapsed;
  352. return;
  353. }
  354. var type = CategoryToType(category);
  355. if (type == null)
  356. return;
  357. formType = type;
  358. parentType = CoreUtils.TypeList(
  359. AppDomain.CurrentDomain.GetAssemblies(),
  360. x => !x.IsAbstract && string.Equals(x.Name, category)
  361. ).FirstOrDefault();
  362. var parentcols = LookupFactory.DefineColumns(parentType);
  363. Progress.SetMessage("Loading Data");
  364. var jobid = Jobs.SelectedValue != null ? (Guid)Jobs.SelectedValue : Guid.Empty;
  365. var isEntityForm = type.IsSubclassOfRawGeneric(typeof(EntityForm<,>));
  366. var query = new MultiQuery();
  367. query.Add(
  368. new QueryDef<QAQuestion>(
  369. new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(form.Key),
  370. null,
  371. null
  372. ),
  373. typeof(QAQuestion)
  374. );
  375. query.Add(
  376. new QueryDef<DigitalFormVariable>(
  377. new Filter<DigitalFormVariable>(x => x.Form.ID).IsEqualTo(form.Key),
  378. null,
  379. new SortOrder<DigitalFormVariable>(x => x.Sequence)
  380. ),
  381. typeof(DigitalFormVariable)
  382. );
  383. var columns = LookupFactory.DefineColumns(type);
  384. var sort = LookupFactory.DefineSort(type);
  385. var JobLink = GetJobLink("", type);
  386. var filtertype = typeof(Filter<>).MakeGenericType(type);
  387. var filter = Activator.CreateInstance(typeof(Filter<>).MakeGenericType(type));
  388. CoreUtils.SetPropertyValue(filter, "Expression", CoreUtils.GetMemberExpression(type, "FormCompleted"));
  389. CoreUtils.SetPropertyValue(filter, "Operator", Operator.IsGreaterThanOrEqualTo);
  390. CoreUtils.SetPropertyValue(filter, "Value", _from);
  391. var ands = filtertype.GetProperty("Ands").GetValue(filter) as IList;
  392. var to = Activator.CreateInstance(filtertype);
  393. CoreUtils.SetPropertyValue(to, "Expression", CoreUtils.GetMemberExpression(type, "FormCompleted"));
  394. CoreUtils.SetPropertyValue(to, "Operator", Operator.IsLessThan);
  395. CoreUtils.SetPropertyValue(to, "Value", _to.AddDays(1));
  396. ands.Add(to);
  397. var formid = Activator.CreateInstance(filtertype);
  398. CoreUtils.SetPropertyValue(formid, "Expression", CoreUtils.GetMemberExpression(type, "Form.ID"));
  399. CoreUtils.SetPropertyValue(formid, "Operator", Operator.IsEqualTo);
  400. CoreUtils.SetPropertyValue(formid, "Value", form.Key);
  401. ands.Add(formid);
  402. if (jobid != Guid.Empty)
  403. {
  404. var job = Activator.CreateInstance(filtertype);
  405. CoreUtils.SetPropertyValue(job, "Expression", CoreUtils.GetMemberExpression(type, JobLink + ".ID"));
  406. CoreUtils.SetPropertyValue(job, "Operator", Operator.IsEqualTo);
  407. CoreUtils.SetPropertyValue(job, "Value", jobid);
  408. ands.Add(job);
  409. }
  410. var colstype = typeof(Columns<>).MakeGenericType(type);
  411. var cols = Activator.CreateInstance(colstype) as IColumns;
  412. cols.Add("ID");
  413. foreach (var col in parentcols.ColumnNames())
  414. cols.Add("Parent." + col);
  415. if(parentColumns.TryGetValue(parentType, out var pColumns))
  416. {
  417. foreach(var (field, name) in pColumns)
  418. {
  419. cols.Add(field);
  420. }
  421. }
  422. cols.Add("Form.ID");
  423. cols.Add("FormData");
  424. cols.Add("FormCompleted");
  425. cols.Add("FormCompletedBy.UserID");
  426. if(isEntityForm)
  427. cols.Add("Processed");
  428. cols.Add("Location.Timestamp");
  429. cols.Add("Location.Latitude");
  430. cols.Add("Location.Longitude");
  431. if (!string.IsNullOrWhiteSpace(JobLink))
  432. cols.Add(JobLink + ".JobNumber");
  433. var querytype = typeof(QueryDef<>).MakeGenericType(type);
  434. query.Add(Activator.CreateInstance(querytype, filter, cols, sort) as IQueryDef, type);
  435. if(parentType == typeof(JobITP))
  436. {
  437. query.Add(
  438. new Filter<JobITP>(x => x.ID).InQuery(filter as Filter<JobITPForm>, x => x.Parent.ID),
  439. new Columns<JobITP>(x => x.ID, x => x.Job.JobNumber));
  440. }
  441. query.Query();
  442. var questions =
  443. query.Get(typeof(QAQuestion)); // new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.QAForm.ID).IsEqualTo(form.Key));
  444. var variables = query.Get(typeof(DigitalFormVariable)).Rows.Select(x => x.ToObject<DigitalFormVariable>()).ToArray();
  445. var formdata = query.Get(type);
  446. var data = new DataTable();
  447. data.Columns.Add("ID", typeof(Guid));
  448. data.Columns.Add("Form_ID", typeof(Guid));
  449. data.Columns.Add("Parent_ID", typeof(Guid));
  450. data.Columns.Add("Location_Timestamp", typeof(DateTime));
  451. data.Columns.Add("Location_Latitude", typeof(double));
  452. data.Columns.Add("Location_Longitude", typeof(double));
  453. data.Columns.Add("FormData", typeof(string));
  454. if (parentType == typeof(JobITP))
  455. {
  456. data.Columns.Add("Job No", typeof(string));
  457. }
  458. if (pColumns != null)
  459. {
  460. foreach (var (field, name) in pColumns)
  461. {
  462. data.Columns.Add(name, typeof(string));
  463. }
  464. }
  465. data.Columns.Add("Description", typeof(string));
  466. data.Columns.Add("Completed", typeof(DateTime));
  467. data.Columns.Add("Completed By", typeof(string));
  468. if(isEntityForm)
  469. data.Columns.Add("Processed", typeof(bool));
  470. if (variables.Any())
  471. {
  472. foreach (var variable in variables)
  473. {
  474. var code = variable.Code.Replace("/", " ");
  475. QuestionCodes[code] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(code.ToLower());
  476. data.Columns.Add(code, typeof(string));
  477. }
  478. }
  479. else if (questions.Rows.Any())
  480. {
  481. Progress.SetMessage("Loading Checks");
  482. qaGrid.Clear();
  483. qaGrid.LoadChecks(form.Value, questions.Rows.Select(x => x.ToObject<QAQuestion>()), new Dictionary<Guid, object>());
  484. qaGrid.CollapseMargins();
  485. var i = 1;
  486. foreach (var row in questions.Rows)
  487. {
  488. var id = row.Get<QAQuestion, Guid>(x => x.ID).ToString();
  489. if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
  490. {
  491. data.Columns.Add(id, typeof(string));
  492. var code = row.Get<QAQuestion, string>(x => x.Code);
  493. QuestionCodes[id] = string.IsNullOrEmpty(code) ? string.Format("{0}.", i) : code;
  494. i++;
  495. }
  496. }
  497. }
  498. foreach (var row in formdata.Rows)
  499. {
  500. var qadata = row["FormData"] != null ? row["FormData"].ToString() : "";
  501. if (!string.IsNullOrWhiteSpace(qadata))
  502. {
  503. var datarow = data.NewRow();
  504. datarow["ID"] = (Guid)row["ID"];
  505. datarow["Form_ID"] = (Guid)row["Form.ID"];
  506. datarow["Parent_ID"] = (Guid)row["Parent.ID"];
  507. datarow["Location_Timestamp"] = (DateTime)row["Location.Timestamp"];
  508. datarow["Location_Latitude"] = (double)row["Location.Latitude"];
  509. datarow["Location_Longitude"] = (double)row["Location.Longitude"];
  510. datarow["FormData"] = (string)row["FormData"];
  511. var desc = new List<string>();
  512. foreach (var col in parentcols.ColumnNames().Where(x => x != "ID"))
  513. {
  514. var val = row["Parent." + col];
  515. if (val != null && val.GetType() != typeof(Guid))
  516. desc.Add(val.ToString());
  517. }
  518. datarow["Description"] = string.Join(" : ", desc);
  519. datarow["Completed"] = (DateTime)row["FormCompleted"];
  520. datarow["Completed By"] = (string)row["FormCompletedBy.UserID"];
  521. if(isEntityForm)
  522. datarow["Processed"] = (bool)row["Processed"];
  523. if(parentType == typeof(JobITP))
  524. {
  525. var jobITP = query.Get<JobITP>().Rows.FirstOrDefault(x => (Guid)x["ID"] == (Guid)row["Parent.ID"]);
  526. datarow["Job No"] = jobITP?["Job.JobNumber"];
  527. }
  528. if (pColumns != null)
  529. {
  530. foreach (var (field, name) in pColumns)
  531. {
  532. datarow[name] = row[field].ToString();
  533. }
  534. }
  535. //datarow["Job No"] = (String)row[JobLink + ".JobNumber"];
  536. var bHasData = false;
  537. if (variables.Any())
  538. {
  539. var dict = Serialization.Deserialize<Dictionary<string, object>>(qadata);
  540. foreach (var key in dict.Keys)
  541. {
  542. var variable = variables.FirstOrDefault(x => string.Equals(key, x.Code));
  543. if (variable != null)
  544. {
  545. var value = variable.ParseValue(dict[key]);
  546. object format = variable.FormatValue(value);
  547. var sKey = key.Replace("/", " ");
  548. if (data.Columns.Contains(sKey))
  549. {
  550. datarow[sKey] = format;
  551. bHasData = true;
  552. }
  553. }
  554. }
  555. }
  556. else
  557. {
  558. var dict = Serialization.Deserialize<Dictionary<Guid, object>>(qadata);
  559. foreach (var key in dict.Keys)
  560. if (data.Columns.Contains(key.ToString()))
  561. {
  562. datarow[key.ToString()] = dict[key];
  563. bHasData = true;
  564. }
  565. }
  566. if (bHasData)
  567. data.Rows.Add(datarow);
  568. }
  569. }
  570. dataGrid.ItemsSource = data;
  571. qaGrid.Visibility = !variables.Any() && questions.Rows.Any() ? Visibility.Visible : Visibility.Collapsed;
  572. dataGrid.Visibility = Visibility.Visible;
  573. }
  574. finally
  575. {
  576. Progress.Close();
  577. }
  578. }
  579. public string? SectionName
  580. {
  581. get {
  582. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  583. if (Category.SelectedValue != null && form.Key != Guid.Empty)
  584. {
  585. return form.Key.ToString();
  586. }
  587. return "Digital Forms";
  588. }
  589. }
  590. public DataModel DataModel(Selection selection)
  591. {
  592. if ((Form.SelectedItem == null) || (String.IsNullOrWhiteSpace(Category.SelectedValue as String)))
  593. return new AutoDataModel<DigitalForm>(new Filter<DigitalForm>().None());
  594. Type formtype = CategoryToType(Category.SelectedValue as String);
  595. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  596. if (formtype != null && (form.Key != Guid.Empty))
  597. {
  598. IFilter filter;
  599. switch (selection)
  600. {
  601. case Selection.Selected:
  602. var formids = dataGrid.SelectedItems.Select(x => (x as DataRowView).Row["ID"]).ToArray();
  603. filter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(formtype)) as IFilter)!;
  604. filter.Expression = CoreUtils.CreateMemberExpression(formtype, "ID");
  605. filter.Operator = Operator.InList;
  606. filter.Value = formids;
  607. break;
  608. case Selection.All:
  609. filter = Filter.Create(formtype).All();
  610. break;
  611. case Selection.None:
  612. default:
  613. filter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(formtype)) as IFilter)!.None();
  614. break;
  615. }
  616. return (Activator.CreateInstance(typeof(DigitalFormReportDataModel<>)!
  617. .MakeGenericType(formtype), new object?[] { filter, form.Key }) as DataModel)!;
  618. }
  619. return new AutoDataModel<DigitalForm>(new Filter<DigitalForm>().None());
  620. }
  621. public Dictionary<string, object[]> Selected()
  622. {
  623. return new Dictionary<string, object[]>();
  624. }
  625. public void Heartbeat(TimeSpan time)
  626. {
  627. }
  628. #endregion
  629. #region Toolbar Handling
  630. private void Category_SelectionChanged(object sender, SelectionChangedEventArgs e)
  631. {
  632. _changing = true;
  633. var category = Category.SelectedValue as string;
  634. var type = CategoryToType(category);
  635. var JobLink = type != null ? GetJobLink("", type) : "";
  636. if (string.IsNullOrWhiteSpace(JobLink))
  637. {
  638. Jobs.SelectedValue = Guid.Empty;
  639. Jobs.IsEnabled = false;
  640. }
  641. else
  642. {
  643. Jobs.IsEnabled = true;
  644. }
  645. var forms = new Dictionary<Guid, string> { { Guid.Empty, "" } };
  646. if (!string.IsNullOrWhiteSpace(category))
  647. {
  648. forms[Guid.Empty] = "Select Form";
  649. var rows = allforms.Rows.Where(r => string.Equals(r.Get<DigitalForm, string>(c => c.AppliesTo), category));
  650. foreach (var row in rows)
  651. forms[row.Get<DigitalForm, Guid>(x => x.ID)] = row.Get<DigitalForm, string>(x => x.Description);
  652. }
  653. Form.ItemsSource = forms;
  654. _changing = false;
  655. Form.SelectedIndex = 0;
  656. Form.IsEnabled = !string.IsNullOrWhiteSpace(category);
  657. OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
  658. }
  659. private void Form_SelectionChanged(object sender, SelectionChangedEventArgs e)
  660. {
  661. if (IsReady && !_changing)
  662. {
  663. Refresh();
  664. OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
  665. }
  666. }
  667. private void Jobs_SelectionChanged(object sender, SelectionChangedEventArgs e)
  668. {
  669. if (IsReady && !_changing)
  670. Refresh();
  671. }
  672. private int WeekDay(DateTime date)
  673. {
  674. if (date.DayOfWeek == DayOfWeek.Sunday)
  675. return 7;
  676. return (int)date.DayOfWeek - 1;
  677. }
  678. private void SetDates(DateTime? from, DateTime? to, bool enable)
  679. {
  680. if (_changing)
  681. return;
  682. _changing = true;
  683. _from = from.HasValue ? from.Value : DateTime.Today;
  684. FromDate.SelectedDate = from;
  685. FromDate.IsEnabled = enable;
  686. _to = to.HasValue ? to.Value : DateTime.Today;
  687. ToDate.SelectedDate = to;
  688. ToDate.IsEnabled = enable;
  689. _changing = false;
  690. if (!enable)
  691. Refresh();
  692. }
  693. private void DateRange_SelectionChanged(object sender, SelectionChangedEventArgs e)
  694. {
  695. if (!IsReady)
  696. return;
  697. if (DateRange.SelectedIndex == 0) // Week To Date
  698. SetDates(DateTime.Today, DateTime.Today, false);
  699. else if (DateRange.SelectedIndex == 1) // Week To Date
  700. SetDates(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(-1), false);
  701. else if (DateRange.SelectedIndex == 2) // Week To Date
  702. SetDates(DateTime.Today.AddDays(0 - WeekDay(DateTime.Today)), DateTime.Today, false);
  703. else if (DateRange.SelectedIndex == 3) // Last 7 Days
  704. SetDates(DateTime.Today.AddDays(-6), DateTime.Today, false);
  705. else if (DateRange.SelectedIndex == 4) // Month To Date
  706. SetDates(new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1), DateTime.Today, false);
  707. else if (DateRange.SelectedIndex == 5) // Last 30 days
  708. SetDates(DateTime.Today.AddDays(-29), DateTime.Today, false);
  709. else if (DateRange.SelectedIndex == 6) // Year To Date
  710. SetDates(new DateTime(DateTime.Today.Year, 1, 1), DateTime.Today, false);
  711. else if (DateRange.SelectedIndex == 7) // Last 12 Months
  712. SetDates(DateTime.Today.AddYears(-1).AddDays(1), DateTime.Today, false);
  713. else if (DateRange.SelectedIndex == 8) // Custom
  714. SetDates(FromDate.SelectedDate.Value, ToDate.SelectedDate.Value, true);
  715. }
  716. private void FromDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  717. {
  718. if (IsReady && !_changing)
  719. {
  720. _from = FromDate.SelectedDate.Value.Date;
  721. Refresh();
  722. }
  723. }
  724. private void ToDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  725. {
  726. if (IsReady && !_changing)
  727. {
  728. _to = ToDate.SelectedDate.Value.Date;
  729. Refresh();
  730. }
  731. }
  732. private void Search_KeyUp(object sender, KeyEventArgs e)
  733. {
  734. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return)
  735. {
  736. _search = Search.Text;
  737. Refresh();
  738. }
  739. }
  740. private void Export_Click(object sender, RoutedEventArgs e)
  741. {
  742. var cat = Category.SelectedValue as string;
  743. //KeyValuePair<Type, String> cat = (KeyValuePair<Type, String>)Category.SelectedItem;
  744. var form = (KeyValuePair<Guid, string>)Form.SelectedItem;
  745. var formname = Regex.Replace(form.Value, "[^ a-zA-Z0-9]", string.Empty);
  746. var filename = string.Format("{0} - {1} - {2:yyyy-MM-dd} - {3:yyyy-MM-dd}.xlsx", cat, formname, FromDate.SelectedDate,
  747. ToDate.SelectedDate);
  748. var options = new ExcelExportingOptions();
  749. options.ExcelVersion = ExcelVersion.Excel2013;
  750. options.ExportStackedHeaders = true;
  751. var excelEngine = dataGrid.ExportToExcel(dataGrid.View, options);
  752. var workBook = excelEngine.Excel.Workbooks[0];
  753. var sheet = workBook.Worksheets[0];
  754. sheet.Name = "Summary";
  755. sheet.UsedRange.AutofitRows();
  756. sheet.UsedRange.AutofitColumns();
  757. sheet = workBook.Worksheets.Create("Questions");
  758. sheet.Move(0);
  759. var questions = new Client<QAQuestion>().Query(new Filter<QAQuestion>(x => x.Form.ID).IsEqualTo(form.Key));
  760. sheet.Range[1, 1].Text = form.Value;
  761. sheet.Range[1, 1, 1, 3].Merge();
  762. var i = 1;
  763. foreach (var row in questions.Rows)
  764. if (!row.Get<QAQuestion, QAAnswer>(x => x.Answer).Equals(QAAnswer.Comment))
  765. {
  766. sheet.Range[i + 2, 1].Text = string.Format("{0}.", i);
  767. sheet.Range[i + 2, 2].Text = string.Format("{0}", row.Get<QAQuestion, string>(x => x.Question));
  768. sheet.Range[i + 2, 3].Text = string.Format("[{0}]", row.Get<QAQuestion, string>(x => x.Code));
  769. i++;
  770. }
  771. sheet.UsedRange.AutofitRows();
  772. sheet.UsedRange.AutofitColumns();
  773. try
  774. {
  775. workBook.SaveAs(filename);
  776. var startInfo = new ProcessStartInfo(filename);
  777. startInfo.Verb = "open";
  778. startInfo.UseShellExecute = true;
  779. Process.Start(startInfo);
  780. }
  781. catch
  782. {
  783. MessageBox.Show(string.Format("Unable to Save/Launch [{0}]!\n\nIs the file already open?", filename));
  784. }
  785. }
  786. #endregion
  787. }
  788. }