Kaynağa Gözat

Simplied aggregates and fixed usages of POIA

Kenric Nugteren 10 ay önce
ebeveyn
işleme
c8337ba0d6

+ 13 - 30
prs.classes/Entities/Job/Materials/JobMaterials.cs

@@ -79,23 +79,6 @@ namespace Comal.Classes
                 { StockMovement => StockMovement.Style.ID, JobMaterial => JobMaterial.Style.ID },
             }.AddRange(Dimensions.GetLinks<StockMovement, JobMaterial>(x => x.Dimensions, x => x.Dimensions));
     }
-
-    public class JobMaterialOnOrderAggregate : CoreAggregate<JobMaterial, PurchaseOrderItemAllocation, double>
-    {
-        public override Expression<Func<PurchaseOrderItemAllocation, double>> Aggregate => x => x.Quantity;
-
-        public override AggregateCalculation Calculation => AggregateCalculation.Sum;
-
-        public override Dictionary<Expression<Func<PurchaseOrderItemAllocation, object?>>, Expression<Func<JobMaterial, object?>>> Links =>
-            new Dictionary<Expression<Func<PurchaseOrderItemAllocation, object?>>, Expression<Func<JobMaterial, object?>>>()
-            {
-                { allocation => allocation.Job.ID, material => material.Job.ID },
-                { allocation => allocation.Item.Product.ID, material => material.Product.ID },
-                { allocation => allocation.Item.Style.ID, material => material.Style.ID },
-            }.AddRange(Dimensions.GetLinks<PurchaseOrderItemAllocation, JobMaterial>(x => x.Item.Dimensions, x => x.Dimensions));
-
-        public override Filter<PurchaseOrderItemAllocation> Filter => new Filter<PurchaseOrderItemAllocation>(x => x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue);
-    }
     
     public class JobMaterialUnionGenerator : AutoEntityUnionGenerator<IJobMaterial>
     {
@@ -104,18 +87,7 @@ namespace Comal.Classes
             AddTable<StockMovement>();
             AddTable<JobBillOfMaterialsItem>();
             AddTable<JobRequisitionItem>();
-            var poia = AddTable<PurchaseOrderItemAllocation>()
-                .AliasField(x => x.Product.ID, x => x.Item.Product.ID)
-                .AliasField(x => x.Style.ID, x => x.Item.Style.ID);
-
-            var dimColJobMaterial = new Column<IJobMaterial>(x => x.Dimensions);
-            var dimColPOIA = new Column<PurchaseOrderItemAllocation>(x => x.Item.Dimensions);
-            foreach(var column in Dimensions.GetFilterColumns())
-            {
-                poia.AliasField(
-                    CoreUtils.CreateLambdaExpression<IJobMaterial>(dimColJobMaterial + "." + column.Property),
-                    CoreUtils.CreateLambdaExpression<PurchaseOrderItemAllocation>(dimColPOIA + "." + column.Property));
-            }
+            AddTable<PurchaseOrderItem>();
         }
 
         public override bool Distinct => true;
@@ -195,9 +167,20 @@ namespace Comal.Classes
         [DoubleEditor(Editable = Editable.Hidden)]
         public double ReservedStock { get; set; }
         
+        private class OnOrderAggregate : ComplexFormulaGenerator<JobMaterial, double>
+        {
+            public override IComplexFormulaNode<JobMaterial, double> GetFormula() =>
+                Aggregate(AggregateCalculation.Sum,
+                    x => x.Property(x => x.Qty),
+                    new Filter<PurchaseOrderItem>(x => x.ReceivedDate).IsEqualTo(DateTime.MinValue))
+                .WithLink(x => x.Job.ID, x => x.Job.ID)
+                .WithLink(x => x.Product.ID, x => x.Product.ID)
+                .WithLink(x => x.Style.ID, x => x.Style.ID)
+                .WithLinks(Classes.Dimensions.GetLinks<PurchaseOrderItem, JobMaterial>(x => x.Dimensions, x => x.Dimensions));
+        }
         [EditorSequence(9)]
         [DoubleEditor]
-        [Aggregate(typeof(JobMaterialOnOrderAggregate))]
+        [ComplexFormula(typeof(OnOrderAggregate))]
         public double OnOrder { get; set; }
 
         [EditorSequence(10)]

