frogsoftware преди 1 година
родител
ревизия
0704c909c7

+ 4 - 1
prs.classes/EnclosedEntities/Dimensions/Dimensions.cs

@@ -154,9 +154,12 @@ namespace Comal.Classes
             {
                 bCalculating = false;
             }
-            
         }
 
+        public void CalculateValueAndUnitSize()
+        {
+            Calculate(Quantity, Length, Width, Height, Weight, Unit.Formula, Unit.Format);
+        }
 
         private void Calculate(object? quantity, object? length, object? width, object? height, object? weight, string? formula, string? format)
         {

+ 6 - 45
prs.classes/Entities/Product/Instance/ProductInstance.cs

@@ -1,30 +1,11 @@
 using InABox.Core;
 using System;
 using System.Collections.Generic;
-using System.Linq.Expressions;
 using System.Text;
 
 namespace Comal.Classes
 {
-    
-    public class ProductInstanceFreeStockAggregate : CoreAggregate<ProductInstance, StockMovement, double>
-    {
-        public override Expression<Func<StockMovement, double>> Aggregate => x => x.Qty;
-
-        public override Filter<StockMovement> Filter => new Filter<StockMovement>(x => x.Job).NotLinkValid();
-
-        public override Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<ProductInstance, object>>> Links =>
-            new Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<ProductInstance, object>>>()
-            {
-                { StockMovement => StockMovement.Product.ID, Instance => Instance.Product.ID },
-                { StockMovement => StockMovement.Style.ID, Instance => Instance.Style.ID },
-                { StockMovement => StockMovement.Dimensions.UnitSize, Instance => Instance.Dimensions.UnitSize },
-            };
-
-        public override AggregateCalculation Calculation => AggregateCalculation.Sum;
-    }
-    
-    public class ProductInstance : DimensionedEntity<StockDimensions>, IRemotable, IPersistent, IProductInstance, ISequenceable
+    public class ProductInstance : DimensionedEntity<ProductDimensions>, ILicense<ProductManagementLicense>, IRemotable, IPersistent, IProductInstance, ISequenceable
     {
         
         [NullEditor]
@@ -38,33 +19,13 @@ namespace Comal.Classes
 
         [EditorSequence(2)]
         [RequiredColumn]
-        [DimensionsEditor(typeof(StockDimensions), AllowEditingUnit = false)]
-        public override StockDimensions Dimensions { get; set; }
+        [DimensionsEditor(typeof(ProductDimensions))]
+        public override ProductDimensions Dimensions { get; set; }
 
         [IntegerEditor]
         [EditorSequence(3)]
-        [LoggableProperty]
         public int MinimumStockLevel { get; set; }
-        
-        [Aggregate(typeof(ProductInstanceFreeStockAggregate))]
-        [DoubleEditor(Editable = Editable.Hidden)]
-        public double FreeStock { get; set; }
-        
-        [CurrencyEditor(Visible = Visible.Optional)]
-        [EditorSequence(5)]
-        [LoggableProperty]
-        public double NettCost { get; set; }
-        
-        [CurrencyEditor(Visible = Visible.Optional)]
-        [EditorSequence(4)]
-        [LoggableProperty]
-        public double AverageCost { get; set; }
-        
-        [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Disabled)]
-        [EditorSequence(5)]
-        [LoggableProperty]
-        public double LastCost { get; set; }
-        
+
+
     }
-    
-}
+}

+ 25 - 26
prs.classes/Entities/PurchaseOrder/PurchaseOrderItem.cs

@@ -136,9 +136,6 @@ namespace Comal.Classes
         [EntityRelationship(DeleteAction.Cascade)]
         public PurchaseOrderLink PurchaseOrderLink { get; set; }
 
-        [NullEditor]
-        public string PONumber { get; set; }
-
         [NullEditor]
         [EntityRelationship(DeleteAction.SetNull)]
         public BillLineLink BillLine { get; set; }
@@ -178,9 +175,12 @@ namespace Comal.Classes
 
         static PurchaseOrderItem()
         {
+
             LinkedProperties.Register<PurchaseOrderItem, ProductLink, String>(x => x.Product, x => x.Code, x => x.SupplierCode);
             LinkedProperties.Register<PurchaseOrderItem, ProductLink, String>(x => x.Product, x => x.Name, x => x.Description);
-            
+            LinkedProperties.Register<PurchaseOrderItem, ProductLink, double>(x => x.Product, x => x.NettCost,
+                x => x.Cost);
+
             LinkedProperties.Register<PurchaseOrderItem, TaxCodeLink, Guid>(x => x.Product.TaxCode, x => x.ID, x => x.TaxCode.ID);
             LinkedProperties.Register<PurchaseOrderItem, TaxCodeLink, String>(x => x.Product.TaxCode, x => x.Code,
                 x => x.TaxCode.Code);
@@ -188,22 +188,28 @@ namespace Comal.Classes
                 x => x.TaxCode.Description);
             LinkedProperties.Register<PurchaseOrderItem, TaxCodeLink, double>(x => x.Product.TaxCode, x => x.Rate,
                 x => x.TaxCode.Rate);
-            LinkedProperties.Register<PurchaseOrderItem, TaxCodeLink, double>(x => x.TaxCode, x => x.Rate, x => x.TaxRate);
-            
+            LinkedProperties.Register<PurchaseOrderItem, TaxCodeLink, double>(x => x.Product.TaxCode, x => x.Rate, x => x.TaxCode.Rate);
+
             LinkedProperties.Register<PurchaseOrderItem, PurchaseGLCodeLink, Guid>(x => x.Product.PurchaseGL, x => x.ID, x => x.PurchaseGL.ID);
+            
             LinkedProperties.Register<PurchaseOrderItem, CostCentreLink, Guid>(x => x.Product.CostCentre, x => x.ID, x => x.CostCentre.ID);
             
             LinkedProperties.Register<PurchaseOrderItem, ProductStyleLink, Guid>(x => x.Product.DefaultInstance.Style, x => x.ID, x => x.Style.ID);
             LinkedProperties.Register<PurchaseOrderItem, ProductStyleLink, String>(x => x.Product.DefaultInstance.Style, x => x.Code, x => x.Style.Code);
             LinkedProperties.Register<PurchaseOrderItem, ProductStyleLink, String>(x => x.Product.DefaultInstance.Style, x => x.Description, x => x.Style.Description);
 
-            LinkedProperties.Register<PurchaseOrderItem, ProductInstanceLink, double>(x => x.Product.DefaultInstance, x => x.NettCost,
-                x => x.Cost);
-
             StockEntity.LinkStockDimensions<PurchaseOrderItem>();
-            
+
+            LinkedProperties.Register<PurchaseOrderItem, TaxCodeLink, double>(x => x.TaxCode, x => x.Rate, x => x.TaxRate);
         }
-        
+
+        private static Column<PurchaseOrderItem> qty = new Column<PurchaseOrderItem>(x => x.Qty);
+        private static Column<PurchaseOrderItem> cost = new Column<PurchaseOrderItem>(x => x.Cost);
+        private static Column<PurchaseOrderItem> extax = new Column<PurchaseOrderItem>(x => x.ExTax);
+        private static Column<PurchaseOrderItem> inctax = new Column<PurchaseOrderItem>(x => x.IncTax);
+        private static Column<PurchaseOrderItem> balance = new Column<PurchaseOrderItem>(x => x.Balance);
+        private static Column<PurchaseOrderItem> received = new Column<PurchaseOrderItem>(x => x.ReceivedDate);
+
         private bool bChanging;
 
         protected override void DoPropertyChanged(string name, object? before, object? after)
