浏览代码

Adding new aggregates for JobRequisitionItem, and colouring columns in reservation management screen

Kenric Nugteren 11 月之前
父节点
当前提交
486c42da84

+ 81 - 12
prs.classes/Entities/Job/Requisitions/JobRequisitionItem.cs

@@ -75,20 +75,20 @@ namespace Comal.Classes
     {
         public override Expression<Func<StockMovement, double>> Aggregate => x => x.Units;
 
-        public override Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<JobRequisitionItem, object>>> Links => new Dictionary<Expression<Func<StockMovement, object>>, Expression<Func<JobRequisitionItem, object>>>
+        public override Dictionary<Expression<Func<StockMovement, object?>>, Expression<Func<JobRequisitionItem, object?>>> Links => new Dictionary<Expression<Func<StockMovement, object?>>, Expression<Func<JobRequisitionItem, object?>>>
         {
             { x => x.JobRequisitionItem.ID, x => x.ID }
         };
 
         public override AggregateCalculation Calculation => AggregateCalculation.Sum;
     }
-    public class JobRequisitionItemOnOrderAggregate : CoreAggregate<JobRequisitionItem, JobRequisitionItemPurchaseOrderItem, double>
+    public class JobRequisitionItemOrdersAggregate : CoreAggregate<JobRequisitionItem, JobRequisitionItemPurchaseOrderItem, double>
     {
         public override Expression<Func<JobRequisitionItemPurchaseOrderItem, double>> Aggregate => x => x.PurchaseOrderItem.Qty;
 
-        public override Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object>>, Expression<Func<JobRequisitionItem, object>>> Links => new Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object>>, Expression<Func<JobRequisitionItem, object>>>
+        public override Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object?>>, Expression<Func<JobRequisitionItem, object?>>> Links => new Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object?>>, Expression<Func<JobRequisitionItem, object?>>>
         {
-            { x => x.JobRequisitionItem.ID, x => x.ID }
+            { x => x.JobRequisitionItem.ID, x => x.ID },
         };
 
         public override AggregateCalculation Calculation => AggregateCalculation.Sum;
@@ -96,13 +96,15 @@ namespace Comal.Classes
         public override Filter<JobRequisitionItemPurchaseOrderItem>? Filter =>
             new Filter<JobRequisitionItemPurchaseOrderItem>(x => x.PurchaseOrderItem.ReceivedDate).IsEqualTo(null);
     }
-    public class JobRequisitionItemTreatmentRequiredAggregate : CoreAggregate<JobRequisitionItem, StockMovement, double>
+
+    public class JobRequisitionItemOnOrderAggregate : CoreAggregate<JobRequisitionItem, JobRequisitionItemPurchaseOrderItem, double>
     {
         public override Expression<Func<JobRequisitionItemPurchaseOrderItem, double>> Aggregate => x => x.PurchaseOrderItem.Qty;
 
-        public override Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object>>, Expression<Func<JobRequisitionItem, object>>> Links => new Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object>>, Expression<Func<JobRequisitionItem, object>>>
+        public override Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object?>>, Expression<Func<JobRequisitionItem, object?>>> Links => new Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object?>>, Expression<Func<JobRequisitionItem, object?>>>
         {
-            { x => x.JobRequisitionItem.ID, x => x.ID }
+            { x => x.JobRequisitionItem.ID, x => x.ID },
+            { x => x.PurchaseOrderItem.Product.ID, x => x.Product.ID },
         };
 
         public override AggregateCalculation Calculation => AggregateCalculation.Sum;
@@ -111,6 +113,48 @@ namespace Comal.Classes
             new Filter<JobRequisitionItemPurchaseOrderItem>(x => x.PurchaseOrderItem.ReceivedDate).IsEqualTo(null);
     }
 
