using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Comal.Classes; using InABox.Core; namespace Comal.Stores { internal class LeaveRequestStore : BaseStore { private void UpdateAssignments(IEnumerable entities) { var empids = entities.Select(x => x.EmployeeLink.ID).ToArray(); var ids = entities.Select(x => x.ID).ToArray(); var empquery = Task.Run(() => { return Provider.Query( new Filter(x => x.ID).InList(empids), new Columns(x => x.ID, x => x.UsualStart, x => x.UsualFinish) ); }); var assquery = Task.Run(() => { return Provider.Query( new Filter(x => x.LeaveRequestLink.ID).InList(ids), new Columns(x => x.ID, x => x.LeaveRequestLink.ID, x => x.Date) ); }); var timequery = Task.Run(() => { return Provider.Query( new Filter(x => x.LeaveRequestLink.ID).InList(ids), new Columns(x => x.ID, x => x.LeaveRequestLink.ID, x => x.Date) ); }); Task.WaitAll(empquery, assquery, timequery); var assignments = assquery.Result; var timesheets = timequery.Result; var employees = empquery.Result; var Updates = new Dictionary(); foreach (var entity in entities) { var emp = employees.Rows.FirstOrDefault(x => x.Get(c => c.ID).Equals(entity.EmployeeLink.ID))?.ToObject(); var normalStart = emp != null && emp.UsualStart.Ticks > 0 ? emp.UsualStart : new TimeSpan(8, 0, 0); var normalFinish = emp != null && emp.UsualFinish.Ticks > 0 ? emp.UsualFinish : normalStart.Add(new TimeSpan(8, 30, 0)); var leavedays = new List(); if (entity.Status == LeaveRequestStatus.Approved) for (var date = entity.From; date <= entity.To; date = date.AddDays(1)) if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday) { var start = date == entity.From && entity.FromTime > normalStart ? entity.FromTime : normalStart; var finish = date == entity.To && entity.ToTime < normalFinish ? entity.ToTime : normalFinish; leavedays.Add(new LeaveDay(date, start, finish)); } var approval = DateTime.Now; var note = string.Format("{0}\nApproved on {1:dd MMM yy} by {2}", entity.Notes, approval, entity.LastUpdateBy); foreach (var leaveday in leavedays) { var assignment = new Assignment(); var assrow = assignments.Rows.FirstOrDefault(r => r.Get(c => c.LeaveRequestLink.ID) == entity.ID && r.Get(c => c.Date) == leaveday.Date); if (assrow != null) { // Don't Delete this Assignment! assignments.Rows.Remove(assrow); assignment.ID = assrow.Get(c => c.ID); //assignment.CommitChanges(); } assignment.EmployeeLink.ID = entity.EmployeeLink.ID; assignment.Date = leaveday.Date; assignment.Start = leaveday.Start; assignment.Finish = leaveday.Finish; assignment.Duration = leaveday.Finish - leaveday.Start; assignment.ActivityLink.ID = entity.LeaveType.ID; assignment.Description = note; assignment.Completed = approval; assignment.LeaveRequestLink.ID = entity.ID; var timesheet = new TimeSheet(); var timerow = timesheets.Rows.FirstOrDefault(r => r.Get(c => c.LeaveRequestLink.ID) == entity.ID && r.Get(c => c.Date) == leaveday.Date); if (timerow != null) { // Don't Delete this Timesheet! timesheets.Rows.Remove(timerow); timesheet.ID = timerow.Get(c => c.ID); //timesheet.CommitChanges(); } timesheet.EmployeeLink.ID = entity.EmployeeLink.ID; timesheet.Date = leaveday.Date; timesheet.Start = leaveday.Start; timesheet.Finish = leaveday.Finish; timesheet.Duration = leaveday.Finish - leaveday.Start; timesheet.ActivityLink.ID = entity.LeaveType.ID; timesheet.Approved = approval; timesheet.ApprovedStart = leaveday.Start; timesheet.ApprovedFinish = leaveday.Finish; timesheet.ApprovedDuration = leaveday.Finish - leaveday.Start; timesheet.Notes = note; timesheet.Confirmed = approval; timesheet.LeaveRequestLink.ID = entity.ID; Updates[timesheet] = assignment; } } var AssignmentsToDelete = new List(); foreach (var row in assignments.Rows) AssignmentsToDelete.Add(new Assignment { ID = row.Get(x => x.ID) }); Provider.Delete(AssignmentsToDelete, UserID); var TimeSheetsToDelete = new List(); foreach (var row in timesheets.Rows) TimeSheetsToDelete.Add(new TimeSheet { ID = row.Get(x => x.ID) }); Provider.Delete(TimeSheetsToDelete, UserID); Provider.Save(Updates.Keys.Where(x => x.IsChanged())); foreach (var update in Updates) update.Value.TimeSheetLink.ID = update.Key.ID; Provider.Save(Updates.Values.Where(x => x.IsChanged())); #region Old Code //Filter assfilter = new Filter(x => x.LeaveRequestLink.ID).IsEqualTo(entity.ID); //assfilter.Ors.Add(new Filter(x => x.Date).IsGreaterThanOrEqualTo(entity.From) // .And(x => x.Date).IsLessThanOrEqualTo(entity.To) // .And(x=>x.EmployeeLink.ID).IsEqualTo(entity.EmployeeLink.ID) //); //List assignments = assStore.Load(assfilter).ToList(); //Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: {0} Assignments Found", assignments.Count)); //List deletes = new List(); //List> updates = new List>(); //if (entity.Approved == DateTime.MinValue) //{ // // Clear Out All Assignments / Timesheets for Unapproved Requests // foreach (var unapproved in assignments.Where(x => x.LeaveRequestLink.ID.Equals(entity.ID))) // deletes.Add(unapproved); //} //else //{ // TimeSpan normalDuration = normalFinish - normalStart; // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Normal Duration is {0} hours", normalDuration.TotalHours)); // // Clear out any existing assignments / timesheets that fall outside the requested dates // foreach (var excluded in assignments.Where(x => (x.LeaveRequestLink.ID == entity.ID) && ((x.Date.Date < entity.From.Date) || (x.Date.Date > entity.To.Date)))) // deletes.Add(excluded); // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Scanning from {0} to {1}", entity.From, entity.To)); // DateTime date = entity.From; // while (date <= entity.To) // { // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Scanning {0}", date)); // if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday)) // { // var current = assignments.FirstOrDefault(x => x.Date.Date.Equals(date) && x.LeaveRequestLink.ID.Equals(entity.ID)); // // Are there any other assignments for the current day // var others = assignments.Where(x => x.Date.Date.Equals(date) && !x.LeaveRequestLink.ID.Equals(entity.ID)); // TimeSpan start = date.Equals(entity.From) ? entity.FromTime > normalStart ? entity.FromTime : normalStart : normalStart; // TimeSpan balance = (date.Equals(entity.To) ? (entity.ToTime < normalFinish ? entity.ToTime : normalFinish) : normalFinish) - start; // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Starting Balance is {0}", balance.TotalHours)); // foreach (var other in others) // { // TimeSpan otherdur = other.Duration; // DateTime otherdate = other.Date; // if (otherdate.TimeOfDay.Add(otherdur) > start) // start = otherdate.TimeOfDay.Add(otherdur); // balance = balance.Subtract(otherdur); // } // Logger.Send(LogType.Information, UserID, String.Format("* LeaveRequest: Finishing Balance is {0}", balance.TotalHours)); // if (balance.Ticks <= 0L) // { // // If the day is already fully assigned, skip or delete it // if (current != null) // deletes.Add(current); // } // else // { // if (current == null) // { // current = new Assignment(); // current.LeaveRequestLink.ID = entity.ID; // current.Date = date; // current.Description = String.Format("Leave Request Approved on {0:dd MMM yy HH:mm}", entity.Approved); // assignments.Add(current); // } // current.ActivityLink.ID = entity.LeaveType.ID; // current.EmployeeLink.ID = entity.EmployeeLink.ID; // current.Date = date; // current.Start = start; // current.Duration = balance; // TimeSheet ts = FindSubStore().Load(new Filter(x => x.ID).IsEqualTo(current.TimeSheetLink.ID)).FirstOrDefault(); // if (ts == null) // ts = new TimeSheet(); // ts.EmployeeLink.ID = current.EmployeeLink.ID; // ts.JobLink.ID = current.JobLink.ID; // ts.ActivityLink.ID = current.ActivityLink.ID; // ts.LeaveRequestLink.ID = current.LeaveRequestLink.ID; // ts.Date = current.Date.Date; // ts.Start = current.Date.TimeOfDay; // ts.Finish = current.Date.TimeOfDay.Add(current.Duration); // ts.Notes = String.Format("Leave Request Approved on {0:dd MMM yy HH:mm}", entity.Approved); // updates.Add(new Tuple(ts,current)); // } // } // date = date.AddDays(1); // } //} //if (deletes.Any()) // assStore.Delete(deletes, "Removing Assignment from Leave Request"); //var tsupdates = updates.Where(x => x.Item1.IsChanged()); //if (tsupdates.Any()) // FindSubStore().Save(tsupdates.Select(x=>x.Item1), "Creating TimeSheet for Leave Request"); //foreach (var update in updates) // update.Item2.TimeSheetLink.ID = update.Item1.ID; //var assupdates = updates.Where(x => x.Item2.IsChanged()); //if (assupdates.Any()) // assStore.Save(assupdates.Select(x=>x.Item2), "Assignment Generated from Approved Leave Request"); #endregion } protected override void OnSave(LeaveRequest entity, ref string auditnote) { base.OnSave(entity, ref auditnote); UpdateAssignments(new[] { entity }); if (entity.HasOriginalValue(c => c.Status)) NotifyEmployee( entity, x => x.EmployeeLink.ID, e => e.HasOriginalValue(x => x.Status), e => string.Format("Leave Request {0}", e.Status), e => { var sb = new StringBuilder(); sb.AppendLine(string.Format( "Your Leave Request submitted {0:dd MMM yyy} for {1:dd MMM yy} - {2:dd MMM yy} has changed from {3} to {4}.", e.Created, e.From, e.To, e.GetOriginalValue(c => c.Status), e.Status )); if (!string.IsNullOrWhiteSpace(e.StatusNotes)) sb.AppendLine(string.Format("\nNotes:\n{0}", e.StatusNotes?.Trim())); return sb.ToString(); } ); } protected override void OnSave(IEnumerable entities, ref string auditnote) { base.OnSave(entities, ref auditnote); UpdateAssignments(entities); } private class LeaveDay { public LeaveDay(DateTime date, TimeSpan start, TimeSpan finish) { Date = date; Start = start; Finish = finish; } public DateTime Date { get; } public TimeSpan Start { get; } public TimeSpan Finish { get; } } //protected override void BeforeDelete(LeaveRequest entity) //{ // base.BeforeDelete(entity); // entity.Status = LeaveRequestStatus.Rejected; // UpdateAssignments(new LeaveRequest[] { entity }); //} } }