Explorar o código

Fix to Timesheeting and leave requests to use new roster system.

Kenric Nugteren hai 5 meses
pai
achega
af2d434d95

+ 4 - 6
prs.desktop/Components/Calendar/Models/EmployeeResourceModel.cs

@@ -17,13 +17,11 @@ namespace PRSDesktop
             RosterStart = Get(c => c.RosterStart);            
         }
 
-        public override Columns<Employee> GetColumns()
-        {
-            return InABox.Core.Columns.None<Employee>().Add(c => c.ID)
+        public override Columns<Employee> GetColumns() => Columns;
+
+        public static new Columns<Employee> Columns =>
+            InABox.Core.Columns.None<Employee>().Add(c => c.ID)
                 .Add(c => c.Name)
-                .Add(c => c.Roster)
                 .Add(c => c.RosterStart);
-        }
-        
     }
 }

+ 6 - 3
prs.desktop/Components/EmployeeSelector/EmployeeSelector.xaml.cs

@@ -127,10 +127,13 @@ namespace PRSDesktop
             using (new EventSuppressor(Suppress.This))
             {
                 var results = Client.QueryMultiple(
-                    new KeyedQueryDef<Employee>(LookupFactory.DefineFilter<Employee>()),
+                    new KeyedQueryDef<Employee>(
+                        LookupFactory.DefineFilter<Employee>(),
+                        EmployeeResourceModel.Columns),
                     new KeyedQueryDef<EmployeeRosterItem>(
                         new Filter<EmployeeRosterItem>(x => x.Employee.ID)
-                            .InQuery(LookupFactory.DefineFilter<Employee>(), x => x.ID)),
+                            .InQuery(LookupFactory.DefineFilter<Employee>(), x => x.ID),
+                        sortorder: new SortOrder<EmployeeRosterItem>(x => x.Day)),
                     new KeyedQueryDef<Team>(
                         LookupFactory.DefineFilter<Team>(),
                         Columns.None<Team>().Add(x => x.ID)
@@ -146,7 +149,7 @@ namespace PRSDesktop
                 _rosters = results.Get<EmployeeRosterItem>().ToObjects<EmployeeRosterItem>()
                     .GroupBy(x => x.Employee.ID, x => x).ToDictionary(x => x.Key, x => x.ToArray());
 
-                _teams = results.Get<Team>().Rows.Select(r => new ListEntry() { Key = r.Get<Team,Guid>(c=>c.ID), Value = r.Get<Team,String>(c=>c.Name) }).ToArray();
+                _teams = results.Get<Team>().Rows.Select(r => new ListEntry() { Key = r.Get<Team, Guid>(c => c.ID), Value = r.Get<Team, String>(c => c.Name) }).ToArray();
                 TeamList.ItemsSource = _teams;
                 
                 ObservableCollection<ListEntry> teamdata = new() { new ListEntry() { Key = Guid.Empty, Value = "All Staff" } };

+ 6 - 3
prs.desktop/Grids/LeaveRequestGrid.cs

@@ -99,9 +99,9 @@ namespace PRSDesktop
         protected override void AfterLoad(IDynamicEditorForm editor, LeaveRequest[] items)
         {
             base.AfterLoad(editor, items);
-            if (items.FirstOrDefault().ID == Guid.Empty)
-                ReloadForms<LeaveRequest, LeaveRequestForm, ActivityForm>(editor, items.FirstOrDefault(), x => x.Activity.ID,
-                    items.FirstOrDefault().LeaveType.ID);
+            if (items.First().ID == Guid.Empty)
+                ReloadForms<LeaveRequest, LeaveRequestForm, ActivityForm>(editor, items.First(), x => x.Activity.ID,
+                    items.First().LeaveType.ID);
         }
 
         protected override BaseEditor? GetEditor(object item, DynamicGridColumn column)
@@ -111,7 +111,10 @@ namespace PRSDesktop
                 return null;
 
             if (!Security.IsAllowed<CanApproveLeaveRequests>() && (column.ColumnName.Equals("Approved") || column.ColumnName.Equals("Status")))
+            {
+                result = result.CloneEditor();
                 result.Editable = Editable.Disabled;
+            }
             return result;
         }
     }