@@ -215,24 +221,17 @@ namespace Comal.Classes
             {
                 bChanging = true;
 
-                if (name.Equals(nameof(Qty)) && after is double qty)
-                    ExTax = qty * Cost;
+                if (qty.IsEqualTo(name))
+                    ExTax = (double)after /* * Dimensions.Value */ * Cost;
 
-                else if (name.Equals(nameof(Cost)) && after is double cost)
-                    ExTax = Qty * cost;
-                
-                else if (name.Equals(nameof(ExTax)) && after is double extax)
-                {
-                    if (Qty == 0)
-                        Qty = 1;
-                    Cost = extax / Qty;
-                }
+                else if (cost.IsEqualTo(name))
+                    ExTax = Qty /* * Dimensions.Value */ * (double)after;
 
-                else if (name.Equals(nameof(IncTax)) && after is double inctax)
-                    Balance = ReceivedDate.IsEmpty() ? inctax : 0.00F;
+                else if (inctax.IsEqualTo(name))
+                    Balance = ReceivedDate.IsEmpty() ? (double)after : 0.00F;
 
-                else if (name.Equals(nameof(ReceivedDate)) && after is DateTime received)
-                    Balance = received.IsEmpty() ? IncTax : 0.00F;
+                else if (received.IsEqualTo(name))
+                    Balance = ((DateTime)after).IsEmpty() ? IncTax : 0.00F;
             }
             finally
             {

+ 2 - 3
prs.classes/Entities/PurchaseOrder/PurchaseOrderItemLink.cs

@@ -8,6 +8,8 @@ namespace Comal.Classes
         [PopupEditor(typeof(PurchaseOrderItem), "PurchaseOrderLink.PONumber", "Product.Code", "Description", "Qty", "ExTax", "TaxCode.ID", "TaxCode.Rate", "Tax", "IncTax", "CostCentre.ID", "PurchaseGL.ID")]
         public override Guid ID { get; set; }
 
+        public JobLink Job { get; set; }
+
         [TextBoxEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         public string Description { get; set; }
 
@@ -17,9 +19,6 @@ namespace Comal.Classes
         [CurrencyEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         public double Cost { get; set; }
 
-        [IntegerEditor(Editable = Editable.Hidden)]
-        public string PONumber { get; set; }
-
         [CodeEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         public string SupplierCode { get; set; }
 

+ 2 - 2
prs.classes/Entities/Staging/Manufacturing/Packet/StagingManufacturingPacketStage.cs

@@ -5,7 +5,7 @@ using System.Text;
 
 namespace Comal.Classes
 {
-    public class StagingManufacturingPacketStage : Entity, IRemotable, IPersistent, IManufacturingPacketStageGenerator, ISequenceable
+    public class StagingManufacturingPacketStage : Entity, IRemotable, IPersistent, IManufacturingPacketStageGenerator, ISequenceable, ILicense<ManufacturingLicense>
     {
         public StagingManufacturingPacketLink Packet { get; set; }
 
@@ -27,4 +27,4 @@ namespace Comal.Classes
         [NullEditor]
         public string QualityChecks { get; set; } = "";
     }
-}
+}

+ 6 - 2
prs.desktop/Components/Calendar/Models/JobModel.cs

@@ -8,13 +8,16 @@ namespace PRSDesktop
     {
         public String? Number { get; }
         public String? Name { get; }
-        public String? Color { get; } 
+        public String? Color { get; }
+
+        public Guid DefaultScopeID { get; set; }
 
         public JobModel(CoreRow row) : base(row)
         {
             Number = Get(c => c.JobNumber);
             Name = $"{Number}: {Get(c => c.Name)}";
             Color = Get(c => c.Color);
+            DefaultScopeID = Get(c => c.DefaultScope.ID);
         }
 
         public override Columns<Job> GetColumns()
@@ -22,7 +25,8 @@ namespace PRSDesktop
             return new Columns<Job>(x => x.ID)
                 .Add(x => x.JobNumber)
                 .Add(x => x.Name)
-                .Add(x => x.Color);
+                .Add(x => x.Color)
+                .Add(x => x.DefaultScope.ID);
         }
     }
 }

+ 485 - 486
prs.desktop/Panels/EmployeePlanner/EmployeeResourcePlanner.xaml.cs

@@ -25,603 +25,602 @@ using Syncfusion.UI.Xaml.Grid.Helpers;
 using Syncfusion.Windows.Tools.Controls;
 using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
 
-namespace PRSDesktop
+namespace PRSDesktop;
+
+public class EmployeeResourcePlannerValue
 {
-    public class EmployeeResourcePlannerValue
-    {
-        public Guid ID { get; set; }
-        
-        public Brush Background { get; set; }
-        public Brush Foreground { get; set; }
-        public String Text { get; set; }
+    public Guid ID { get; set; }
+    
+    public Brush Background { get; set; }
+    public Brush Foreground { get; set; }
+    public String Text { get; set; }
 
-        private String _color = "";
-        public String Color
+    private String _color = "";
+    public String Color
+    {
+        get { return _color; }
+        set
         {
-            get { return _color; }
-            set
-            {
-                _color = value;
-                var color = String.IsNullOrWhiteSpace(value) ? Colors.Transparent : (Color)ColorConverter.ConvertFromString(value);
-                Background = new SolidColorBrush(color);
-                Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(color));
-            }
+            _color = value;
+            var color = String.IsNullOrWhiteSpace(value) ? Colors.Transparent : (Color)ColorConverter.ConvertFromString(value);
+            Background = new SolidColorBrush(color);
+            Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(color));
         }
     }
+}
+
+public partial class EmployeeResourcePlanner : UserControl
+{
+
+    private enum Suppress
+    {
+        This
+    }
     
-    public partial class EmployeeResourcePlanner : UserControl
+    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 CoreFilterDefinitions _jobfilters = new CoreFilterDefinitions();
+    
+    public event LoadSettings<EmployeeResourcePlannerProperties> LoadSettings;
+    public event SaveSettings<EmployeeResourcePlannerProperties> SaveSettings;
+
+    private void DoLoadSettings()
     {
+        Properties = LoadSettings?.Invoke(this) ?? new EmployeeResourcePlannerProperties();
+        _jobfilters = new GlobalConfiguration<CoreFilterDefinitions>("Job").Load();
 
-        private enum Suppress
-        {
-            This
-        }
-        
-        private EmployeeResourceModel[] _employees = new EmployeeResourceModel[] { };
-        private StandardLeaveModel[] _standardleaves = new StandardLeaveModel[] { };
-        private LeaveRequestModel[] _leaverequests = new LeaveRequestModel[] { };
-        private JobModel[] _jobs = new JobModel[] { };
-        private ActivityModel[] _activities = new ActivityModel[] { };
+    }
+    
+    private void DoSaveSettings()
+    {
+        SaveSettings?.Invoke(this, Properties);
+    }
+    
+    public EmployeeResourcePlannerProperties Properties { get; set; }
 
-        private CoreFilterDefinitions _jobfilters = new CoreFilterDefinitions();
-        
-        public event LoadSettings<EmployeeResourcePlannerProperties> LoadSettings;
-        public event SaveSettings<EmployeeResourcePlannerProperties> SaveSettings;
+    public EmployeeResourcePlanner()
+    {
+        using (new EventSuppressor(Suppress.This))
+            InitializeComponent();
+    }
 
-        private void DoLoadSettings()
+    private Filter<Job>? GetJobFilter()
+    {
+        var jobfilter = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter));
+        return !String.IsNullOrWhiteSpace(jobfilter?.Filter)
+            ? Serialization.Deserialize<Filter<Job>>(jobfilter.Filter)
+            : LookupFactory.DefineFilter<Job>();           
+    }
+    
+    public void Setup()
+    {
+        using (new EventSuppressor(Suppress.This))
         {
-            Properties = LoadSettings?.Invoke(this) ?? new EmployeeResourcePlannerProperties();
-            _jobfilters = new GlobalConfiguration<CoreFilterDefinitions>("Job").Load();
+            DoLoadSettings();
 
-        }
-        
-        private void DoSaveSettings()
-        {
-            SaveSettings?.Invoke(this, Properties);
-        }
-        
-        public EmployeeResourcePlannerProperties Properties { get; set; }
+            EmployeeSelector.Setup();
+            EmployeeSelector.Settings = Properties.EmployeeSettings;
+            EmployeeSelector.Selection = Properties.EmployeeSelection;
 
-        public EmployeeResourcePlanner()
-        {
-            using (new EventSuppressor(Suppress.This))
-                InitializeComponent();
-        }
+            LeaveType.SelectedIndex = Properties.IncludeUnApprovedLeave ? 1 : 0;
 
-        private Filter<Job>? GetJobFilter()
-        {
-            var jobfilter = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter));
-            return !String.IsNullOrWhiteSpace(jobfilter?.Filter)
-                ? Serialization.Deserialize<Filter<Job>>(jobfilter.Filter)
-                : LookupFactory.DefineFilter<Job>();           
-        }
-        
-        public void Setup()
-        {
-            using (new EventSuppressor(Suppress.This))
-            {
-                DoLoadSettings();
-
-                EmployeeSelector.Setup();
-                EmployeeSelector.Settings = Properties.EmployeeSettings;
-                EmployeeSelector.Selection = Properties.EmployeeSelection;
-
-                LeaveType.SelectedIndex = Properties.IncludeUnApprovedLeave ? 1 : 0;
-
-                FromDate.DateTime = DateTime.Today;
-                ToDate.DateTime = DateTime.Today.AddYears(1);
-                
-                MultiQuery query = new MultiQuery();
-                
-                query.Add<Job>(
-                    GetJobFilter(), 
-                    JobModel.Columns,
-                    new SortOrder<Job>(x => x.JobNumber)
-                );
-                
-                query.Add<StandardLeave>(
-                    null,
-                    StandardLeaveModel.Columns
-                );
-                
-                query.Add<LeaveRequest>(
-                    new Filter<LeaveRequest>(x => x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected),
-                    LeaveRequestModel.Columns
-                );
-
-                query.Add<Activity>(
-                    LookupFactory.DefineFilter<Activity>(),
-                    new Columns<Activity>(x => x.ID).Add(x => x.Code).Add(x => x.Description),
-                    new SortOrder<Activity>(x => x.Code)
-                );
-
-                query.Query();
-
-                _jobs = query.Get<Job>().Rows.Select(r => new JobModel(r)).ToArray();
-                _standardleaves = query.Get<StandardLeave>().Rows.Select(r=>new StandardLeaveModel(r)).ToArray();
-                _leaverequests = query.Get<LeaveRequest>().Rows.Select(r => new LeaveRequestModel(r)).ToArray();
-                _activities = query.Get<Activity>().Rows.Select(r => new ActivityModel(r)).ToArray();
-                ActivityType.ItemsSource = _activities;
-                ActivityType.SelectedValue = Properties.ActivityType;
-                
-                JobFilter.ItemsSource = _jobfilters;
-                JobFilter.SelectedValue = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter));
-            }
+            FromDate.DateTime = DateTime.Today;
+            ToDate.DateTime = DateTime.Today.AddYears(1);
+            
+            MultiQuery query = new MultiQuery();
+            
+            query.Add<Job>(
+                GetJobFilter(), 
+                JobModel.Columns,
+                new SortOrder<Job>(x => x.JobNumber)
+            );
+            
+            query.Add<StandardLeave>(
+                null,
+                StandardLeaveModel.Columns
+            );
+            
+            query.Add<LeaveRequest>(
+                new Filter<LeaveRequest>(x => x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected),
+                LeaveRequestModel.Columns
+            );
 
