Просмотр исходного кода

Fixed Issues with RequisitionItemGrid
Fixed crash in Product Holding Grid Recalculate() function
Fixed Shortage calculation in Reservation Management Screen

frankvandenbos 7 месяцев назад
Родитель
Сommit
061ca15606

+ 14 - 2
prs.classes/Entities/Job/Requisitions/JobRequisitionItem.cs

@@ -219,7 +219,7 @@ namespace Comal.Classes
         {
             public override IComplexFormulaNode<JobRequisitionItem, double> GetFormula() =>
                 Aggregate<RequisitionItem>(AggregateCalculation.Sum, x => x.Property(x => x.Quantity), new Filter<RequisitionItem>(x => x.RequisitionLink.StockUpdated).IsEqualTo(DateTime.MinValue))
-                .WithLink(x => x.SourceJRI.ID, x => x.ID);
+                .WithLink(x => x.JobRequisitionItem.ID, x => x.ID);
         }
         [ComplexFormula(typeof(PickRequestedFormula))]
         [DoubleEditor(Editable = Editable.Disabled)]
@@ -241,6 +241,16 @@ namespace Comal.Classes
         [EditorSequence(17)]
         public double Issued { get; set; }
         
+                
+        private class TotalIssuedFormula : ComplexFormulaGenerator<JobRequisitionItem, double>
+        {
+            public override IComplexFormulaNode<JobRequisitionItem, double> GetFormula() =>
+                Formula(FormulaOperator.Multiply, Property(x => x.Issued), Property(x => x.Dimensions.Value));
+        }
+        [DoubleEditor(Editable = Editable.Hidden)]
+        [ComplexFormula(typeof(TotalIssuedFormula))]
+        public double TotalIssued { get; set; }
+        
         private class TotalAllocatedFormula : ComplexFormulaGenerator<JobRequisitionItem, double>
         {
             public override IComplexFormulaNode<JobRequisitionItem, double> GetFormula() =>
@@ -256,7 +266,9 @@ namespace Comal.Classes
                 If<JobRequisitionItem, double, bool>(
                         Property<JobRequisitionItem, double>(x => x.TotalQty)
                         , Condition.GreaterThan,
-                        Property<JobRequisitionItem, double>(x => x.TotalAllocated))
+                        Formula(FormulaOperator.Add, 
+                            Property<JobRequisitionItem, double>(x => x.TotalAllocated), 
+                            Property<JobRequisitionItem, double>(x => x.TotalIssued)))
                     .Then(Constant(true))
                     .Else(Constant(false));
             //Formula(FormulaOperator.Subtract, Property(x => x.InStock), Property(x => x.Allocated));

+ 1 - 1
prs.classes/Entities/Job/Requisitions/JobRequisitionLink.cs

@@ -13,7 +13,7 @@ namespace Comal.Classes
 
         public JobLink Job { get; set; }
 