+ 1 - 12
prs.classes/Entities/PurchaseOrder/PurchaseOrder.cs

@@ -313,18 +313,10 @@ namespace Comal.Classes
                     .Add(x => x.NettCost)
             );
             
-            query.Add(
-                new Filter<PurchaseOrderItemAllocation>(x=>x.Item.ID).InList(itemsList.ToArray(x => x.ID)),
-                Columns.None<PurchaseOrderItemAllocation>()
-                    .Add(x=>x.Job.ID)
-                    .Add(x=>x.Item.ID)
-            );
-            
             query.Query();
 
             var supplierProducts = query.Get<SupplierProduct>().ToArray<SupplierProduct>();
             var productInstances = query.Get<ProductInstance>().ToArray<ProductInstance>();
-            var allocations = query.Get<PurchaseOrderItemAllocation>().ToArray<PurchaseOrderItemAllocation>();
             
             foreach (var item in itemsList)
             {
@@ -334,10 +326,7 @@ namespace Comal.Classes
                     && x.Product.ID == item.Product.ID
                     && x.Style.ID == item.Style.ID
                     && x.Dimensions.Equals(item.Dimensions)
-                    // Not super here - this simply takes the "first" allocation, and uses that job number
-                    // we should either get smart and use the allocation that produces the lowest price
-                    // or allow the user to reorder allocations (ie make them ISequenceable
-                    && x.Job.ID == (allocations.FirstOrDefault(x=>x.Item.ID == item.ID)?.Job.ID ?? Guid.Empty));
+                    && x.Job.ID == item.Job.ID);
                 if (supplierProduct != null)
                 {
                     UpdateValue<string>(item, x => x.SupplierCode, supplierProduct.SupplierCode);

+ 1 - 1
prs.classes/Entities/PurchaseOrder/PurchaseOrderItem.cs

@@ -11,7 +11,7 @@ namespace Comal.Classes
     [UserTracking(typeof(Bill))]
     [Caption("Purchase Order Items")]
     public class PurchaseOrderItem : StockEntity, IRemotable, IPersistent, IOneToMany<PurchaseOrder>, ITaxable, IOneToMany<Consignment>, IOneToMany<Job>,
-        ILicense<AccountsPayableLicense>, IPostableFragment<PurchaseOrder>
+        ILicense<AccountsPayableLicense>, IPostableFragment<PurchaseOrder>, IJobMaterial
     {
         
         [RequiredColumn]

+ 2 - 15
prs.desktop/Panels/Factory/FactoryPanel.xaml.cs

@@ -732,7 +732,8 @@ namespace PRSDesktop
 
                 var item = new PurchaseOrderItem();
                 item.PurchaseOrderLink.ID = order.ID;
-                jobmappings[item] = treatment.Packet.SetoutLink.JobLink.ID;
+                item.Job.ID = treatment.Packet.SetoutLink.JobLink.ID;
+                jobmappings[item] = item.Job.ID;
                 item.Packet.ID = packet.ID;
                 item.Product.ID = window.ProductID;
                 if(product is not null)
@@ -767,21 +768,7 @@ namespace PRSDesktop
 
             new Client<PurchaseOrderItem>().Save(orderitems, "Created by Factory Floor Purchase");
 
-            var poias = new List<PurchaseOrderItemAllocation>();
             Progress.SetMessage("Updating Packets");
-            foreach (var orderitem in orderitems)
-            {
-                var poia = new PurchaseOrderItemAllocation();
-                poia.Item.ID = orderitem.ID;
-                poia.Job.ID = jobmappings[orderitem];
-                poia.Quantity = orderitem.Qty;
-                poias.Add(poia);
-                var packet = packetupdates.FirstOrDefault(x => x.ID.Equals(orderitem.Packet.ID));
-                if (packet != null)
-                    packet.OrderItem.ID = orderitem.ID;
-            }
-
-            new Client<PurchaseOrderItemAllocation>().Save(poias, "");
             new Client<ManufacturingPacket>().Save(packetupdates.Where(x => x.IsChanged()), "");
 
 

+ 5 - 15
prs.desktop/Panels/Jobs/BillOfMaterials/JobBillOfMaterialsItemsGrid.cs

@@ -236,24 +236,12 @@ public class JobBillOfMaterialsItemGrid : DynamicDataGrid<JobBillOfMaterialsItem
                 .Add(x => x.Dimensions.UnitSize)
                 .Add(x => x.Dimensions.Value)
                 .Add(x => x.Style.ID)
-                .Add(x => x.DueDate)
-        );
+                .Add(x => x.Job.ID)
+                .Add(x => x.DueDate));
 
         if (table.Rows.Any())
         {
             var poItems = AddPOItems(table, new List<PurchaseOrderItem>());
-            List<PurchaseOrderItemAllocation> poias = new();
-            foreach (var poItem in poItems)
-            {
-                var poia = new PurchaseOrderItemAllocation();
-                poia.Item.ID = poItem.ID;
-                poia.Job.ID = Job.ID;
-                poia.Quantity = poItem.Qty;
-                poias.Add(poia);
-            }
-            if (poias.Any())
-                Client.Save(poias, "Updated on Create Purchase Order from BOM Dashboard");
-
 
             var BOMItems = MatchBOMItems(poItems, new List<JobBillOfMaterialsItem>());
 
@@ -292,7 +280,8 @@ public class JobBillOfMaterialsItemGrid : DynamicDataGrid<JobBillOfMaterialsItem
                 if (bomItem.Product.ID == item.Product.ID
                     && bomItem.Dimensions.Equals(item.Dimensions)
                     && bomItem.Style.ID == item.Style.ID
-                    && bomItem.Quantity.IsEffectivelyEqual(item.Qty))
+                    && bomItem.Quantity.IsEffectivelyEqual(item.Qty)
+                    && bomItem.Job.ID == item.Job.ID)
                 {
                     bomItem.PurchaseOrderItem.ID = item.ID;
                     bomItem.PurchaseOrderItem.DueDate = item.DueDate;
@@ -326,6 +315,7 @@ public class JobBillOfMaterialsItemGrid : DynamicDataGrid<JobBillOfMaterialsItem
             POItem.Dimensions.UnitSize = BOMItem.Dimensions.UnitSize;
             POItem.Description = BOMItem.Product.Name + " (" + BOMItem.Dimensions.ToString() + ")";
             POItem.Cost = BOMItem.UnitCost;
+            POItem.Job.ID = BOMItem.Job.ID;
             items.Add(POItem);
         }
         result.LoadRows(items);

