TimesheetWidget.xaml.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Linq;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using Comal.Classes;
  9. using InABox.Clients;
  10. using InABox.Configuration;
  11. using InABox.Core;
  12. using PRS.Shared;
  13. using PRSDesktop.WidgetGroups;
  14. namespace PRSDesktop
  15. {
  16. public class TimesheetWidgetProperties : IUserConfigurationSettings, IDashboardProperties { }
  17. public class TimesheetWidgetElement : DashboardElement<TimesheetWidget, HumanResources, TimesheetWidgetProperties> { }
  18. /// <summary>
  19. /// Interaction logic for TimesheetWidget.xaml
  20. /// </summary>
  21. public partial class TimesheetWidget : UserControl, IDashboardWidget<HumanResources, TimesheetWidgetProperties>
  22. {
  23. private DateTime _date = DateTime.Today;
  24. private Guid _groupid = CoreUtils.FullGuid;
  25. private CoreTable activities;
  26. private Dictionary<Guid, Tuple<Employee, List<EmployeeRosterItem>>> employeeData;
  27. private readonly DataTable report = new();
  28. private CoreTable timesheets;
  29. public TimesheetWidget()
  30. {
  31. InitializeComponent();
  32. report.Columns.Add("ID", typeof(Guid));
  33. report.Columns.Add("Name", typeof(string));
  34. report.Columns.Add("Leave", typeof(string));
  35. report.Columns.Add("LateStart", typeof(TimeSpan));
  36. report.Columns.Add("EarlyFinish", typeof(TimeSpan));
  37. report.Columns.Add("ClockIn", typeof(string));
  38. report.Columns.Add("ClockOut", typeof(string));
  39. report.PrimaryKey = new[] { report.Columns[0] };
  40. }
  41. public DateTime Date
  42. {
  43. get => _date;
  44. set
  45. {
  46. _date = value;
  47. LoadTimeSheets();
  48. }
  49. }
  50. public Guid GroupID
  51. {
  52. get => _groupid;
  53. set
  54. {
  55. _groupid = value;
  56. LoadEmployees(value);
  57. }
  58. }
  59. public TimesheetWidgetProperties Properties { get; set; }
  60. public event LoadSettings<TimesheetWidgetProperties>? LoadSettings;
  61. public event SaveSettings<TimesheetWidgetProperties>? SaveSettings;
  62. public void Setup()
  63. {
  64. LoadEmployees(GroupID);
  65. LoadActivities();
  66. }
  67. public void Refresh()
  68. {
  69. LoadTimeSheets();
  70. }
  71. public void Shutdown(CancelEventArgs? cancel)
  72. {
  73. }
  74. private void ClearReport()
  75. {
  76. Report.ItemsSource = null;
  77. }
  78. private void LoadEmployees(Guid id)
  79. {
  80. ClearReport();
  81. employeeData = null;
  82. var employeeFilter = id != CoreUtils.FullGuid ? new Filter<Employee>(x => x.Group.ID).IsEqualTo(id) : null;
  83. Client.QueryMultiple(
  84. (results, e) =>
  85. {
  86. if(results != null)
  87. {
  88. var rosterItems = results.Get<EmployeeRosterItem>()
  89. .ToObjects<EmployeeRosterItem>().GroupBy(x => x.Employee.ID)
  90. .ToDictionary(x => x.Key, x => x);
  91. employeeData = results.Get<Employee>().ToObjects<Employee>()
  92. .ToDictionary(x => x.ID, x =>
  93. {
  94. return new Tuple<Employee, List<EmployeeRosterItem>>(x, rosterItems.GetValueOrDefault(x.ID)?.ToList() ?? new());
  95. });
  96. CheckData();
  97. }
  98. else if(e != null)
  99. {
  100. Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
  101. Dispatcher.Invoke(() =>
  102. {
  103. MessageBox.Show($"Error loading data: {e.Message}");
  104. });
  105. }
  106. },
  107. new KeyedQueryDef<Employee>(
  108. employeeFilter,
  109. null,
  110. null),
  111. new KeyedQueryDef<EmployeeRosterItem>(
  112. new Filter<EmployeeRosterItem>(x => x.Employee).InQuery(employeeFilter, x => x.ID),
  113. null));
  114. }
  115. private void LoadActivities()
  116. {
  117. ClearReport();
  118. activities = null;
  119. new Client<Activity>().Query(
  120. new Filter<Activity>(x => x.IsLeave).IsEqualTo(true),
  121. new Columns<Activity>(
  122. x => x.ID,
  123. x => x.Description
  124. ),
  125. null,
  126. (o, e) =>
  127. {
  128. activities = o;
  129. CheckData();
  130. }
  131. );
  132. }
  133. private void LoadTimeSheets()
  134. {
  135. ClearReport();
  136. timesheets = null;
  137. new Client<TimeSheet>().Query(
  138. new Filter<TimeSheet>(x => x.Date).IsEqualTo(_date),
  139. null,
  140. new SortOrder<TimeSheet>(x => x.EmployeeLink.Name),
  141. (o, e) =>
  142. {
  143. timesheets = o;
  144. CheckData();
  145. }
  146. );
  147. }
  148. private void CheckData()
  149. {
  150. if (employeeData != null && activities != null && timesheets != null)
  151. ProcessData();
  152. }
  153. private string Codify(string name)
  154. {
  155. var result = "";
  156. var comps = name.ToUpper().Split(' ');
  157. foreach (var comp in comps)
  158. if (comp.Any())
  159. result += comp.First();
  160. return string.IsNullOrWhiteSpace(result) ? "??" : result;
  161. }
  162. private void ProcessData()
  163. {
  164. try
  165. {
  166. report.Rows.Clear();
  167. foreach (var time in timesheets.Rows)
  168. {
  169. var empid = time.Get<TimeSheet, Guid>(x => x.EmployeeLink.ID);
  170. var empname = time.Get<TimeSheet, string>(x => x.EmployeeLink.Name);
  171. if (report.Rows.Find(empid) == null)
  172. {
  173. if (employeeData.TryGetValue(empid, out var data))
  174. {
  175. var (employee, rosters) = data;
  176. var userid = employee.UserLink.UserID;
  177. var date = time.Get<TimeSheet, DateTime>(c => c.Date);
  178. var rosterday = RosterUtils.GetRoster(rosters, employee.RosterStart, date);
  179. var shifts = RosterUtils.GetBlocks(rosterday, date, TimeSpan.Zero, TimeSpan.FromDays(1));
  180. var shiftstart = shifts.Aggregate(TimeSpan.MaxValue, (time, block) => block.Start < time ? block.Start : time);
  181. var shiftend = shifts.Aggregate(TimeSpan.Zero, (time, block) => block.Finish > time ? block.Finish : time);
  182. var rows = timesheets.Rows.Where(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
  183. var start = new TimeSpan(long.MaxValue);
  184. TimeSpan? late = null;
  185. var finish = new TimeSpan(long.MinValue);
  186. TimeSpan? early = null;
  187. var leave = "";
  188. var clockin = "";
  189. var clockout = "";
  190. var leaves = new List<string>();
  191. foreach (var row in rows)
  192. {
  193. var activity = row.Get<TimeSheet, Guid>(x => x.ActivityLink.ID);
  194. var activityrow = activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(activity));
  195. if (activityrow != null)
  196. {
  197. var thisleave = Codify(activityrow.Get<Activity, string>(x => x.Description));
  198. if (!leaves.Contains(thisleave))
  199. leaves.Add(thisleave);
  200. }
  201. leave = string.Join(",", leaves);
  202. var createdby = row.Get<TimeSheet, string>(x => x.CreatedBy);
  203. if (createdby == null)
  204. createdby = "";
  205. if (shiftstart.Ticks != 0)
  206. {
  207. var thisstart = row.Get<TimeSheet, TimeSpan>(x => x.Start);
  208. if (thisstart < start)
  209. {
  210. start = thisstart;
  211. if (start > shiftstart)
  212. late = !late.HasValue || start < late.Value ? start : late;
  213. else
  214. late = null;
  215. clockin = createdby.Equals(userid) ? "" : createdby;
  216. }
  217. }
  218. if (shiftend.Ticks != 0)
  219. {
  220. var thisfinish = row.Get<TimeSheet, TimeSpan>(x => x.Finish);
  221. if (thisfinish.Ticks == 0)
  222. {
  223. shiftend = new TimeSpan(0);
  224. early = null;
  225. }
  226. else
  227. {
  228. if (thisfinish > finish)
  229. {
  230. finish = thisfinish;
  231. if (finish < shiftend)
  232. early = !early.HasValue || finish > early.Value ? finish : early;
  233. else
  234. early = null;
  235. clockout = createdby.Equals(userid) ? "" : createdby;
  236. }
  237. }
  238. }
  239. }
  240. leave = string.Join(",", leaves);
  241. if (!string.IsNullOrEmpty(leave) || late.HasValue || early.HasValue || !string.IsNullOrEmpty(clockin) ||
  242. !string.IsNullOrEmpty(clockout))
  243. report.Rows.Add(empid, empname, leave, late, early, clockin, clockout);
  244. }
  245. }
  246. }
  247. }
  248. catch (Exception e)
  249. {
  250. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  251. }
  252. Dispatcher.Invoke(() => { Report.ItemsSource = report; });
  253. }
  254. }
  255. }