-        }
-        
-        public void Shutdown(CancelEventArgs? cancel)
-        {
+            query.Add<Activity>(
+                LookupFactory.DefineFilter<Activity>(),
+                new Columns<Activity>(x => x.ID).Add(x => x.Code).Add(x => x.Description),
+                new SortOrder<Activity>(x => x.Code)
+            );
+
+            query.Query();
+
+            _jobs = query.Get<Job>().Rows.Select(r => new JobModel(r)).ToArray();
+            _standardleaves = query.Get<StandardLeave>().Rows.Select(r=>new StandardLeaveModel(r)).ToArray();
+            _leaverequests = query.Get<LeaveRequest>().Rows.Select(r => new LeaveRequestModel(r)).ToArray();
+            _activities = query.Get<Activity>().Rows.Select(r => new ActivityModel(r)).ToArray();
+            ActivityType.ItemsSource = _activities;
+            ActivityType.SelectedValue = Properties.ActivityType;
+            
+            JobFilter.ItemsSource = _jobfilters;
+            JobFilter.SelectedValue = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter));
         }
 
-        public void Refresh()
+    }
+    
+    public void Shutdown(CancelEventArgs? cancel)
+    {
+    }
+
+    public void Refresh()
+    {
+        using (new WaitCursor())
         {
-            using (new WaitCursor())
-            {
-                _employees = EmployeeSelector.GetEmployeeData((row, rosters) => new EmployeeResourceModel(row, rosters));
-                var empids = _employees.Select(x => x.ID).ToArray();
+            _employees = EmployeeSelector.GetEmployeeData((row, rosters) => new EmployeeResourceModel(row, rosters));
+            var empids = _employees.Select(x => x.ID).ToArray();
 
-                DateTime fromdate = FromDate.DateTime.HasValue ? FromDate.DateTime.Value.Date : DateTime.Today;
-                DateTime todate = ToDate.DateTime.HasValue ? ToDate.DateTime.Value.Date : DateTime.Today.AddYears(1);
+            DateTime fromdate = FromDate.DateTime.HasValue ? FromDate.DateTime.Value.Date : DateTime.Today;
+            DateTime todate = ToDate.DateTime.HasValue ? ToDate.DateTime.Value.Date : DateTime.Today.AddYears(1);
+
+            MultiQuery query = new MultiQuery();
+            
+            query.Add<Assignment>(
+                new Filter<Assignment>(x => x.EmployeeLink.ID).InList(empids)
+                    .And(x => x.Date).IsGreaterThanOrEqualTo(fromdate)
+                    .And(x => x.Date).IsLessThanOrEqualTo(todate),
+                AssignmentModel.Columns,
+                new SortOrder<Assignment>(x => x.EmployeeLink.ID).ThenBy(x => x.Date).ThenBy(x => x.Booked.Duration, SortDirection.Descending)
+            );
 
-                MultiQuery query = new MultiQuery();
-                
-                query.Add<Assignment>(
-                    new Filter<Assignment>(x => x.EmployeeLink.ID).InList(empids)
-                        .And(x => x.Date).IsGreaterThanOrEqualTo(fromdate)
-                        .And(x => x.Date).IsLessThanOrEqualTo(todate),
-                    AssignmentModel.Columns,
-                    new SortOrder<Assignment>(x => x.EmployeeLink.ID).ThenBy(x => x.Date).ThenBy(x => x.Booked.Duration, SortDirection.Descending)
-                );
 
+            query.Query();
 
-                query.Query();
+            var assignments = query.Get<Assignment>().Rows.Select(r => new AssignmentModel(r)).ToArray();
 
-                var assignments = query.Get<Assignment>().Rows.Select(r => new AssignmentModel(r)).ToArray();
 
+            var data = new DataTable();
+            data.Columns.Add("Date", typeof(DateTime));
 
-                var data = new DataTable();
-                data.Columns.Add("Date", typeof(DateTime));
+            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)
-                    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();
-                        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 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);
-                    }
-
-                    data.Rows.Add(values.ToArray());
+                    values.Add(value);
                 }
 
