using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Runtime.InteropServices; using InABox.Clients; using InABox.Core; namespace Comal.Classes { // public class PurchaseOrderDueDate : CoreAggregate // { // public override Expression> Aggregate => x => x.DueDate; // // public override AggregateCalculation Calculation => AggregateCalculation.Minimum; // // public override Filter? Filter => new Filter(c => c.DueDate).IsNotEqualTo(DateTime.MinValue); // // public override Dictionary>, Expression>> Links => // new Dictionary>, Expression>>() // { // { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } // }; // } public class PurchaseOrderUnreceivedQtyAggregate : CoreAggregate { public override Expression> Aggregate => x => x.Qty; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } }; public override Filter? Filter => new Filter(x => x.ReceivedDate).IsEqualTo(DateTime.MinValue); } public class PurchaseOrderReceivedQtyAggregate : CoreAggregate { public override Expression> Aggregate => x => x.Qty; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } }; public override Filter? Filter => new Filter(x => x.ReceivedDate).IsNotEqualTo(DateTime.MinValue); } public class PurchaseOrderExTax : CoreAggregate { public override Expression> Aggregate => x => x.ExTax; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } }; } public class PurchaseOrderTax : CoreAggregate { public override Expression> Aggregate => x => x.Tax; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } }; } public class PurchaseOrderIncTax : CoreAggregate { public override Expression> Aggregate => x => x.IncTax; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } }; } public class PurchaseOrderBalance : CoreAggregate { public override Expression> Aggregate => x => x.Balance; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { PurchaseOrderItem => PurchaseOrderItem.PurchaseOrderLink.ID, PurchaseOrder => PurchaseOrder.ID } }; } [UserTracking(typeof(Bill))] public class PurchaseOrder : Entity, IRemotable, IPersistent, IStringAutoIncrement, IOneToMany, ILicense, IDataEntryInstance, IPostable, IMergeable { private bool bChanging; [UniqueCodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)] [EditorSequence(0)] public string PONumber { get; set; } [RequiredColumn] [EntityRelationship(DeleteAction.SetNull)] [EditorSequence(1)] public SupplierLink SupplierLink { get; set; } [MemoEditor] [EditorSequence(2)] public string Description { get; set; } [EditorSequence(3)] public PurchaseOrderCategoryLink Category { get; set; } [EditorSequence(4)] public EmployeeLink RaisedBy { get; set; } [DateEditor] [EditorSequence(5)] public DateTime DueDate { get; set; } private class IssuedDateInformation : EditorInformation { public override string GetInfo(PurchaseOrder item) => item.IssuedBy.Name; } [DateTimeEditor(Information = typeof(IssuedDateInformation))] [RequiredColumn,LoggableProperty] [EditorSequence(6)] public DateTime IssuedDate { get; set; } private class EmployeeLookup : LookupDefinitionGenerator { public override Columns DefineColumns() { return base.DefineColumns().Add(x => x.Name); } } // 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 [NullEditor] [LookupDefinition(typeof(EmployeeLookup))] public EmployeeLink IssuedBy { get; set; } [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [Aggregate(typeof(PurchaseOrderExTax))] public double ExTax { get; set; } [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [Aggregate(typeof(PurchaseOrderTax))] public double Tax { get; set; } [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [Aggregate(typeof(PurchaseOrderIncTax))] public double IncTax { get; set; } [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [Aggregate(typeof(PurchaseOrderBalance))] public double Balance { get; set; } [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)] [Aggregate(typeof(PurchaseOrderUnreceivedQtyAggregate))] public double Unreceived { get; set; } [DoubleEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [Aggregate(typeof(PurchaseOrderReceivedQtyAggregate))] public double Received { get; set; } //[CodeEditor(Visible = Visible.Default, Editable = Editable.Hidden)] [NullEditor] public string SupplierCode { get; set; } //[TextBoxEditor] [NullEditor] public string SupplierName { get; set; } [DoNotPersist] [DoNotSerialize] public static string PONumberPrefix { get; set; } [NullEditor] [LoggableProperty] public DateTime Posted { get; set; } [NullEditor] [LoggableProperty] [RequiredColumn] public PostedStatus PostedStatus { get; set; } [NullEditor] public string PostedNote { get; set; } [NullEditor] public string PostedReference { get; set; } [Obsolete("Replaced by multiple Datetime stamps", true)] [NullEditor] public PurchaseOrderStatus Status { get; set; } public Expression> AutoIncrementField() => x => x.PONumber; public Filter AutoIncrementFilter() => null; public string AutoIncrementPrefix() => PONumberPrefix; public string AutoIncrementFormat() => "{0:D6}"; protected override void DoPropertyChanged(string name, object? before, object? after) { base.DoPropertyChanged(name, before, after); if (bChanging) return; bChanging = true; if (name.Equals(nameof(IssuedDate)) && before is DateTime _old && after is DateTime _new && _new.IsEmpty() != _old.IsEmpty()) { Employee? _emp = _new.IsEmpty() ? new Employee() : Client.Query( new Filter(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid), Columns.None().Add(x => x.ID).Add(x => x.Name) ).Rows.FirstOrDefault()?.ToObject(); IssuedBy.ID = _emp.ID; IssuedBy.Synchronise(_emp); } bChanging = false; } static PurchaseOrder() { LinkedProperties.Register(x => x.SupplierLink, x => x.Code, x => x.SupplierCode); LinkedProperties.Register(x => x.SupplierLink, x => x.Name, x => x.SupplierName); } public static void UpdateCosts(IEnumerable items, Guid supplierid, Dictionary changes) { void UpdateValue(PurchaseOrderItem item,Expression> property, TType value) { CoreUtils.MonitorChanges( item, () => CoreUtils.SetPropertyValue(item, CoreUtils.GetFullPropertyName(property, "."), value), changes ); } var productids = items.Where(x => x.Product.ID != Guid.Empty).Select(x => x.Product.ID).ToArray(); MultiQuery query = new MultiQuery(); query.Add( new Filter(x=>x.SupplierLink.ID).IsEqualTo(supplierid) .And(x=>x.Product.ID).InList(productids), Columns.None().Add(x=>x.Product.ID) .Add(x=>x.Style.ID) .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local) .Add(x=>x.Job.ID) .Add(x=>x.SupplierCode) .Add(x=>x.SupplierDescription) .Add(x=>x.SupplierLink.ID) .Add(x=>x.ForeignCurrencyPrice) .Add(x=>x.CostPrice) ); query.Add( new Filter(x=>x.Product.ID).InList(productids), Columns.None().Add(x=>x.Product.ID) .Add(x => x.Style.ID) .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local) .Add(x => x.NettCost) ); query.Query(); var supplierProducts = query.Get().ToArray(); var productInstances = query.Get().ToArray(); foreach (var item in items) { //Check Supplier / Job Specific Pricing var supplierProduct = supplierProducts.FirstOrDefault(x => x.SupplierLink.ID == item.PurchaseOrderLink.SupplierLink.ID && x.Product.ID == item.Product.ID && x.Style.ID == item.Style.ID && x.Dimensions.Equals(item.Dimensions) && x.Job.ID == item.Job.ID); if (supplierProduct != null) { UpdateValue(item, x => x.SupplierCode, supplierProduct.SupplierCode); UpdateValue(item, x => x.Description, supplierProduct.SupplierDescription); UpdateValue(item, x => x.ForeignCurrencyCost, supplierProduct.ForeignCurrencyPrice); UpdateValue(item, x => x.Cost, supplierProduct.CostPrice); continue; } // Check Supplier Pricing supplierProduct = supplierProducts.FirstOrDefault(x => x.SupplierLink.ID == item.PurchaseOrderLink.SupplierLink.ID && x.Product.ID == item.Product.ID && x.Style.ID == item.Style.ID && x.Dimensions.Equals(item.Dimensions) && x.Job.ID == Guid.Empty); if (supplierProduct != null) { UpdateValue(item, x => x.SupplierCode, supplierProduct.SupplierCode); UpdateValue(item, x => x.Description, supplierProduct.SupplierDescription); UpdateValue(item, x => x.ForeignCurrencyCost, supplierProduct.ForeignCurrencyPrice); UpdateValue(item, x => x.Cost, supplierProduct.CostPrice); continue; } // Check Specific Product Instance var productInstance = productInstances.FirstOrDefault(x => x.Product.ID == item.Product.ID && x.Style.ID == item.Style.ID && x.Dimensions.Equals(item.Dimensions)); if (productInstance != null) UpdateValue(item, x => x.Cost, productInstance.NettCost); else UpdateValue(item, x => x.Cost, 0.0F); UpdateValue(item, x => x.ForeignCurrencyCost, 0.0F); } } } }