-        [IntegerEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
+        [IntegerEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         public int Number { get; set; }
 
         [TextBoxEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]

+ 0 - 1
prs.classes/Entities/Requisition/RequisitionItem.cs

@@ -94,7 +94,6 @@ namespace Comal.Classes
         
         // This one is for the Source Requisition Item (if generated from a JRI)
         // This can't be changed
-        [NullEditor]
         [RequiredColumn]
         public JobRequisitionItemLink SourceJRI { get; set; }
         

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

@@ -241,6 +241,9 @@ namespace Comal.Classes
         {
             columns ??= Columns.None<JobRequisitionItem>();
             columns.Add(x => x.ID)
+                .Add(x => x.Product.ID)
+                .Add(x => x.Style.ID)
+                .AddDimensionsColumns(x => x.Dimensions)
                 .Add(x => x.Job.ID)
                 .Add(x => x.Job.JobNumber)
                 .Add(x => x.Job.Name)
@@ -251,7 +254,8 @@ namespace Comal.Classes
             var items = new Client<JobRequisitionItem>().Query(
                     new Filter<JobRequisitionItem>(x => x.ID).InQuery(StockHolding.GetFilter(holding), x => x.JobRequisitionItem.ID),
                     columns)
-                .ToObjects<JobRequisitionItem>();
+                .ToObjects<JobRequisitionItem>()
+                .Where(x=>x.Product.ID == holding.Product.ID && x.Style.ID == holding.Style.ID && x.Dimensions.Equals(holding.Dimensions));
             if (holding.Available > 0 || alwaysshowunallocated)
             {
                 var requi = new JobRequisitionItem() { Qty = holding.Available };

+ 5 - 0
prs.desktop/Panels/Products/Locations/StockHoldingGrid.cs

@@ -334,6 +334,11 @@ public class StockHoldingGrid : DynamicDataGrid<StockHolding>
         var holding = row.ToObject<StockHolding>();
 
         var grid = (DynamicGridUtils.CreateDynamicGrid(typeof(DynamicDataGrid<>), typeof(JobRequisitionItem)) as DynamicDataGrid<JobRequisitionItem>)!;
+        grid.Options.SelectColumns = true;
+        grid.Options.AddRows = false;
+        grid.Options.EditRows = false;
+        grid.Options.DeleteRows = false;
+        grid.Options.MultiSelect = false;
         grid.OnDefineFilter += (type) =>
         {
             if(type == typeof(JobRequisitionItem))

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

@@ -125,9 +125,9 @@ public class ProductHoldingControl : DynamicDataGrid<StockHolding>, IProductCont
                 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 Products List");
                 
                 progress.Report("Creating Movements");

+ 51 - 20
prs.desktop/Panels/Requisitions/RequisitionItemEditor/RequisitionItemEditor.xaml.cs

@@ -188,7 +188,7 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
 
     #region Allocations
     
-    private IEnumerable<StockSelectionItem> CreateStockSelectionItems(IEnumerable<IGrouping<Guid, StockMovement>> groups, Func<StockMovement,string> description)
+    private IEnumerable<StockSelectionItem> CreateStockSelectionItems(IEnumerable<IGrouping<Tuple<Guid,Guid>, StockMovement>> groups, Tuple<Guid,Guid,double>[] values, Func<StockMovement,string> description)
     {
         
         var _result = new List<StockSelectionItem>();
@@ -198,15 +198,20 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
             if (!_units.IsEffectivelyEqual(0.0))
             {
                 var _holding = new StockHolding();
-                _holding.Location.ID = _group.Key;
+                _holding.Location.ID = _group.Key.Item1;
+                _holding.Job.ID = _group.Key.Item2;
                 _holding.Location.Synchronise(_group.FirstOrDefault()?.Location ?? new StockLocationLink());
                 _holding.Product.ID = Item.Product.ID;
                 _holding.Product.Synchronise(Item.Product);
                 _holding.Style.ID = Item.Style.ID;
                 _holding.Style.Synchronise(Item.Style);
+                _holding.Job.CopyFrom(_group.FirstOrDefault()?.Job ?? new JobLink());
                 _holding.Dimensions.CopyFrom(Item.Dimensions);
                 _holding.Location.Area.Code = description(_group.FirstOrDefault() ?? new StockMovement());
                 _holding.Units = _units;
+                
+                _holding.AverageValue = values.FirstOrDefault(x=>x.Item1 == _group.Key.Item1 && x.Item2 == _group.Key.Item2)?.Item3 ?? 0.0;
+
                 var _jri = new JobRequisitionItem()
                 {
                     ID = _group.FirstOrDefault()?.JobRequisitionItem.ID ?? Guid.Empty
@@ -219,12 +224,13 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
     
     private void LoadAllocations()
     {
-        var movements = Client.Query(
-            new Filter<StockMovement>(x=>x.Product.ID).IsEqualTo(Item.Product.ID)
+        MultiQuery query = new MultiQuery();
+        
+        query.Add(new Filter<StockMovement>(x=>x.Product.ID).IsEqualTo(Item.Product.ID)
                 .And(x=>x.Style.ID).IsEqualTo(Item.Style.ID)
                 .And(x=>x.Dimensions).DimensionEquals(Item.Dimensions)
                 .And(
-                    new Filter<StockMovement>(x => x.JobRequisitionItem.ID).IsEqualTo(Item.SourceJRI.ID)
+                    new Filter<StockMovement>(x => x.JobRequisitionItem.ID).IsEqualTo(Item.JobRequisitionItem.ID)
                         .Or(new Filter<StockMovement>(x => x.Job.ID).IsEqualTo(Item.RequisitionLink.JobLink.ID)
                                 .And(x => x.JobRequisitionItem.ID).IsEqualTo(Guid.Empty))
                         .Or(new Filter<StockMovement>(x => x.Job.ID).IsEqualTo(Guid.Empty)
@@ -241,15 +247,29 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
                 .Add(x=>x.JobRequisitionItem.Requisition.Number)
                 .Add(x=>x.JobRequisitionItem.Requisition.Description)
                 .Add(x => x.Units)
-        ).Rows.Select(x=>x.ToObject<StockMovement>()).ToArray();
+        );
+        
+        query.Add(new Filter<StockHolding>(x=>x.Product.ID).IsEqualTo(Item.Product.ID)
+                .And(x=>x.Style.ID).IsEqualTo(Item.Style.ID)
+                .And(x=>x.Dimensions).DimensionEquals(Item.Dimensions),
+            Columns.None<StockHolding>()
+                .Add(x => x.Location.ID)
+                .Add(x => x.Job.ID)
+                .Add(x => x.AverageValue)
+        );
+        
+        query.Query();
+        var values = query.Get<StockHolding>().ToTuples<StockHolding,Guid,Guid,double>(x=>x.Location.ID, x=>x.Job.ID, x=>x.AverageValue).ToArray();
+        var movements = query.Get<StockMovement>().ToArray<StockMovement>();
         
         List<StockSelectionItem> items = new();
         
-        var allocations = movements.Where(x => x.JobRequisitionItem.ID == Item.SourceJRI.ID)
-            .GroupBy(x => x.Location.ID);
+        var allocations = movements.Where(x => x.JobRequisitionItem.ID == Item.JobRequisitionItem.ID)
+            .GroupBy(x => new Tuple<Guid,Guid>(x.Location.ID,x.Job.ID));
         items.AddRange(
             CreateStockSelectionItems(
-                allocations, 
+                allocations,
+                values,
                 (m) => $"{m.Job.JobNumber}:{m.JobRequisitionItem.Requisition.Number} {m.JobRequisitionItem.Requisition.Description}"
             )
         );
@@ -258,19 +278,21 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
         var reserves = movements.Where(x =>
                 x.JobRequisitionItem.ID != Guid.Empty && x.Job.ID == Item.RequisitionLink.JobLink.ID &&
                 x.JobRequisitionItem.ID == Guid.Empty)
-            .GroupBy(x => x.Location.ID);
+            .GroupBy(x => new Tuple<Guid,Guid>(x.Location.ID, x.Job.ID));
         items.AddRange(
             CreateStockSelectionItems(
                 reserves, 
+                values,
                 (m) => $"{m.Job.JobNumber} (Unallocated Stock)"
             )
         );
         
         var freeitems = movements.Where(x => x.Job.ID == Guid.Empty && x.JobRequisitionItem.ID == Guid.Empty)
-            .GroupBy(x => x.Location.ID);
+            .GroupBy(x => new Tuple<Guid,Guid>(x.Location.ID,x.Job.ID));
         items.AddRange(
             CreateStockSelectionItems(
-                freeitems, 
+                freeitems,
+                values,
                 (m) => $"General Stock"
             )
         );
@@ -331,15 +353,15 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
             var newItem = newItems.Count == 0 ? Item : CopyRequisitionItem();
             newItem.Location.CopyFrom(item.Holding.Location);
             newItem.Cost = item.Holding.AverageValue;
-            newItem.JobRequisitionItem.CopyFrom(item.JRI);
+            newItem.SourceJRI.CopyFrom(item.JRI);
             newItem.JobLink.CopyFrom(item.Holding.Job);
             
             // Automagically attach to Requisition if it seems appropriate
             // ie selected from a JRI allocation, and current source jri is blank
-            if (newItem.SourceJRI.ID == Guid.Empty
+            if (newItem.JobRequisitionItem.ID == Guid.Empty
                 && newItem.RequisitionLink.JobLink.ID == item.Holding.Job.ID
                 && item.JRI.ID != Guid.Empty)
-                newItem.SourceJRI.ID = item.JRI.ID;
+                newItem.JobRequisitionItem.ID = item.JRI.ID;
 
             newItem.Quantity = item.Issued;
             newItem.ActualQuantity = item.Issued;
@@ -353,7 +375,7 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
         {
             var newItem = CopyRequisitionItem();
             newItem.Location.CopyFrom(new StockLocationLink());
-            newItem.JobRequisitionItem.CopyFrom(new JobRequisitionItemLink());
+            newItem.SourceJRI.CopyFrom(new JobRequisitionItemLink());
             newItem.JobLink.CopyFrom(new JobLink());
             newItem.Quantity = remainder;
             newItem.Done = false;
@@ -473,7 +495,7 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
                 newItem.Description = Item.Description;
                 newItem.Image.CopyFrom(Item.Image);
                 newItem.RequisitionLink.ID = Item.RequisitionLink.ID;
-                newItem.JobRequisitionItem.ID = item.ID;
+                newItem.JobRequisitionItem.CopyFrom(Item.JobRequisitionItem);
                 newItem.Product.CopyFrom(Item.Product);
                 newItem.Style.CopyFrom(Item.Style);
                 newItem.Location.CopyFrom(Item.Location);
@@ -481,10 +503,19 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
                 newItem.JobLink.CopyFrom(Item.JobLink);
                 newItem.EditType = RequisitionItemEditType.Normal;
             }
-            newItem.JobRequisitionItem.ID = item.ID;
+            
+            // Automagically attach to Requisition if it seems appropriate
+            // ie selected from a JRI allocation, and current source jri is blank
+            if (newItem.JobRequisitionItem.ID == Guid.Empty
+                && newItem.RequisitionLink.JobLink.ID == StockHolding.Job.ID
+                && item.ID != Guid.Empty)
+                newItem.JobRequisitionItem.ID = item.ID;
+            
+            newItem.SourceJRI.ID = item.ID;
             newItem.Quantity = item.Taken;
             newItem.ActualQuantity = item.Taken;
             newItem.Cost = StockHolding.AverageValue;
+            newItem.Done = true;
             remainder -= item.Taken;
 
             newItems.Add(newItem);
@@ -497,8 +528,8 @@ public partial class RequisitionItemEditor : INotifyPropertyChanged
             newItem.Description = Item.Description;
             newItem.Image.CopyFrom(Item.Image);
             newItem.RequisitionLink.ID = Item.RequisitionLink.ID;
-
-            newItem.JobRequisitionItem.ID = Guid.Empty;
+            newItem.JobRequisitionItem.CopyFrom(Item.JobRequisitionItem);
+            newItem.SourceJRI.ID = Guid.Empty;
             newItem.Product.CopyFrom(Item.Product);
             newItem.Style.CopyFrom(Item.Style);
             newItem.Dimensions.CopyFrom(Item.Dimensions, true);

+ 8 - 3
prs.desktop/Panels/Requisitions/RequisitionItemGrid.cs

@@ -98,9 +98,14 @@ public class RequisitionItemGrid : DynamicDataGrid<RequisitionItem>
             return false;
 
         var item = LoadItem(row);
-        item.Done = !item.Done;
-        item.Location.CopyFrom(new StockLocationLink());
-        item.JobRequisitionItem.CopyFrom(new JobRequisitionItemLink());
+        if (item.Done)
+        {
+            item.Done = false;
+            item.Location.CopyFrom(new StockLocationLink());
+            item.JobLink.CopyFrom(new JobLink());
+            item.SourceJRI.CopyFrom(new JobRequisitionItemLink());
+            item.ActualQuantity = 0.0;
+        }
         SaveItem(item);
         return true;
     }

+ 3 - 2
prs.desktop/Panels/Requisitions/RequisitionPanel.xaml.cs

@@ -508,8 +508,9 @@ public partial class RequisitionPanel : UserControl, IPanel<Requisition>
         if (_requisition.StockUpdated.IsEmpty())
         {
             var emptyrows = Items.Data.Rows.Where(r =>
-                !Entity.IsEntityLinkValid<RequisitionItem, StockLocationLink>(x => x.Location, r) &&
-                r.Get<RequisitionItem, bool>(c => c.Product.NonStock).Equals(false));
+                !r.Get<RequisitionItem,double>(x=>x.ActualQuantity).IsEffectivelyEqual(0.0)
+                && !Entity.IsEntityLinkValid<RequisitionItem, StockLocationLink>(x => x.Location, r) 
+                && r.Get<RequisitionItem, bool>(c => c.Product.NonStock).Equals(false));
             if (emptyrows.Any())
             {
                 MessageWindow.ShowMessage(

+ 1 - 1
prs.desktop/Panels/Reservation Management/JobRequisitionItemSelectionGrid.cs

@@ -86,7 +86,7 @@ public class JobRequisitionItemSelectionItem : BaseObject
 
     public bool CanPlus => Editable && Issued < MaxValue;
 
-    public JobRequisitionItem JRI { get; set; }
+    public JobRequisitionItem? JRI { get; set; }
 }
 
 public abstract class JobRequisitionItemSelectionGrid<T> : DynamicItemsListGrid<T>, INotifyPropertyChanged

+ 4 - 4
prs.desktop/Panels/Reservation Management/StockSelectionPage.xaml.cs

@@ -20,17 +20,17 @@ namespace PRSDesktop;
 
 public class StockSelectionItem : JobRequisitionItemSelectionItem
 {
-    public string Area => Holding.Location.Area.Code;
+    public string Area => Holding?.Location?.Area?.Code ?? "";
 
     public string Requisition => JRI is null
         ? "Unrequisitioned Items"
         : $"{JRI.Job.JobNumber}: #{JRI.Requisition.Number} ({JRI.Requisition.Description})";
 
-    public string Location => Holding.Location.Code;
+    public string Location => Holding?.Location?.Code ?? "";
 
-    public string Style => Holding.Style.Code;
+    public string Style => Holding?.Style?.Code ?? "";
 
-    public StockHolding Holding { get; set; }
+    public StockHolding? Holding { get; set; }
 }
 
 public class StockSelectionGrid : JobRequisitionItemSelectionGrid<StockSelectionItem>

+ 4 - 3
prs.stores/RequisitionStore.cs

@@ -45,7 +45,7 @@ namespace Comal.Stores
         private bool LoadRequisitionItems(Requisition entity, ref IList<RequisitionItem> requisitionitems)
         {
             requisitionitems ??= Provider.Query(
-                    new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID),
+                    new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID).And(x=>x.ActualQuantity).IsNotEqualTo(0.0),
                     Columns.None<RequisitionItem>().Add(x => x.ID)
                         .Add(x => x.Description)
                         .Add(x => x.Quantity)
@@ -279,7 +279,8 @@ namespace Comal.Stores
             batch.Employee.ID = entity.Employee.ID;
             batch.Requisition.ID = entity.ID;
             FindSubStore<StockMovementBatch>().Save(batch, "");
-
+            
+            var timestamp = entity.Filled;
             var updates = new List<StockMovement>();
             foreach (var item in items)
             {
@@ -302,7 +303,7 @@ namespace Comal.Stores
                 }
 
                 var qty = item.ActualQuantity;
-                var timestamp = entity.Filled;
+                
                 var txnid = Guid.NewGuid();
                 if (holdingQty.IsEffectivelyLessThan(qty))
                 {