-                dataGrid.ItemsSource = data;
+                data.Rows.Add(values.ToArray());
             }
+
+            dataGrid.ItemsSource = data;
         }
-        
-        private bool CheckAssignments(EmployeeResourceModel employee, DateTime curdate, AssignmentModel[] assignments, EmployeeResourcePlannerValue value)
+    }
+    
+    private 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)
+            return false;
+
+        value.ID = assignment.ID;
+        value.Text = (value.ID != Guid.Empty) ? assignment.JobNumber : "XX";
+        value.Color = assignment.Color;
+        return true;
+    }
+
+    private bool CheckRoster(EmployeeResourceModel employee, DateTime curdate, EmployeeResourcePlannerValue value)
+    {
+        value.Text = "";
+        var roster = RosterUtils.GetRoster(employee.Roster, employee.Start, curdate);
+
+        var color1 = Colors.LightGray;
+        var color2 = Colors.LightGray;
+        if (roster?.Enabled == true)
         {
-            var assignment = assignments.FirstOrDefault(x => (x.EmployeeID == employee.ID) && (x.Date == curdate.Date));
-            if (assignment == null)
-                return false;
-
-            value.ID = assignment.ID;
-            value.Text = (value.ID != Guid.Empty) ? assignment.JobNumber : "XX";
-            value.Color = assignment.Color;
-            return true;
+            color1 = Colors.LightYellow;
+            if (roster.Duration >= 5.0F)
+                color2 = Colors.LightYellow;
         }
 
-        private bool CheckRoster(EmployeeResourceModel employee, DateTime curdate, EmployeeResourcePlannerValue value)
-        {
-            value.Text = "";
-            var roster = RosterUtils.GetRoster(employee.Roster, employee.Start, curdate);
+        value.Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(ImageUtils.MixColors(color1, 0.5, color2))) { Opacity = 0.8 };
+        value.Background = new LinearGradientBrush(color1,color2,90.0F) { Opacity = 0.8 };
 
-            var color1 = Colors.LightGray;
-            var color2 = Colors.LightGray;
-            if (roster?.Enabled == true)
-            {
-                color1 = Colors.LightYellow;
-                if (roster.Duration >= 5.0F)
-                    color2 = Colors.LightYellow;
-            }
+        return roster?.Enabled == false;
+    }
+    
+    private EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves)
+    {
+        var standardleave = standardleaves.FirstOrDefault(x => 
+            (x.From <= curdate) 
+            && (x.To.Add(x.ToTime) > curdate)
+        );
+        return (standardleave != null)
+            ? new EmployeeResourcePlannerValue() { Text = standardleave.Code, Color = standardleave.Color}
+            : null;
+    }
 
-            value.Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(ImageUtils.MixColors(color1, 0.5, color2))) { Opacity = 0.8 };
-            value.Background = new LinearGradientBrush(color1,color2,90.0F) { Opacity = 0.8 };
+    private bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value)
+    {
+        if (leavevalue == null)
+            return false;
+        value.Text = leavevalue.Text;
+        value.Color = leavevalue.Color;
+        return true;
+    }
+    
+    private bool CheckLeaveRequest(EmployeeResourceModel employee, DateTime curdate, LeaveRequestModel[] leaverequests, EmployeeResourcePlannerValue value)
+    {
+        var leaverequest = leaverequests.FirstOrDefault(c => 
+            (c.EmployeeID == employee.ID) 
+            && (c.From <= curdate) 
+            && (c.To.Add(c.ToTime) > curdate) 
+            && (Properties.IncludeUnApprovedLeave ? true : c.Status == LeaveRequestStatus.Approved));
 
-            return roster?.Enabled == false;
-        }
-        
-        private EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves)
+        if (leaverequest == null)
+            return false;
+        value.Text = leaverequest.Code;
+        value.Color = (leaverequest.Status == LeaveRequestStatus.Approved) ? leaverequest.Color : Colors.DimGray.ToString();
+        return true;
+    }
+    
+    #region AutoGenerate Columns / Styling
+    
+    private class EmployeeResourcePlannerBackgroundConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            var standardleave = standardleaves.FirstOrDefault(x => 
-                (x.From <= curdate) 
-                && (x.To.Add(x.ToTime) > curdate)
-            );
-            return (standardleave != null)
-                ? new EmployeeResourcePlannerValue() { Text = standardleave.Code, Color = standardleave.Color}
-                : null;
+            if (value is not EmployeeResourcePlannerValue val)
+                return DependencyProperty.UnsetValue;
+            return val.Background;
         }
 
-        private bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value)
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            if (leavevalue == null)
-                return false;
-            value.Text = leavevalue.Text;
-            value.Color = leavevalue.Color;
-            return true;
+            throw new NotImplementedException();
         }
-        
-        private bool CheckLeaveRequest(EmployeeResourceModel employee, DateTime curdate, LeaveRequestModel[] leaverequests, EmployeeResourcePlannerValue value)
+    }
+
+    private class EmployeeResourcePlannerForegroundConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            var leaverequest = leaverequests.FirstOrDefault(c => 
-                (c.EmployeeID == employee.ID) 
-                && (c.From <= curdate) 
-                && (c.To.Add(c.ToTime) > curdate) 
-                && (Properties.IncludeUnApprovedLeave ? true : c.Status == LeaveRequestStatus.Approved));
-
-            if (leaverequest == null)
-                return false;
-            value.Text = leaverequest.Code;
-            value.Color = (leaverequest.Status == LeaveRequestStatus.Approved) ? leaverequest.Color : Colors.DimGray.ToString();
-            return true;
+            if (value is not EmployeeResourcePlannerValue val)
+                return DependencyProperty.UnsetValue;
+            return val.Foreground;
         }
-        
-        #region AutoGenerate Columns / Styling
-        
-        private class EmployeeResourcePlannerBackgroundConverter : IValueConverter
-        {
-            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                if (value is not EmployeeResourcePlannerValue val)
-                    return DependencyProperty.UnsetValue;
-                return val.Background;
-            }
 
-            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                throw new NotImplementedException();
-            }
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
         }
+    }
 
-        private class EmployeeResourcePlannerForegroundConverter : IValueConverter
+    private class EmployeeResourcePlannerFontStyleConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                if (value is not EmployeeResourcePlannerValue val)
-                    return DependencyProperty.UnsetValue;
-                return val.Foreground;
-            }
-
-            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                throw new NotImplementedException();
-            }
+            if (value is not EmployeeResourcePlannerValue val)
+                return DependencyProperty.UnsetValue;
+            return FontStyles.Normal;
         }
 
-        private class EmployeeResourcePlannerFontStyleConverter : IValueConverter
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                if (value is not EmployeeResourcePlannerValue val)
-                    return DependencyProperty.UnsetValue;
-                return FontStyles.Normal;
-            }
-
-            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                throw new NotImplementedException();
-            }
+            throw new NotImplementedException();
         }
+    }
 