+ 27 - 27
prs.desktop/Panels/Jobs/Orders/JobOrderGrid.cs

@@ -8,39 +8,39 @@ using InABox.Wpf;
 
 namespace PRSDesktop
 {
-    public class JobOrderGrid : DynamicDataGrid<PurchaseOrderItemAllocation>, IMasterDetailControl<Job,PurchaseOrderItemAllocation>, IDataModelSource
+    public class JobOrderGrid : DynamicDataGrid<PurchaseOrderItem>, IMasterDetailControl<Job,PurchaseOrderItem>, IDataModelSource
     {
         
         public Job? Master { get; set; }
 
-        public Filter<PurchaseOrderItemAllocation> MasterDetailFilter => (Master?.ID ?? Guid.Empty) != Guid.Empty
-            ? new Filter<PurchaseOrderItemAllocation>(x => x.Job.ID).IsEqualTo(Master.ID)
-            : new Filter<PurchaseOrderItemAllocation>().None();
+        public Filter<PurchaseOrderItem> MasterDetailFilter => (Master?.ID ?? Guid.Empty) != Guid.Empty
+            ? new Filter<PurchaseOrderItem>(x => x.Job.ID).IsEqualTo(Master.ID)
+            : new Filter<PurchaseOrderItem>().None();
         
         public JobOrderGrid()
         {
             ColumnsTag = "JobOrders";
-            HiddenColumns.Add(x => x.Item.PurchaseOrderLink.SupplierLink.ID);
-            HiddenColumns.Add(x => x.Item.PurchaseOrderLink.Category.ID);
-            HiddenColumns.Add(x => x.Item.ID);
-            HiddenColumns.Add(x => x.Item.Product.ID);
-            HiddenColumns.Add(x => x.Item.Product.Code);
-            HiddenColumns.Add(x => x.Item.Product.Name);
-            HiddenColumns.Add(x => x.Item.Description);
-            HiddenColumns.Add(x => x.Item.TaxCode.ID);
-            HiddenColumns.Add(x => x.Item.TaxCode.Code);
-            HiddenColumns.Add(x => x.Item.TaxCode.Description);
-            HiddenColumns.Add(x => x.Item.TaxCode.Rate);
-            HiddenColumns.Add(x => x.Item.TaxRate);
-            HiddenColumns.Add(x => x.Item.ExTax);
-            HiddenColumns.Add(x => x.Item.Tax);
-            HiddenColumns.Add(x => x.Item.IncTax);
-            HiddenColumns.Add(x => x.Item.BillLine.ID);
-            HiddenColumns.Add(x => x.Item.Consignment.ID);
-            HiddenColumns.Add(x => x.Item.Product.DigitalForm.ID);
-            HiddenColumns.Add(x => x.Item.Product.DigitalForm.Description);
-            HiddenColumns.Add(x => x.Item.PurchaseOrderLink.SupplierLink.Code);
-            HiddenColumns.Add(x => x.Item.PurchaseOrderLink.SupplierLink.Name);
+            HiddenColumns.Add(x => x.PurchaseOrderLink.SupplierLink.ID);
+            HiddenColumns.Add(x => x.PurchaseOrderLink.Category.ID);
+            HiddenColumns.Add(x => x.ID);
+            HiddenColumns.Add(x => x.Product.ID);
+            HiddenColumns.Add(x => x.Product.Code);
+            HiddenColumns.Add(x => x.Product.Name);
+            HiddenColumns.Add(x => x.Description);
+            HiddenColumns.Add(x => x.TaxCode.ID);
+            HiddenColumns.Add(x => x.TaxCode.Code);
+            HiddenColumns.Add(x => x.TaxCode.Description);
+            HiddenColumns.Add(x => x.TaxCode.Rate);
+            HiddenColumns.Add(x => x.TaxRate);
+            HiddenColumns.Add(x => x.ExTax);
+            HiddenColumns.Add(x => x.Tax);
+            HiddenColumns.Add(x => x.IncTax);
+            HiddenColumns.Add(x => x.BillLine.ID);
+            HiddenColumns.Add(x => x.Consignment.ID);
+            HiddenColumns.Add(x => x.Product.DigitalForm.ID);
+            HiddenColumns.Add(x => x.Product.DigitalForm.Description);
+            HiddenColumns.Add(x => x.PurchaseOrderLink.SupplierLink.Code);
+            HiddenColumns.Add(x => x.PurchaseOrderLink.SupplierLink.Name);
         }
         protected override void DoReconfigure(DynamicGridOptions options)
         {
@@ -59,11 +59,11 @@ namespace PRSDesktop
         public DataModel DataModel(Selection selection)
         {
             var ids = ExtractValues(x => x.ID, selection).ToArray();
-            return new BaseDataModel<PurchaseOrderItemAllocation>(new Filter<PurchaseOrderItemAllocation>(x => x.ID).InList(ids));
+            return new BaseDataModel<PurchaseOrderItem>(new Filter<PurchaseOrderItem>(x => x.ID).InList(ids));
         }
         
         protected override void Reload(
-        	Filters<PurchaseOrderItemAllocation> criteria, Columns<PurchaseOrderItemAllocation> columns, ref SortOrder<PurchaseOrderItemAllocation>? sort,
+        	Filters<PurchaseOrderItem> criteria, Columns<PurchaseOrderItem> columns, ref SortOrder<PurchaseOrderItem>? sort,
         	CancellationToken token, Action<CoreTable?, Exception?> action)
         {
             criteria.Add(MasterDetailFilter);

+ 1 - 1
prs.desktop/Panels/Jobs/ProjectsPanel.cs

@@ -156,7 +156,7 @@ public class ProjectsPanel : MasterDetailPanel<Job,ProjectsGrid,ProjectsPanelSet
         DoCreatePanel<JobRequisitionPanel>(Security.CanView<JobRequisition>, "Requisitions");
         DoCreatePanel<JobStockGrid>(Security.CanView<StockHolding>, "Stock Holdings");
         DoCreatePanel<JobPickingListPanel>(Security.CanView<Requisition>, "Picking Lists");
-        DoCreateGrid<JobOrderGrid, PurchaseOrderItemAllocation>(Security.CanView<PurchaseOrderItem>, "Orders");
+        DoCreateGrid<JobOrderGrid, PurchaseOrderItem>(Security.CanView<PurchaseOrderItem>, "Orders");
         DoCreatePanel<JobDesignPanel>(Security.CanView<Setout>, "Designs");
         DoCreateGrid<ManufacturingGrid, ManufacturingPacket>(Security.CanView<ManufacturingPacket>, "Manufacturing");
         DoCreateGrid<ReadyToGoGrid, DeliveryItem>(Security.CanView<DeliveryItem>, "Dispatch");

+ 1 - 0
prs.desktop/Panels/Jobs/Requisitions/JobRequisitionItemGrid.cs

@@ -121,6 +121,7 @@ internal class JobRequisitionItemGrid : DynamicDataGrid<JobRequisitionItem>, IMa
                     _poi.Dimensions.UnitSize = _jri.Dimensions.UnitSize;
                     _poi.Description = _jri.Product.Name + " (" + _jri.Dimensions.ToString() + ")";
                     _poi.Cost = _jri.UnitCost;
+                    _poi.Job.ID = _jri.Job.ID;
                     _pois[_jri] = _poi;
                 }
                 Client.Save(_pois.Values, "Created From Requisition Screen");

+ 1 - 1
prs.desktop/Panels/Jobs/ServicePanel.cs

@@ -30,7 +30,7 @@ public class ServicePanel : MasterDetailPanel<Job,ServiceGrid,ServicePanelSettin
     protected override void CreatePages()
     {
         CreatePage<JobDetailPanel<JobDetails>>("Details");
-        CreatePage<JobDetailGrid<JobOrderGrid, PurchaseOrderItemAllocation>>(Security.CanView<PurchaseOrderItem>, "Orders");
+        CreatePage<JobDetailGrid<JobOrderGrid, PurchaseOrderItem>>(Security.CanView<PurchaseOrderItem>, "Orders");
         CreatePage<JobDetailPanel<JobPickingListPanel>>(Security.CanView<Requisition>, "Picking Lists");
         CreatePage<JobDetailGrid<JobAssignmentGrid, Assignment>>(Security.CanView<Assignment>, "Assignments");
         CreatePage<JobDetailGrid<JobFormGrid, JobForm>>(Security.CanView<JobForm>, "Forms");

+ 1 - 1
prs.desktop/Panels/Jobs/ServicePanel_Old.xaml.cs

@@ -48,7 +48,7 @@ public partial class ServicePanel_Old : UserControl, IPanel<Job>
             new JobDetailPanel<JobPickingListPanel>(Requisitions),
             new JobDetailPanel<InvoicePanel>(Invoices),
             new JobDetailGrid<JobFormGrid, JobForm>(Forms),
-            new JobDetailGrid<JobOrderGrid, PurchaseOrderItemAllocation>(Orders),
+            new JobDetailGrid<JobOrderGrid, PurchaseOrderItem>(Orders),
             new JobDetailGrid<JobAssignmentGrid, Assignment>(Assignments),
         };
     }

+ 22 - 83
prs.desktop/Panels/Jobs/Summary/JobSummaryGrid.cs

@@ -528,13 +528,13 @@ internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailContr
     private void ViewOnOrder(CoreRow row)
     {
         var item = row.ToObject<JobMaterial>();
-        ShowDetailGrid<PurchaseOrderItemAllocation>(
+        ShowDetailGrid<PurchaseOrderItem>(
             OnOrderColumn.Property,
-            x => x.Item.Product.ID,
+            x => x.Product.ID,
             item.Product.ID,
-            x => x.Item.Style.ID,
+            x => x.Style.ID,
             StyleColumnVisible() ? item.Style.ID : null,
-            x => x.Item.Dimensions,
+            x => x.Dimensions,
             DimensionsColumnVisible() ? item.Dimensions : null,
             x => x.Job.ID,
             null,
@@ -565,19 +565,19 @@ internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailContr
     private void ViewFreeOnOrder(CoreRow row)
     {
         var item = row.ToObject<JobMaterial>();
-        ShowDetailGrid<PurchaseOrderItemAllocation>(
+        ShowDetailGrid<PurchaseOrderItem>(
             FreeOnOrderColumn.Property,
-            x => x.Item.Product.ID,
+            x => x.Product.ID,
             item.Product.ID,
-            x => x.Item.Style.ID,
+            x => x.Style.ID,
             StyleColumnVisible() ? item.Style.ID : null,
-            x => x.Item.Dimensions,
+            x => x.Dimensions,
             DimensionsColumnVisible() ? item.Dimensions : null,
             null,
 
             IncludeReserves
-                ? new Filter<PurchaseOrderItemAllocation>(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)
-                : new Filter<PurchaseOrderItemAllocation>(x => x.Job.JobStatus.Active).IsEqualTo(false),
+                ? new Filter<PurchaseOrderItem>(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)
+                : new Filter<PurchaseOrderItem>(x => x.Job.JobStatus.Active).IsEqualTo(false),
             null
         );
     }
@@ -691,27 +691,6 @@ internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailContr
 
         return result;
     }
-    
-    private CoreRow[] GetAllocationRows(IEnumerable<CoreRow> rows, Columns<PurchaseOrderItemAllocation> columns, Guid? jobID, Key key, Func<CoreRow, bool>? extrafilter = null)
-    {
-        int jobcol = columns.IndexOf(x => x.Job.ID);
-        int productcol = columns.IndexOf(x => x.Item.Product.ID);
-        int stylecol = key.StyleID.HasValue ? columns.IndexOf(x => x.Item.Style.ID) : -1;
-        int unitcol = columns.IndexOf(x => x.Item.Dimensions.UnitSize);
-
-        var dimCols = Dimensions.GetFilterColumnIndices<PurchaseOrderItemAllocation>(columns, x => x.Item.Dimensions);
-
-        var subset = rows
-            .Where(r =>
-                (!jobID.HasValue || Guid.Equals(jobID, r.Values[jobcol]))
-                && Guid.Equals(key.ProductID, r.Values[productcol])
-                && (!key.StyleID.HasValue || Guid.Equals(key.StyleID, r.Values[stylecol]))
-                && (key.Dimensions is null || key.Dimensions.Equals(r.ToDimensions<StockDimensions>(dimCols)))
-                && ((extrafilter == null) || extrafilter(r))
-            );
-
-        return subset.ToArray();
-    }
 
     private CoreRow[] GetRows<TSource>(IEnumerable<CoreRow> rows, Columns<TSource> columns, Guid? jobID, Key key, Func<CoreRow, bool>? extrafilter = null) where TSource : IJobMaterial
     {
@@ -779,22 +758,22 @@ internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailContr
                                 .Add(x => x.Units)
                                 .Add(x => x.Job.ID)
                                 .Add(x => x.Job.JobStatus.Active)),
-                        new KeyedQueryDef<PurchaseOrderItemAllocation>(
-                            new Filter<PurchaseOrderItemAllocation>(x => x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue)
-                                .And(x => x.Item.Product.ID).InList(pids)
-                                .And(new Filter<PurchaseOrderItemAllocation>(x => x.Job.ID).IsEqualTo(Guid.Empty).Or(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)),
-                            Columns.None<PurchaseOrderItemAllocation>().Add(x => x.Item.Product.ID)
-                                .Add(x => x.Item.Style.ID)
-                                .AddDimensionsColumns(x => x.Item.Dimensions, Dimensions.ColumnsType.Local)
-                                .Add(x => x.Quantity)
+                        new KeyedQueryDef<PurchaseOrderItem>(
+                            new Filter<PurchaseOrderItem>(x => x.ReceivedDate).IsEqualTo(DateTime.MinValue)
+                                .And(x => x.Product.ID).InList(pids)
+                                .And(new Filter<PurchaseOrderItem>(x => x.Job.ID).IsEqualTo(Guid.Empty).Or(x => x.Job.ID).IsNotEqualTo(Master?.ID ?? Guid.Empty)),
+                            Columns.None<PurchaseOrderItem>().Add(x => x.Product.ID)
+                                .Add(x => x.Style.ID)
+                                .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
+                                .Add(x => x.Qty)
                                 .Add(x => x.Job.ID)
                                 .Add(x => x.Job.JobStatus.Active)));
 
                     var freestock = results.Get<StockHolding>();
                     var freestockcolumns = Columns.None<StockHolding>().Add(freestock.Columns.Select(x => x.ColumnName));
 
-                    var freeorders = results.Get<PurchaseOrderItemAllocation>();
-                    var freeordercolumns = Columns.None<PurchaseOrderItemAllocation>().Add(freeorders.Columns.Select(x => x.ColumnName));
+                    var freeorders = results.Get<PurchaseOrderItem>();
+                    var freeordercolumns = Columns.None<PurchaseOrderItem>().Add(freeorders.Columns.Select(x => x.ColumnName));
 
                     var hasStyle = StyleColumnVisible();
                     var hasDimensions = DimensionsColumnVisible();
@@ -849,8 +828,8 @@ internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailContr
                                 x => x.FreeOnHand);
                             newrow.Set<JobMaterial, double>(x => x.FreeOnHand, freeonhand);
 
-                            var freeorderrows = GetAllocationRows(freeorders.Rows, freeordercolumns, null, key,
-                                IncludeReserves ? null : (r) => !r.Get<PurchaseOrderItemAllocation, bool>(x => x.Job.JobStatus.Active));
+                            var freeorderrows = GetRows(freeorders.Rows, freeordercolumns, null, key,
+                                IncludeReserves ? null : (r) => !r.Get<PurchaseOrderItem, bool>(x => x.Job.JobStatus.Active));
                             var freeonorder = Aggregate(freeorderrows, freeordercolumns, hasStyle, false, x => x.Quantity, newrow,
                                 x => x.FreeOnOrder);
                             newrow.Set<JobMaterial, double>(x => x.FreeOnOrder, freeonorder);
@@ -938,46 +917,6 @@ internal class JobSummaryGrid : DynamicDataGrid<JobMaterial>, IMasterDetailContr
         Progress.Close();
         return result;
     }
-    
-    private void PurchaseOrderOnSave(IDynamicEditorForm form, PurchaseOrder[] items)
-    {
-        Progress.ShowModal("Working", progress =>
-        {
-            
-            var poItems = new Client<PurchaseOrderItem>().Query(
-                new Filter<PurchaseOrderItem>(x => x.PurchaseOrderLink.ID).InList(items.Select(x=>x.ID).ToArray()),
-                Columns.None<PurchaseOrderItem>()
-                    .Add(x => x.ID)
-                    .Add(x => x.Product.ID)
-                    .Add(x => x.Qty)
-                    .Add(x => x.Dimensions.UnitSize)
-                    .Add(x => x.Dimensions.Value)
-                    .Add(x => x.Style.ID)
-                    .Add(x => x.DueDate)
-            ).Rows.ToObjects<PurchaseOrderItem>().ToArray();
-
-            if (poItems.Any())
-            {
-                List<PurchaseOrderItemAllocation> poias = new();
-                var jobID = Master?.ID ?? Guid.Empty;
-                if(jobID != Guid.Empty)
-                {
-                    foreach (var poItem in poItems)
-                    {
-                        var poia = new PurchaseOrderItemAllocation();
-                        poia.Item.ID = poItem.ID;
-                        poia.Job.ID = jobID;
-                        poia.Quantity = poItem.Qty;
-                        poias.Add(poia);
-                    }
-                }
-
-                if (poias.Any())
-                    Client.Save(poias, "Updated on Create Purchase Order from BOM Dashboard");
-
-            }
-        });
-    }
 
     #endregion
 }

+ 3 - 0
prs.desktop/Panels/Reservation Management/ReservationManagementPanel.xaml.cs

@@ -571,6 +571,9 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
                 LookupFactory.DoLookups<PurchaseOrderItem, TaxCode, TaxCodeLink>(
                     orderItems.WithIndex().Select(x => new Tuple<PurchaseOrderItem, Guid>(x.Value.Item1, perSupplier[x.Key].SupplierProduct.TaxCode.ID)),
                     x => x.TaxCode);
+                LookupFactory.DoLookups<PurchaseOrderItem, Job, JobLink>(
+                    orderItems.WithIndex().Select(x => new Tuple<PurchaseOrderItem, Guid>(x.Value.Item1, x.Value.Item2.Job.ID)),
+                    x => x.Job);
 
                 foreach (var (i, item) in perSupplier.WithIndex())
                 {

+ 31 - 31
prs.desktop/Panels/Stock Forecast/StockForecastGrid.cs

@@ -493,22 +493,22 @@ public class StockForecastGrid : DynamicItemsListGrid<StockForecastItem>, IDataM
                 );               
                 break;
             case ColumnTag.GeneralPurchaseOrders:
-                ShowDetailGrid(
-                    "Purchase Order Allocations", 
-                    () => BuildDetailGrid<PurchaseOrderItemAllocation>(
-                        ColumnTag.GeneralPurchaseOrders.ToString(), 
-                        x => x.Item.Product.ID, 
-                        item.Product.ID, 
-                        x => x.Item.Style.ID, 
-                        styleid, 
-                        x => x.Item.Dimensions,
-                        item.Dimensions,
-                        null,
-                        new Filter<PurchaseOrderItemAllocation>(x=>x.Job.ID).IsEqualTo(Guid.Empty)
-                            .And(x=>x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue),
-                        null
-                    )
-                );
+                //ShowDetailGrid(
+                //    "Purchase Order Allocations", 
+                //    () => BuildDetailGrid<PurchaseOrderItemAllocation>(
+                //        ColumnTag.GeneralPurchaseOrders.ToString(), 
+                //        x => x.Item.Product.ID, 
+                //        item.Product.ID, 
+                //        x => x.Item.Style.ID, 
+                //        styleid, 
+                //        x => x.Item.Dimensions,
+                //        item.Dimensions,
+                //        null,
+                //        new Filter<PurchaseOrderItemAllocation>(x=>x.Job.ID).IsEqualTo(Guid.Empty)
+                //            .And(x=>x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue),
+                //        null
+                //    )
+                //);
                 break;
             case ColumnTag.JobStockRequired:
                 ShowDetailGrid(
@@ -558,21 +558,21 @@ public class StockForecastGrid : DynamicItemsListGrid<StockForecastItem>, IDataM
                 );
                 break;
             case ColumnTag.JobPurchaseOrders:
-                ShowDetailGrid(
-                    "Purchase Orders", 
-                    () => BuildDetailGrid<PurchaseOrderItemAllocation>(
-                        ColumnTag.GeneralPurchaseOrders.ToString(), 
-                        x => x.Item.Product.ID, 
-                        item.Product.ID, 
-                        x => x.Item.Style.ID, 
-                        styleid, 
-                        x => x.Item.Dimensions,
-                        item.Dimensions,
-                        x => x.Job.ID,
-                        new Filter<PurchaseOrderItemAllocation>(x => x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue),
-                        null
-                    )
-                );                  
+                //ShowDetailGrid(
+                //    "Purchase Orders", 
+                //    () => BuildDetailGrid<PurchaseOrderItemAllocation>(
+                //        ColumnTag.GeneralPurchaseOrders.ToString(), 
+                //        x => x.Item.Product.ID, 
+                //        item.Product.ID, 
+                //        x => x.Item.Style.ID, 
+                //        styleid, 
+                //        x => x.Item.Dimensions,
+                //        item.Dimensions,
+                //        x => x.Job.ID,
+                //        new Filter<PurchaseOrderItemAllocation>(x => x.Item.ReceivedDate).IsEqualTo(DateTime.MinValue),
+                //        null
+                //    )
+                //);                  
                 break;
         }
     }

+ 1 - 1
prs.stores/PurchaseOrderItemStore.cs

@@ -256,7 +256,7 @@ internal class PurchaseOrderItemStore : BaseStore<PurchaseOrderItem>
         
         // If there is any left over (ie over/under-ordered), now we can create
         // a second transaction to receive the unallocated stock
-        CreateMovement(entity, locationid, movements, null, null, freeQty, poCost);
+        CreateMovement(entity, locationid, movements, entity.Job, null, freeQty, poCost);
 
         FindSubStore<StockMovementBatch>().Save(batch, "Received on PO");
         foreach(var mvt in movements)