+    public class JobRequisitionItemAllocatedAggregate : CoreAggregate<JobRequisitionItem, StockMovement, double>
+    {
+        public override Expression<Func<StockMovement, double>> Aggregate => x => x.Units;
+
+        public override Dictionary<Expression<Func<StockMovement, object?>>, Expression<Func<JobRequisitionItem, object?>>> Links => new Dictionary<Expression<Func<StockMovement, object?>>, Expression<Func<JobRequisitionItem, object?>>>
+        {
+            { x => x.JobRequisitionItem.ID, x => x.ID },
+            { x => x.Style.ID, x => x.Style.ID },
+        };
+
+        public override AggregateCalculation Calculation => AggregateCalculation.Sum;
+    }
+    public class JobRequisitionItemTreatmentOnOrderFormula : IFormula<JobRequisitionItem, double>
+    {
+        public Expression<Func<JobRequisitionItem, double>> Value => x => x.TotalOrders;
+        public Expression<Func<JobRequisitionItem, double>>[] Modifiers => new Expression<Func<JobRequisitionItem, double>>[] { x => x.OnOrder };
+        public FormulaOperator Operator => FormulaOperator.Subtract;
+        public FormulaType Type => FormulaType.Virtual;
+    }
+    public class JobRequisitionItemTreatmentRequiredFormula : IFormula<JobRequisitionItem, double>
+    {
+        public Expression<Func<JobRequisitionItem, double>> Value => x => x.InStock;
+        public Expression<Func<JobRequisitionItem, double>>[] Modifiers => new Expression<Func<JobRequisitionItem, double>>[] { x => x.Allocated };
+        public FormulaOperator Operator => FormulaOperator.Subtract;
+        public FormulaType Type => FormulaType.Virtual;
+    }
+
+    public class JobRequisitionItemIssuedAggregate : CoreAggregate<JobRequisitionItem, StockMovement, double>
+    {
+        public override Expression<Func<StockMovement, double>> Aggregate => x => x.Issued;
+
+        public override Dictionary<Expression<Func<StockMovement, object?>>, Expression<Func<JobRequisitionItem, object?>>> Links => new Dictionary<Expression<Func<StockMovement, object?>>, Expression<Func<JobRequisitionItem, object?>>>
+        {
+            { x => x.JobRequisitionItem.ID, x => x.ID },
+            { x => x.Style.ID, x => x.Style.ID },
+        };
+
+        public override Filter<StockMovement>? Filter => new Filter<StockMovement>(x => x.Type).IsEqualTo(StockMovementType.Issue);
+
+        public override AggregateCalculation Calculation => AggregateCalculation.Sum;
+    }
+
     public interface IJobRequisitionItem : IEntity
     {
 
@@ -184,11 +228,36 @@ namespace Comal.Classes
         [EditorSequence(10)]
         public double InStock { get; set; }
 
+        [Aggregate(typeof(JobRequisitionItemOrdersAggregate))]
+        [DoubleEditor(Editable = Editable.Disabled, Visible = Visible.Optional)]
+        [EditorSequence(11)]
+        public double TotalOrders { get; set; }
+
         [Aggregate(typeof(JobRequisitionItemOnOrderAggregate))]
         [DoubleEditor(Editable = Editable.Disabled)]
-        [EditorSequence(11)]
+        [EditorSequence(12)]
         public double OnOrder { get; set; }
 
+        [Formula(typeof(JobRequisitionItemTreatmentRequiredFormula))]
+        [DoubleEditor(Editable = Editable.Disabled)]
+        [EditorSequence(13)]
+        public double TreatmentRequired { get; set; }
+
+        [Formula(typeof(JobRequisitionItemTreatmentOnOrderFormula))]
+        [DoubleEditor(Editable = Editable.Disabled)]
+        [EditorSequence(14)]
+        public double TreatmentOnOrder { get; set; }
+
+        [Aggregate(typeof(JobRequisitionItemAllocatedAggregate))]
+        [DoubleEditor(Editable = Editable.Disabled)]
+        [EditorSequence(15)]
+        public double Allocated { get; set; }
+
+        [Aggregate(typeof(JobRequisitionItemIssuedAggregate))]
+        [DoubleEditor(Editable = Editable.Disabled)]
+        [EditorSequence(16)]
+        public double Issued { get; set; }
+
         [EntityRelationship(DeleteAction.SetNull)]
         [RequiredColumn]
         [Obsolete("Replaced with JobRequisitionItemPurchaseOrderItem")]
@@ -200,11 +269,11 @@ namespace Comal.Classes
         public string PurchaseOrderNumbers { get; set; }
 
         [RequiredColumn]
-        [EditorSequence(12)]
+        [EditorSequence(17)]
         public DateTime Cancelled { get; set; } = DateTime.MinValue;
 
         [RequiredColumn]
-        [EditorSequence(13)]
+        [EditorSequence(18)]
         public DateTime Archived { get; set; } = DateTime.MinValue;
 
         [RequiredColumn]
@@ -213,7 +282,7 @@ namespace Comal.Classes
         public DateTime Ordered { get; set; } = DateTime.MinValue;
 
         [RequiredColumn]
-        [EditorSequence(14)]
+        [EditorSequence(19)]
         public DateTime OrderRequired { get; set; } = DateTime.MinValue;
 
         [NullEditor]
@@ -349,7 +418,7 @@ namespace Comal.Classes
     {
         public override Expression<Func<JobRequisitionItemPurchaseOrderItem, string>> Aggregate => x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber;
 
-        public override Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object>>, Expression<Func<JobRequisitionItem, object>>> Links { get; } = new Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object>>, Expression<Func<JobRequisitionItem, object>>>
+        public override Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object?>>, Expression<Func<JobRequisitionItem, object?>>> Links { get; } = new Dictionary<Expression<Func<JobRequisitionItemPurchaseOrderItem, object?>>, Expression<Func<JobRequisitionItem, object?>>>
         {
             { x => x.JobRequisitionItem.ID, x => x.ID }
         };

+ 3 - 7
prs.desktop/Panels/Reservation Management/ReservationManagementHoldingsGrid.xaml.cs

@@ -132,7 +132,7 @@ public partial class ReservationManagementHoldingsGrid
                     x => x.Location.ID,
                     x => x.Location.Code,
                     x => x.Location.Description,
-                    x => x.Location.Area.Description,
+                    x => x.Location.Area.Code,
                     x => x.Job.ID,
                     x => x.JobRequisitionItem.ID)
                     .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Data))
