using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using InABox.Core; using PRSClasses; namespace Comal.Classes { [UserTracking(typeof(Bill))] [Caption("Purchase Order Items")] public class PurchaseOrderItem : StockEntity, IRemotable, IPersistent, IOneToMany, ITaxable, IOneToMany, IOneToMany, ILicense, IPostableFragment, IJobMaterial { [RequiredColumn] [EntityRelationship(DeleteAction.Cascade)] public PurchaseOrderLink PurchaseOrderLink { get; set; } [EntityRelationship(DeleteAction.SetNull)] [EditorSequence(1)] [RequiredColumn] public override ProductLink Product { get; set; } [EntityRelationship(DeleteAction.SetNull)] [EditorSequence(2)] public ProductStyleLink Style { get; set; } [EditorSequence(3)] [RequiredColumn] [DimensionsEditor(typeof(StockDimensions))] public override StockDimensions Dimensions { get; set; } private class AllocationsFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Aggregate( AggregateCalculation.Concat, x => x.Property(x => x.Job.JobNumber)) .WithLink(x => x.Item.ID, x => x.ID); } [ComplexFormula(typeof(AllocationsFormula))] [TextBoxEditor(Visible=Visible.Optional,Editable = Editable.Hidden)] public string Allocations { get; set; } [EntityRelationship(DeleteAction.SetNull)] [EditorSequence(4)] public JobLink Job { get; set; } [MemoEditor(Visible = Visible.Default)] [EditorSequence(6)] public string Description { get; set; } [DoubleEditor(Visible = Visible.Default)] [EditorSequence(7)] public double Qty { get; set; } = 1; private class AllocatedFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => If( Property(x=>x.Dimensions.Unit.Conversion), Condition.Equals, Constant(""), "" ) .Then( Aggregate( AggregateCalculation.Sum, Property(a => a.Quantity) ) .WithLink(x => x.Item.ID, x => x.ID) ) .Else( Aggregate( AggregateCalculation.Sum, Formula( FormulaOperator.Divide, Property(a => a.Quantity), Property(a => a.Item.Dimensions.Value) ) ).WithLink(x => x.Item.ID, x => x.ID) ); } [ComplexFormula(typeof(AllocatedFormula))] [DoubleEditor(Editable = Editable.Hidden)] public double Allocated { get; set; } private class UnallocatedFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Formula( FormulaOperator.Subtract, Property(x=>x.Qty), Property(x=>x.Allocated) ); } [ComplexFormula(typeof(UnallocatedFormula))] [DoubleEditor(Editable = Editable.Hidden)] public double Unallocated { get; set; } [CurrencyEditor(Visible = Visible.Optional)] [EditorSequence(8)] public double ForeignCurrencyCost { get; set; } [CurrencyEditor(Visible = Visible.Default)] [EditorSequence(9)] public double Cost { get; set; } [CurrencyEditor(Visible = Visible.Default, Summary = Summary.Sum)] [EditorSequence(10)] public double ExTax { get; set; } [EditorSequence(11)] public TaxCodeLink TaxCode { get; set; } [NullEditor] public double TaxRate { get; set; } [EditorSequence(12)] [CurrencyEditor(Visible = Visible.Default, Summary = Summary.Sum)] public double Tax { get; set; } [EditorSequence(13)] [CurrencyEditor(Visible = Visible.Default, Summary = Summary.Sum)] public double IncTax { get; set; } [EditorSequence("Additional",1)] [IntegerEditor(Visible = Visible.Optional)] public int PORevision { get; set; } [CodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)] [EditorSequence("Additional",2)] public string SupplierCode { get; set; } [EditorSequence("Additional",3)] public PurchaseGLCodeLink PurchaseGL { get; set; } [EditorSequence("Additional",4)] public CostCentreLink CostCentre { get; set; } [DateTimeEditor(Visible = Visible.Default)] [EditorSequence("Additional",5)] public DateTime DueDate { get; set; } [EditorSequence("Additional",6)] [EntityRelationship(DeleteAction.SetNull)] public ConsignmentLink Consignment { get; set; } private class ConsignmentParcelLookup : LookupDefinitionGenerator { public override Filter DefineFilter(PurchaseOrderItem[] items) { if (items.Select(x => x.Consignment.ID).Distinct().Count() != 1) return new Filter().None(); return new Filter(x => x.Consignment.ID).IsEqualTo(items.FirstOrDefault()?.Consignment.ID ?? CoreUtils.FullGuid); } public override Columns DefineFilterColumns() => Columns.None().Add(x=>x.Consignment.ID); } [LookupDefinition(typeof(ConsignmentParcelLookup))] [EditorSequence("Additional",7)] [EntityRelationship(DeleteAction.SetNull)] public ConsignmentParcelLink ConsignmentParcel { get; set; } [EditorSequence("Additional",8)] public StockLocationLink StockLocation { get; set; } [DateTimeEditor(Visible = Visible.Default)] [EditorSequence("Additional",9)] public DateTime ReceivedDate { get; set; } [TextBoxEditor(Visible = Visible.Optional)] [EditorSequence("Additional",10)] public string ReceivedReference { get; set; } [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden, Summary = Summary.Sum)] public double Balance { get; set; } [Editable(Editable.Disabled)] [EntityRelationship(DeleteAction.SetNull)] public BillLineLink BillLine { get; set; } [NullEditor] public string PostedReference { get; set; } [EntityRelationship(DeleteAction.SetNull)] [NullEditor] [Obsolete("Replaced with Product", true)] public ProductLink ProductLink { get { return Product; } set { /* We cannot set the 'Product' to this value, because that would stuff the SubObject internal linking, so we do nothing instead. */ } } [EntityRelationship(DeleteAction.SetNull)] [NullEditor] [Obsolete("Replaced with Style", true)] public ProductStyleLink StyleLink { get { return Style; } set { /* Same as ProductLink */ } } [NullEditor] [Obsolete("Replaced with Dimensions", true)] public double UnitSize { get; set; } [NullEditor] [Obsolete] public StockMovementLink StockMovement { get; set; } [NullEditor] [EntityRelationship(DeleteAction.SetNull)] public ManufacturingPacketLink Packet { get; set; } private class FormCountAggregate : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Count( x => x.Property(x => x.ID)) .WithLink(x => x.Parent.ID, x => x.ID); } [NullEditor] [ComplexFormula(typeof(FormCountAggregate))] public int FormCount { get; set; } private class OpenFormsAggregate : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Count( x => x.Property(x => x.ID), new Filter(x => x.FormCompleted).IsEqualTo(DateTime.MinValue) .Or(x => x.FormData).IsEqualTo("")) .WithLink(x => x.Parent.ID, x => x.ID); } [NullEditor] [ComplexFormula(typeof(OpenFormsAggregate))] public int OpenForms { get; set; } static PurchaseOrderItem() { LinkedProperties.Register(x => x.Product, x => x.Name, x => x.Description); LinkedProperties.Register(x => x.Product.TaxCode, x => x.ID, x => x.TaxCode.ID); LinkedProperties.Register(x => x.Product.TaxCode, x => x.Code, x => x.TaxCode.Code); LinkedProperties.Register(x => x.Product.TaxCode, x => x.Description, x => x.TaxCode.Description); LinkedProperties.Register(x => x.Product.TaxCode, x => x.Rate, x => x.TaxCode.Rate); LinkedProperties.Register(x => x.TaxCode, x => x.Rate, x => x.TaxRate); LinkedProperties.Register(x => x.Product.PurchaseGL, x => x.ID, x => x.PurchaseGL.ID); LinkedProperties.Register(x => x.Product.CostCentre, x => x.ID, x => x.CostCentre.ID); LinkedProperties.Register(x => x.Product.DefaultInstance.Style, x => x.ID, x => x.Style.ID); LinkedProperties.Register(x => x.Product.DefaultInstance.Style, x => x.Code, x => x.Style.Code); LinkedProperties.Register(x => x.Product.DefaultInstance.Style, x => x.Description, x => x.Style.Description); LinkedProperties.Register(x => x.Product.DefaultInstance, x => x.NettCost, x => x.Cost); StockEntity.LinkStockDimensions(); DefaultColumns.Add(x => x.PurchaseOrderLink.PONumber, caption: "PONumber"); DefaultColumns.Add(x => x.Description); DefaultColumns.Add(x => x.Product.Code, caption: "Product", width: 100); DefaultColumns.Add(x => x.Style.Code, caption: "Style", width: 100); DefaultColumns.Add(x => x.Dimensions.UnitSize, width: 70, caption: "Size"); DefaultColumns.Add(x => x.Job.JobNumber, caption: "Job", width: 70); DefaultColumns.Add(x => x.Qty, width: 50); DefaultColumns.Add(x => x.Cost); DefaultColumns.Add(x => x.ExTax); DefaultColumns.Add(x => x.TaxCode.Code, caption: "Tax", width: 50); DefaultColumns.Add(x => x.CostCentre.Code, width: 70); DefaultColumns.Add(x => x.PurchaseGL.Code, width: 70); DefaultColumns.Add(x => x.ReceivedDate, width: 100); } private bool bChanging; protected override void DoPropertyChanged(string name, object? before, object? after) { base.DoPropertyChanged(name, before, after); if (bChanging) return; try { bChanging = true; if (name.Equals(nameof(Qty)) && after is double qty) ExTax = qty * Cost; else if (name.Equals(nameof(ForeignCurrencyCost)) && (after is double foreigncost) && PurchaseOrderLink.SupplierLink.Currency.ID != Guid.Empty) { Cost = foreigncost / (PurchaseOrderLink.SupplierLink.Currency.ExchangeRate.IsEffectivelyEqual(0.0) ? 1.0 : PurchaseOrderLink.SupplierLink.Currency.ExchangeRate); ExTax = Qty * Cost; } else if (name.Equals(nameof(Cost)) && (after is double cost)) { ExTax = cost * Qty; if (PurchaseOrderLink.SupplierLink.Currency.ID != Guid.Empty) ForeignCurrencyCost = cost * (PurchaseOrderLink.SupplierLink.Currency.ExchangeRate.IsEffectivelyEqual(0.0) ? 1.0 : PurchaseOrderLink.SupplierLink.Currency.ExchangeRate); } else if (name.Equals(nameof(ExTax)) && after is double extax) { if (Qty == 0) Qty = 1; Cost = extax / Qty; if (PurchaseOrderLink.SupplierLink.Currency.ID != Guid.Empty) ForeignCurrencyCost = Cost * (PurchaseOrderLink.SupplierLink.Currency.ExchangeRate.IsEffectivelyEqual(0.0) ? 1.0 : PurchaseOrderLink.SupplierLink.Currency.ExchangeRate); } else if (name.Equals(nameof(IncTax)) && after is double inctax) Balance = ReceivedDate.IsEmpty() ? inctax : 0.00F; else if (name.Equals(nameof(ReceivedDate)) && after is DateTime received) Balance = received.IsEmpty() ? IncTax : 0.00F; } finally { bChanging = false; } } } }