-        private class EmployeeResourcePlannerFontWeightConverter : IValueConverter
+    private class EmployeeResourcePlannerFontWeightConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                if (value is not EmployeeResourcePlannerValue val)
-                    return DependencyProperty.UnsetValue;
-                return FontWeights.Normal;
-            }
-
-            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                throw new NotImplementedException();
-            }
+            if (value is not EmployeeResourcePlannerValue val)
+                return DependencyProperty.UnsetValue;
+            return FontWeights.Normal;
         }
 
-        private class EmployeeResourcePlannerContentConverter : IValueConverter
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                if (value is not EmployeeResourcePlannerValue val)
-                    return DependencyProperty.UnsetValue;
-                return val.Text;
-            }
-
-            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
-            {
-                throw new NotImplementedException();
-            }
+            throw new NotImplementedException();
         }
-        
-        private void DataGrid_AutoGeneratingColumn(object? sender, AutoGeneratingColumnArgs e)
+    }
+
+    private class EmployeeResourcePlannerContentConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
-            e.Column.TextAlignment = TextAlignment.Center;
-            e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center;
-            e.Column.ColumnSizer = GridLengthUnitType.None;
+            if (value is not EmployeeResourcePlannerValue val)
+                return DependencyProperty.UnsetValue;
+            return val.Text;
+        }
 
-            var value = (e.Column.ValueBinding as Binding)!;
-            if (value.Path.Path.Equals("Date"))
-            {
-                e.Column.Width = 80;
-                e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
-                e.Column.AllowFocus = false;
-            }
-            else
-            {
-                var style = new Style(typeof(GridCell));
-                style.Setters.Add(new Setter(BackgroundProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerBackgroundConverter() }));
-                style.Setters.Add(new Setter(ForegroundProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerForegroundConverter() }));
-                style.Setters.Add(new Setter(FontStyleProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerFontStyleConverter() }));
-                style.Setters.Add(new Setter(FontWeightProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerFontWeightConverter() }));
-                e.Column.CellStyle = style;
-                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;
-
-                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() };
-                //e.Column.UseBindingValue = true;
-                e.Column.AllowFocus = true;
-            }
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
         }
+    }
+    
+    private void DataGrid_AutoGeneratingColumn(object? sender, AutoGeneratingColumnArgs e)
+    {
+        e.Column.TextAlignment = TextAlignment.Center;
+        e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center;
+        e.Column.ColumnSizer = GridLengthUnitType.None;
 
-        #endregion
-        
-        private bool HasData()
+        var value = (e.Column.ValueBinding as Binding)!;
+        if (value.Path.Path.Equals("Date"))
         {
-            foreach (var cell in dataGrid.GetSelectedCells())
-            {
-                if (!cell.IsDataRowCell)
-                    continue;
-                var propertyCollection = dataGrid.View.GetPropertyAccessProvider();
-                var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName);
-                if (cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty)
-                    return true;
-            }
+            e.Column.Width = 80;
+            e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
+            e.Column.AllowFocus = false;
+        }
+        else
+        {
+            var style = new Style(typeof(GridCell));
+            style.Setters.Add(new Setter(BackgroundProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerBackgroundConverter() }));
+            style.Setters.Add(new Setter(ForegroundProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerForegroundConverter() }));
+            style.Setters.Add(new Setter(FontStyleProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerFontStyleConverter() }));
+            style.Setters.Add(new Setter(FontWeightProperty, new Binding(value.Path.Path) { Converter = new EmployeeResourcePlannerFontWeightConverter() }));
+            e.Column.CellStyle = style;
+            e.Column.Width = 55;
+            e.Column.HeaderStyle = Resources["ContentHeaderStyle"] as Style;
 
-            return false;
+            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;
+
+            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() };
+            //e.Column.UseBindingValue = true;
+            e.Column.AllowFocus = true;
         }
-        
-        private bool HasData(GridCellInfo cell)
+    }
+
+    #endregion
+    
+    private bool HasData()
+    {
+        foreach (var cell in dataGrid.GetSelectedCells())
         {
             if (!cell.IsDataRowCell)
-                return false;
+                continue;
             var propertyCollection = dataGrid.View.GetPropertyAccessProvider();
             var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName);
-            return cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty;
+            if (cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty)
+                return true;
         }
 
-        private void DataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
+        return false;
+    }
+    
+    private bool HasData(GridCellInfo cell)
+    {
+        if (!cell.IsDataRowCell)
+            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;
+    }
+
+    private void DataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
+    {
+        var vc = dataGrid.GetVisualContainer();
+        var p = Mouse.GetPosition(vc);
+        var rci = vc.PointToCellRowColumnIndex(p);
+        if (rci.RowIndex < 1 || rci.ColumnIndex < 1)
         {
-            var vc = dataGrid.GetVisualContainer();
-            var p = Mouse.GetPosition(vc);
-            var rci = vc.PointToCellRowColumnIndex(p);
-            if (rci.RowIndex < 1 || rci.ColumnIndex < 1)
-            {
-                e.Handled = true;
-                return;
-            }
+            e.Handled = true;
+            return;
+        }
 
-            dataGrid.ContextMenu.Items.Clear();
-            var bAssign = !HasData(dataGrid.CurrentCellInfo);
-            var bClear = HasData();
+        dataGrid.ContextMenu.Items.Clear();
+        var bAssign = !HasData(dataGrid.CurrentCellInfo);
+        var bClear = HasData();
 
-            if (bAssign)
+        if (bAssign)
+        {
+            foreach (var job in _jobs)
             {
-                foreach (var job in _jobs)
+                var assign = new MenuItem
                 {
-                    var assign = new MenuItem
-                    {
-                        Header = job.Name,
-                        Tag = job
-                    };
-                    assign.Click += AssignJobClick;
-                    dataGrid.ContextMenu.Items.Add(assign);
-                }
+                    Header = job.Name,
+                    Tag = job
+                };
+                assign.Click += AssignJobClick;
+                dataGrid.ContextMenu.Items.Add(assign);
             }
-            
-            
-            if (bClear && bAssign)
-                dataGrid.ContextMenu.Items.Add(new Separator());
-            
-            
-            if (bClear)
-            {
-                var clear = new MenuItem { Header = "Clear Assignments" };
-                clear.Click += ClearJobClick;
-                dataGrid.ContextMenu.Items.Add(clear);
-            }
-            
         }
         
-        private void GetSelectionData(out DateTime from, out DateTime to, out Guid[] employees, out Guid[] assignments)
+        
+        if (bClear && bAssign)
+            dataGrid.ContextMenu.Items.Add(new Separator());
+        
+        
+        if (bClear)
         {
-            var emps = new List<Guid>();
-            var items = new List<Guid>();
-            from = DateTime.MaxValue;
-            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);
-            }
-
-            employees = emps.ToArray();
-            assignments = items.ToArray();
+            var clear = new MenuItem { Header = "Clear Assignments" };
+            clear.Click += ClearJobClick;
+            dataGrid.ContextMenu.Items.Add(clear);
         }