@@ -280,12 +280,8 @@ public partial class ReservationManagementHoldingsGrid
             {
                 holding = new StockHolding();
 
-                holding.Location.ID = mvt.Location.ID;
-                holding.Location.Description = mvt.Location.Description;
-                holding.Location.Area.Description = mvt.Location.Area.Description;
-                holding.Style.ID = mvt.Style.ID;
-                holding.Style.Description = mvt.Style.Description;
-                holding.Style.Code = mvt.Style.Code;
+                holding.Location.CopyFrom(mvt.Location);
+                holding.Style.CopyFrom(mvt.Style);
                 holding.Dimensions.CopyFrom(mvt.Dimensions);
 
                 holdings.Add(new(mvt.Location.ID, mvt.JobRequisitionItem.ID), holding);

+ 80 - 9
prs.desktop/Panels/Reservation Management/ReservationManagementItemGrid.cs

@@ -9,6 +9,7 @@ using System;
 using System.Collections.Generic;
 using System.Drawing;
 using System.Linq;
+using System.Linq.Expressions;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Media;
@@ -45,13 +46,15 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
 
         protected override Brush? GetCellBackground(CoreRow row, DynamicColumnBase column)
         {
+            if (!Grid.ShowColors) return null;
+
             if (column is DynamicGridColumn col)
             {
                 if (String.Equals(col.ColumnName,
                         CoreUtils.GetFullPropertyName<JobRequisitionItem, DateTime>(x => x.Requisition.DueDate, ".")))
                 {
                     var due = row.Get<JobRequisitionItem, DateTime>(x => x.Requisition.DueDate);
-                    if (Grid.ShowColors && !due.IsEmpty())
+                    if (!due.IsEmpty())
                     {
                         var background = DateTime.Today > due.Date
                             ? Colors.Salmon
@@ -64,18 +67,67 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
                     }
                 }
             }
-            return null;
+            else if(column is DynamicActionColumn dac)
+            {
+                if (dac == Grid.InStockColumn
+                    || dac == Grid.OnOrderColumn)
+                {
+                    return Colors.LightBlue.ToBrush(0.5);
+                }
+                else if (dac == Grid.TreatmentRequiredColumn
+                    || dac == Grid.TreatmentOnOrderColumn)
+                {
+                    return Colors.LightYellow.ToBrush(0.5);
+                }
+                else if (dac == Grid.AllocatedColumn
+                    || dac == Grid.IssuedColumn)
+                {
+                    return Colors.LightSeaGreen.ToBrush(0.5);
+                }
+            }
+
+            var qty = row.Get<JobRequisitionItem, double>(x => x.Qty);
+            if(row.Get<JobRequisitionItem, double>(x => x.Issued) >= qty)
+            {
+                return Colors.Silver.ToBrush(0.5);
+            }
+            else if(row.Get<JobRequisitionItem, double>(x => x.Allocated) >= qty)
+            {
+                return Colors.LightGreen.ToBrush(0.5);
+            }
+            else if(row.Get<JobRequisitionItem, double>(x => x.InStock) >= qty)
+            {
+                return Colors.Orange.ToBrush(0.5);
+            }
+            else
+            {
+                return Colors.LightSalmon.ToBrush(0.5);
+            }
         }
     }
 
