Explorar el Código

ProductInstance.AverageCost is now automatically calculated from Free Stock Movements

frankvandenbos hace 1 mes
padre
commit
82616152df

+ 48 - 4
prs.classes/Entities/Product/Instance/ProductInstance.cs

@@ -1,15 +1,17 @@
 using InABox.Core;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Linq.Expressions;
 using System.Text;
+using InABox.Clients;
 
 namespace Comal.Classes
 {
 
     public class ProductInstanceFreeStockAggregate : CoreAggregate<ProductInstance, StockMovement, double>
     {
-        public override Expression<Func<StockMovement, double>> Aggregate => x => x.Qty;
+        public override Expression<Func<StockMovement, double>> Aggregate => x => x.Units;
 
         public override Filter<StockMovement> Filter => new Filter<StockMovement>(x => x.Job).NotLinkValid();
 
@@ -23,7 +25,32 @@ namespace Comal.Classes
 
         public override AggregateCalculation Calculation => AggregateCalculation.Sum;
     }
+    
+    public class ProductInstanceFreeStockValueAggregate : CoreAggregate<ProductInstance, StockMovement, double>
+    {
+        public override Expression<Func<StockMovement, double>> Aggregate => x => x.Value;
+
+        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 },
+            }.AddRange(Dimensions.GetLinks<StockMovement, ProductInstance>(x => x.Dimensions, x => x.Dimensions));
 
+        public override AggregateCalculation Calculation => AggregateCalculation.Sum;
+    }
+
+    public class ProductInstanceAverageCostFormula : IFormula<ProductInstance, double>
+    {
+        public Expression<Func<ProductInstance, double>> Value => x => x.FreeStockValue;
+        public Expression<Func<ProductInstance, double>>[] Modifiers => new Expression<Func<ProductInstance, double>>[] { x => x.FreeStock };
+        public FormulaOperator Operator => FormulaOperator.Divide;
+        public FormulaType Type => FormulaType.Virtual;
+    }
+    
     public class ProductInstance : StockEntity, IRemotable, IPersistent, IProductInstance,
         ISequenceable, ILicense<ProductManagementLicense>
     {
@@ -50,15 +77,20 @@ namespace Comal.Classes
         [Aggregate(typeof(ProductInstanceFreeStockAggregate))]
         [DoubleEditor(Editable = Editable.Hidden)]
         public double FreeStock { get; set; }
-
+        
+        [EditorSequence(5)]
+        [Aggregate(typeof(ProductInstanceFreeStockValueAggregate))]
+        [DoubleEditor(Editable = Editable.Hidden)]
+        public double FreeStockValue { get; set; }
+        
         [CurrencyEditor(Visible = Visible.Optional)]
         [EditorSequence(5)]
         [LoggableProperty]
         public double NettCost { get; set; }
-
+        
+        [Formula(typeof(ProductInstanceAverageCostFormula))]
         [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Disabled)]
         [EditorSequence(6)]
-        [LoggableProperty]
         public double AverageCost { get; set; }
 
         [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Disabled)]
@@ -70,5 +102,17 @@ namespace Comal.Classes
         [Obsolete("", true)]
         public double Parameter { get; set; }
 
+        public double RecalculateAverageCost()
+        {
+            var movements = Client.Query(
+                new Filter<StockMovement>(x=>x.Product.ID).IsEqualTo(Product.ID)
+                    .And(x => x.Style.ID).IsEqualTo(Style.ID)
+                    .And(x => x.Dimensions).DimensionEquals(Dimensions)
+                    .And(x => x.Job.ID).IsEqualTo(Guid.Empty),
+                Columns.None<StockMovement>().Add(x=>x.Units).Add(x=>x.Cost)
+            ).Rows.ToObjects<StockMovement>().ToArray();
+            return movements.Average(x => x.Units * x.Cost);
+        }
+
     }
 }

+ 1 - 0
prs.classes/Entities/Stock/StockHolding/StockHolding.cs