+ 0 - 31
prs.desktop/Grids/TimesheetGrid.cs

@@ -383,37 +383,6 @@ namespace PRSDesktop
             return leavegrid.EditItems(new[] { leave });
         }
 
-        public override bool EditItems(TimeSheet[] items, Func<Type, CoreTable?>? PageDataHandler = null, bool PreloadPages = false)
-        {
-            var leaveids = items.Select(x => x.LeaveRequestLink.ID).Distinct().ToArray();
-            if (leaveids.Length > 1 && leaveids.Contains(Guid.Empty))
-            {
-                MessageBox.Show(
-                    "At least one of these timesheets is linked to a leave request!\nPlease select either regular or leave timesheets and try again.");
-                return false;
-            }
-
-            if (!leaveids.Contains(Guid.Empty))
-            {
-                if (!Security.CanView<LeaveRequest>())
-                {
-                    MessageBox.Show("Editing leave requests is not permitted here");
-                    return false;
-                }
-
-                LeaveRequest[] leaves;
-                using (new WaitCursor())
-                {
-                    leaves = new Client<LeaveRequest>().Load(new Filter<LeaveRequest>(x => x.ID).InList(leaveids));
-                    leavegrid ??= new LeaveRequestGrid();
-                }
-
-                return leavegrid.EditItems(leaves);
-            }
-
-            return base.EditItems(items, PageDataHandler, PreloadPages);
-        }
-
         protected override Dictionary<string, object?> EditorValueChanged(IDynamicEditorForm editor, TimeSheet[] items, string name, object value)
         {
             var result = base.EditorValueChanged(editor, items, name, value);

+ 33 - 29
prs.desktop/Panels/Attendance/AttendancePanel.xaml.cs

@@ -31,6 +31,7 @@ namespace PRSDesktop
         private readonly DispatcherTimer columnsizer = new();
 
         public CoreTable Employees;
+        private Dictionary<Guid, EmployeeRosterItem[]> Rosters;
 
         private readonly List<AttendanceKanban> Kanbans = new();
         public CoreTable LeaveRequests;
@@ -162,29 +163,35 @@ namespace PRSDesktop
         {
             Kanban.Columns.Clear();
 
- 
-            MultiQuery query = new MultiQuery();
-
-            query.Add<Employee>(
-                LookupFactory.DefineFilter<Employee>(),
-                Columns.Required<Employee>().Add(
-                    x => x.ID,
-                    x => x.Name,
-                    x => x.Thumbnail.ID,
-                    x => x.Group.ID,
-                    x => x.Group.Description,
-                    x => x.Type,
-                    x => x.ShowOnInOutBoard,
-                    x => x.Roster,
-                    x => x.RosterStart
-                ),
-                new SortOrder<Employee>(x => x.Name)
-            );
-            query.Add<Activity>();
-            query.Query();
+            var data = Client.QueryMultiple(
+                new KeyedQueryDef<Employee>(
+                    LookupFactory.DefineFilter<Employee>(),
+                    Columns.Required<Employee>().Add(
+                        x => x.ID,
+                        x => x.Name,
+                        x => x.Thumbnail.ID,
+                        x => x.Group.ID,
+                        x => x.Group.Description,
+                        x => x.Type,
+                        x => x.ShowOnInOutBoard,
+                        x => x.RosterStart),
+                    new SortOrder<Employee>(x => x.Name)),
+                new KeyedQueryDef<EmployeeRosterItem>(
+                    new Filter<EmployeeRosterItem>(x => x.Employee.ID)
+                        .InQuery(LookupFactory.DefineFilter<Employee>(), x => x.ID),
+                    sortorder: new SortOrder<EmployeeRosterItem>(x => x.Day)),
+                new KeyedQueryDef<Activity>(
+                    null,
+                    Columns.None<Activity>()
+                        .Add(x => x.ID)
+                        .Add(x => x.IsLeave)
+                        .Add(x => x.IsDefault)));
             
-            Employees = query.Get<Employee>();
-            Activities = query.Get<Activity>();
+            Employees = data.Get<Employee>();
+            Activities = data.Get<Activity>();
+            Rosters = data.GetObjects<EmployeeRosterItem>()
+                .GroupBy(x => x.Employee.ID)
+                .ToDictionary(x => x.Key, x => x.ToArray());
 
             CreateColumns();
 
@@ -322,7 +329,7 @@ namespace PRSDesktop
             var lastrow = TimeSheets.Rows.LastOrDefault(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
 
             var actid = lastrow.Get<TimeSheet, Guid>(c => c.ActivityLink.ID);
-            var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
+            var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID) == actid);
 
             var color = "White";
             var finish = lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish);