+    private DynamicActionColumn InStockColumn;
+    private DynamicActionColumn OnOrderColumn;
+    private DynamicActionColumn TreatmentRequiredColumn;
+    private DynamicActionColumn TreatmentOnOrderColumn;
+    private DynamicActionColumn AllocatedColumn;
+    private DynamicActionColumn IssuedColumn;
+
     public ReservationManagementItemGrid()
     {
         _userSettings = new UserConfiguration<ReservationManagementUserSettings>().Load();
         FilterComponent.SetSettings(_userSettings.Filters, false);
 
         HiddenColumns.Add(x => x.ID);
+
         HiddenColumns.Add(x => x.Qty);
         HiddenColumns.Add(x => x.InStock);
+        HiddenColumns.Add(x => x.OnOrder);
+        HiddenColumns.Add(x => x.TreatmentOnOrder);
+        HiddenColumns.Add(x => x.TreatmentRequired);
+        HiddenColumns.Add(x => x.Allocated);
+        HiddenColumns.Add(x => x.Issued);
+
         HiddenColumns.Add(x => x.Product.ID);
         HiddenColumns.Add(x => x.Product.Code);
         HiddenColumns.Add(x => x.Product.Group.ID);
@@ -112,6 +164,14 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
         HiddenColumns.Add(x => x.Dimensions.Unit.Code);
         HiddenColumns.Add(x => x.Dimensions.Unit.Description);
 
+        AddDoubleColumn(x => x.Qty, "Qty.");
+        InStockColumn = AddDoubleColumn(x => x.InStock, "Stk.");
+        OnOrderColumn = AddDoubleColumn(x => x.OnOrder, "Ord.");
+        TreatmentRequiredColumn = AddDoubleColumn(x => x.TreatmentRequired, "Req.");
+        TreatmentOnOrderColumn = AddDoubleColumn(x => x.TreatmentOnOrder, "Ord.");
+        AllocatedColumn = AddDoubleColumn(x => x.Allocated, "Stk.");
+        IssuedColumn = AddDoubleColumn(x => x.Issued, "Iss.");
+
         if (Security.CanEdit<JobRequisitionItem>())
             ActionColumns.Add(new DynamicMenuColumn(BuildMenu));
 
@@ -123,6 +183,13 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
         ArchiveButton.IsEnabled = false;
     }
 
+    private DynamicActionColumn AddDoubleColumn(Expression<Func<JobRequisitionItem, object>> property, string header)
+    {
+        var col = new DynamicTextColumn<JobRequisitionItem>(property) { Format = "F2", HeaderText = header, Width = 50 };
+        ActionColumns.Add(col);
+        return col;
+    }
+
     protected override IDynamicGridUIComponent<JobRequisitionItem> CreateUIComponent()
     {
         return new UIComponent(this);
@@ -156,18 +223,22 @@ public class ReservationManagementItemGrid : DynamicDataGrid<JobRequisitionItem>
         columns.Add<JobRequisitionItem, string>(x => x.Requisition.Job.JobNumber, 70, "Job", "", Alignment.MiddleCenter);
         columns.Add<JobRequisitionItem, int>(x => x.Requisition.Number, 50, "Requi", "", Alignment.MiddleCenter);
         columns.Add<JobRequisitionItem, string>(x => x.Product.Code, 100, "Product Code", "", Alignment.MiddleLeft);
-        columns.Add<JobRequisitionItem, string>(x => x.Product.Name, 200, "Product Name", "", Alignment.MiddleLeft);
-        columns.Add<JobRequisitionItem, string>(x => x.Style.Description, 150, "Style", "", Alignment.MiddleLeft);
-        columns.Add<JobRequisitionItem, double>(x => x.Qty, 50, "Qty", "", Alignment.MiddleCenter);
+        columns.Add<JobRequisitionItem, string>(x => x.Product.Name, 0, "Product Name", "", Alignment.MiddleLeft);
+        columns.Add<JobRequisitionItem, string>(x => x.Style.Code, 100, "Style", "", Alignment.MiddleLeft);
         columns.Add<JobRequisitionItem, string>(x => x.Dimensions.UnitSize, 70, "Size", "", Alignment.MiddleLeft);
         columns.Add<JobRequisitionItem, JobRequisitionItemStatus>(x => x.Status, 90, "Status", "", Alignment.MiddleCenter);
-        columns.Add<JobRequisitionItem, double>(x => x.InStock, 50, "Stk.", "", Alignment.MiddleCenter);
-        columns.Add<JobRequisitionItem, double>(x => x.OnOrder, 50, "Ord.", "", Alignment.MiddleCenter);
-        columns.Add<JobRequisitionItem, string>(x => x.PurchaseOrderNumbers, 100, "Orders", "", Alignment.MiddleLeft);
-        columns.Add<JobRequisitionItem, string>(x => x.Notes, 0, "Notes", "", Alignment.MiddleLeft);
+
         return columns;
     }
 
+    protected override void ConfigureColumnGroups()
+    {
+        GetColumnGrouping()
+            .AddGroup("Stock", InStockColumn, OnOrderColumn)
+            .AddGroup("Treatment", TreatmentRequiredColumn, TreatmentOnOrderColumn)
+            .AddGroup("Allocated", AllocatedColumn, IssuedColumn);
+    }
+
     protected override void SelectItems(CoreRow[]? rows)
     {
         base.SelectItems(rows);