LeaveRequestStore.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using Comal.Classes;
  7. using InABox.Core;
  8. namespace Comal.Stores
  9. {
  10. internal class LeaveRequestStore : BaseStore<LeaveRequest>
  11. {
  12. private void UpdateAssignments(IEnumerable<LeaveRequest> entities)
  13. {
  14. var empids = entities.Select(x => x.EmployeeLink.ID).ToArray();
  15. var ids = entities.Select(x => x.ID).ToArray();
  16. var empquery = Task.Run(() =>
  17. {
  18. return Provider.Query(
  19. new Filter<Employee>(x => x.ID).InList(empids),
  20. new Columns<Employee>(x => x.ID, x => x.UsualStart, x => x.UsualFinish)
  21. );
  22. });
  23. var assquery = Task.Run(() =>
  24. {
  25. return Provider.Query(
  26. new Filter<Assignment>(x => x.LeaveRequestLink.ID).InList(ids),
  27. new Columns<Assignment>(x => x.ID, x => x.LeaveRequestLink.ID, x => x.Date)
  28. );
  29. });
  30. var timequery = Task.Run(() =>
  31. {
  32. return Provider.Query(
  33. new Filter<TimeSheet>(x => x.LeaveRequestLink.ID).InList(ids),
  34. new Columns<TimeSheet>(x => x.ID, x => x.LeaveRequestLink.ID, x => x.Date)
  35. );
  36. });
  37. Task.WaitAll(empquery, assquery, timequery);
  38. var assignments = assquery.Result;
  39. var timesheets = timequery.Result;
  40. var employees = empquery.Result;
  41. var Updates = new Dictionary<TimeSheet, Assignment>();
  42. foreach (var entity in entities)
  43. {
  44. var emp = employees.Rows.FirstOrDefault(x => x.Get<Employee, Guid>(c => c.ID).Equals(entity.EmployeeLink.ID))?.ToObject<Employee>();
  45. var normalStart = emp != null && emp.UsualStart.Ticks > 0 ? emp.UsualStart : new TimeSpan(8, 0, 0);
  46. var normalFinish = emp != null && emp.UsualFinish.Ticks > 0 ? emp.UsualFinish : normalStart.Add(new TimeSpan(8, 30, 0));
  47. var leavedays = new List<LeaveDay>();
  48. if (entity.Status == LeaveRequestStatus.Approved)
  49. for (var date = entity.From; date <= entity.To; date = date.AddDays(1))
  50. if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday)
  51. {
  52. var start = date == entity.From && entity.FromTime > normalStart ? entity.FromTime : normalStart;
  53. var finish = date == entity.To && entity.ToTime < normalFinish ? entity.ToTime : normalFinish;
  54. leavedays.Add(new LeaveDay(date, start, finish));
  55. }
  56. var approval = DateTime.Now;
  57. var note = string.Format("{0}\nApproved on {1:dd MMM yy} by {2}", entity.Notes, approval, entity.LastUpdateBy);
  58. foreach (var leaveday in leavedays)
  59. {
  60. var assignment = new Assignment();
  61. var assrow = assignments.Rows.FirstOrDefault(r =>
  62. r.Get<Assignment, Guid>(c => c.LeaveRequestLink.ID) == entity.ID &&
  63. r.Get<Assignment, DateTime>(c => c.Date) == leaveday.Date);
  64. if (assrow != null)
  65. {
  66. // Don't Delete this Assignment!
  67. assignments.Rows.Remove(assrow);
  68. assignment.ID = assrow.Get<Assignment, Guid>(c => c.ID);
  69. //assignment.CommitChanges();
  70. }
  71. assignment.EmployeeLink.ID = entity.EmployeeLink.ID;
  72. assignment.Date = leaveday.Date;
  73. assignment.Start = leaveday.Start;
  74. assignment.Finish = leaveday.Finish;
  75. assignment.Duration = leaveday.Finish - leaveday.Start;
  76. assignment.ActivityLink.ID = entity.LeaveType.ID;
  77. assignment.Description = note;
  78. assignment.Completed = approval;
  79. assignment.LeaveRequestLink.ID = entity.ID;
  80. var timesheet = new TimeSheet();
  81. var timerow = timesheets.Rows.FirstOrDefault(r =>
  82. r.Get<TimeSheet, Guid>(c => c.LeaveRequestLink.ID) == entity.ID && r.Get<TimeSheet, DateTime>(c => c.Date) == leaveday.Date);
  83. if (timerow != null)
  84. {
  85. // Don't Delete this Timesheet!
  86. timesheets.Rows.Remove(timerow);
  87. timesheet.ID = timerow.Get<TimeSheet, Guid>(c => c.ID);
  88. //timesheet.CommitChanges();
  89. }
  90. timesheet.EmployeeLink.ID = entity.EmployeeLink.ID;
  91. timesheet.Date = leaveday.Date;
  92. timesheet.Start = leaveday.Start;
  93. timesheet.Finish = leaveday.Finish;
  94. timesheet.Duration = leaveday.Finish - leaveday.Start;
  95. timesheet.ActivityLink.ID = entity.LeaveType.ID;
  96. timesheet.Approved = approval;
  97. timesheet.ApprovedStart = leaveday.Start;
  98. timesheet.ApprovedFinish = leaveday.Finish;
  99. timesheet.ApprovedDuration = leaveday.Finish - leaveday.Start;
  100. timesheet.Notes = note;
  101. timesheet.Confirmed = approval;
  102. timesheet.LeaveRequestLink.ID = entity.ID;
  103. Updates[timesheet] = assignment;
  104. }
  105. }
  106. var AssignmentsToDelete = new List<Assignment>();
  107. foreach (var row in assignments.Rows)
  108. AssignmentsToDelete.Add(new Assignment { ID = row.Get<Assignment, Guid>(x => x.ID) });
  109. Provider.Delete(AssignmentsToDelete, UserID);
  110. var TimeSheetsToDelete = new List<TimeSheet>();
  111. foreach (var row in timesheets.Rows)
  112. TimeSheetsToDelete.Add(new TimeSheet { ID = row.Get<TimeSheet, Guid>(x => x.ID) });
  113. Provider.Delete(TimeSheetsToDelete, UserID);
  114. Provider.Save(Updates.Keys.Where(x => x.IsChanged()));
  115. foreach (var update in Updates)
  116. update.Value.TimeSheetLink.ID = update.Key.ID;
  117. Provider.Save(Updates.Values.Where(x => x.IsChanged()));
  118. #region Old Code
  119. //Filter<Assignment> assfilter = new Filter<Assignment>(x => x.LeaveRequestLink.ID).IsEqualTo(entity.ID);
  120. //assfilter.Ors.Add(new Filter<Assignment>(x => x.Date).IsGreaterThanOrEqualTo(entity.From)
  121. // .And(x => x.Date).IsLessThanOrEqualTo(entity.To)
  122. // .And(x=>x.EmployeeLink.ID).IsEqualTo(entity.EmployeeLink.ID)
  123. //);
  124. //List<Assignment> assignments = assStore.Load(assfilter).ToList();
  125. //Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: {0} Assignments Found", assignments.Count));
  126. //List<Assignment> deletes = new List<Assignment>();
  127. //List<Tuple<TimeSheet, Assignment>> updates = new List<Tuple<TimeSheet, Assignment>>();
  128. //if (entity.Approved == DateTime.MinValue)
  129. //{
  130. // // Clear Out All Assignments / Timesheets for Unapproved Requests
  131. // foreach (var unapproved in assignments.Where(x => x.LeaveRequestLink.ID.Equals(entity.ID)))
  132. // deletes.Add(unapproved);
  133. //}
  134. //else
  135. //{
  136. // TimeSpan normalDuration = normalFinish - normalStart;
  137. // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Normal Duration is {0} hours", normalDuration.TotalHours));
  138. // // Clear out any existing assignments / timesheets that fall outside the requested dates
  139. // foreach (var excluded in assignments.Where(x => (x.LeaveRequestLink.ID == entity.ID) && ((x.Date.Date < entity.From.Date) || (x.Date.Date > entity.To.Date))))
  140. // deletes.Add(excluded);
  141. // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Scanning from {0} to {1}", entity.From, entity.To));
  142. // DateTime date = entity.From;
  143. // while (date <= entity.To)
  144. // {
  145. // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Scanning {0}", date));
  146. // if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))
  147. // {
  148. // var current = assignments.FirstOrDefault(x => x.Date.Date.Equals(date) && x.LeaveRequestLink.ID.Equals(entity.ID));
  149. // // Are there any other assignments for the current day
  150. // var others = assignments.Where(x => x.Date.Date.Equals(date) && !x.LeaveRequestLink.ID.Equals(entity.ID));
  151. // TimeSpan start = date.Equals(entity.From) ? entity.FromTime > normalStart ? entity.FromTime : normalStart : normalStart;
  152. // TimeSpan balance = (date.Equals(entity.To) ? (entity.ToTime < normalFinish ? entity.ToTime : normalFinish) : normalFinish) - start;
  153. // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Starting Balance is {0}", balance.TotalHours));
  154. // foreach (var other in others)
  155. // {
  156. // TimeSpan otherdur = other.Duration;
  157. // DateTime otherdate = other.Date;
  158. // if (otherdate.TimeOfDay.Add(otherdur) > start)
  159. // start = otherdate.TimeOfDay.Add(otherdur);
  160. // balance = balance.Subtract(otherdur);
  161. // }
  162. // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Finishing Balance is {0}", balance.TotalHours));
  163. // if (balance.Ticks <= 0L)
  164. // {
  165. // // If the day is already fully assigned, skip or delete it
  166. // if (current != null)
  167. // deletes.Add(current);
  168. // }
  169. // else
  170. // {
  171. // if (current == null)
  172. // {
  173. // current = new Assignment();
  174. // current.LeaveRequestLink.ID = entity.ID;
  175. // current.Date = date;
  176. // current.Description = String.Format("Leave Request Approved on {0:dd MMM yy HH:mm}", entity.Approved);
  177. // assignments.Add(current);
  178. // }
  179. // current.ActivityLink.ID = entity.LeaveType.ID;
  180. // current.EmployeeLink.ID = entity.EmployeeLink.ID;
  181. // current.Date = date;
  182. // current.Start = start;
  183. // current.Duration = balance;
  184. // TimeSheet ts = FindSubStore<TimeSheet>().Load(new Filter<TimeSheet>(x => x.ID).IsEqualTo(current.TimeSheetLink.ID)).FirstOrDefault();
  185. // if (ts == null)
  186. // ts = new TimeSheet();
  187. // ts.EmployeeLink.ID = current.EmployeeLink.ID;
  188. // ts.JobLink.ID = current.JobLink.ID;
  189. // ts.ActivityLink.ID = current.ActivityLink.ID;
  190. // ts.LeaveRequestLink.ID = current.LeaveRequestLink.ID;
  191. // ts.Date = current.Date.Date;
  192. // ts.Start = current.Date.TimeOfDay;
  193. // ts.Finish = current.Date.TimeOfDay.Add(current.Duration);
  194. // ts.Notes = String.Format("Leave Request Approved on {0:dd MMM yy HH:mm}", entity.Approved);
  195. // updates.Add(new Tuple<TimeSheet, Assignment>(ts,current));
  196. // }
  197. // }
  198. // date = date.AddDays(1);
  199. // }
  200. //}
  201. //if (deletes.Any())
  202. // assStore.Delete(deletes, "Removing Assignment from Leave Request");
  203. //var tsupdates = updates.Where(x => x.Item1.IsChanged());
  204. //if (tsupdates.Any())
  205. // FindSubStore<TimeSheet>().Save(tsupdates.Select(x=>x.Item1), "Creating TimeSheet for Leave Request");
  206. //foreach (var update in updates)
  207. // update.Item2.TimeSheetLink.ID = update.Item1.ID;
  208. //var assupdates = updates.Where(x => x.Item2.IsChanged());
  209. //if (assupdates.Any())
  210. // assStore.Save(assupdates.Select(x=>x.Item2), "Assignment Generated from Approved Leave Request");
  211. #endregion
  212. }
  213. protected override void OnSave(LeaveRequest entity, ref string auditnote)
  214. {
  215. base.OnSave(entity, ref auditnote);
  216. UpdateAssignments(new[] { entity });
  217. if (entity.HasOriginalValue(c => c.Status))
  218. NotifyEmployee(
  219. entity,
  220. x => x.EmployeeLink.ID,
  221. e => e.HasOriginalValue(x => x.Status),
  222. e => string.Format("Leave Request {0}", e.Status),
  223. e =>
  224. {
  225. var sb = new StringBuilder();
  226. sb.AppendLine(string.Format(
  227. "Your Leave Request submitted {0:dd MMM yyy} for {1:dd MMM yy} - {2:dd MMM yy} has changed from {3} to {4}.",
  228. e.Created,
  229. e.From,
  230. e.To,
  231. e.GetOriginalValue(c => c.Status),
  232. e.Status
  233. ));
  234. if (!string.IsNullOrWhiteSpace(e.StatusNotes))
  235. sb.AppendLine(string.Format("\nNotes:\n{0}", e.StatusNotes?.Trim()));
  236. return sb.ToString();
  237. }
  238. );
  239. }
  240. protected override void OnSave(IEnumerable<LeaveRequest> entities, ref string auditnote)
  241. {
  242. base.OnSave(entities, ref auditnote);
  243. UpdateAssignments(entities);
  244. }
  245. private class LeaveDay
  246. {
  247. public LeaveDay(DateTime date, TimeSpan start, TimeSpan finish)
  248. {
  249. Date = date;
  250. Start = start;
  251. Finish = finish;
  252. }
  253. public DateTime Date { get; }
  254. public TimeSpan Start { get; }
  255. public TimeSpan Finish { get; }
  256. }
  257. //protected override void BeforeDelete(LeaveRequest entity)
  258. //{
  259. // base.BeforeDelete(entity);
  260. // entity.Status = LeaveRequestStatus.Rejected;
  261. // UpdateAssignments(new LeaveRequest[] { entity });
  262. //}
  263. }
  264. }