@@ -363,7 +370,7 @@ namespace PRSDesktop
                 return false;
 
             var actid = row.Get<StandardLeave, Guid>(c => c.LeaveType.ID);
-            var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
+            var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID) == actid);
             var color = actrow?.Get<Activity, string>(c => c.Color);
             if (string.IsNullOrWhiteSpace(color))
                 color = "Gainsboro";
@@ -395,7 +402,7 @@ namespace PRSDesktop
                 return false;
 
             var actid = row.Get<LeaveRequest, Guid>(c => c.LeaveType.ID);
-            var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
+            var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID) == actid);
             var color = actrow?.Get<Activity, string>(c => c.Color);
             if (string.IsNullOrWhiteSpace(color))
                 color = "Gainsboro";
@@ -422,10 +429,7 @@ namespace PRSDesktop
 
         private bool CheckRoster(Guid empid, AttendanceKanban kanban, CoreRow empdata)
         {
-            var rosterdata = empdata.Get<Employee, String>(c => c.Roster);
-            var rosters = !String.IsNullOrWhiteSpace(rosterdata)
-                ? Serialization.Deserialize<List<EmployeeRosterItem>>(rosterdata).ToArray()
-                : null;
+            var rosters = Rosters.GetValueOrDefault(empid);
             var roster = RosterUtils.GetRoster(rosters, empdata.Get<Employee,DateTime>(c=>c.RosterStart), DateTime.Today);
             
             if ((roster == null) || (!roster.Enabled))

+ 4 - 7
prs.desktop/Panels/Employees/Rosters/EmployeeRosterItemGrid.cs

@@ -61,14 +61,13 @@ public class EmployeeRosterItemGrid : BaseEmployeeRosterItemGrid<Employee, Emplo
     public override void DeleteItems(params CoreRow[] rows)
     {
         base.DeleteItems(rows);
-        var deletes = rows.Select(x => x.ToObject<EmployeeRosterItem>()).OfType<EmployeeRosterItem>().ToArray();
-        Client.Delete(deletes,"Deleted by User");
+        Client.Delete(rows.ToObjects<EmployeeRosterItem>(),"Deleted by User");
         UpdateRoster(null);
     }
     
     private bool SelectRoster(Button arg1, CoreRow[] arg2)
     {
-        MultiSelectDialog<EmployeeRoster> dlg = new MultiSelectDialog<EmployeeRoster>(
+        var dlg = new MultiSelectDialog<EmployeeRoster>(
             null,
             Columns.None<EmployeeRoster>().Add(x => x.ID).Add(x => x.Code).Add(x => x.Description),
             false);
@@ -79,11 +78,9 @@ public class EmployeeRosterItemGrid : BaseEmployeeRosterItemGrid<Employee, Emplo
             
             if (roster.ID != Guid.Empty)
             {
-                var newroster = new Client<EmployeeRosterTemplateItem>().Query(
+                var newroster = Client.Query(
                         new Filter<EmployeeRosterTemplateItem>(x => x.Roster.ID).IsEqualTo(roster.ID)
-                    ).Rows
-                    .Select(x => x.ToObject<EmployeeRosterTemplateItem>().ToEmployeeRosterItem(Item))
-                    .ToArray();
+                    ).Rows.ToArray(x => x.ToObject<EmployeeRosterTemplateItem>().ToEmployeeRosterItem(Item));
                 
                 Client.Save(newroster,"");
             }

+ 14 - 13
prs.desktop/Panels/Timesheets/TimeSheetLeaveRequestGrid.cs

@@ -104,20 +104,23 @@ namespace PRSDesktop
                 .ToArray();
 
             progress.Report("Loading Leave Requests");
-            var employees = new Client<Employee>().Query(
-                new Filter<Employee>(x=>x.ID).InList(employeeids),
+            var employees = Client.Query(
+                new Filter<Employee>(x => x.ID).InList(employeeids),
                 Columns.None<Employee>().Add(x => x.ID)
-                    .Add(x=>x.Name)
-                    .Add(x=>x.Roster)
-                    .Add(x=>x.RosterStart)
+                    .Add(x => x.Name)
+                    .Add(x => x.RosterStart)
                     .Add(x => x.StartDate)
-                    .Add(x => x.FinishDate)
-            ).Rows.Select(x=>x.ToObject<Employee>()).ToArray();
-
-            var rosters = employees.ToDictionary<Employee, Guid, String>(x => x.ID, x => x.Roster);
+                    .Add(x => x.FinishDate))
+                .ToArray<Employee>();
+            var rosters = Client.Query(
+                new Filter<EmployeeRosterItem>(x => x.Employee.ID).InList(employeeids),
+                orderby: new SortOrder<EmployeeRosterItem>(x => x.Day))
+                .ToObjects<EmployeeRosterItem>()
+                .GroupBy(x => x.Employee.ID)
+                .ToDictionary(x => x.Key, x => x.ToArray());
 
             int i = 0;
-            List<LeaveRequest> leaves = new List<LeaveRequest>();
+            var leaves = new List<LeaveRequest>();
             foreach (var row in Data.Rows)
             {
                 if (SelectedIDs.Contains(row.Get<LeaveRequest, Guid>(x => x.ID)))
@@ -126,9 +129,7 @@ namespace PRSDesktop
                     var employee = employees.FirstOrDefault(x => x.ID == leave.EmployeeLink.ID);
                     if (employee != null)
                     {
-                        var roster = !String.IsNullOrWhiteSpace(rosters[employee.ID])
-                            ? Serialization.Deserialize<List<EmployeeRosterItem>>(rosters[employee.ID])?.OrderBy(x => x.Day).ToArray()
-                            : null;
+                        var roster = rosters.GetValueOrDefault(employee.ID);
                         progress.Report($"Processing Leave Request {((double)i * 100.0F / (double)SelectedIDs.Count):F2}");
                         var timesheets = RosterUtils.CreateLeaveTimesheets(
                             employee,

+ 15 - 15
prs.desktop/Panels/Timesheets/TimeSheetStandardLeaveGrid.cs

@@ -99,22 +99,24 @@ namespace PRSDesktop
                 .Or(x => x.StartDate).IsLessThanOrEqualTo(To));
             empdates.Ands.Add(new Filter<Employee>(x => x.FinishDate).IsEqualTo(DateTime.MinValue)
                 .Or(x => x.FinishDate).IsGreaterThanOrEqualTo(From));
-            
+
             var employees = new Client<Employee>().Query(
                 empdates,
                 Columns.None<Employee>().Add(x => x.ID)
-                    .Add(x=>x.Name)
-                    .Add(x => x.Roster) 
+                    .Add(x => x.Name)
                     .Add(x => x.RosterStart)
                     .Add(x => x.StartDate)
-                    .Add(x => x.FinishDate)
-            ).Rows.Select(x=>x.ToObject<Employee>()).ToArray();
-            //var employeeids = employees.Select(x=>x.ID).ToArray();
-
-            var rosters = employees.ToDictionary<Employee, Guid, String>(x => x.ID, x => x.Roster);
+                    .Add(x => x.FinishDate))
+                .ToArray<Employee>();
+            var rosters = Client.Query(
+                new Filter<EmployeeRosterItem>(x => x.Employee.ID).InList(employees.ToArray(x => x.ID)),
+                orderby: new SortOrder<EmployeeRosterItem>(x => x.Day))
+                .ToObjects<EmployeeRosterItem>()
+                .GroupBy(x => x.Employee.ID)
+                .ToDictionary(x => x.Key, x => x.ToArray());
 
             int i = 0;
-            List<StandardLeave> leaves = new List<StandardLeave>();
+            var leaves = new List<StandardLeave>();
             foreach (var row in Data.Rows)
             {
                 if (SelectedIDs.Contains(row.Get<StandardLeave,Guid>(x=>x.ID)))
@@ -122,9 +124,7 @@ namespace PRSDesktop
                     var leave = row.ToObject<StandardLeave>();
                     foreach (var employee in employees)
                     {
-                        var roster = !String.IsNullOrWhiteSpace(rosters[employee.ID])
-                            ? Serialization.Deserialize<List<EmployeeRosterItem>>(rosters[employee.ID])?.OrderBy(x => x.Day).ToArray()
-                            : null;
+                        var roster = rosters.GetValueOrDefault(employee.ID);
                         progress.Report($"Processing Standard Leave {((double)i * 100.0F)/((double)SelectedIDs.Count * employees.Length):F2}%");
                         var timesheets = RosterUtils.CreateLeaveTimesheets(
                             employee,
@@ -140,7 +140,7 @@ namespace PRSDesktop
                                 timesheet.StandardLeaveLink.ID = leave.ID;
                             }
                         );
-                        new Client<TimeSheet>().Save(timesheets, "Updated from TimeSheet leave Processor");
+                        Client.Save(timesheets, "Updated from TimeSheet leave Processor");
                         i++;
                     }
                     leave.Processed = DateTime.Now;
@@ -148,10 +148,10 @@ namespace PRSDesktop
                 }
             }
 
-            if (leaves.Any())
+            if (leaves.Count != 0)
             {
                 progress.Report("Saving Standard Leaves");
-                new Client<StandardLeave>().Save(leaves, "Updated from TimeSheet leave Processor");
+                Client.Save(leaves, "Updated from TimeSheet leave Processor");
             }
         }
         

+ 3 - 15
prs.shared/Utilities/RosterUtils.cs

@@ -93,19 +93,8 @@ namespace PRS.Shared
         
         public static TimeSheet[] CreateLeaveTimesheets(Employee employee, EmployeeRosterItem[]? roster, DateTime from, TimeSpan fromtime, DateTime to, TimeSpan totime, Guid activityid, Action<TimeSheet> customise)
         {
-            
             var result = new List<TimeSheet>();
             
-            DateTime rosterstart = employee.RosterStart.IsEmpty()
-                ? from.StartOfWeek(DayOfWeek.Monday)
-                : employee.RosterStart;
-            
-            if ((roster == null) || !roster.Any())
-                roster = DefaultRoster();
-            
-            while (rosterstart.AddDays(roster.Length) <= from)
-                rosterstart = rosterstart.AddDays(roster.Length);
-            
             DateTime currentdate = from;
             while (currentdate <= to)
             {
@@ -114,12 +103,11 @@ namespace PRS.Shared
                     && (employee.FinishDate.IsEmpty() || (employee.FinishDate >= currentdate))
                 )
                 {
-                    var currentroster = GetRoster(roster, rosterstart, currentdate);
+                    var currentroster = GetRoster(roster, employee.RosterStart, currentdate);
                     if (currentroster?.Enabled == true)
                     {
-
-                        TimeSpan currentfrom = (currentdate.Date == from.Date) ? fromtime : new TimeSpan(0);
-                        TimeSpan currentto = (currentdate.Date == to.Date) ? totime : new TimeSpan(1, 0, 0, 0);
+                        var currentfrom = (currentdate.Date == from.Date) ? fromtime : new TimeSpan(0);
+                        var currentto = (currentdate.Date == to.Date) ? totime : new TimeSpan(1, 0, 0, 0);
 
                         var shifts = currentroster.GetBlocks(currentdate, currentfrom, currentto);
                         foreach (var shift in shifts)