ManufacturingTemplateAnalysis.xaml.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Linq;
  6. using System.Text.RegularExpressions;
  7. using System.Windows;
  8. using System.Windows.Controls;
  9. using System.Windows.Data;
  10. using System.Windows.Input;
  11. using Comal.Classes;
  12. using InABox.Clients;
  13. using InABox.Configuration;
  14. using InABox.Core;
  15. using InABox.WPF;
  16. using PRSDesktop.WidgetGroups;
  17. using Syncfusion.UI.Xaml.Grid;
  18. using Syncfusion.UI.Xaml.Grid.Cells;
  19. using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
  20. namespace PRSDesktop
  21. {
  22. public class ManufacturingTemplateAnalysisProperties : IUserConfigurationSettings, IDashboardProperties { }
  23. public class ManufacturingTemplateAnalysisElement : DashboardElement<ManufacturingTemplateAnalysis, Manufacturing, ManufacturingTemplateAnalysisProperties> { }
  24. /// <summary>
  25. /// Interaction logic for ManufacturingTemplateAnalysis.xaml
  26. /// </summary>
  27. public partial class ManufacturingTemplateAnalysis : UserControl, IPanel<ManufacturingTemplate>, IDashboardWidget<Manufacturing, ManufacturingTemplateAnalysisProperties>
  28. {
  29. private bool _activeonly;
  30. private DateTime _from;
  31. private string _search = "";
  32. private DateTime _to;
  33. private DataTable data;
  34. private readonly Dictionary<string, string> SectionDisplayNames = new() { { "Total", "Total" } };
  35. private ManufacturingSection[] sections;
  36. private Dictionary<Guid, ManufacturingTemplateStage[]> stages;
  37. private ManufacturingTemplate[] templates;
  38. public ManufacturingTemplateAnalysis()
  39. {
  40. _from = DateTime.Today.AddDays(0 - WeekDay(DateTime.Today));
  41. _to = DateTime.Today;
  42. _activeonly = true;
  43. InitializeComponent();
  44. dataGrid.CellRenderers.Remove("StackedHeader");
  45. dataGrid.CellRenderers.Add("StackedHeader", new GridCustomStackedRenderer(Resources));
  46. }
  47. public bool IsReady { get; set; }
  48. public void CreateToolbarButtons(IPanelHost host)
  49. {
  50. }
  51. public string SectionName => "Manufacturing Template Analysis";
  52. public ManufacturingTemplateAnalysisProperties Properties { get; set; }
  53. public event LoadSettings<ManufacturingTemplateAnalysisProperties>? LoadSettings;
  54. public event SaveSettings<ManufacturingTemplateAnalysisProperties>? SaveSettings;
  55. public DataModel DataModel(Selection selection)
  56. {
  57. return new AutoDataModel<ManufacturingTemplate>(null);
  58. }
  59. public void Refresh()
  60. {
  61. Progress.ShowModal("Loading Data", (progress) =>
  62. {
  63. data.Rows.Clear();
  64. MultiQuery query = new MultiQuery();
  65. query.Add(
  66. new Filter<ManufacturingTemplate>(x => x.ID).IsNotEqualTo(Guid.Empty).TextSearch(_search, x => x.Code, x => x.Name),
  67. new Columns<ManufacturingTemplate>(x => x.ID)
  68. .Add(x => x.Name)
  69. .Add(x => x.Code),
  70. new SortOrder<ManufacturingTemplate>(x => x.Code)
  71. );
  72. query.Add(
  73. new Filter<ManufacturingPacket>(x => x.Completed).IsGreaterThanOrEqualTo(_from).And(x => x.Completed).IsLessThan(_to.AddDays(1)),
  74. new Columns<ManufacturingPacket>
  75. (
  76. x => x.ID,
  77. x => x.ManufacturingTemplateLink.ID,
  78. x => x.Quantity
  79. )
  80. );
  81. query.Add(
  82. new Filter<ManufacturingHistory>(x => x.Packet.Completed).IsGreaterThanOrEqualTo(_from).And(x => x.Packet.Completed)
  83. .IsLessThan(_to.AddDays(1)),
  84. new Columns<ManufacturingHistory>
  85. (
  86. x => x.Packet.ID,
  87. x => x.Section.ID,
  88. x => x.QADuration,
  89. x => x.WorkDuration
  90. )
  91. );
  92. query.Query();
  93. templates = query.Get<ManufacturingTemplate>().ToObjects<ManufacturingTemplate>().ToArray();
  94. var packets = query.Get<ManufacturingPacket>().ToObjects<ManufacturingPacket>();
  95. ;
  96. var history = query.Get<ManufacturingHistory>().ToObjects<ManufacturingHistory>()
  97. .GroupBy(x => x.Packet.ID)
  98. .ToDictionary(x => x.Key, x => x.ToList());
  99. foreach (var template in templates)
  100. {
  101. progress.Report(string.Format("Processing {0}: {1}", template.Code, template.Name));
  102. var templateStageSections = (stages.GetValueOrDefault(template.ID) ?? Enumerable.Empty<ManufacturingTemplateStage>())
  103. .Select(x => x.Section.ID).Where(x => sections.Any(y => x == y.ID));
  104. var values = new List<object>();
  105. values.Add(template.Code);
  106. values.Add(template.Name);
  107. var times = new Dictionary<Guid, long>();
  108. foreach (var section in sections)
  109. times[section.ID] = 0L;
  110. var qty = 0;
  111. var pkts = packets.Where(p => p.ManufacturingTemplateLink.ID.Equals(template.ID));
  112. foreach (var p in pkts)
  113. {
  114. var thisqty = p.Quantity;
  115. if (thisqty > 0)
  116. {
  117. qty += thisqty;
  118. if (history.TryGetValue(p.ID, out var histories))
  119. {
  120. foreach (var section in templateStageSections)
  121. foreach (var hist in histories.Where(x => x.Section.ID == section))
  122. times[section] += hist.QADuration.Ticks + hist.WorkDuration.Ticks;
  123. }
  124. }
  125. }
  126. if (qty > 0)
  127. values.Add(qty);
  128. else
  129. values.Add(null);
  130. var total = 0L;
  131. foreach (var section in sections)
  132. {
  133. total += times[section.ID];
  134. if (qty > 0 && times[section.ID] > 0)
  135. values.Add(Math.Truncate(new TimeSpan(times[section.ID] / qty).TotalHours * 100.0F) / 100.0F);
  136. else
  137. values.Add(null);
  138. }
  139. if (qty > 0 && total > 0)
  140. values.Add(Math.Truncate(new TimeSpan(total / qty).TotalHours * 100.0F) / 100.0F);
  141. else
  142. values.Add(null);
  143. if (!_activeonly || qty > 0)
  144. data.Rows.Add(values.ToArray());
  145. }
  146. });
  147. }
  148. public Dictionary<string, object[]> Selected()
  149. {
  150. return new Dictionary<string, object[]>();
  151. }
  152. public void Setup()
  153. {
  154. FromDate.SelectedDate = _from;
  155. ToDate.SelectedDate = _to;
  156. dataGrid.ScrollMode = ScrollMode.Async;
  157. sections = new Client<ManufacturingSection>().Load(
  158. new Filter<ManufacturingSection>(x => x.Hidden).IsEqualTo(false),
  159. new SortOrder<ManufacturingSection>(x => x.Factory.Sequence).ThenBy(x => x.Sequence)
  160. );
  161. stages = new Client<ManufacturingTemplateStage>().Load().GroupBy(x => x.Template.ID).ToDictionary(x => x.Key, x => x.ToArray());
  162. data = new DataTable();
  163. data.Columns.Add("Code", typeof(string));
  164. data.Columns.Add("Description", typeof(string));
  165. data.Columns.Add("Qty", typeof(int));
  166. var columns = new Dictionary<string, List<string>>();
  167. foreach (var section in sections)
  168. {
  169. if (!columns.ContainsKey(section.Factory.Name))
  170. columns[section.Factory.Name] = new List<string>();
  171. var columnname = string.Format("{0}:{1}", section.Factory.Name, Regex.Replace(section.Name, "[^a-zA-Z0-9]", ""));
  172. columns[section.Factory.Name].Add(columnname);
  173. data.Columns.Add(columnname, typeof(double));
  174. SectionDisplayNames[columnname] = section.Name;
  175. }
  176. data.Columns.Add("Total", typeof(double));
  177. dataGrid.ItemsSource = data;
  178. var stackedHeaderRow1 = new StackedHeaderRow();
  179. stackedHeaderRow1.StackedColumns.Add(new StackedColumn
  180. { ChildColumns = "Code,Description,Qty", HeaderText = "Template Details", MappingName = "TemplateDetails" });
  181. foreach (var key in columns.Keys)
  182. stackedHeaderRow1.StackedColumns.Add(new StackedColumn
  183. { ChildColumns = string.Join(",", columns[key]), HeaderText = key, MappingName = key });
  184. stackedHeaderRow1.StackedColumns.Add(new StackedColumn { ChildColumns = "Total", HeaderText = "", MappingName = "Total" });
  185. dataGrid.StackedHeaderRows.Add(stackedHeaderRow1);
  186. }
  187. public void Shutdown(CancelEventArgs? cancel)
  188. {
  189. }
  190. public void Heartbeat(TimeSpan time)
  191. {
  192. }
  193. private void DataGrid_AutoGeneratingColumn(object sender, AutoGeneratingColumnArgs e)
  194. {
  195. e.Column.TextAlignment = TextAlignment.Center;
  196. e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center;
  197. e.Column.ColumnSizer = GridLengthUnitType.None;
  198. var value = e.Column.ValueBinding as Binding;
  199. if (value.Path.Path.Equals("Code"))
  200. {
  201. e.Column.Width = 100;
  202. e.Column.HeaderStyle = Application.Current.Resources["TemplateHeaderStyle"] as Style;
  203. }
  204. else if (value.Path.Path.Equals("Description"))
  205. {
  206. e.Column.Width = 300;
  207. e.Column.HeaderStyle = Application.Current.Resources["TemplateHeaderStyle"] as Style;
  208. }
  209. else if (value.Path.Path.Equals("Qty"))
  210. {
  211. e.Column.Width = 60;
  212. e.Column.HeaderStyle = Application.Current.Resources["TemplateHeaderStyle"] as Style;
  213. }
  214. else
  215. {
  216. var style = new Style(typeof(GridCell));
  217. //style.Setters.Add(new Setter(GridCell.BackgroundProperty, new Binding(value.Path.Path) { Converter = new LeaveBackgroundConverter() { Colors = activityColors } }));
  218. //style.Setters.Add(new Setter(GridCell.ForegroundProperty, new Binding(value.Path.Path) { Converter = new LeaveForegroundConverter() }));
  219. //style.Setters.Add(new Setter(GridCell.FontStyleProperty, new Binding(value.Path.Path) { Converter = new LeaveFontStyleConverter() }));
  220. //style.Setters.Add(new Setter(GridCell.FontWeightProperty, new Binding(value.Path.Path) { Converter = new LeaveFontWeightConverter() }));
  221. e.Column.CellStyle = style;
  222. e.Column.Width = 50;
  223. e.Column.HeaderStyle = Application.Current.Resources["TemplateHeaderStyle"] as Style;
  224. // e.Column.HeaderStyle = Resources["DataHeaderStyle"] as Style;
  225. e.Column.HeaderText = SectionDisplayNames[value.Path.Path];
  226. }
  227. }
  228. private void DataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
  229. {
  230. }
  231. private void DataGrid_QueryRowHeight(object sender, QueryRowHeightEventArgs e)
  232. {
  233. e.Height = e.RowIndex == 1 ? 150 : 30;
  234. e.Handled = true;
  235. }
  236. private void ActiveItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
  237. {
  238. if (IsReady && !_changing)
  239. {
  240. _activeonly = ActiveItems.SelectedIndex == 1;
  241. Refresh();
  242. }
  243. }
  244. private void Search_KeyUp(object sender, KeyEventArgs e)
  245. {
  246. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return)
  247. {
  248. _search = Search.Text;
  249. Refresh();
  250. }
  251. }
  252. private void Export_Click(object sender, RoutedEventArgs e)
  253. {
  254. }
  255. private class GridCustomStackedRenderer : GridStackedHeaderCellRenderer
  256. {
  257. private readonly ResourceDictionary _resources;
  258. public GridCustomStackedRenderer(ResourceDictionary resources)
  259. {
  260. _resources = resources;
  261. }
  262. public override void OnInitializeEditElement(DataColumnBase dataColumn, GridStackedHeaderCellControl uiElement, object dataContext)
  263. {
  264. uiElement.Style = _resources["GroupHeaderStyle"] as Style;
  265. base.OnInitializeEditElement(dataColumn, uiElement, dataContext);
  266. }
  267. }
  268. #region Date Handling
  269. private bool _changing;
  270. public event DataModelUpdateEvent? OnUpdateDataModel;
  271. private void SetDates(DateTime from, DateTime to, bool enable)
  272. {
  273. if (_changing)
  274. return;
  275. _changing = true;
  276. _from = from;
  277. FromDate.SelectedDate = from;
  278. FromDate.IsEnabled = enable;
  279. _to = to;
  280. ToDate.SelectedDate = to;
  281. ToDate.IsEnabled = enable;
  282. _changing = false;
  283. if (!enable)
  284. Refresh();
  285. }
  286. private int WeekDay(DateTime date)
  287. {
  288. if (date.DayOfWeek == DayOfWeek.Sunday)
  289. return 7;
  290. return (int)date.DayOfWeek - 1;
  291. }
  292. private void DateRange_SelectionChanged(object sender, SelectionChangedEventArgs e)
  293. {
  294. if (!IsReady)
  295. return;
  296. if (DateRange.SelectedIndex == 0) // Week To Date
  297. SetDates(DateTime.Today.AddDays(0 - WeekDay(DateTime.Today)), DateTime.Today, false);
  298. else if (DateRange.SelectedIndex == 1) // Last 7 Days
  299. SetDates(DateTime.Today.AddDays(-6), DateTime.Today, false);
  300. else if (DateRange.SelectedIndex == 2) // Month To Date
  301. SetDates(new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1), DateTime.Today, false);
  302. else if (DateRange.SelectedIndex == 3) // Last 30 days
  303. SetDates(DateTime.Today.AddDays(-29), DateTime.Today, false);
  304. else if (DateRange.SelectedIndex == 4) // Year To Date
  305. SetDates(new DateTime(DateTime.Today.Year, 1, 1), DateTime.Today, false);
  306. else if (DateRange.SelectedIndex == 5) // Last 12 Months
  307. SetDates(DateTime.Today.AddYears(-1).AddDays(1), DateTime.Today, false);
  308. else if (DateRange.SelectedIndex == 6) // Custom
  309. SetDates(FromDate.SelectedDate.Value, ToDate.SelectedDate.Value, true);
  310. }
  311. private void FromDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  312. {
  313. if (IsReady && !_changing)
  314. {
  315. _from = FromDate.SelectedDate.Value.Date;
  316. Refresh();
  317. }
  318. }
  319. private void ToDate_SelectedDateChanged(object sender, SelectionChangedEventArgs e)
  320. {
  321. if (IsReady && !_changing)
  322. {
  323. _to = ToDate.SelectedDate.Value.Date;
  324. Refresh();
  325. }
  326. }
  327. #endregion
  328. }
  329. }