|
@@ -23,6 +23,9 @@ using Syncfusion.Windows.Tools.Controls;
|
|
|
using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
|
|
|
using PRS.Shared;
|
|
|
using Columns = InABox.Core.Columns;
|
|
|
+using InABox.Wpf;
|
|
|
+using Syncfusion.Data.Extensions;
|
|
|
+using NPOI.OpenXmlFormats.Spreadsheet;
|
|
|
|
|
|
namespace PRSDesktop;
|
|
|
|
|
@@ -58,7 +61,25 @@ public class JobResourcePlannerProperties : IUserConfigurationSettings, IDashboa
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-public partial class JobResourcePlanner : UserControl
|
|
|
+public enum JobPlannerDisplayMode
|
|
|
+{
|
|
|
+ JobColumns,
|
|
|
+ DateColumns
|
|
|
+}
|
|
|
+
|
|
|
+public class JobResourcePlannerSettings : BaseObject, IGlobalConfigurationSettings
|
|
|
+{
|
|
|
+ [EnumLookupEditor(typeof(JobPlannerDisplayMode))]
|
|
|
+ [EditorSequence(1)]
|
|
|
+ public JobPlannerDisplayMode DisplayMode { get; set; }
|
|
|
+
|
|
|
+ public JobResourcePlannerSettings()
|
|
|
+ {
|
|
|
+ DisplayMode = JobPlannerDisplayMode.DateColumns;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+public partial class JobResourcePlanner : UserControl, IPropertiesPanel<JobResourcePlannerSettings>
|
|
|
{
|
|
|
private enum Suppress
|
|
|
{
|
|
@@ -74,11 +95,23 @@ public partial class JobResourcePlanner : UserControl
|
|
|
private EmployeeResourceModel[] _emps = new EmployeeResourceModel[] { };
|
|
|
|
|
|
private List<AssignmentModel> _assignments = new List<AssignmentModel>();
|
|
|
+
|
|
|
+ private DateTime[] _dates = Array.Empty<DateTime>();
|
|
|
+ private double[] _totals = Array.Empty<double>();
|
|
|
+ private double[] _available = Array.Empty<double>();
|
|
|
|
|
|
public JobResourcePlannerProperties Properties { get; set; }
|
|
|
public event LoadSettings<JobResourcePlannerProperties>? LoadSettings;
|
|
|
public event SaveSettings<JobResourcePlannerProperties>? SaveSettings;
|
|
|
|
|
|
+ JobResourcePlannerSettings IPropertiesPanel<JobResourcePlannerSettings>.Properties
|
|
|
+ {
|
|
|
+ get => Settings;
|
|
|
+ set => Settings = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ private JobResourcePlannerSettings Settings { get; set; }
|
|
|
+
|
|
|
private void DoLoadSettings()
|
|
|
{
|
|
|
Properties = LoadSettings?.Invoke(this);
|
|
@@ -265,31 +298,34 @@ public partial class JobResourcePlanner : UserControl
|
|
|
var empids = _emps.Select(x => x.ID).ToArray();
|
|
|
var actids = _activities.Select(x => x.ID).ToArray();
|
|
|
|
|
|
- DateTime todate = DateTime.Today.AddMonths(Properties.MonthsToView);
|
|
|
+ DateTime fromDate = DateTime.Today;
|
|
|
+ DateTime toDate = DateTime.Today.AddMonths(Properties.MonthsToView);
|
|
|
|
|
|
MultiQuery query = new MultiQuery();
|
|
|
|
|
|
query.Add<Assignment>(
|
|
|
new Filter<Assignment>(x=>x.EmployeeLink.ID).InList(empids)
|
|
|
- .And(x=>x.Date).IsGreaterThanOrEqualTo(DateTime.Today)
|
|
|
- .And(x=>x.Date).IsLessThanOrEqualTo(DateTime.Today.AddMonths(Properties.MonthsToView)),
|
|
|
+ .And(x=>x.Date).IsGreaterThanOrEqualTo(fromDate)
|
|
|
+ .And(x=>x.Date).IsLessThanOrEqualTo(toDate),
|
|
|
AssignmentModel.Columns
|
|
|
);
|
|
|
query.Query();
|
|
|
_assignments = query.Get<Assignment>().Rows.Select(r => new AssignmentModel(r)).ToList();
|
|
|
|
|
|
var data = new DataTable();
|
|
|
- data.Columns.Add("Date", typeof(DateTime));
|
|
|
- data.PrimaryKey = new System.Data.DataColumn[] { data.Columns[0] };
|
|
|
-
|
|
|
- data.Columns.Add("Total", typeof(object));
|
|
|
- data.Columns.Add("Available", typeof(object));
|
|
|
-
|
|
|
- foreach (var job in _jobs)
|
|
|
- data.Columns.Add(job.ID.ToString(), typeof(object));
|
|
|
-
|
|
|
- DateTime date = DateTime.Today;
|
|
|
- while (date <= DateTime.Today.AddMonths(Properties.MonthsToView))
|
|
|
+
|
|
|
+ var dates = new List<DateTime>();
|
|
|
+ for (var curdate = fromDate; curdate <= toDate; curdate = curdate.AddDays(1))
|
|
|
+ {
|
|
|
+ dates.Add(curdate);
|
|
|
+ }
|
|
|
+ _dates = dates.ToArray();
|
|
|
+
|
|
|
+ var dataValues = new object?[dates.Count, _jobs.Length];
|
|
|
+ var available = new double[dates.Count];
|
|
|
+ var totals = new double[dates.Count];
|
|
|
+
|
|
|
+ foreach (var (dateIdx, date) in dates.WithIndex())
|
|
|
{
|
|
|
double avail = 0.0F;
|
|
|
|
|
@@ -308,57 +344,188 @@ public partial class JobResourcePlanner : UserControl
|
|
|
|
|
|
}
|
|
|
|
|
|
- double total = avail;
|
|
|
+ var total = avail;
|
|
|
|
|
|
var values = new List<object?> { date };
|
|
|
|
|
|
var anyjobstoday = _assignments.Where(x => (x.Date.Date == date.Date));
|
|
|
avail -= anyjobstoday.Aggregate<AssignmentModel, double>(0F, (value, model) => value + model.BookedDuration.TotalHours);
|
|
|
|
|
|
- foreach (var job in _jobs)
|
|
|
+ foreach (var (jobIdx, job) in _jobs.WithIndex())
|
|
|
{
|
|
|
var thisjobtoday = _assignments.Where(x => (x.Date.Date == date.Date) && (x.JobID == job.ID));
|
|
|
if (thisjobtoday.Any())
|
|
|
{
|
|
|
var assigned = thisjobtoday.Aggregate<AssignmentModel, double>(0F,
|
|
|
(value, model) => value + model.BookedDuration.TotalHours);
|
|
|
- values.Add(assigned / Properties.HoursPerDay);
|
|
|
+ dataValues[dateIdx, jobIdx] = assigned / Properties.HoursPerDay;
|
|
|
}
|
|
|
else
|
|
|
- values.Add(null);
|
|
|
+ dataValues[dateIdx, jobIdx] = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ available[dateIdx] = avail / Properties.HoursPerDay;
|
|
|
+ totals[dateIdx] = total / Properties.HoursPerDay;
|
|
|
+ }
|
|
|
+ _totals = totals;
|
|
|
+ _available = available;
|
|
|
+
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ data.Columns.Add("Date", typeof(DateTime));
|
|
|
+
|
|
|
+ data.Columns.Add("Available", typeof(object));
|
|
|
+
|
|
|
+ foreach (var job in _jobs)
|
|
|
+ data.Columns.Add(job.ID.ToString(), typeof(object));
|
|
|
+
|
|
|
+ foreach(var (dateIdx, date) in dates.WithIndex())
|
|
|
+ {
|
|
|
+ var values = new List<object?>(_jobs.Length + 3) { date };
|
|
|
+
|
|
|
+ foreach (var (jobIdx, job) in _jobs.WithIndex())
|
|
|
+ {
|
|
|
+ values.Add(dataValues[dateIdx, jobIdx]);
|
|
|
+ }
|
|
|
+
|
|
|
+ values.Insert(1, available[dateIdx]);
|
|
|
+
|
|
|
+ data.Rows.Add(values.ToArray());
|
|
|
}
|
|
|
+ }
|
|
|
+ else if(Settings.DisplayMode == JobPlannerDisplayMode.DateColumns)
|
|
|
+ {
|
|
|
+ data.Columns.Add("Job", typeof(object));
|
|
|
+
|
|
|
+ var availableRow = new List<object?> { "Available" };
|
|
|
+ foreach(var (dateIdx, date) in dates.WithIndex())
|
|
|
+ {
|
|
|
+ data.Columns.Add(dateIdx.ToString(), typeof(object));
|
|
|
+ availableRow.Add(available[dateIdx]);
|
|
|
+ }
|
|
|
+ data.Rows.Add(availableRow.ToArray());
|
|
|
+
|
|
|
+ foreach (var (jobIdx, job) in _jobs.WithIndex())
|
|
|
+ {
|
|
|
+ var values = new List<object?>(dates.Count + 1) { job };
|
|
|
|
|
|
- values.Insert(1,avail / Properties.HoursPerDay);
|
|
|
- values.Insert(1,total / Properties.HoursPerDay);
|
|
|
+ foreach(var (dateIdx, date) in dates.WithIndex())
|
|
|
+ {
|
|
|
+ values.Add(dataValues[dateIdx, jobIdx]);
|
|
|
+ }
|
|
|
|
|
|
- data.Rows.Add(values.ToArray());
|
|
|
- date = date.AddDays(1);
|
|
|
+ data.Rows.Add(values.ToArray());
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
dataGrid.ItemsSource = data;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private interface ICellWrapper
|
|
|
+ {
|
|
|
+ DataRowView Row { get; }
|
|
|
+
|
|
|
+ string ColumnName { get; }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class GridCellInfoWrapper : ICellWrapper
|
|
|
+ {
|
|
|
+ private GridCellInfo Cell;
|
|
|
+
|
|
|
+ public DataRowView Row => (Cell.RowData as DataRowView)!;
|
|
|
+
|
|
|
+ public string ColumnName => (Cell.Column.ValueBinding as Binding)!.Path.Path;
|
|
|
+
|
|
|
+ public GridCellInfoWrapper(GridCellInfo cell)
|
|
|
+ {
|
|
|
+ Cell = cell;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public class GridCellWrapper : ICellWrapper
|
|
|
+ {
|
|
|
+ private GridCell Cell;
|
|
|
+
|
|
|
+ public DataRowView Row => (Cell.DataContext as DataRowView)!;
|
|
|
+
|
|
|
+ public string ColumnName => (Cell.ColumnBase?.GridColumn.ValueBinding as Binding)?.Path.Path ?? "";
|
|
|
+
|
|
|
+ public GridCellWrapper(GridCell cell)
|
|
|
+ {
|
|
|
+ Cell = cell;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int? GetDateIndex(ICellWrapper cell)
|
|
|
+ {
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ return _dates.IndexOf((DateTime)cell.Row.Row.ItemArray.First()!);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(int.TryParse(cell.ColumnName, out var idx))
|
|
|
+ {
|
|
|
+ return idx;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private double? GetTotal(ICellWrapper cell)
|
|
|
+ {
|
|
|
+ var dateIndex = GetDateIndex(cell);
|
|
|
+ return dateIndex.HasValue ? _totals[dateIndex.Value] : null;
|
|
|
+ }
|
|
|
+ private double? GetAvailable(ICellWrapper cell)
|
|
|
+ {
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ var avail = cell.Row["Available"];
|
|
|
+ if(avail is double d)
|
|
|
+ {
|
|
|
+ return d;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var dateIndex = GetDateIndex(cell);
|
|
|
+ return dateIndex.HasValue ? _available[dateIndex.Value] : null;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
private abstract class LeaveConverter : IMultiValueConverter
|
|
|
{
|
|
|
+ protected JobResourcePlanner Planner { get; set; }
|
|
|
+ public LeaveConverter(JobResourcePlanner planner)
|
|
|
+ {
|
|
|
+ Planner = planner;
|
|
|
+ }
|
|
|
|
|
|
protected System.Windows.Media.Color GetColor(object[] value)
|
|
|
{
|
|
|
- if ((value[0] != DBNull.Value) && (value[0] != DependencyProperty.UnsetValue))
|
|
|
+ if ((value[0] != DBNull.Value) && (value[0] != DependencyProperty.UnsetValue) && (value[0] is not double d || d != 0.0))
|
|
|
return Colors.DarkSeaGreen;
|
|
|
if (value[1] is GridCell cell)
|
|
|
{
|
|
|
- if (cell.DataContext is DataRowView rowview)
|
|
|
- {
|
|
|
- var total = rowview.Row["Total"];
|
|
|
- if ((total == DBNull.Value) || ((double)total == 0.0F))
|
|
|
- return Colors.LightGray;
|
|
|
-
|
|
|
- var avail = rowview.Row["Available"];
|
|
|
- if ((avail == DBNull.Value) || ((double)avail == 0.0F))
|
|
|
- return Colors.LightSalmon;
|
|
|
- return Colors.LightYellow;
|
|
|
- }
|
|
|
+ var cellWrp = new GridCellWrapper(cell);
|
|
|
+ var total = Planner.GetTotal(cellWrp);
|
|
|
+ var available = Planner.GetAvailable(cellWrp);
|
|
|
+
|
|
|
+ if (!total.HasValue || total == 0.0)
|
|
|
+ return Colors.LightGray;
|
|
|
+
|
|
|
+ if (!available.HasValue || available == 0.0F)
|
|
|
+ return Colors.LightSalmon;
|
|
|
+ return Colors.LightYellow;
|
|
|
}
|
|
|
|
|
|
return Colors.WhiteSmoke;
|
|
@@ -374,6 +541,8 @@ public partial class JobResourcePlanner : UserControl
|
|
|
|
|
|
private class LeaveBackgroundConverter : LeaveConverter
|
|
|
{
|
|
|
+ public LeaveBackgroundConverter(JobResourcePlanner planner): base(planner) { }
|
|
|
+
|
|
|
public override object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
|
|
|
{
|
|
|
return new SolidColorBrush(base.GetColor(value)) { Opacity = 0.8 };
|
|
@@ -382,6 +551,8 @@ public partial class JobResourcePlanner : UserControl
|
|
|
|
|
|
private class LeaveForegroundConverter : LeaveConverter
|
|
|
{
|
|
|
+ public LeaveForegroundConverter(JobResourcePlanner planner): base(planner) { }
|
|
|
+
|
|
|
public override object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
|
|
|
{
|
|
|
return new SolidColorBrush(ImageUtils.GetForegroundColor(base.GetColor(value)));
|
|
@@ -390,12 +561,12 @@ public partial class JobResourcePlanner : UserControl
|
|
|
|
|
|
private void DataGrid_AutoGeneratingColumn(object sender, AutoGeneratingColumnArgs e)
|
|
|
{
|
|
|
- MultiBinding CreateBinding<TConverter>(String path) where TConverter : IMultiValueConverter, new()
|
|
|
+ MultiBinding CreateBinding<TConverter>(String path, TConverter converter) where TConverter : IMultiValueConverter
|
|
|
{
|
|
|
var binding = new MultiBinding();
|
|
|
binding.Bindings.Add(new Binding(path));
|
|
|
binding.Bindings.Add(new Binding() { RelativeSource = new RelativeSource(RelativeSourceMode.Self) });
|
|
|
- binding.Converter = new TConverter();
|
|
|
+ binding.Converter = converter;
|
|
|
return binding;
|
|
|
}
|
|
|
|
|
@@ -407,9 +578,17 @@ public partial class JobResourcePlanner : UserControl
|
|
|
e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
|
|
|
e.Column.AllowFocus = false;
|
|
|
}
|
|
|
- else if (value.Path.Path.Equals("Total"))
|
|
|
+ else if (value.Path.Path.Equals("Job"))
|
|
|
{
|
|
|
- e.Cancel = true;
|
|
|
+ e.Column.Width = 200;
|
|
|
+ e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
|
|
|
+ e.Column.AllowFocus = false;
|
|
|
+ e.Column.TextAlignment = TextAlignment.Left;
|
|
|
+ e.Column.DisplayBinding = new Binding
|
|
|
+ {
|
|
|
+ Path = new PropertyPath(e.Column.MappingName),
|
|
|
+ Converter = new FuncConverter<object?, object?>(x => x is JobModel job ? job.Name : x)
|
|
|
+ };
|
|
|
}
|
|
|
else if (value.Path.Path.Equals("Available"))
|
|
|
{
|
|
@@ -425,17 +604,27 @@ public partial class JobResourcePlanner : UserControl
|
|
|
e.Column = new GridNumericColumn() { NumberDecimalDigits = 2, MappingName = e.Column.MappingName};
|
|
|
e.Column.Width = 40;
|
|
|
e.Column.HeaderStyle = Resources["ContentHeaderStyle"] as Style;
|
|
|
- var jobid = Guid.Parse(value.Path.Path);
|
|
|
- e.Column.HeaderText = _jobs.FirstOrDefault(x=>x.ID == jobid)?.Name ?? jobid.ToString();
|
|
|
+
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ e.Column.HeaderText = (Guid.TryParse(value.Path.Path, out var id)
|
|
|
+ ? _jobs.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) };
|
|
|
e.Column.AllowFocus = true;
|
|
|
var style = new Style(typeof(GridCell));
|
|
|
- style.Setters.Add(new Setter(BackgroundProperty, CreateBinding<LeaveBackgroundConverter>(value.Path.Path)));
|
|
|
- style.Setters.Add(new Setter(ForegroundProperty, CreateBinding<LeaveForegroundConverter>(value.Path.Path)));
|
|
|
+ style.Setters.Add(new Setter(BackgroundProperty, CreateBinding<LeaveBackgroundConverter>(value.Path.Path, new(this))));
|
|
|
+ style.Setters.Add(new Setter(ForegroundProperty, CreateBinding<LeaveForegroundConverter>(value.Path.Path, new(this))));
|
|
|
e.Column.CellStyle = style;
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
e.Column.TextAlignment = TextAlignment.Center;
|
|
|
e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center;
|
|
@@ -482,31 +671,102 @@ public partial class JobResourcePlanner : UserControl
|
|
|
|
|
|
}
|
|
|
|
|
|
- private bool ExtractSelection(out Guid jobid, out DateTime[] dates)
|
|
|
+ private void GetCellData(ICellWrapper cell, out (Guid jobID, DateTime date) result)
|
|
|
{
|
|
|
- var selected = dataGrid.SelectionController.SelectedCells;
|
|
|
- var colname = selected.Select(x => x.Column.MappingName).Distinct().FirstOrDefault();
|
|
|
- if (Guid.TryParse(colname, out Guid job))
|
|
|
+ result = (Guid.Empty, DateTime.MinValue);
|
|
|
+
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ if (Guid.TryParse(cell.ColumnName, out var emp))
|
|
|
+ {
|
|
|
+ result.jobID = emp;
|
|
|
+ }
|
|
|
+
|
|
|
+ result.date = (DateTime)cell.Row.Row.ItemArray.First()!;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(int.TryParse(cell.ColumnName, out var idx))
|
|
|
+ {
|
|
|
+ result.date = _dates[idx];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ result.date = DateTime.MinValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var jobModel = cell.Row.Row.ItemArray.First() as JobModel;
|
|
|
+ result.jobID = jobModel?.ID ?? Guid.Empty;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private ICellWrapper Wrap(GridCellInfo cell)
|
|
|
+ {
|
|
|
+ return new GridCellInfoWrapper(cell);
|
|
|
+ }
|
|
|
+ private ICellWrapper Wrap(GridCell cell)
|
|
|
+ {
|
|
|
+ return new GridCellWrapper(cell);
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool ExtractSelection(out Guid[] jobs, out DateTime[] dates)
|
|
|
+ {
|
|
|
+ var from = DateTime.MaxValue;
|
|
|
+ var to = DateTime.MinValue;
|
|
|
+
|
|
|
+ var jobList = new List<Guid>();
|
|
|
+
|
|
|
+ foreach (var cell in dataGrid.GetSelectedCells())
|
|
|
+ {
|
|
|
+ GetCellData(Wrap(cell), out var result);
|
|
|
+ if (result.jobID == Guid.Empty) continue;
|
|
|
+
|
|
|
+ if (!jobList.Contains(result.jobID))
|
|
|
+ jobList.Add(result.jobID);
|
|
|
+
|
|
|
+ if(result.date != DateTime.MinValue)
|
|
|
+ {
|
|
|
+ if (result.date < from)
|
|
|
+ from = result.date;
|
|
|
+ if (result.date > to)
|
|
|
+ to = result.date;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(jobList.Count > 0 && to != DateTime.MinValue && from != DateTime.MaxValue)
|
|
|
{
|
|
|
- jobid = job;
|
|
|
- dates = selected.Select(x => ((DataRowView)x.RowData).Row["Date"]).Cast<DateTime>().ToArray();
|
|
|
+ jobs = jobList.ToArray();
|
|
|
+ var datesList = new List<DateTime>();
|
|
|
+ for(DateTime date = from; date <= to; date = date.AddDays(1))
|
|
|
+ {
|
|
|
+ datesList.Add(date);
|
|
|
+ }
|
|
|
+ dates = datesList.ToArray();
|
|
|
return true;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- jobid = Guid.Empty;
|
|
|
- dates = new DateTime[] { };
|
|
|
+ jobs = [];
|
|
|
+ dates = [];
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void DataGrid_OnMouseUp(object sender, MouseButtonEventArgs e)
|
|
|
{
|
|
|
- if (ExtractSelection(out Guid jobid, out DateTime[] dates))
|
|
|
+ if (ExtractSelection(out var jobIDs, out var dates))
|
|
|
{
|
|
|
- LoadAssignedEmployees(jobid, dates);
|
|
|
- LoadAvailableEmployees(dates);
|
|
|
- }
|
|
|
+ if(jobIDs.Length == 1)
|
|
|
+ {
|
|
|
+ LoadAssignedEmployees(jobIDs, dates);
|
|
|
+ LoadAvailableEmployees(dates);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ AvailableEmployees.Items = [];
|
|
|
+ AssignedEmployees.Items = [];
|
|
|
+ AvailableEmployees.Refresh(false, true);
|
|
|
+ AssignedEmployees.Refresh(false, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private JobPlannerEmployee GetEmployee(Guid id, List<JobPlannerEmployee> list)
|
|
@@ -551,11 +811,11 @@ public partial class JobResourcePlanner : UserControl
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void LoadAssignedEmployees(Guid jobid, DateTime[] dates)
|
|
|
+ private void LoadAssignedEmployees(Guid[] jobIDs, DateTime[] dates)
|
|
|
{
|
|
|
List<JobPlannerEmployee> assignedemployees = new List<JobPlannerEmployee>();
|
|
|
- foreach (var assignment in _assignments.Where(x => dates.Contains(x.Date) && (x.JobID == jobid)))
|
|
|
- GetEmployee(assignment.EmployeeID,assignedemployees).Time += assignment.BookedDuration;
|
|
|
+ foreach (var assignment in _assignments.Where(x => dates.Contains(x.Date) && jobIDs.Contains(x.JobID)))
|
|
|
+ GetEmployee(assignment.EmployeeID, assignedemployees).Time += assignment.BookedDuration;
|
|
|
AssignedEmployees.Items = assignedemployees.OrderBy(x=>x.Name).ToList();
|
|
|
AssignedEmployees.Refresh(false, true);
|
|
|
}
|
|
@@ -696,7 +956,7 @@ public partial class JobResourcePlanner : UserControl
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- if (ExtractSelection(out Guid jobid, out DateTime[] dates))
|
|
|
+ if (ExtractSelection(out var jobIDs, out var dates))
|
|
|
{
|
|
|
|
|
|
if (dataGrid.ItemsSource is DataTable table)
|
|
@@ -707,6 +967,8 @@ public partial class JobResourcePlanner : UserControl
|
|
|
{
|
|
|
foreach (var date in dates)
|
|
|
{
|
|
|
+ var dateIdx = _dates.IndexOf(date);
|
|
|
+
|
|
|
var emp = _emps.FirstOrDefault(x => x.ID == available.ID);
|
|
|
if (emp != null)
|
|
|
{
|
|
@@ -725,8 +987,8 @@ public partial class JobResourcePlanner : UserControl
|
|
|
foreach (var assignment in assignments)
|
|
|
CheckEdges(assignment.BookedStart, assignment.BookedFinish);
|
|
|
edges.Sort();
|
|
|
-
|
|
|
- double adjustment = 0.0F;
|
|
|
+
|
|
|
+ var adjustment = new double[jobIDs.Length];
|
|
|
for (int i = 0; i < edges.Count - 1; i++)
|
|
|
{
|
|
|
var start = edges[i];
|
|
@@ -737,26 +999,70 @@ public partial class JobResourcePlanner : UserControl
|
|
|
&& (!IsLeaveRequest(date,emp,start,finish))
|
|
|
&& !IsAssigned(assignments, start, finish))
|
|
|
{
|
|
|
- Assignment assignment = new Assignment();
|
|
|
- assignment.ActivityLink.ID = Properties.ActivityType;
|
|
|
- assignment.EmployeeLink.ID = emp.ID;
|
|
|
- assignment.Date = date;
|
|
|
- assignment.JobLink.ID = jobid;
|
|
|
- assignment.Booked.Start = start;
|
|
|
- assignment.Booked.Finish = finish;
|
|
|
- assignment.Booked.Duration = finish - start;
|
|
|
- updates.Add(assignment);
|
|
|
- adjustment += assignment.Booked.Duration.TotalHours;
|
|
|
+ foreach(var (idx, jobid) in jobIDs.WithIndex())
|
|
|
+ {
|
|
|
+ Assignment assignment = new Assignment();
|
|
|
+ assignment.ActivityLink.ID = Properties.ActivityType;
|
|
|
+ assignment.EmployeeLink.ID = emp.ID;
|
|
|
+ assignment.Date = date;
|
|
|
+ assignment.JobLink.ID = jobid;
|
|
|
+ assignment.Booked.Start = start;
|
|
|
+ assignment.Booked.Finish = finish;
|
|
|
+ assignment.Booked.Duration = finish - start;
|
|
|
+ updates.Add(assignment);
|
|
|
+ adjustment[idx] += assignment.Booked.Duration.TotalHours;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ System.Data.DataRow row = table.Rows[dateIdx];
|
|
|
+ row.BeginEdit();
|
|
|
+ foreach(var (idx, jobid) in jobIDs.WithIndex())
|
|
|
+ {
|
|
|
+ var adj = adjustment[idx];
|
|
|
+
|
|
|
+ _available[dateIdx] = Math.Max(0F, _available[dateIdx] - (adj / Properties.HoursPerDay));
|
|
|
+ row["Available"] = _available[dateIdx];
|
|
|
+
|
|
|
+ double jobvalue = (row[jobid.ToString()] == DBNull.Value)
|
|
|
+ ? adj / Properties.HoursPerDay
|
|
|
+ : (double)row[jobid.ToString()] + (adj / Properties.HoursPerDay);
|
|
|
+ row[jobid.ToString()] = jobvalue <= 0F ? null : jobvalue;
|
|
|
+ }
|
|
|
+ row.EndEdit();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var availableRow = table.Rows[0];
|
|
|
+ availableRow.BeginEdit();
|
|
|
+
|
|
|
+ foreach(var (idx, jobid) in jobIDs.WithIndex())
|
|
|
+ {
|
|
|
+ var job = _jobs.WithIndex().First(x => x.Value.ID == jobid);
|
|
|
+ var row = table.Rows[job.Key + 1];
|
|
|
+
|
|
|
+ var adj = adjustment[idx];
|
|
|
+
|
|
|
+ _available[dateIdx] = Math.Max(0F, _available[dateIdx] - (adj / Properties.HoursPerDay));
|
|
|
+ availableRow[dateIdx.ToString()] = _available[dateIdx];
|
|
|
+
|
|
|
+ row.BeginEdit();
|
|
|
+ double jobvalue = (row[dateIdx.ToString()] == DBNull.Value)
|
|
|
+ ? adj / Properties.HoursPerDay
|
|
|
+ : (double)row[dateIdx.ToString()] + (adj / Properties.HoursPerDay);
|
|
|
+ row[dateIdx.ToString()] = jobvalue <= 0F ? null : jobvalue;
|
|
|
+ row.EndEdit();
|
|
|
+ }
|
|
|
+ availableRow.EndEdit();
|
|
|
+
|
|
|
+ foreach(var row in table.Rows.Cast<System.Data.DataRow>())
|
|
|
+ {
|
|
|
+ row.BeginEdit();
|
|
|
+ row[dateIdx.ToString()] = row[dateIdx.ToString()];
|
|
|
+ row.EndEdit();
|
|
|
}
|
|
|
}
|
|
|
- System.Data.DataRow row = table.Rows.Find(date);
|
|
|
- row.BeginEdit();
|
|
|
- double jobvalue = (row[jobid.ToString()] == DBNull.Value)
|
|
|
- ? adjustment / Properties.HoursPerDay
|
|
|
- : (double)row[jobid.ToString()] + (adjustment / Properties.HoursPerDay);
|
|
|
- row[jobid.ToString()] = jobvalue <= 0F ? null : jobvalue;
|
|
|
- row["Available"] = Math.Max(0F, (double)row["Available"] - (adjustment / Properties.HoursPerDay));
|
|
|
- row.EndEdit();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -789,31 +1095,72 @@ public partial class JobResourcePlanner : UserControl
|
|
|
|
|
|
private void AssignedEmployees_OnOnAction(object sender, JobPlannerEmployee[] employees)
|
|
|
{
|
|
|
- if (ExtractSelection(out Guid jobid, out DateTime[] dates))
|
|
|
+ if (ExtractSelection(out var jobIDs, out var dates))
|
|
|
{
|
|
|
if (dataGrid.ItemsSource is DataTable table)
|
|
|
{
|
|
|
foreach (var date in dates)
|
|
|
{
|
|
|
+ var dateIdx = _dates.IndexOf(date);
|
|
|
+
|
|
|
var emptimes = _assignments.Where(x =>
|
|
|
- (x.JobID == jobid)
|
|
|
+ jobIDs.Contains(x.JobID)
|
|
|
&& (x.Date == date)
|
|
|
&& employees.Any(e => e.ID == x.EmployeeID)
|
|
|
).ToArray();
|
|
|
var emptime = emptimes.Aggregate(TimeSpan.Zero, (time, ass) => time += ass.BookedDuration);
|
|
|
- System.Data.DataRow row = table.Rows.Find(date);
|
|
|
- row.BeginEdit();
|
|
|
- double value = (row[jobid.ToString()] == DBNull.Value)
|
|
|
- ? 0.0F
|
|
|
- : (double)row[jobid.ToString()] - (emptime.TotalHours / Properties.HoursPerDay);
|
|
|
- row[jobid.ToString()] = value <= 0F ? null : value;
|
|
|
- row["Available"] = (double)row["Available"] + (emptime.TotalHours/Properties.HoursPerDay);
|
|
|
- row.EndEdit();
|
|
|
+ if(Settings.DisplayMode == JobPlannerDisplayMode.JobColumns)
|
|
|
+ {
|
|
|
+ System.Data.DataRow row = table.Rows[dateIdx];
|
|
|
+ row.BeginEdit();
|
|
|
+ foreach(var jobid in jobIDs)
|
|
|
+ {
|
|
|
+ _available[dateIdx] = _available[dateIdx] + (emptime.TotalHours / Properties.HoursPerDay);
|
|
|
+ row["Available"] = _available[dateIdx];
|
|
|
+
|
|
|
+ double value = (row[jobid.ToString()] == DBNull.Value)
|
|
|
+ ? 0.0F
|
|
|
+ : (double)row[jobid.ToString()] - (emptime.TotalHours / Properties.HoursPerDay);
|
|
|
+ row[jobid.ToString()] = value <= 0F ? null : value;
|
|
|
+ }
|
|
|
+ row.EndEdit();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var availableRow = table.Rows[0];
|
|
|
+ availableRow.BeginEdit();
|
|
|
+
|
|
|
+ foreach(var jobid in jobIDs)
|
|
|
+ {
|
|
|
+ var jobIdx = _jobs.WithIndex().First(x => x.Value.ID == jobid).Key;
|
|
|
+
|
|
|
+ _available[dateIdx] = _available[dateIdx] + (emptime.TotalHours/Properties.HoursPerDay);
|
|
|
+ availableRow[dateIdx.ToString()] = _available[dateIdx];
|
|
|
+
|
|
|
+ var row = table.Rows[jobIdx + 1];
|
|
|
+ row.BeginEdit();
|
|
|
+
|
|
|
+ double value = (row[dateIdx.ToString()] == DBNull.Value)
|
|
|
+ ? 0.0F
|
|
|
+ : (double)row[dateIdx.ToString()] - (emptime.TotalHours / Properties.HoursPerDay);
|
|
|
+ row[dateIdx.ToString()] = value <= 0F ? null : value;
|
|
|
+ row.EndEdit();
|
|
|
+ }
|
|
|
+
|
|
|
+ availableRow.EndEdit();
|
|
|
+
|
|
|
+ foreach(var row in table.Rows.Cast<System.Data.DataRow>())
|
|
|
+ {
|
|
|
+ row.BeginEdit();
|
|
|
+ row[dateIdx.ToString()] = row[dateIdx.ToString()];
|
|
|
+ row.EndEdit();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var assignments = _assignments.Where(x =>
|
|
|
- (x.JobID == jobid)
|
|
|
+ jobIDs.Contains(x.JobID)
|
|
|
&& dates.Contains(x.Date)
|
|
|
&& employees.Any(e => e.ID == x.EmployeeID)
|
|
|
).ToArray();
|