+        
+    }
+    
+    private void GetSelectionData(out DateTime from, out DateTime to, out Guid[] employees, out Guid[] assignments)
+    {
+        var emps = new List<Guid>();
+        var items = new List<Guid>();
+        from = DateTime.MaxValue;
+        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);
+        }
+
+        employees = emps.ToArray();
+        assignments = items.ToArray();
+    }
 
 
-        private void AssignJobClick(object sender, RoutedEventArgs e)
+    private void AssignJobClick(object sender, RoutedEventArgs e)
+    {
+        if ((sender as MenuItem)?.Tag is not JobModel job)
+            return;
+        GetSelectionData(out var from, out var to, out var ids, out var assignments);
+        var updates = new List<Assignment>();
+        foreach (var id in ids)
         {
-            JobModel? job = (sender as MenuItem)?.Tag as JobModel;
-            if (job == null)
-                return;
-            GetSelectionData(out var from, out var to, out var ids, out var assignments);
-            var updates = new List<Assignment>();
-            foreach (var id in ids)
+            for (DateTime curdate = from; curdate <= to; curdate = curdate.AddDays(1))
             {
-                for (DateTime curdate = from; curdate <= to; curdate = curdate.AddDays(1))
+                var employee = _employees.FirstOrDefault(x => x.ID == id);
+                if (employee != null)
                 {
-                    var employee = _employees.FirstOrDefault(x => x.ID == id);
-                    if (employee != null)
+                    bool bAvail = 
+                        (GetStandardLeave(curdate, _standardleaves) == null)
+                        && !CheckLeaveRequest(employee, curdate, _leaverequests, new EmployeeResourcePlannerValue());
+                    
+                    var roster = bAvail ? RosterUtils.GetRoster(employee.Roster, employee.Start, curdate) : null;
+                    if (roster?.Enabled == true)
                     {
-                        bool bAvail = 
-                            (GetStandardLeave(curdate, _standardleaves) == null)
-                            && !CheckLeaveRequest(employee, curdate, _leaverequests, new EmployeeResourcePlannerValue());
-                        
-                        var roster = bAvail ? RosterUtils.GetRoster(employee.Roster, employee.Start, curdate) : null;
-                        if (roster?.Enabled == true)
-                        {
-                            var assign = new Assignment();
-                            assign.Date = curdate;
-                            assign.Booked.Start = roster.Start;
-                            assign.Booked.Finish = roster.Finish;
-                            assign.JobLink.ID = job.ID;
-                            assign.EmployeeLink.ID = id;
-                            assign.ActivityLink.ID = Properties.ActivityType;
-                            updates.Add(assign);
-                        }
-
-                        if (roster?.SplitShift == true)
-                        {
-                            var assign = new Assignment();
-                            assign.Date = curdate;
-                            assign.Booked.Start = roster.Start2;
-                            assign.Booked.Finish = roster.Finish2;
-                            assign.JobLink.ID = job.ID;
-                            assign.EmployeeLink.ID = id;
-                            assign.ActivityLink.ID = Properties.ActivityType;
-                            updates.Add(assign);                           
-                        }
+                        var assign = new Assignment();
+                        assign.Date = curdate;
+                        assign.Booked.Start = roster.Start;
+                        assign.Booked.Finish = roster.Finish;
+                        assign.JobLink.ID = job.ID;
+                        assign.EmployeeLink.ID = id;
+                        assign.ActivityLink.ID = Properties.ActivityType;
+                        assign.JobScope.ID = job.DefaultScopeID;
+                        updates.Add(assign);
+                    }
+
+                    if (roster?.SplitShift == true)
+                    {
+                        var assign = new Assignment();
+                        assign.Date = curdate;
+                        assign.Booked.Start = roster.Start2;
+                        assign.Booked.Finish = roster.Finish2;
+                        assign.JobLink.ID = job.ID;
+                        assign.EmployeeLink.ID = id;
+                        assign.ActivityLink.ID = Properties.ActivityType;
+                        assign.JobScope.ID = job.DefaultScopeID;
+                        updates.Add(assign);                           
                     }
                 }
             }
-            if (updates.Any())
+        }
+        if (updates.Any())
+        {
+            using (new WaitCursor())
             {
-                using (new WaitCursor())
-                {
-                    new Client<Assignment>().Save(updates, "Assigned from Employee Resource Planner");
-                    Refresh();
-                }
+                new Client<Assignment>().Save(updates, "Assigned from Employee Resource Planner");
+                Refresh();
             }
         }
+    }
 
 
-        private void ClearJobClick(object sender, RoutedEventArgs e)
+    private void ClearJobClick(object sender, RoutedEventArgs e)
+    {
+        GetSelectionData(out DateTime from, out DateTime to, out Guid[] ids, out Guid[] assignments);
+        if (assignments.Any() && MessageBox.Show("Clear Assignments?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
         {
-            GetSelectionData(out DateTime from, out DateTime to, out Guid[] ids, out Guid[] assignments);
-            if (assignments.Any() && MessageBox.Show("Clear Assignments?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+            var deletes = assignments.Select(x => new Assignment() { ID = x }).ToArray();
+            using (new WaitCursor())
             {
-                var deletes = assignments.Select(x => new Assignment() { ID = x }).ToArray();
-                using (new WaitCursor())
-                {
-                    new Client<Assignment>().Delete(deletes, "Deleted from Employee Resource Planner");
-                    Refresh();
-                }
+                new Client<Assignment>().Delete(deletes, "Deleted from Employee Resource Planner");
+                Refresh();
             }
         }
-        
-        public void Heartbeat(TimeSpan time)
-        {
+    }
+    
+    public void Heartbeat(TimeSpan time)
+    {
 
-        }
+    }
 
-        private void _employees_OnSettingsChanged(object sender, EmployeeSelectorSettingsChangedArgs args)
-        {
-            Properties.EmployeeSettings = args.Settings;
-            DoSaveSettings();
-        }
+    private void _employees_OnSettingsChanged(object sender, EmployeeSelectorSettingsChangedArgs args)
+    {
+        Properties.EmployeeSettings = args.Settings;
+        DoSaveSettings();
+    }
 
-        private void _employees_OnSelectionChanged(object sender, EmployeeSelectorSelectionChangedArgs args)
-        {
-            Properties.EmployeeSelection = args.Selection;
-            DoSaveSettings();
-            Refresh();
-        }
+    private void _employees_OnSelectionChanged(object sender, EmployeeSelectorSelectionChangedArgs args)
+    {
+        Properties.EmployeeSelection = args.Selection;
+        DoSaveSettings();
+        Refresh();
+    }
 
-        private void DateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.This))
-                return;
-            Refresh();
-        }
+    private void DateTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.This))
+            return;
+        Refresh();
+    }
 
-        private void LeaveType_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.This))
-                return;
-            Properties.IncludeUnApprovedLeave = LeaveType.SelectedIndex > 0;
-            DoSaveSettings();
-            Refresh();
-        }
+    private void LeaveType_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.This))
+            return;
+        Properties.IncludeUnApprovedLeave = LeaveType.SelectedIndex > 0;
+        DoSaveSettings();
+        Refresh();
+    }
 
-        private void ActivityType_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.This))
-                return;
-            Properties.ActivityType = (Guid)(ActivityType.SelectedValue ?? Guid.Empty);
-            DoSaveSettings();
-        }
+    private void ActivityType_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.This))
+            return;
+        Properties.ActivityType = (Guid)(ActivityType.SelectedValue ?? Guid.Empty);
+        DoSaveSettings();
+    }
 
-        private void JobFilter_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    private void JobFilter_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.This))
+            return;
+        var sel = JobFilter.SelectedValue as CoreFilterDefinition;
+        Properties.JobFilter = sel?.Name ?? "";
+        using (new WaitCursor())
         {
-            if (EventSuppressor.IsSet(Suppress.This))
-                return;
-            var sel = JobFilter.SelectedValue as CoreFilterDefinition;
-            Properties.JobFilter = sel?.Name ?? "";
-            using (new WaitCursor())
-            {
-                DoSaveSettings();
-                _jobs = new Client<Job>().Query(
-                    GetJobFilter(),
-                    JobModel.Columns,
-                    new SortOrder<Job>(x => x.JobNumber)
-                ).Rows.Select(r => new JobModel(r)).ToArray();
-            }
+            DoSaveSettings();
+            _jobs = new Client<Job>().Query(
+                GetJobFilter(),
+                JobModel.Columns,
+                new SortOrder<Job>(x => x.JobNumber)
+            ).Rows.Select(r => new JobModel(r)).ToArray();
         }
