using System; using System.Collections.Generic; using System.Linq.Expressions; using InABox.Core; namespace Comal.Classes { public enum InvoiceType { Standard, ProgressClaim } [UserTracking("Accounts Receivable")] public class Invoice : Entity, IPersistent, IRemotable, INumericAutoIncrement, ILicense, IExportable, IPostable { [EditorSequence(1)] [IntegerEditor(Visible = Visible.Default, Editable = Editable.Enabled)] public int Number { get; set; } [EditorSequence(2)] [DateEditor(Visible = Visible.Default, TodayVisible = true)] public DateTime Date { get; set; } = DateTime.Today; [EditorSequence(3)] [MemoEditor(Visible = Visible.Default)] public string Description { get; set; } [EditorSequence(4)] public JobLink JobLink { get; set; } [EditorSequence(5)] [RequiredColumn] public CustomerLink CustomerLink { get; set; } private class ClaimedFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Aggregate(AggregateCalculation.Sum, x => x.Property(x => x.ExTax)) .WithLink(x => x.InvoiceLink.ID, x => x.ID); } [EditorSequence(6)] [CurrencyEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [ComplexFormula(typeof(ClaimedFormula))] public double Claimed { get; set; } [EditorSequence(7)] [CurrencyEditor(Summary = Summary.Sum)] public double Retained { get; set; } private class ExTaxFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Formula(FormulaOperator.Subtract, Property(x => x.Claimed), Property(x => x.Retained)); } [EditorSequence(8)] [CurrencyEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [ComplexFormula(typeof(ExTaxFormula))] public double ExTax { get; set; } private class TaxFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Aggregate(AggregateCalculation.Sum, x => x.Property(x => x.Tax)) .WithLink(x => x.InvoiceLink.ID, x => x.ID); } [EditorSequence(9)] [CurrencyEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [ComplexFormula(typeof(TaxFormula))] public double Tax { get; set; } private class IncTaxFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Aggregate(AggregateCalculation.Sum, x => x.Property(x => x.IncTax)) .WithLink(x => x.InvoiceLink.ID, x => x.ID); } [EditorSequence(10)] [CurrencyEditor(Visible = Visible.Default, Editable = Editable.Hidden, Summary = Summary.Sum)] [ComplexFormula(typeof(IncTaxFormula))] public double IncTax { get; set; } private class AmountPaidFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Aggregate(AggregateCalculation.Sum, x => x.Property(x => x.Amount)) .WithLink(x => x.InvoiceLink.ID, x => x.ID); } [EditorSequence(11)] [CurrencyEditor(Editable = Editable.Hidden)] [ComplexFormula(typeof(AmountPaidFormula))] public double AmountPaid { get; set; } private class BalanceFormula : ComplexFormulaGenerator { public override IComplexFormulaNode GetFormula() => Formula(FormulaOperator.Subtract, Property(x => x.IncTax), Property(x => x.AmountPaid)); } /// /// Balance = - . /// [EditorSequence(12)] [CurrencyEditor(Editable = Editable.Hidden, Summary = Summary.Sum)] [ComplexFormula(typeof(BalanceFormula))] public double Balance { get; set; } [EditorSequence(13)] [LookupDefinition(typeof(AccountsReceivablePaymentTermsLookup))] [RequiredColumn] public PaymentTermsLink Terms { get; set; } [EditorSequence(14)] [DateEditor(Visible = Visible.Default, TodayVisible = true)] public DateTime DueDate { get; set; } = DateTime.Today; [EditorSequence(15)] public SalesGLCodeLink SellGL { get; set; } [NullEditor] [LoggableProperty] [RequiredColumn] public PostedStatus PostedStatus { get; set; } = PostedStatus.NeverPosted; [NullEditor] [LoggableProperty] public DateTime Posted { get; set; } [NullEditor] public string PostedNote { get; set; } [NullEditor] public string PostedReference { get; set; } [NullEditor] public InvoiceType Type { get; set; } public Expression> AutoIncrementField() { return x => x.Number; } public Filter? AutoIncrementFilter() { return null; } public override string ToString() { return string.Format("{0}: {1}", Number, Description); } private static string DATE = CoreUtils.GetFullPropertyName(x => x.Date, "."); private static string CUSTOMERLINKTERMSCALCULATION = CoreUtils.GetFullPropertyName(x => x.CustomerLink.Terms.Calculation, "."); private static string TERMSCALCULATION = CoreUtils.GetFullPropertyName(x => x.Terms.Calculation, "."); private static string AMOUNTPAID = CoreUtils.GetFullPropertyName(x => x.AmountPaid, "."); private static string INCTAX = CoreUtils.GetFullPropertyName(x => x.IncTax, "."); protected override void DoPropertyChanged(string name, object? before, object? after) { base.DoPropertyChanged(name, before, after); if (name.Equals(AMOUNTPAID)) Balance = IncTax - (double)(after ?? 0.0); else if (name.Equals(INCTAX)) Balance = (double)(after ?? 0.0) - AmountPaid; else if (name.Equals(DATE)) DueDate = CalculateTerms((DateTime)(after ?? ""),Terms.Calculation); else if (name.Equals(TERMSCALCULATION)) DueDate = CalculateTerms(Date, (string)(after ?? "")); } private DateTime CalculateTerms(DateTime date, string calculation) { if (string.IsNullOrWhiteSpace(calculation)) return date; var model = new PaymentTermsCalculationModel { Date = date }; var expr = new CoreExpression(calculation); if(expr.Evaluate(model).Get(out var eval, out var e)) { return eval; } else { Logger.Send(LogType.Information, "", $"Error in Formula: [{calculation}] ({e.Message})"); return date; } } static Invoice() { LinkedProperties.Register(x=>x.CustomerLink.Terms,x=>x.ID, x=>x.Terms.ID); LinkedProperties.Register(x=>x.CustomerLink.Terms,x=>x.Code, x=>x.Terms.Code); LinkedProperties.Register(x=>x.CustomerLink.Terms,x=>x.Description, x=>x.Terms.Description); LinkedProperties.Register(x=>x.CustomerLink.Terms,x=>x.Calculation, x=>x.Terms.Calculation); LinkedProperties.Register(x=>x.CustomerLink.GLCode,x=>x.ID, x=>x.SellGL.ID); } } }