@@ -272,6 +272,7 @@ namespace Comal.Classes
             List<StockMovement> _result = new List<StockMovement>();
             var movements = Client.Query(
                 new Filter<StockMovement>(x => x.Location.ID).IsEqualTo(holding.Location.ID)
+                    .And(x=>x.Product.ID).IsEqualTo(holding.Product.ID)
                     .And(x => x.Style.ID).IsEqualTo(holding.Style.ID)
                     .And(x => x.Dimensions).DimensionEquals(holding.Dimensions)
                     .And(x => x.Job.ID).IsEqualTo(holding.Job.ID),

+ 23 - 6
prs.desktop/Panels/Products/Locations/StockHoldingGrid.cs

@@ -126,18 +126,35 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
                 Client.Save(_batch,"Stock value adjusted from holding grid");
                 
                 progress.Report("Creating Movements");
-                List<StockMovement> _updates = new List<StockMovement>();
+                
                 foreach (var _row in rows)
                 {
+                    progress.Report("Adjusting Values");
+                    List<StockMovement> _updates = new List<StockMovement>();
                     var _holding = _row.ToObject<StockHolding>();
-                    _holding.AverageValue = _newvalue;
-                    _holding.Value = _newvalue * _holding.Units;
-                    Client.Save(_holding,"Stock value adjusted from holding grid");
                     _updates.AddRange(_holding.AdjustValue(_newvalue, _batch));
+                    
+                    progress.Report("Saving Movements");
+                    Client.Save(_updates,"Stock value adjusted from holding grid");
+                    
+                    // progress.Report("Updating Product Instances");
+                    // var instance = Client.Query(
+                    //     new Filter<ProductInstance>(x => x.Product.ID).IsEqualTo(_holding.Product.ID)
+                    //         .And(x => x.Style.ID).IsEqualTo(_holding.Style.ID)
+                    //         .And(x => x.Dimensions).IsEqualTo(_holding.Dimensions),
+                    //     Columns.Required<ProductInstance>().Add(x=>x.AverageCost)
+                    // ).Rows.FirstOrDefault()?.ToObject<ProductInstance>();
+                    // if (instance != null)
+                    // {
+                    //     var newinstanceaverage = instance.RecalculateAverageCost();
+                    //     if (!newinstanceaverage.IsEffectivelyEqual(instance.AverageCost))
+                    //     {
+                    //         instance.AverageCost = newinstanceaverage;
+                    //         Client.Save(instance,"Average Cost Updated by Stock Holding");
+                    //     }
+                    // }
                 }
                 
-                progress.Report("Saving Movements");
-                Client.Save(_updates,"Stock value adjusted from holding grid");
             });
             MessageBox.Show("All Done");
             return true;

+ 26 - 7
prs.desktop/Panels/Products/Master List/ProductHoldingControl.cs

@@ -130,19 +130,38 @@ public class ProductHoldingControl : DynamicDataGrid<StockHolding>, IProductCont
                 _batch.Employee.ID = App.EmployeeID;
                 Client.Save(_batch,"Stock value adjusted from Products List");
                 
-                progress.Report("Creating Movements");
-                List<StockMovement> _updates = new List<StockMovement>();
+                
                 foreach (var _row in rows)
                 {
+                    progress.Report("Creating Movements");
+                    List<StockMovement> _updates = new List<StockMovement>();
                     var _holding = _row.ToObject<StockHolding>();
-                    _holding.AverageValue = _newvalue;
-                    _holding.Value = _newvalue * _holding.Units;
-                    Client.Save(_holding,"Stock value adjusted from Products List");
                     _updates.AddRange(_holding.AdjustValue(_newvalue, _batch));
+                    
+                    progress.Report("Saving Movements");
+                    Client.Save(_updates,"Stock value adjusted from Products List");
+                    
+                    // progress.Report("Updating Product Instances");
+                    // var instance = Client.Query(
+                    //     new Filter<ProductInstance>(x => x.Product.ID).IsEqualTo(_holding.Product.ID)
+                    //         .And(x => x.Style.ID).IsEqualTo(_holding.Style.ID)
+                    //         .And(x => x.Dimensions).IsEqualTo(_holding.Dimensions),
+                    //     Columns.Required<ProductInstance>().Add(x=>x.AverageCost)
+                    // ).Rows.FirstOrDefault()?.ToObject<ProductInstance>();
+                    // if (instance != null)
+                    // {
+                    //     var newinstanceaverage = instance.RecalculateAverageCost();
+                    //     if (!newinstanceaverage.IsEffectivelyEqual(instance.AverageCost))
+                    //     {
+                    //         instance.AverageCost = newinstanceaverage;
+                    //         Client.Save(instance,"Average Cost Updated by Products List");
+                    //     }
+                    // }
+                    
+                    
                 }
                 