+    }
 
-        private void JobFilterButton_Click(object sender, RoutedEventArgs e)
+    private void JobFilterButton_Click(object sender, RoutedEventArgs e)
+    {
+        var window = new DynamicGridFilterEditor(_jobfilters, typeof(Job));
+        if (window.ShowDialog() == true)
         {
-            var window = new DynamicGridFilterEditor(_jobfilters, typeof(Job));
-            if (window.ShowDialog() == true)
-            {
-                new GlobalConfiguration<CoreFilterDefinitions>("Job").Save(_jobfilters);
-                JobFilter.SelectedValue = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter));
-            }
+            new GlobalConfiguration<CoreFilterDefinitions>("Job").Save(_jobfilters);
+            JobFilter.SelectedValue = _jobfilters.FirstOrDefault(x => String.Equals(x.Name, Properties.JobFilter));
         }
     }
-    
-}
+}

+ 0 - 17
prs.desktop/Panels/Jobs/JobBillOfMaterialsItemsGrid.cs

@@ -69,7 +69,6 @@ namespace PRSDesktop
             HiddenColumns.Add(x => x.PurchaseOrderItem.ID);
             HiddenColumns.Add(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber);
             HiddenColumns.Add(x => x.PurchaseOrderItem.ReceivedDate);
-            HiddenColumns.Add(x => x.PurchaseOrderItem.PONumber);
             HiddenColumns.Add(x => x.Packet.ID);
 
             AddButton("Create Requi", null, CreateRequi);
@@ -105,7 +104,6 @@ namespace PRSDesktop
                 JobBillOfMaterialsItem BOMitem = row.ToObject<JobBillOfMaterialsItem>();
                 JobRequisitionItem requiItem = new JobRequisitionItem();
                 requiItem.Qty = BOMitem.Quantity;
-                requiItem.UnitCost = BOMitem.UnitCost;
                 requiItem.Product.ID = BOMitem.Product.ID;
                 requiItem.Product.Code = BOMitem.Product.Code;
                 requiItem.Product.Name = BOMitem.Product.Name;
@@ -118,7 +116,6 @@ namespace PRSDesktop
                 requiItem.Dimensions.CopyFrom(BOMitem.Dimensions);
                 requiItem.Job.ID = BillOfMaterials.Job.ID;
                 requiItem.Job.Synchronise(BillOfMaterials.Job);
-                requiItem.Supplier.ID = BOMitem.Supplier.ID;
                 requiItem.Notes = "Create from BOM " + BOMitem.BillOfMaterials.Description + " on " + DateTime.Now.ToString("hh:mm t dd-MMM-yy") + " by " + empName;
                 requiItems.Add(requiItem);
             }
@@ -146,7 +143,6 @@ namespace PRSDesktop
             result.BillOfMaterials.Synchronise(BillOfMaterials);
             result.Job.ID = BillOfMaterials.Job.ID;
             result.Job.Synchronise(BillOfMaterials.Job);
-            result.Quantity = 1;
             return result;
         }
 
@@ -157,19 +153,6 @@ namespace PRSDesktop
             base.Reload(criteria, columns, ref sort, action);
         }
 
-
-        protected override void OnAfterEditorValueChanged(DynamicEditorGrid grid, JobBillOfMaterialsItem[] items, AfterEditorValueChangedArgs args, Dictionary<string, object?> changes)
-        {
-            base.OnAfterEditorValueChanged(grid, items, args, changes);
-            if (args.ColumnName.Equals("Product.ID") || args.ColumnName.Equals("Dimensions") || args.ColumnName.StartsWith("Dimensions.") || args.ColumnName.Equals("Style.ID") || args.ColumnName.Equals("Supplier.ID"))
-            {
-                JobBillOfMaterialsItem.UpdateCosts(
-                    items, 
-                    changes
-                );
-            }
-        }
-
         #region Create PO
         private void GetEmpID()
         {

+ 0 - 14
prs.desktop/Panels/Jobs/JobRequisitionItemGrid.cs

@@ -149,21 +149,8 @@ namespace PRSDesktop
             result.Requisition.Synchronise(Requisition);
             result.Job.ID = Requisition.Job.ID;
             result.Job.Synchronise(Requisition.Job);
-            result.Qty = 1;
             return result;
         }
-        
-        protected override void OnAfterEditorValueChanged(DynamicEditorGrid grid, JobRequisitionItem[] items, AfterEditorValueChangedArgs args, Dictionary<string, object?> changes)
-        {
-            base.OnAfterEditorValueChanged(grid, items, args, changes);
-            if (args.ColumnName.Equals("Product.ID") || args.ColumnName.Equals("Dimensions") || args.ColumnName.StartsWith("Dimensions.") || args.ColumnName.Equals("Style.ID") || args.ColumnName.Equals("Supplier.ID"))
-            {
-                JobRequisitionItem.UpdateCosts(
-                    items, 
-                    changes
-                );
-            }
-        }
 
         public override DynamicGridColumns GenerateColumns()
         {
@@ -177,7 +164,6 @@ namespace PRSDesktop
             columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 50, "Size", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.DueDate, 80, "Due", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.ReceivedDate, 80, "Received", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, JobRequisitionItemStatus>(x => x.Status, 80, "Status", "", Alignment.MiddleLeft);

+ 2 - 1
prs.desktop/Panels/Products/Master List/ProductsPanel.xaml

@@ -19,7 +19,8 @@
         </dynamicgrid:DynamicSplitPanel.Header>
 
         <dynamicgrid:DynamicSplitPanel.Master>
-            <local:ProductsGrid Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" x:Name="Products" />
+            <local:ProductsGrid Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" x:Name="Products"
+                                AfterRefresh="Products_AfterRefresh"/>
         </dynamicgrid:DynamicSplitPanel.Master>
 
         <dynamicgrid:DynamicSplitPanel.Detail>

+ 6 - 0
prs.desktop/Panels/Products/Master List/ProductsPanel.xaml.cs

@@ -84,6 +84,7 @@ namespace PRSDesktop
 
         public void Refresh()
         {
+            ProductDetails.IsEnabled = false;
             Products.Refresh(false, true);
             //RefreshSubPage(ProductDetails.SelectedContent as IProductGrid);
         }
@@ -163,6 +164,11 @@ namespace PRSDesktop
             return env;
         }
 
+        private void Products_AfterRefresh(object sender, AfterRefreshEventArgs args)
+        {
+            ProductDetails.IsEnabled = true;
+        }
+
         private void RefreshSubPage(IProductControl control)
         {
             if (SplitPanel.View == DynamicSplitPanelView.Master)

+ 0 - 1
prs.desktop/Panels/Products/Reservation Management/JobRequisitionReviewGrid.cs

@@ -256,7 +256,6 @@ namespace PRSDesktop
             columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 50, "Size", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
-            columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderItem.PONumber, 80, "PO Number", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.DueDate, 80, "Due", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, DateTime>(x => x.PurchaseOrderItem.ReceivedDate, 80, "Received", "", Alignment.MiddleLeft);
             columns.Add<JobRequisitionItem, string>(x => x.Notes, 300, "Notes", "", Alignment.MiddleLeft);

+ 22 - 0
prs.desktop/Panels/Suppliers/Bills/SupplierBillLineGrid.cs

@@ -45,6 +45,28 @@ public class SupplierBillLineGrid : DynamicOneToManyGrid<Bill, BillLine>
         ActionColumns.Add(new DynamicImageColumn(pencil, BillLineEdit_Click));
     }
 
