|
@@ -24,12 +24,15 @@ using Syncfusion.UI.Xaml.Grid;
|
|
|
using Syncfusion.UI.Xaml.Grid.Helpers;
|
|
|
using Syncfusion.Windows.Tools.Controls;
|
|
|
using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
|
|
|
+using System.Windows.Documents;
|
|
|
|
|
|
namespace PRSDesktop;
|
|
|
|
|
|
public class EmployeeResourcePlannerValue
|
|
|
{
|
|
|
- public Guid ID { get; set; }
|
|
|
+ public Guid[] IDs { get; set; } = Array.Empty<Guid>();
|
|
|
+
|
|
|
+ public AssignmentModel[] Assignments = Array.Empty<AssignmentModel>();
|
|
|
|
|
|
public Brush Background { get; set; }
|
|
|
public Brush Foreground { get; set; }
|
|
@@ -43,31 +46,59 @@ public class EmployeeResourcePlannerValue
|
|
|
{
|
|
|
_color = value;
|
|
|
var color = String.IsNullOrWhiteSpace(value) ? Colors.Transparent : (Color)ColorConverter.ConvertFromString(value);
|
|
|
- Background = new SolidColorBrush(color);
|
|
|
+ Background = new SolidColorBrush(color) { Opacity = 0.8 };
|
|
|
Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(color));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-public partial class EmployeeResourcePlanner : UserControl
|
|
|
+public enum EmployeePlannerDisplayMode
|
|
|
+{
|
|
|
+ EmployeeColumns,
|
|
|
+ DateColumns
|
|
|
+}
|
|
|
+
|
|
|
+public class EmployeeResourcePlannerSettings : BaseObject, IGlobalConfigurationSettings
|
|
|
+{
|
|
|
+ [EnumLookupEditor(typeof(EmployeePlannerDisplayMode))]
|
|
|
+ [EditorSequence(1)]
|
|
|
+ public EmployeePlannerDisplayMode DisplayMode { get; set; }
|
|
|
+
|
|
|
+ public EmployeeResourcePlannerSettings()
|
|
|
+ {
|
|
|
+ DisplayMode = EmployeePlannerDisplayMode.DateColumns;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public partial class EmployeeResourcePlanner : UserControl, IPropertiesPanel<EmployeeResourcePlannerSettings>
|
|
|
{
|
|
|
|
|
|
private enum Suppress
|
|
|
{
|
|
|
This
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private EmployeeResourceModel[] _employees = Array.Empty<EmployeeResourceModel>();
|
|
|
private StandardLeaveModel[] _standardleaves = Array.Empty<StandardLeaveModel>();
|
|
|
private LeaveRequestModel[] _leaverequests = Array.Empty<LeaveRequestModel>();
|
|
|
private JobModel[] _jobs = Array.Empty<JobModel>();
|
|
|
private ActivityModel[] _activities = Array.Empty<ActivityModel>();
|
|
|
|
|
|
+ private DateTime[] _dates = Array.Empty<DateTime>();
|
|
|
+
|
|
|
private CoreFilterDefinitions _jobfilters = new CoreFilterDefinitions();
|
|
|
|
|
|
public event LoadSettings<EmployeeResourcePlannerProperties> LoadSettings;
|
|
|
public event SaveSettings<EmployeeResourcePlannerProperties> SaveSettings;
|
|
|
|
|
|
+ EmployeeResourcePlannerSettings IPropertiesPanel<EmployeeResourcePlannerSettings>.Properties
|
|
|
+ {
|
|
|
+ get => Settings;
|
|
|
+ set => Settings = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private EmployeeResourcePlannerSettings Settings { get; set; }
|
|
|
+
|
|
|
private void DoLoadSettings()
|
|
|
{
|
|
|
Properties = LoadSettings?.Invoke(this) ?? new EmployeeResourcePlannerProperties();
|
|
@@ -179,48 +210,89 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
|
|
|
var assignments = query.Get<Assignment>().Rows.Select(r => new AssignmentModel(r)).ToArray();
|
|
|
|
|
|
-
|
|
|
var data = new DataTable();
|
|
|
- data.Columns.Add("Date", typeof(DateTime));
|
|
|
+ if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns)
|
|
|
+ {
|
|
|
+ data.Columns.Add("Date", typeof(DateTime));
|
|
|
|
|
|
- foreach (var employee in _employees)
|
|
|
- data.Columns.Add(employee.ID.ToString(), typeof(object));
|
|
|
+ foreach (var employee in _employees)
|
|
|
+ {
|
|
|
+ data.Columns.Add(employee.ID.ToString(), typeof(object));
|
|
|
+ }
|
|
|
+
|
|
|
+ for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
|
|
|
+ {
|
|
|
+ var leavevalue = GetStandardLeave(curdate, _standardleaves);
|
|
|
+ var values = new List<object> { curdate };
|
|
|
+ foreach (var employee in _employees)
|
|
|
+ {
|
|
|
+ var value = new EmployeeResourcePlannerValue();
|
|
|
+ // Note use of short-circuiting here.
|
|
|
+ var bOK = CheckAssignments(employee, curdate, assignments, value)
|
|
|
+ || CheckRoster(employee, curdate, value)
|
|
|
+ || CheckStandardLeave(leavevalue, value)
|
|
|
+ || CheckLeaveRequest(employee, curdate, _leaverequests, value);
|
|
|
+
|
|
|
+ values.Add(value);
|
|
|
+ }
|
|
|
|
|
|
- for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
|
|
|
+ data.Rows.Add(values.ToArray());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- var leavevalue = GetStandardLeave(curdate, _standardleaves);
|
|
|
- var values = new List<object> { curdate };
|
|
|
+ data.Columns.Add("Employee", typeof(object));
|
|
|
+
|
|
|
+ var dates = new List<DateTime>();
|
|
|
+ for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
|
|
|
+ {
|
|
|
+ data.Columns.Add(dates.Count.ToString(), typeof(object));
|
|
|
+ dates.Add(curdate);
|
|
|
+ }
|
|
|
+ _dates = dates.ToArray();
|
|
|
+
|
|
|
foreach (var employee in _employees)
|
|
|
{
|
|
|
- var value = new EmployeeResourcePlannerValue();
|
|
|
- var bOK = CheckAssignments(employee, curdate, assignments, value);
|
|
|
- bOK = bOK || CheckRoster(employee, curdate, value);
|
|
|
- bOK = bOK || CheckStandardLeave(leavevalue, value);
|
|
|
- bOK = bOK || CheckLeaveRequest(employee, curdate, _leaverequests, value);
|
|
|
+ var values = new List<object> { employee };
|
|
|
+ for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
|
|
|
+ {
|
|
|
+ var leavevalue = GetStandardLeave(curdate, _standardleaves);
|
|
|
+ var value = new EmployeeResourcePlannerValue();
|
|
|
+ var bOK = CheckAssignments(employee, curdate, assignments, value);
|
|
|
+ bOK = bOK || CheckRoster(employee, curdate, value);
|
|
|
+ bOK = bOK || CheckStandardLeave(leavevalue, value);
|
|
|
+ bOK = bOK || CheckLeaveRequest(employee, curdate, _leaverequests, value);
|
|
|
+
|
|
|
+ values.Add(value);
|
|
|
+ }
|
|
|
|
|
|
- values.Add(value);
|
|
|
+ data.Rows.Add(values.ToArray());
|
|
|
}
|
|
|
-
|
|
|
- data.Rows.Add(values.ToArray());
|
|
|
}
|
|
|
|
|
|
+
|
|
|
dataGrid.ItemsSource = data;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private bool CheckAssignments(EmployeeResourceModel employee, DateTime curdate, AssignmentModel[] assignments, EmployeeResourcePlannerValue value)
|
|
|
+ private static bool CheckAssignments(EmployeeResourceModel employee, DateTime curdate, AssignmentModel[] assignments, EmployeeResourcePlannerValue value)
|
|
|
{
|
|
|
- var assignment = assignments.FirstOrDefault(x => (x.EmployeeID == employee.ID) && (x.Date == curdate.Date));
|
|
|
- if (assignment == null)
|
|
|
+ var dateAssignments = assignments.Where(x => (x.EmployeeID == employee.ID) && (x.Date == curdate.Date)).ToArray();
|
|
|
+ if (dateAssignments.Length == 0)
|
|
|
return false;
|
|
|
|
|
|
- value.ID = assignment.ID;
|
|
|
- value.Text = (value.ID != Guid.Empty) ? assignment.JobNumber : "XX";
|
|
|
- value.Color = assignment.Color;
|
|
|
+ value.IDs = assignments.Select(x => x.ID).ToArray();
|
|
|
+ value.Text = dateAssignments.Length == 1
|
|
|
+ ? (dateAssignments[0].ID != Guid.Empty ? (dateAssignments[0].JobNumber ?? "") : "XX")
|
|
|
+ : $"{dateAssignments.Length} jobs";
|
|
|
+ value.Assignments = dateAssignments;
|
|
|
+
|
|
|
+ value.Color = Colors.LightGreen.ToString();
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- private bool CheckRoster(EmployeeResourceModel employee, DateTime curdate, EmployeeResourcePlannerValue value)
|
|
|
+ private static bool CheckRoster(EmployeeResourceModel employee, DateTime curdate, EmployeeResourcePlannerValue value)
|
|
|
{
|
|
|
value.Text = "";
|
|
|
var roster = RosterUtils.GetRoster(employee.Roster, employee.Start, curdate);
|
|
@@ -240,7 +312,7 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
return roster?.Enabled == false;
|
|
|
}
|
|
|
|
|
|
- private EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves)
|
|
|
+ private static EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves)
|
|
|
{
|
|
|
var standardleave = standardleaves.FirstOrDefault(x =>
|
|
|
(x.From <= curdate)
|
|
@@ -251,7 +323,7 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
: null;
|
|
|
}
|
|
|
|
|
|
- private bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value)
|
|
|
+ private static bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value)
|
|
|
{
|
|
|
if (leavevalue == null)
|
|
|
return false;
|
|
@@ -266,7 +338,7 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
(c.EmployeeID == employee.ID)
|
|
|
&& (c.From <= curdate)
|
|
|
&& (c.To.Add(c.ToTime) > curdate)
|
|
|
- && (Properties.IncludeUnApprovedLeave ? true : c.Status == LeaveRequestStatus.Approved));
|
|
|
+ && (Properties.IncludeUnApprovedLeave || c.Status == LeaveRequestStatus.Approved));
|
|
|
|
|
|
if (leaverequest == null)
|
|
|
return false;
|
|
@@ -359,7 +431,14 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
e.Column.ColumnSizer = GridLengthUnitType.None;
|
|
|
|
|
|
var value = (e.Column.ValueBinding as Binding)!;
|
|
|
- if (value.Path.Path.Equals("Date"))
|
|
|
+ if (value.Path.Path.Equals("Employee"))
|
|
|
+ {
|
|
|
+ e.Column.Width = 150;
|
|
|
+ e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
|
|
|
+ e.Column.AllowFocus = false;
|
|
|
+ e.Column.DisplayBinding = new Binding { Path = new PropertyPath(e.Column.MappingName + ".Name") };
|
|
|
+ }
|
|
|
+ else if (value.Path.Path.Equals("Date"))
|
|
|
{
|
|
|
e.Column.Width = 80;
|
|
|
e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
|
|
@@ -376,9 +455,19 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
e.Column.Width = 55;
|
|
|
e.Column.HeaderStyle = Resources["ContentHeaderStyle"] as Style;
|
|
|
|
|
|
- e.Column.HeaderText = (Guid.TryParse(value.Path.Path, out Guid id))
|
|
|
- ? _employees.FirstOrDefault(x => String.Equals(x.ID, id))?.Name ?? value.Path.Path
|
|
|
- : value.Path.Path;
|
|
|
+ if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns)
|
|
|
+ {
|
|
|
+ e.Column.HeaderText = (Guid.TryParse(value.Path.Path, out var id)
|
|
|
+ ? _employees.FirstOrDefault(x => x.ID == id)?.Name ?? value.Path.Path
|
|
|
+ : value.Path.Path);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(int.TryParse(value.Path.Path, out var idx))
|
|
|
+ {
|
|
|
+ e.Column.HeaderText = _dates[idx].ToString("dd/MM/yyyy");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
e.Column.DisplayBinding = new Binding { Path = new PropertyPath(e.Column.MappingName), Converter = new EmployeeResourcePlannerContentConverter() };
|
|
|
//e.Column.ValueBinding = new Binding() { Path = new PropertyPath(e.Column.MappingName), Converter = new LeaveContentConverter() };
|
|
@@ -397,7 +486,7 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
continue;
|
|
|
var propertyCollection = dataGrid.View.GetPropertyAccessProvider();
|
|
|
var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName);
|
|
|
- if (cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty)
|
|
|
+ if (cellValue is EmployeeResourcePlannerValue val && val.IDs.Length > 0)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
@@ -410,7 +499,7 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
return false;
|
|
|
var propertyCollection = dataGrid.View.GetPropertyAccessProvider();
|
|
|
var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName);
|
|
|
- return cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty;
|
|
|
+ return cellValue is EmployeeResourcePlannerValue val && val.IDs.Length > 0;
|
|
|
}
|
|
|
|
|
|
private void DataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
|
|
@@ -455,6 +544,46 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
}
|
|
|
|
|
|
}
|
|
|
+
|
|
|
+ private void dataGrid_CellToolTipOpening(object sender, GridCellToolTipOpeningEventArgs e)
|
|
|
+ {
|
|
|
+ var record = (e.Record as DataRowView)?[e.Column.MappingName];
|
|
|
+ if (record is not EmployeeResourcePlannerValue value) return;
|
|
|
+
|
|
|
+ if(value.IDs.Length > 0)
|
|
|
+ {
|
|
|
+ e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(
|
|
|
+ typeof(ToolTip),
|
|
|
+ () =>
|
|
|
+ {
|
|
|
+ var border = new Border
|
|
|
+ {
|
|
|
+ BorderBrush = new SolidColorBrush(Colors.Gray),
|
|
|
+ BorderThickness = new Thickness(0.75),
|
|
|
+ CornerRadius = new CornerRadius(5),
|
|
|
+ Background = new SolidColorBrush(Colors.LightYellow),
|
|
|
+ Padding = new Thickness(5),
|
|
|
+ };
|
|
|
+ var panel = new StackPanel();
|
|
|
+ foreach (var assignment in value.Assignments)
|
|
|
+ {
|
|
|
+ var textBlock = new TextBlock();
|
|
|
+ textBlock.Inlines.Add(new Run
|
|
|
+ {
|
|
|
+ Text = assignment.JobNumber,
|
|
|
+ FontWeight = FontWeights.Bold
|
|
|
+ });
|
|
|
+ textBlock.Inlines.Add(new Run
|
|
|
+ {
|
|
|
+ Text = $": {assignment.EffectiveStart():hh':'mm} - {assignment.EffectiveFinish():hh':'mm}"
|
|
|
+ });
|
|
|
+ panel.Children.Add(textBlock);
|
|
|
+ }
|
|
|
+ border.Child = panel;
|
|
|
+ return border;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
private void GetSelectionData(out DateTime from, out DateTime to, out Guid[] employees, out Guid[] assignments)
|
|
|
{
|
|
@@ -464,19 +593,45 @@ public partial class EmployeeResourcePlanner : UserControl
|
|
|
to = DateTime.MinValue;
|
|
|
foreach (var cell in dataGrid.GetSelectedCells())
|
|
|
{
|
|
|
- var binding = (cell.Column.ValueBinding as Binding)!;
|
|
|
- if (Guid.TryParse(binding.Path.Path, out var emp))
|
|
|
- if (!emps.Contains(emp))
|
|
|
- emps.Add(emp);
|
|
|
var row = (cell.RowData as DataRowView)!;
|
|
|
- var date = (DateTime)row.Row.ItemArray.First()!;
|
|
|
- if (date < from)
|
|
|
- from = date;
|
|
|
- if (date > to)
|
|
|
- to = date;
|
|
|
- Guid itemid = (row[binding.Path.Path] as EmployeeResourcePlannerValue).ID;
|
|
|
- if (itemid != Guid.Empty)
|
|
|
- items.Add(itemid);
|
|
|
+ var binding = (cell.Column.ValueBinding as Binding)!;
|
|
|
+
|
|
|
+ DateTime date;
|
|
|
+ if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns)
|
|
|
+ {
|
|
|
+ if (Guid.TryParse(binding.Path.Path, out var emp))
|
|
|
+ if (!emps.Contains(emp))
|
|
|
+ emps.Add(emp);
|
|
|
+
|
|
|
+ date = (DateTime)row.Row.ItemArray.First()!;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(int.TryParse(binding.Path.Path, out var idx))
|
|
|
+ {
|
|
|
+ date = _dates[idx];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ date = DateTime.MinValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var empID = ((EmployeeResourceModel)row.Row.ItemArray.First()!).ID;
|
|
|
+ if (!emps.Contains(empID))
|
|
|
+ emps.Add(empID);
|
|
|
+ }
|
|
|
+ if(date != DateTime.MinValue)
|
|
|
+ {
|
|
|
+ if (date < from)
|
|
|
+ from = date;
|
|
|
+ if (date > to)
|
|
|
+ to = date;
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach(var id in (row[binding.Path.Path] as EmployeeResourcePlannerValue)!.IDs)
|
|
|
+ {
|
|
|
+ items.Add(id);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
employees = emps.ToArray();
|