-                progress.Report("Saving Movements");
-                Client.Save(_updates,"Stock value adjusted from Products List");
+
             });
             MessageBox.Show("All Done");
             return true;

+ 13 - 3
prs.desktop/Panels/Products/Master List/ProductInstanceControl.cs

@@ -179,8 +179,8 @@ public class ProductInstanceControl : DynamicDataGrid<ProductInstance>, IProduct
             Progress.ShowModal("Updating Average Cost", progress =>
             {
                 var _instance = rows[0].ToObject<ProductInstance>();
-                _instance.AverageCost = _newvalue;
-                Client.Save(_instance,"Updated from Product Master List");
+                //_instance.AverageCost = _newvalue;
+                //Client.Save(_instance,"Updated from Product Master List");
                 
                 
                 progress.Report("Loading Holdings");
@@ -190,6 +190,11 @@ public class ProductInstanceControl : DynamicDataGrid<ProductInstance>, IProduct
                         .And(x=>x.Dimensions).DimensionEquals(_instance.Dimensions)
                         .And(x=>x.Job.ID).IsEqualTo(Guid.Empty),
                     Columns.Required<StockHolding>()
+                        .Add(x=>x.Product.ID)
+                        .Add(x=>x.Style.ID)
+                        .AddDimensionsColumns(x=>x.Dimensions)
+                        .Add(x=>x.Location.ID)
+                        .Add(x=>x.AverageValue)
                     ).Rows.ToObjects<StockHolding>()
                     .ToArray();
                 if (_holdings.Any())
@@ -198,18 +203,23 @@ public class ProductInstanceControl : DynamicDataGrid<ProductInstance>, IProduct
                     StockMovementBatch _batch = new StockMovementBatch()
                     {
                         Type = StockMovementBatchType.Transfer,
-                        Employee = new EmployeeLink() { ID = App.EmployeeID },
                         Notes = "Stock Value Adjustment"
                     };
+                    _batch.Employee.ID = App.EmployeeID;
                     Client.Save(_batch, "Stock value adjusted from Product Master List");
 
 
                     progress.Report("Creating Movements");
                     List<StockMovement> _updates = new List<StockMovement>();
                     foreach (var _holding in _holdings)
+                    {
                         _updates.AddRange(_holding.AdjustValue(_newvalue, _batch));
+                        //_holding.AverageValue = _newvalue;
+                        //_holding.Value = _newvalue * _holding.Units;
+                    }
 
                     progress.Report("Saving Movements");
+                    //Client.Save(_holdings,"Stock value adjusted from holding grid");
                     Client.Save(_updates, "Stock value adjusted from Product Master List");
                 }
             });

+ 146 - 146
prs.shared/Database Update Scripts/Update_8_23.cs

@@ -20,35 +20,35 @@ internal class Update_8_23 : DatabaseUpdateScript
         
         CheckDimensions<StockMovement>(_provider);
 
-        var holdings = _provider.Query(
-            null,
-            Columns.None<StockHolding>()
-                .Add(x => x.Location.ID)
-                .Add(x => x.Product.ID)
-                .Add(x => x.Job.ID)
-                .Add(x => x.Style.ID)
-                .Add(x => x.Dimensions.Unit.ID)
-                .Add(x => x.Dimensions.Length)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Dimensions.Height)
-                .Add(x => x.Dimensions.Quantity)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.AverageValue)
-        ).Rows.ToObjects<StockHolding>().ToArray();
-        
-        var instances = _provider.Query(
-            null,
-            Columns.None<ProductInstance>()
-                .Add(x => x.Product.ID)
-                .Add(x => x.Style.ID)
-                .Add(x => x.Dimensions.Unit.ID)
-                .Add(x => x.Dimensions.Length)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Dimensions.Height)
-                .Add(x => x.Dimensions.Quantity)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.AverageCost)
-        ).Rows.ToObjects<ProductInstance>().ToArray();
+        // var holdings = _provider.Query(
+        //     null,
+        //     Columns.None<StockHolding>()
+        //         .Add(x => x.Location.ID)
+        //         .Add(x => x.Product.ID)
+        //         .Add(x => x.Job.ID)
+        //         .Add(x => x.Style.ID)
+        //         .Add(x => x.Dimensions.Unit.ID)
+        //         .Add(x => x.Dimensions.Length)
+        //         .Add(x => x.Dimensions.Width)
+        //         .Add(x => x.Dimensions.Height)
+        //         .Add(x => x.Dimensions.Quantity)
+        //         .Add(x => x.Dimensions.Width)
+        //         .Add(x => x.AverageValue)
+        // ).Rows.ToObjects<StockHolding>().ToArray();
+        //
+        // var instances = _provider.Query(
+        //     null,
+        //     Columns.None<ProductInstance>()
+        //         .Add(x => x.Product.ID)
+        //         .Add(x => x.Style.ID)
+        //         .Add(x => x.Dimensions.Unit.ID)
+        //         .Add(x => x.Dimensions.Length)
+        //         .Add(x => x.Dimensions.Width)
+        //         .Add(x => x.Dimensions.Height)
+        //         .Add(x => x.Dimensions.Quantity)
+        //         .Add(x => x.Dimensions.Width)
+        //         .Add("AverageCost")
+        // ).Rows.ToObjects<ProductInstance>().ToArray();
 
         //CheckStockMovementCosts(_provider, holdings, instances);
 