+    public override DynamicGridColumns GenerateColumns()
+    {
+        if (IsDirectEditMode())
+        {
+            var columns = new DynamicGridColumns();
+
+            columns.Add<BillLine, string>(x => x.Description, 0, "Description", "", Alignment.MiddleLeft);
+            columns.Add<BillLine, Guid>(x => x.OrderItem.ID, 100, "POItem", "", Alignment.MiddleLeft);
+            columns.Add<BillLine, Guid>(x => x.PurchaseGL.ID, 100, "Purchase GL", "", Alignment.MiddleLeft);
+            columns.Add<BillLine, double>(x => x.ExTax, 70, "Ex. Tax", "", Alignment.MiddleLeft);
+            columns.Add<BillLine, Guid>(x => x.TaxCode.ID, 70, "Tax Code", "", Alignment.MiddleLeft);
+            columns.Add<BillLine, double>(x => x.Tax, 70, "Tax", "", Alignment.MiddleLeft);
+            columns.Add<BillLine, double>(x => x.IncTax, 70, "Inc. Tax", "", Alignment.MiddleLeft);
+
+            return columns;
+        }
+        else
+        {
+            return base.GenerateColumns();
+        }
+    }
+
     protected override void CustomiseEditor(BillLine[] items, DynamicGridColumn column, BaseEditor editor)
     {
         base.CustomiseEditor(items, column, editor);

+ 28 - 8
prs.shared/Editors/Dimensions/DimensionsEditorControl.cs

@@ -123,7 +123,7 @@ namespace PRS.Shared
 
         private void UpdateColumn(int column, bool visible, DoubleTextBox box)
         {
-            if (!visible)
+            if (!visible && box.Value != 0.0 && box.Value != null)
             {
                 box.Value = 0.0;
             }
@@ -180,8 +180,30 @@ namespace PRS.Shared
             return box;
         }
 
+        private TUnit? GetSelectedUnit()
+        {
+            if (Combo.SelectedValue is not Guid unitID) return null;
+            if (Combo.SelectedItem is not Tuple<string, TUnit> tuple) return null;
+            return tuple.Item2;
+        }
+        private bool IsBoxVisible(DoubleTextBox box)
+        {
+            var unit = GetSelectedUnit();
+            if (unit is null) return false;
+
+            if (box == QuantityBox) return unit.HasQuantity;
+            if (box == LengthBox) return unit.HasLength;
+            if (box == WidthBox) return unit.HasWidth;
+            if (box == HeightBox) return unit.HasHeight;
+            if (box == WeightBox) return unit.HasWeight;
+
+            return false;
+        }
+
         private void Box_ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
+            // Don't trigger value changed if invisible, this will have been handled by the SelectionChanged event handler.
+            if (d is not DoubleTextBox box || !IsBoxVisible(box)) return;
             CheckChanged();
         }
 
@@ -239,19 +261,17 @@ namespace PRS.Shared
             if (!property.StartsWith($"{ColumnName}.")) return;
             property = property[(ColumnName.Length + 1)..];
 
-            if (value is null) return;
-
             if (property == "Unit.ID")
             {
                 Combo.SelectedValue = value is Guid guid ? guid : Guid.Empty;
                 return;
             }
 
-            if (property == "Quantity") QuantityBox.Value = (double)value;
-            if (property == "Length") LengthBox.Value = (double)value;
-            if (property == "Width") WidthBox.Value = (double)value;
-            if (property == "Height") HeightBox.Value = (double)value;
-            if (property == "Weight") WeightBox.Value = (double)value;
+            if (property == "Quantity") QuantityBox.Value = (double)(value ?? 0.0);
+            if (property == "Length") LengthBox.Value = (double)(value ?? 0.0);
+            if (property == "Width") WidthBox.Value = (double)(value ?? 0.0);
+            if (property == "Height") HeightBox.Value = (double)(value ?? 0.0);
+            if (property == "Weight") WeightBox.Value = (double)(value ?? 0.0);
         }
 
     }

+ 9 - 6
prs.shared/Posters/Timberline/BillTimberlinePoster.cs

@@ -282,6 +282,7 @@ public class Module
 
             model.SetColumns(new Columns<Bill>(x => x.ID)
                 .Add(x => x.SupplierLink.Code)
+                .Add(x => x.Description)
                 .Add(x => x.Number)
                 .Add(x => x.IncTax)
                 .Add(x => x.Tax)
@@ -304,10 +305,12 @@ public class Module
             model.AddChildTable<BillLine, PurchaseOrderItem>(x => x.OrderItem.ID, x => x.ID, isdefault: true,
                 parentalias: "Bill_BillLine", childalias: "POItem",
                 columns: new Columns<PurchaseOrderItem>(x => x.ID)
-                    .Add(x => x.PONumber)
+                    .Add(x => x.PurchaseOrderLink.PONumber)
                     .Add(x => x.Job.JobNumber)
                     .Add(x => x.Qty)
-                    .Add(x => x.Cost));
+                    .Add(x => x.Cost)
+                    .Add(x => x.PostedReference)
+                    );
 
             Script?.Execute(methodname: "BeforePost", parameters: new object[] { model });
             return true;
@@ -343,7 +346,7 @@ public class Module
                 {
                     Vendor = bill.SupplierLink.Code,
                     Invoice = bill.Number,
-                    Description = "",
+                    Description = bill.Description,
                     Amount = bill.IncTax,
                     Tax = bill.Tax,
                     // DiscountOffered
@@ -404,12 +407,12 @@ public class Module
                         };
                         if (purchaseOrderItems.TryGetValue(billLine.OrderItem.ID, out var poItem))
                         {
-                            apdf.Commitment = poItem.PONumber;
+                            apdf.Commitment = poItem.PurchaseOrderLink.PONumber;
                             apdf.Job = poItem.Job.JobNumber;
-                            if (int.TryParse(poItem.ReceivedReference, out var itemNumber))
+                            if (int.TryParse(poItem.PostedReference, out var itemNumber))
                             {
                                 apdf.CommitmentLineItem = itemNumber;
-                                billLine.PostedReference = poItem.ReceivedReference;
+                                billLine.PostedReference = poItem.PostedReference;
                             }
                             apdf.Units = poItem.Qty;
                             apdf.UnitCost = poItem.Cost;

+ 33 - 1
prs.stores/JobStore.cs

@@ -31,7 +31,39 @@ namespace Comal.Stores
 
             StoreUtils.Geocode(entity.SiteAddress);
         }
-        
+
+        protected override void AfterSave(Job entity)
+        {
+            base.AfterSave(entity);
+
+            if(entity.HasOriginalValue(x => x.ID))
+            {
+                CreateDefaultScope(entity);
+            }
+        }
+
+        private void CreateDefaultScope(Job job)
+        {
+            var scope = new JobScope
+            {
+                Description = "Default Scope",
+                Type = JobScopeType.Contract
+            };
+            scope.Job.ID = job.ID;
+            FindSubStore<JobScope>().Save(scope, "Created automatically on job creation.");
+
+            // Save the job again, with a default scope set. We create a lighter job so we're not saving all the same properties over again.
+            var lightJob = new Job
+            {
+                ID = job.ID
+            };
+            lightJob.DefaultScope.ID = scope.ID;
+            Provider.Save(lightJob);
+
+            // Update default scope for sending the entity back to the client.
+            job.DefaultScope.ID = scope.ID;
+        }
+
         protected override void AfterDelete(Job entity)
         {
             base.AfterDelete(entity);