Browse Source

Obsoleted PurchaseOrder.Status and made PurchaseOrders mergeable
Fixed JRI Calculation when Receiving Purchase Order Items
Added Indicator columns to PurchaseOrder Grid
Tightened Up "Receive Items" on PurchaseOrderItem Grid
Re-enabled Purchase Link on Purchase Order tems
Added ReceievdQty Aggregate on Purchase Order
Added Code to Employee Lookup Columns
Improved Purchase Order Editor Layout

frogsoftware 11 months ago
parent
commit
2aa5682903

+ 6 - 3
prs.classes/Entities/Employee/EmployeeLink.cs

@@ -5,14 +5,17 @@ namespace Comal.Classes
 {
 {
     public class EmployeeLink : EntityLink<Employee>, IEmployee
     public class EmployeeLink : EntityLink<Employee>, IEmployee
     {
     {
-        [LookupEditor(typeof(Employee))]
-        [RequiredColumn]
-        [LoggableProperty]
+        [EditorSequence(1)]
+        [CodePopupEditor(typeof(Employee))]
+        [RequiredColumn,LoggableProperty]
         public override Guid ID { get; set; }
         public override Guid ID { get; set; }
 
 
+        [EditorSequence(2)]
+        [RequiredColumn]
         [CodeEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         [CodeEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         public string Code { get; set; }
         public string Code { get; set; }
 
 
+        [RequiredColumn]
         [TextBoxEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
         [TextBoxEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
         public string Name { get; set; }
         public string Name { get; set; }
 
 

+ 1 - 0
prs.classes/Entities/Employee/EmployeeLookups.cs

@@ -10,6 +10,7 @@ namespace Comal.Classes
         {
         {
             return Columns.None<Employee>().Add(
             return Columns.None<Employee>().Add(
                 x => x.ID,
                 x => x.ID,
+                x => x.Code,
                 x => x.Name
                 x => x.Name
             );
             );
         }
         }

+ 81 - 79
prs.classes/Entities/PurchaseOrder/PurchaseOrder.cs

@@ -2,6 +2,8 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Linq.Expressions;
 using System.Linq.Expressions;
+using System.Runtime.InteropServices;
+using InABox.Clients;
 using InABox.Core;
 using InABox.Core;
 
 
 namespace Comal.Classes
 namespace Comal.Classes
@@ -34,7 +36,22 @@ namespace Comal.Classes
             };
             };
 
 
         public override Filter<PurchaseOrderItem>? Filter => new Filter<PurchaseOrderItem>(x => x.ReceivedDate).IsEqualTo(DateTime.MinValue);
         public override Filter<PurchaseOrderItem>? Filter => new Filter<PurchaseOrderItem>(x => x.ReceivedDate).IsEqualTo(DateTime.MinValue);
-    }    
+    }
+    
+    public class PurchaseOrderReceivedQtyAggregate : CoreAggregate<PurchaseOrder, PurchaseOrderItem, double>
+    {
+        public override Expression<Func<PurchaseOrderItem, double>> Aggregate => x => x.Qty;
+
+        public override AggregateCalculation Calculation => AggregateCalculation.Sum;
+
+        public override Dictionary<Expression<Func<PurchaseOrderItem, object?>>, Expression<Func<PurchaseOrder, object?>>> Links =>
+            new Dictionary<Expression<Func<PurchaseOrderItem, object?>>, Expression<Func<PurchaseOrder, object?>>>()
+            {
+                { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID }
+            };
+        
+        public override Filter<PurchaseOrderItem>? Filter => new Filter<PurchaseOrderItem>(x => x.ReceivedDate).IsNotEqualTo(DateTime.MinValue);
+    }  
     
     
     public class PurchaseOrderExTax : CoreAggregate<PurchaseOrder, PurchaseOrderItem, double>
     public class PurchaseOrderExTax : CoreAggregate<PurchaseOrder, PurchaseOrderItem, double>
     {
     {
@@ -90,7 +107,7 @@ namespace Comal.Classes
 
 
     [UserTracking(typeof(Bill))]
     [UserTracking(typeof(Bill))]
     public class PurchaseOrder : Entity, IRemotable, IPersistent, IStringAutoIncrement<PurchaseOrder>, IOneToMany<Supplier>,
     public class PurchaseOrder : Entity, IRemotable, IPersistent, IStringAutoIncrement<PurchaseOrder>, IOneToMany<Supplier>,
-        ILicense<AccountsPayableLicense>, IDataEntryInstance, IPostable
+        ILicense<AccountsPayableLicense>, IDataEntryInstance, IPostable, IMergeable
     {
     {
         private bool bChanging;
         private bool bChanging;
 
 
@@ -106,68 +123,83 @@ namespace Comal.Classes
         [MemoEditor]
         [MemoEditor]
         [EditorSequence(2)]
         [EditorSequence(2)]
         public string Description { get; set; }
         public string Description { get; set; }
-
-        [NotesEditor]
-        [EditorSequence("Notes",1)]
-        public string[] Notes { get; set; }
         
         
         [EditorSequence(3)]
         [EditorSequence(3)]
         public PurchaseOrderCategoryLink Category { get; set; }
         public PurchaseOrderCategoryLink Category { get; set; }
-        
-        [DateTimeEditor]
+
         [EditorSequence(4)]
         [EditorSequence(4)]
-        public DateTime IssuedDate { get; set; }
+        public EmployeeLink RaisedBy { get; set; }
 
 
         [DateEditor]
         [DateEditor]
         [EditorSequence(5)]
         [EditorSequence(5)]
         public DateTime DueDate { get; set; }
         public DateTime DueDate { get; set; }
         
         
-        [EditorSequence("Additional",1)]
-        public EmployeeLink RaisedBy { get; set; }
+        private class IssuedDateInformation : EditorInformation<PurchaseOrder>
+        {
+            public override string GetInfo(PurchaseOrder item) => item.IssuedBy.Name;
+        }
         
         
-        [EditorSequence("Additional",2)]
-        [TimestampEditor]
-        public DateTime DataEntered { get; set; }
+        [DateTimeEditor(Information = typeof(IssuedDateInformation))]
+        [RequiredColumn,LoggableProperty]
+        [EditorSequence(6)]
+        public DateTime IssuedDate { get; set; }
         
         
-        [EditorSequence("Additional",3)]
+        // This information might be printed out on the PO report, so we store this in the database
+        // Other properties uch as Closed/Cancelled/Checked etc are simply logged in the Audit Trail
+        [RequiredColumn]
+        [NullEditor]
         public EmployeeLink IssuedBy { get; set; }
         public EmployeeLink IssuedBy { get; set; }
         
         
-        [TimestampEditor]
-        [EditorSequence("Additional",4)]
-        public DateTime ClosedDate { get; set; }
-        
-        [TimestampEditor]
-        [EditorSequence("Additional",5)]
-        public DateTime CancelledDate { get; set; }
-
-        [EditorSequence(10)]
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [Aggregate(typeof(PurchaseOrderExTax))]
         [Aggregate(typeof(PurchaseOrderExTax))]
         public double ExTax { get; set; }
         public double ExTax { get; set; }
-
-        [EditorSequence(11)]
+        
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [Aggregate(typeof(PurchaseOrderTax))]
         [Aggregate(typeof(PurchaseOrderTax))]
         public double Tax { get; set; }
         public double Tax { get; set; }
-
-        [EditorSequence(12)]
+        
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [Aggregate(typeof(PurchaseOrderIncTax))]
         [Aggregate(typeof(PurchaseOrderIncTax))]
         public double IncTax { get; set; }
         public double IncTax { get; set; }
-
-        [EditorSequence(13)]
+        
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [Aggregate(typeof(PurchaseOrderBalance))]
         [Aggregate(typeof(PurchaseOrderBalance))]
         public double Balance { get; set; }
         public double Balance { get; set; }
-
-        [EditorSequence(13)]
+        
+        [EditorSequence("Additional",2)]
+        [LoggableProperty]
+        [TimestampEditor]
+        public DateTime DataEntered { get; set; }
+        
+        [EditorSequence("Additional",3)]
+        [TimestampEditor]
+        [LoggableProperty]
+        public DateTime CheckedDate { get; set; }
+        
+        [RequiredColumn, LoggableProperty]
+        [TimestampEditor]
+        [EditorSequence("Additional",4)]
+        public DateTime ClosedDate { get; set; }
+        
+        [TimestampEditor]
+        [LoggableProperty]
+        [EditorSequence("Additional",5)]
+        public DateTime CancelledDate { get; set; }
+        
+        [NotesEditor]
+        [EditorSequence("Notes",1)]
+        public string[] Notes { get; set; }
+        
+        
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
         [Aggregate(typeof(PurchaseOrderUnreceivedQtyAggregate))]
         [Aggregate(typeof(PurchaseOrderUnreceivedQtyAggregate))]
         public double Unreceived { get; set; }
         public double Unreceived { get; set; }
+        
+        [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)]
+        [Aggregate(typeof(PurchaseOrderReceivedQtyAggregate))]
+        public double Received { get; set; }
+
 
 
-        [EditorSequence(14)]
-        [EnumLookupEditor(typeof(PurchaseOrderStatus), Editable = Editable.Hidden)]
-        public PurchaseOrderStatus Status { get; set; }
         
         
         //[CodeEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         //[CodeEditor(Visible = Visible.Default, Editable = Editable.Hidden)]
         [NullEditor]
         [NullEditor]
@@ -195,7 +227,11 @@ namespace Comal.Classes
 
 
         [NullEditor]
         [NullEditor]
         public string PostedReference { get; set; }
         public string PostedReference { get; set; }
-
+        
+        [Obsolete("Replaced by multiple Datetime stamps", true)]
+        [NullEditor]
+        public PurchaseOrderStatus Status { get; set; }
+        
         public Expression<Func<PurchaseOrder, string>> AutoIncrementField() => x => x.PONumber;
         public Expression<Func<PurchaseOrder, string>> AutoIncrementField() => x => x.PONumber;
         public Filter<PurchaseOrder> AutoIncrementFilter() => null;
         public Filter<PurchaseOrder> AutoIncrementFilter() => null;
         public string AutoIncrementPrefix() => PONumberPrefix;
         public string AutoIncrementPrefix() => PONumberPrefix;
@@ -207,51 +243,17 @@ namespace Comal.Classes
             if (bChanging)
             if (bChanging)
                 return;
                 return;
             bChanging = true;
             bChanging = true;
-
-            if (name.Equals("Status"))
+            if (name.Equals(nameof(IssuedDate)) && before is DateTime _old && after is DateTime _new && _new.IsEmpty() != _old.IsEmpty())
             {
             {
-                var status = (PurchaseOrderStatus)after;
-                if (status.Equals(PurchaseOrderStatus.Closed))
-                {
-                    if (ClosedDate == DateTime.MinValue)
-                        ClosedDate = DateTime.Now;
-                    if (IssuedDate == DateTime.MinValue)
-                        IssuedDate = DateTime.Now;
-                }
-                else if (status == PurchaseOrderStatus.Issued)
-                {
-                    if (ClosedDate != DateTime.MinValue)
-                        ClosedDate = DateTime.MinValue;
-                    if (IssuedDate == DateTime.MinValue)
-                        IssuedDate = DateTime.Now;
-                }
-                else if(status == PurchaseOrderStatus.Cancelled)
-                {
-                    CancelledDate = DateTime.Now;
-                }
-                else
-                {
-                    if (ClosedDate != DateTime.MinValue)
-                        ClosedDate = DateTime.MinValue;
-                    if (IssuedDate != DateTime.MinValue)
-                        IssuedDate = DateTime.MinValue;
-                }
+                Employee? _emp = _new.IsEmpty()
+                    ? new Employee()
+                    : Client.Query<Employee>(
+                        new Filter<Employee>(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid),
+                        Columns.None<Employee>().Add(x => x.ID).Add(x => x.Name)
+                    ).Rows.FirstOrDefault()?.ToObject<Employee>();
+                IssuedBy.ID = _emp.ID;
+                IssuedBy.Synchronise(_emp);
             }
             }
-            else
-            {
-                var status = PurchaseOrderStatus.Closed;
-                if (CancelledDate != DateTime.MinValue)
-                    status = PurchaseOrderStatus.Cancelled;
-                else if (ClosedDate != DateTime.MinValue)
-                    status = PurchaseOrderStatus.Closed;
-                else if (IssuedDate != DateTime.MinValue)
-                    status = PurchaseOrderStatus.Issued;
-                else
-                    status = PurchaseOrderStatus.Draft;
-                if (Status != status)
-                    Status = status;
-            }
-
             bChanging = false;
             bChanging = false;
         }
         }
 
 

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

@@ -44,7 +44,6 @@ namespace Comal.Classes
         
         
         [RequiredColumn]
         [RequiredColumn]
         [EntityRelationship(DeleteAction.Cascade)]
         [EntityRelationship(DeleteAction.Cascade)]
-        [NullEditor]
         public PurchaseOrderLink PurchaseOrderLink { get; set; }
         public PurchaseOrderLink PurchaseOrderLink { get; set; }
         
         
         [EntityRelationship(DeleteAction.SetNull)]
         [EntityRelationship(DeleteAction.SetNull)]

+ 1 - 1
prs.desktop/Dashboards/Accounts/OpenPurchaseOrdersDashboard.cs

@@ -59,7 +59,7 @@ namespace PRSDesktop.Dashboards
 
 
         protected override void Reload(Filters<PurchaseOrder> criteria, Columns<PurchaseOrder> columns, ref SortOrder<PurchaseOrder>? sort, Action<CoreTable?, Exception?> action)
         protected override void Reload(Filters<PurchaseOrder> criteria, Columns<PurchaseOrder> columns, ref SortOrder<PurchaseOrder>? sort, Action<CoreTable?, Exception?> action)
         {
         {
-            criteria.Add(new Filter<PurchaseOrder>(x => x.Status).IsEqualTo(PurchaseOrderStatus.Issued));
+            criteria.Add(new Filter<PurchaseOrder>(x => x.IssuedDate).IsNotEqualTo(DateTime.MinValue));
             base.Reload(criteria, columns, ref sort, action);
             base.Reload(criteria, columns, ref sort, action);
         }
         }
         
         

+ 30 - 13
prs.desktop/Panels/PurchaseOrders/SupplierPurchaseOrderItemOneToMany.cs

@@ -419,8 +419,9 @@ public class SupplierPurchaseOrderItemOneToMany : DynamicOneToManyGrid<PurchaseO
         {
         {
             var items = LoadItems(rows);
             var items = LoadItems(rows);
             foreach (var item in items)
             foreach (var item in items)
-                item.ReceivedDate = now;
-            new Client<PurchaseOrderItem>().Save(items, "Consignment Items Received");
+                item.ReceivedDate = item.ReceivedDate.IsEmpty() ? now : DateTime.MinValue;
+            now = items.Select(x => x.ReceivedDate).FirstOrDefault();
+            new Client<PurchaseOrderItem>().Save(items, now.IsEmpty() ? "Cleared Received Date" : $"Updated Received Date to {now:g}");
         }
         }
 
 
         return true;
         return true;
@@ -477,25 +478,41 @@ public class SupplierPurchaseOrderItemOneToMany : DynamicOneToManyGrid<PurchaseO
 
 
     protected override void SelectItems(CoreRow[]? rows)
     protected override void SelectItems(CoreRow[]? rows)
     {
     {
+        // Check if we can actually edit the selected lines
+        var _editable = !ReadOnly && Security.CanEdit<Consignment>();
+        
+        // Check to ensure NO selected lines are received
+        var _allunreceived = rows?.All(r => r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty()) == true;
+        
+        // Check to ensure ALL select lines are received
+        var _allreceived = rows?.All(r => !r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty()) == true;
+        
+        // Check to ensure NO selected lines are already linked to a PO
+        var _anyconsigmments = rows?.Any(r => r.Get<PurchaseOrderItem,Guid>(c=>c.Consignment.ID) != Guid.Empty) == true;
+        
+        // Check to Ensure NO selected lines are already linked to a Bill
+        var _anybills = rows?.Any(r => r.Get<PurchaseOrderItem,Guid>(c=>c.BillLine.ID) != Guid.Empty) == true;
+
         if (createConsignment != null)
         if (createConsignment != null)
         {
         {
             createConsignment.IsEnabled =
             createConsignment.IsEnabled =
-                rows != null
-                && !rows.Any(r => Entity.IsEntityLinkValid<PurchaseOrderItem, ConsignmentLink>(x => x.Consignment, r))
-                && !rows.Any(r => !r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty())
-                && !ReadOnly && Security.CanEdit<Consignment>();
+                _anyconsigmments == false
+                && _allunreceived
+                && _editable;
         }
         }
 
 
+        receive.Content = _allreceived
+            ? "Un-Receive Items"
+            : "Receive Items";
+        
         receive.IsEnabled =
         receive.IsEnabled =
-            rows != null
-            && !rows.Any(r => Entity.IsEntityLinkValid<PurchaseOrderItem, ConsignmentLink>(x => x.Consignment, r))
-            && !rows.Any(r => r.Get<PurchaseOrderItem, DateTime>(c => c.ReceivedDate).IsEmpty() == false)
-            && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();
+            _anyconsigmments == false
+            && (_allreceived || _allunreceived)
+            && _editable;
 
 
         bill.IsEnabled =
         bill.IsEnabled =
-            rows != null
-            && !rows.Any(r => r.IsEntityLinkValid<PurchaseOrderItem, BillLineLink>(x => x.BillLine))
-            && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();
+            _anybills == false
+            && _editable;
 
 
         assignLocation.IsEnabled =
         assignLocation.IsEnabled =
             rows != null && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();
             rows != null && !ReadOnly && Security.CanEdit<PurchaseOrderItem>();

+ 32 - 1
prs.desktop/Panels/PurchaseOrders/SupplierPurchaseOrders.cs

@@ -42,6 +42,10 @@ public class SupplierPurchaseOrders : DynamicDataGrid<PurchaseOrder>
     
     
     private SupplierPurchaseOrdersSettings _settings;
     private SupplierPurchaseOrdersSettings _settings;
 
 
+    public BitmapImage _truck = PRSDesktop.Resources.truck.AsBitmapImage();
+    public BitmapImage _tick = PRSDesktop.Resources.tick.AsBitmapImage();
+    public BitmapImage _warning = PRSDesktop.Resources.warning.AsBitmapImage();
+
     public SupplierPurchaseOrders()
     public SupplierPurchaseOrders()
     {
     {
         _settings = new UserConfiguration<SupplierPurchaseOrdersSettings>().Load();
         _settings = new UserConfiguration<SupplierPurchaseOrdersSettings>().Load();
@@ -51,14 +55,41 @@ public class SupplierPurchaseOrders : DynamicDataGrid<PurchaseOrder>
         OnEditorValueChanged += SupplierPurchaseOrders_OnEditorValueChanged;
         OnEditorValueChanged += SupplierPurchaseOrders_OnEditorValueChanged;
         OnCustomiseEditor += SupplierPurchaseOrders_OnCustomiseEditor;
         OnCustomiseEditor += SupplierPurchaseOrders_OnCustomiseEditor;
         
         
+        HiddenColumns.Add(x => x.IssuedDate);
         HiddenColumns.Add(x => x.ClosedDate);
         HiddenColumns.Add(x => x.ClosedDate);
         HiddenColumns.Add(x => x.Balance);
         HiddenColumns.Add(x => x.Balance);
-
+        HiddenColumns.Add(x => x.Unreceived);
+        HiddenColumns.Add(x => x.Received);
+        
+        ActionColumns.Add(new DynamicImageColumn(IssuedStatus));
+        ActionColumns.Add(new DynamicImageColumn(ReceivedStatus));
+        
         PostUtils.AddPostColumn(this);
         PostUtils.AddPostColumn(this);
 
 
         close = AddButton("Close Order", null, CloseOrder);
         close = AddButton("Close Order", null, CloseOrder);
         close.IsEnabled = false;
         close.IsEnabled = false;
     }
     }
+
+    private BitmapImage? IssuedStatus(CoreRow? row)
+    {
+        return row == null
+            ? _tick
+            : !row.Get<PurchaseOrder, DateTime>(x => x.IssuedDate).IsEmpty()
+                ? _tick
+                : null;
+    }
+
+    private BitmapImage? ReceivedStatus(CoreRow? row)
+    {
+        return row == null
+            ? _truck
+            : row.Get<PurchaseOrder, double>(x => x.Unreceived).IsEffectivelyEqual(0.0)
+                ? _tick
+                : !row.Get<PurchaseOrder, double>(x => x.Received).IsEffectivelyEqual(0.0)
+                    ? _warning
+                    : null;
+    }
+
     protected override void DoReconfigure(DynamicGridOptions options)
     protected override void DoReconfigure(DynamicGridOptions options)
     {
     {
         base.DoReconfigure(options);
         base.DoReconfigure(options);

+ 1 - 1
prs.desktop/prsdesktop.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 
 #define MyAppName "PRS Desktop"
 #define MyAppName "PRS Desktop"
-#define MyAppVersion "8.08b"
+#define MyAppVersion "8.08e"
 #define MyAppPublisher "PRS Digital"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSDesktop.exe"
 #define MyAppExeName "PRSDesktop.exe"

+ 1 - 1
prs.licensing/PRSLicensing.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 
 #define MyAppName "PRS Licensing"
 #define MyAppName "PRS Licensing"
-#define MyAppVersion "8.08b"
+#define MyAppVersion "8.08e"
 #define MyAppPublisher "PRS Digital"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSLicensing.exe"
 #define MyAppExeName "PRSLicensing.exe"

+ 1 - 1
prs.server/PRSServer.iss

@@ -8,7 +8,7 @@
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 #define public Dependency_Path_NetCoreCheck "dependencies\"
 
 
 #define MyAppName "PRS Server"
 #define MyAppName "PRS Server"
-#define MyAppVersion "8.08b"
+#define MyAppVersion "8.08e"
 #define MyAppPublisher "PRS Digital"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSServer.exe"
 #define MyAppExeName "PRSServer.exe"

+ 12 - 2
prs.stores/PurchaseOrderItemStore.cs

@@ -324,11 +324,21 @@ internal class PurchaseOrderItemStore : BaseStore<PurchaseOrderItem>
         { 
         { 
             poCost += entity.Cost * entity.Consignment.ExTax / consigntask.Result;
             poCost += entity.Cost * entity.Consignment.ExTax / consigntask.Result;
         }        
         }        
+        
         foreach (var jri in jris)
         foreach (var jri in jris)
         {
         {
-            CreateMovement(entity, locationid, movements, jri, jri.Qty, poCost);
-            _pototal -= jri.Qty;
+            // Going through each jri, make sure we don't allocate more than the po line allows
+            var jriQty = Math.Min(jri.Qty, _pototal);
+            // And reduce the po balance by the jri Allocation
+            _pototal -= jriQty;
+            
+            // Let's not make zero-quantity transactions
+            if (!jriQty.IsEffectivelyEqual(0.0))
+                CreateMovement(entity, locationid, movements, jri, jriQty, poCost);
         }
         }
+        
+        // If there is any left over (ie over-ordered), now we can create a
+        // second transaction to receive the unallocated stock
         if (!_pototal.IsEffectivelyEqual(0.0F))
         if (!_pototal.IsEffectivelyEqual(0.0F))
             CreateMovement(entity, locationid, movements, null, _pototal, poCost);
             CreateMovement(entity, locationid, movements, null, _pototal, poCost);
 
 

+ 2 - 7
prs.stores/PurchaseOrderStore.cs

@@ -14,11 +14,6 @@ namespace Comal.Stores
         {
         {
             base.BeforeSave(entity);
             base.BeforeSave(entity);
             Guid? empid = null;
             Guid? empid = null;
-            if (entity.HasOriginalValue(x => x.IssuedDate) && entity.GetOriginalValue(x => x.IssuedDate).IsEmpty())
-            {
-                empid ??= GetEmployeeIDFromUserGuid();
-                entity.IssuedBy.ID = empid.Value;
-            }
             if (entity.ID == Guid.Empty)
             if (entity.ID == Guid.Empty)
             {
             {
                 empid ??= GetEmployeeIDFromUserGuid();
                 empid ??= GetEmployeeIDFromUserGuid();
@@ -32,9 +27,9 @@ namespace Comal.Stores
 
 
             UpdateTrackingKanban<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(entity, p =>
             UpdateTrackingKanban<PurchaseOrderKanban, PurchaseOrder, PurchaseOrderLink>(entity, p =>
             {
             {
-                return p.Status == PurchaseOrderStatus.Closed
+                return !p.ClosedDate.IsEmpty() 
                     ? KanbanStatus.Complete
                     ? KanbanStatus.Complete
-                    : p.Status.Equals(PurchaseOrderStatus.Issued)
+                    : !p.IssuedDate.IsEmpty()
                         ? KanbanStatus.Waiting
                         ? KanbanStatus.Waiting
                         : KanbanStatus.Open;
                         : KanbanStatus.Open;
             });
             });