@@ -66,123 +66,123 @@ internal class Update_8_23 : DatabaseUpdateScript
     //     }
     // }
 
-    private void CheckStockMovementCosts(IProvider provider, StockHolding[] holdings, ProductInstance[] instances)
-    {
-        
-        var items = provider.Query(
-            new Filter<StockMovement>(x=>x.Product.ID).IsNotEqualTo(Guid.Empty).And(x=>x.Cost).IsEqualTo(0.0),
-            Columns.None<StockMovement>()
-                .Add(x => x.ID)
-                .Add(x => x.Location.ID)
-                .Add(x => x.Product.ID)
-                .Add(x => x.Job.ID)
-                .Add(x => x.Style.ID)
-                .Add(x => x.Dimensions.Unit.ID)
-                .Add(x => x.Dimensions.Length)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Dimensions.Height)
-                .Add(x => x.Dimensions.Quantity)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Cost)
-        ).Rows.ToQueue();
-        
-        while (items.Any())
-        {
-            Logger.Send(LogType.Information,"",$"Updating {nameof(StockMovement)} Costs ({items.Count} remaining)..");
-            var updates = items.Dequeue(100).ToObjects<StockMovement>().ToArray();
-            foreach (var item in updates)
-            {
-                var holding = holdings.FirstOrDefault(x =>
-                    Guid.Equals(x.Product.ID, item.Product.ID)
-                    && Guid.Equals(x.Location.ID, item.Location.ID)
-                    && Guid.Equals(x.Style.ID, item.Style.ID)
-                    && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
-                    && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
-                    && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
-                    && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
-                    && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
-                    && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
-                );
-                if (holding != null)
-                    item.Cost = holding.AverageValue;
-                else
-                {
-                    var instance = instances.FirstOrDefault(x =>
-                        Guid.Equals(x.Product.ID, item.Product.ID)
-                        && Guid.Equals(x.Style.ID, item.Style.ID)
-                        && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
-                        && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
-                        && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
-                        && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
-                        && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
-                        && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
-                    );
-                    if (instance != null)
-                        item.Cost = instance.AverageCost;
-                }
-            }
-            provider.Save(updates.Where(x=>x.IsChanged()));
-        }
-    }
-    
-       private void CheckRequisitionItemCosts(IProvider provider, StockHolding[] holdings, ProductInstance[] instances)
-    {
-        
-        var items = provider.Query(
-            new Filter<RequisitionItem>(x=>x.Product.ID).IsNotEqualTo(Guid.Empty).And(x=>x.Cost).IsEqualTo(0.0),
-            Columns.None<RequisitionItem>()
-                .Add(x => x.ID)
-                .Add(x => x.Location.ID)
-                .Add(x => x.Product.ID)
-                .Add(x => x.RequisitionLink.JobLink.ID)
-                .Add(x => x.Style.ID)
-                .Add(x => x.Dimensions.Unit.ID)
-                .Add(x => x.Dimensions.Length)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Dimensions.Height)
-                .Add(x => x.Dimensions.Quantity)
-                .Add(x => x.Dimensions.Width)
-                .Add(x => x.Cost)
-        ).Rows.ToObjects<RequisitionItem>().ToQueue();
-        
-        while (items.Any())
-        {
-            Logger.Send(LogType.Information,"",$"Updating {nameof(RequisitionItem)} Costs ({items.Count} remaining)..");
-            var updates = items.Dequeue(100).ToArray();
-            foreach (var item in updates)
-            {
-                var holding = holdings.FirstOrDefault(x =>
-                    Guid.Equals(x.Product.ID, item.Product.ID)
-                    && Guid.Equals(x.Location.ID, item.Location.ID)
-                    && Guid.Equals(x.Style.ID, item.Style.ID)
-                    && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
-                    && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
-                    && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
-                    && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
-                    && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
-                    && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
-                );
-                if (holding != null)
-                    item.Cost = holding.AverageValue;
-                else
-                {
-                    var instance = instances.FirstOrDefault(x =>
-                        Guid.Equals(x.Product.ID, item.Product.ID)
-                        && Guid.Equals(x.Style.ID, item.Style.ID)
-                        && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
-                        && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
-                        && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
-                        && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
-                        && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
-                        && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
-                    );
-                    if (instance != null)
-                        item.Cost = instance.AverageCost;
-                }
-            }
-            provider.Save(updates.Where(x=>x.IsChanged()));
-        }
-    }
+    // private void CheckStockMovementCosts(IProvider provider, StockHolding[] holdings, ProductInstance[] instances)
+    // {
+    //     
+    //     var items = provider.Query(
+    //         new Filter<StockMovement>(x=>x.Product.ID).IsNotEqualTo(Guid.Empty).And(x=>x.Cost).IsEqualTo(0.0),
+    //         Columns.None<StockMovement>()
+    //             .Add(x => x.ID)
+    //             .Add(x => x.Location.ID)
+    //             .Add(x => x.Product.ID)
+    //             .Add(x => x.Job.ID)
+    //             .Add(x => x.Style.ID)
+    //             .Add(x => x.Dimensions.Unit.ID)
+    //             .Add(x => x.Dimensions.Length)
+    //             .Add(x => x.Dimensions.Width)
+    //             .Add(x => x.Dimensions.Height)
+    //             .Add(x => x.Dimensions.Quantity)
+    //             .Add(x => x.Dimensions.Width)
+    //             .Add(x => x.Cost)
+    //     ).Rows.ToQueue();
+    //     
+    //     while (items.Any())
+    //     {
+    //         Logger.Send(LogType.Information,"",$"Updating {nameof(StockMovement)} Costs ({items.Count} remaining)..");
+    //         var updates = items.Dequeue(100).ToObjects<StockMovement>().ToArray();
+    //         foreach (var item in updates)
+    //         {
+    //             var holding = holdings.FirstOrDefault(x =>
+    //                 Guid.Equals(x.Product.ID, item.Product.ID)
+    //                 && Guid.Equals(x.Location.ID, item.Location.ID)
+    //                 && Guid.Equals(x.Style.ID, item.Style.ID)
+    //                 && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
+    //                 && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
+    //                 && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
+    //                 && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
+    //                 && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
+    //                 && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
+    //             );
+    //             if (holding != null)
+    //                 item.Cost = holding.AverageValue;
+    //             else
+    //             {
+    //                 var instance = instances.FirstOrDefault(x =>
+    //                     Guid.Equals(x.Product.ID, item.Product.ID)
+    //                     && Guid.Equals(x.Style.ID, item.Style.ID)
+    //                     && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
+    //                     && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
+    //                     && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
+    //                     && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
+    //                     && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
+    //                     && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
+    //                 );
+    //                 if (instance != null)
+    //                     item.Cost = (double)(CoreUtils.GetPropertyValue(instance,"AverageCost") ?? 0.0);
+    //             }
+    //         }
+    //         provider.Save(updates.Where(x=>x.IsChanged()));
+    //     }
+    // }
+    //
+    //    private void CheckRequisitionItemCosts(IProvider provider, StockHolding[] holdings, ProductInstance[] instances)
+    // {
+    //     
+    //     var items = provider.Query(
+    //         new Filter<RequisitionItem>(x=>x.Product.ID).IsNotEqualTo(Guid.Empty).And(x=>x.Cost).IsEqualTo(0.0),
+    //         Columns.None<RequisitionItem>()
+    //             .Add(x => x.ID)
+    //             .Add(x => x.Location.ID)
+    //             .Add(x => x.Product.ID)
+    //             .Add(x => x.RequisitionLink.JobLink.ID)
+    //             .Add(x => x.Style.ID)
+    //             .Add(x => x.Dimensions.Unit.ID)
+    //             .Add(x => x.Dimensions.Length)
+    //             .Add(x => x.Dimensions.Width)
+    //             .Add(x => x.Dimensions.Height)
+    //             .Add(x => x.Dimensions.Quantity)
+    //             .Add(x => x.Dimensions.Width)
+    //             .Add(x => x.Cost)
+    //     ).Rows.ToObjects<RequisitionItem>().ToQueue();
+    //     
+    //     while (items.Any())
+    //     {
+    //         Logger.Send(LogType.Information,"",$"Updating {nameof(RequisitionItem)} Costs ({items.Count} remaining)..");
+    //         var updates = items.Dequeue(100).ToArray();
+    //         foreach (var item in updates)
+    //         {
+    //             var holding = holdings.FirstOrDefault(x =>
+    //                 Guid.Equals(x.Product.ID, item.Product.ID)
+    //                 && Guid.Equals(x.Location.ID, item.Location.ID)
+    //                 && Guid.Equals(x.Style.ID, item.Style.ID)
+    //                 && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
+    //                 && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
+    //                 && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
+    //                 && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
+    //                 && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
+    //                 && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
+    //             );
+    //             if (holding != null)
+    //                 item.Cost = holding.AverageValue;
+    //             else
+    //             {
+    //                 var instance = instances.FirstOrDefault(x =>
+    //                     Guid.Equals(x.Product.ID, item.Product.ID)
+    //                     && Guid.Equals(x.Style.ID, item.Style.ID)
+    //                     && Guid.Equals(x.Dimensions.Unit.ID, item.Dimensions.Unit.ID)
+    //                     && x.Dimensions.Length.IsEffectivelyEqual(item.Dimensions.Length)
+    //                     && x.Dimensions.Width.IsEffectivelyEqual(item.Dimensions.Width)
+    //                     && x.Dimensions.Height.IsEffectivelyEqual(item.Dimensions.Height)
+    //                     && x.Dimensions.Weight.IsEffectivelyEqual(item.Dimensions.Weight)
+    //                     && x.Dimensions.Quantity.IsEffectivelyEqual(item.Dimensions.Quantity)
+    //                 );
+    //                 if (instance != null)
+    //                     item.Cost = (double)(CoreUtils.GetPropertyValue(instance,"AverageCost") ?? 0.0);
+    //             }
+    //         }
+    //         provider.Save(updates.Where(x=>x.IsChanged()));
+    //     }
+    // }
     
     private void CheckDimensions<T>(IProvider provider) where T : StockEntity, new()
     {

+ 55 - 55
prs.stores/PurchaseOrderItemStore.cs

@@ -194,20 +194,20 @@ internal class PurchaseOrderItemStore : BaseStore<PurchaseOrderItem>
         var totalAllocations = allocations.Sum(x => x.Quantity);
         var freeQty = entity.Qty - totalAllocations;
 
-        var instancetask = Task.Run(
-            () => !freeQty.IsEffectivelyEqual(0.0) 
-                ? Provider.Query(
-                    new Filter<ProductInstance>(x => x.Product.ID).IsEqualTo(entity.Product.ID)
-                        .And(x => x.Style.ID).IsEqualTo(entity.Style.ID)
-                        .And(x => x.Dimensions).DimensionEquals(entity.Dimensions),
-                    Columns.Required<ProductInstance>()
-                        .Add(x => x.ID)
-                        .Add(x => x.FreeStock)
-                        .Add(x => x.AverageCost)
-                        .Add(x => x.LastCost)
-                ).Rows.FirstOrDefault()
-                : null
-        );
+        // var instancetask = Task.Run(
+        //     () => !freeQty.IsEffectivelyEqual(0.0) 
+        //         ? Provider.Query(
+        //             new Filter<ProductInstance>(x => x.Product.ID).IsEqualTo(entity.Product.ID)
+        //                 .And(x => x.Style.ID).IsEqualTo(entity.Style.ID)
+        //                 .And(x => x.Dimensions).DimensionEquals(entity.Dimensions),
+        //             Columns.Required<ProductInstance>()
+        //                 .Add(x => x.ID)
+        //                 .Add(x => x.FreeStock)
+        //                 .Add(x => x.AverageCost)
+        //                 .Add(x => x.LastCost)
+        //         ).Rows.FirstOrDefault()
+        //         : null
+        // );
         
         var batch = new StockMovementBatch
         {
@@ -254,50 +254,50 @@ internal class PurchaseOrderItemStore : BaseStore<PurchaseOrderItem>
         }
 
         // We need the instancetask to return before updating any stock movements
-        instancetask.Wait();
+        //instancetask.Wait();
         
         FindSubStore<StockMovement>().Save(movements, "Updated by Purchase Order Modification");
 
-        // Update the AverageCost on the instance
-        if (!freeQty.IsEffectivelyEqual(0.0))
-        {
-            var instance = instancetask.Result?.ToObject<ProductInstance>();
-            if (instance == null)
-            {
-                instance = new ProductInstance();
-                instance.Product.ID = entity.Product.ID;
-                instance.Style.ID = entity.Style.ID;
-                instance.Dimensions.CopyFrom(entity.Dimensions);
-            }
-            
-            instance.LastCost = entity.Cost;
-
-            var freeqty = instance.FreeStock;
-            var freeavg = instance.AverageCost;
-            var freecost = instance.FreeStock * freeavg;
-
-            var poqty = freeQty * (Math.Abs(entity.Dimensions.Value) > 0.0001F ? entity.Dimensions.Value : 1.0F);
-            var pocost = entity.Cost * poqty;
-            
-            if (!consigntask.Result.IsEffectivelyEqual(0.0))
-                pocost += freeQty * entity.Cost * entity.Consignment.ExTax / consigntask.Result;
-            
-            var totalqty = freeqty + poqty;
-            var totalcost = freecost + pocost;
-
-            var averagecost = Math.Abs(totalqty) > 0.0001F
-                ? totalcost / totalqty
-                : pocost;
-
-            if (Math.Abs(averagecost - freeavg) > 0.0001F)
-            {
-                instance.AverageCost = averagecost;
-                FindSubStore<ProductInstance>().Save(instance,
-                    $"Updated Average Cost: " +
-                    $"({freeqty} @ {freeavg:C2}) + ({poqty} @ {entity.Cost:C2}) = {totalcost:C2} / {totalqty}"
-                );
-            }
-        }
+        // // Update the AverageCost on the instance
+        // if (!freeQty.IsEffectivelyEqual(0.0))
+        // {
+        //     var instance = instancetask.Result?.ToObject<ProductInstance>();
+        //     if (instance == null)
+        //     {
+        //         instance = new ProductInstance();
+        //         instance.Product.ID = entity.Product.ID;
+        //         instance.Style.ID = entity.Style.ID;
+        //         instance.Dimensions.CopyFrom(entity.Dimensions);
+        //     }
+        //     
+        //     instance.LastCost = entity.Cost;
+        //
+        //     var freeqty = instance.FreeStock;
+        //     var freeavg = instance.AverageCost;
+        //     var freecost = instance.FreeStock * freeavg;
+        //
+        //     var poqty = freeQty * (Math.Abs(entity.Dimensions.Value) > 0.0001F ? entity.Dimensions.Value : 1.0F);
+        //     var pocost = entity.Cost * poqty;
+        //     
+        //     if (!consigntask.Result.IsEffectivelyEqual(0.0))
+        //         pocost += freeQty * entity.Cost * entity.Consignment.ExTax / consigntask.Result;
+        //     
+        //     var totalqty = freeqty + poqty;
+        //     var totalcost = freecost + pocost;
+        //
+        //     var averagecost = Math.Abs(totalqty) > 0.0001F
+        //         ? totalcost / totalqty
+        //         : pocost;
+        //
+        //     if (Math.Abs(averagecost - freeavg) > 0.0001F)
+        //     {
+        //         instance.AverageCost = averagecost;
+        //         FindSubStore<ProductInstance>().Save(instance,
+        //             $"Updated Average Cost: " +
+        //             $"({freeqty} @ {freeavg:C2}) + ({poqty} @ {entity.Cost:C2}) = {totalcost:C2} / {totalqty}"
+        //         );
+        //     }
+        // }
 
         entity.CancelChanges();
     }

+ 1 - 1
prs.stores/StockHoldingStore.cs

@@ -11,7 +11,7 @@ using HoldingDictionary = Dictionary<(Guid product, Guid style, Guid location, G
 
 public class StockHoldingStore : BaseStore<StockHolding>
 {
-
+    
     public enum Action
     {
         Increase,