TimesheetWidget.xaml.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. Columns.None<Activity>().Add(
  122. x => x.ID,
  123. x => x.Description
  124. ),
  125. null,
  126. CoreRange.All,
  127. (o, e) =>
  128. {
  129. activities = o;
  130. CheckData();
  131. }
  132. );
  133. }
  134. private void LoadTimeSheets()
  135. {
  136. ClearReport();
  137. timesheets = null;
  138. new Client<TimeSheet>().Query(
  139. new Filter<TimeSheet>(x => x.Date).IsEqualTo(_date),
  140. null,
  141. new SortOrder<TimeSheet>(x => x.EmployeeLink.Name),
  142. CoreRange.All,
  143. (o, e) =>
  144. {
  145. timesheets = o;
  146. CheckData();
  147. }
  148. );
  149. }
  150. private void CheckData()
  151. {
  152. if (employeeData != null && activities != null && timesheets != null)
  153. ProcessData();
  154. }
  155. private string Codify(string name)
  156. {
  157. var result = "";
  158. var comps = name.ToUpper().Split(' ');
  159. foreach (var comp in comps)
  160. if (comp.Any())
  161. result += comp.First();
  162. return string.IsNullOrWhiteSpace(result) ? "??" : result;
  163. }
  164. private void ProcessData()
  165. {
  166. try
  167. {
  168. report.Rows.Clear();
  169. foreach (var time in timesheets.Rows)
  170. {
  171. var empid = time.Get<TimeSheet, Guid>(x => x.EmployeeLink.ID);
  172. var empname = time.Get<TimeSheet, string>(x => x.EmployeeLink.Name);
  173. if (report.Rows.Find(empid) == null)
  174. {
  175. if (employeeData.TryGetValue(empid, out var data))
  176. {
  177. var (employee, rosters) = data;
  178. var userid = employee.UserLink.UserID;
  179. var date = time.Get<TimeSheet, DateTime>(c => c.Date);
  180. var rosterday = RosterUtils.GetRoster(rosters, employee.RosterStart, date);
  181. var shifts = RosterUtils.GetBlocks(rosterday, date, TimeSpan.Zero, TimeSpan.FromDays(1));
  182. var shiftstart = shifts.Aggregate(TimeSpan.MaxValue, (time, block) => block.Start < time ? block.Start : time);
  183. var shiftend = shifts.Aggregate(TimeSpan.Zero, (time, block) => block.Finish > time ? block.Finish : time);
  184. var rows = timesheets.Rows.Where(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
  185. var start = new TimeSpan(long.MaxValue);
  186. TimeSpan? late = null;
  187. var finish = new TimeSpan(long.MinValue);
  188. TimeSpan? early = null;
  189. var leave = "";
  190. var clockin = "";
  191. var clockout = "";
  192. var leaves = new List<string>();
  193. foreach (var row in rows)
  194. {
  195. var activity = row.Get<TimeSheet, Guid>(x => x.ActivityLink.ID);
  196. var activityrow = activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(activity));
  197. if (activityrow != null)
  198. {
  199. var thisleave = Codify(activityrow.Get<Activity, string>(x => x.Description));
  200. if (!leaves.Contains(thisleave))
  201. leaves.Add(thisleave);
  202. }
  203. leave = string.Join(",", leaves);
  204. var createdby = row.Get<TimeSheet, string>(x => x.CreatedBy);
  205. if (createdby == null)
  206. createdby = "";
  207. if (shiftstart.Ticks != 0)
  208. {
  209. var thisstart = row.Get<TimeSheet, TimeSpan>(x => x.Start);
  210. if (thisstart < start)
  211. {
  212. start = thisstart;
  213. if (start > shiftstart)
  214. late = !late.HasValue || start < late.Value ? start : late;
  215. else
  216. late = null;
  217. clockin = createdby.Equals(userid) ? "" : createdby;
  218. }
  219. }
  220. if (shiftend.Ticks != 0)
  221. {
  222. var thisfinish = row.Get<TimeSheet, TimeSpan>(x => x.Finish);
  223. if (thisfinish.Ticks == 0)
  224. {
  225. shiftend = new TimeSpan(0);
  226. early = null;
  227. }
  228. else
  229. {
  230. if (thisfinish > finish)
  231. {
  232. finish = thisfinish;
  233. if (finish < shiftend)
  234. early = !early.HasValue || finish > early.Value ? finish : early;
  235. else
  236. early = null;
  237. clockout = createdby.Equals(userid) ? "" : createdby;
  238. }
  239. }
  240. }
  241. }
  242. leave = string.Join(",", leaves);
  243. if (!string.IsNullOrEmpty(leave) || late.HasValue || early.HasValue || !string.IsNullOrEmpty(clockin) ||
  244. !string.IsNullOrEmpty(clockout))
  245. report.Rows.Add(empid, empname, leave, late, early, clockin, clockout);
  246. }
  247. }
  248. }
  249. }
  250. catch (Exception e)
  251. {
  252. Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
  253. }
  254. Dispatcher.Invoke(() => { Report.ItemsSource = report; });
  255. }
  256. }
  257. }