/// <summary> /// Get the bases for tax calculations /// </summary> /// <param name="codes">The collection of tax codes.</param> /// <param name="taxInStoreCurrency">if set to <c>true</c> [tax in store currency].</param> /// <param name="calculateBasePrice">if set to <c>true</c> [Calculate the base price].</param> /// <param name="calculationBase">The calculation base.</param> /// <param name="limitBase">The limit base.</param> protected virtual void GetBases(ReadOnlyCollection <TaxCode> codes, bool taxInStoreCurrency, bool calculateBasePrice, out decimal calculationBase, out decimal limitBase) { decimal basePrice = decimal.Zero; if (calculateBasePrice) { basePrice = this.TaxIncludedInPrice ? Provider.GetBasePriceForTaxIncluded(this.LineItem, codes) : LineItem.NetAmountPerUnit; } //1. Get initial value for the Calculation Base switch (this.TaxBase) { case TaxBase.PercentPerTax: // Base is the amount of the other tax switch (this.TaxLimitBase) { case TaxLimitBase.InvoiceWithoutVat: case TaxLimitBase.InvoiceWithVat: calculationBase = Math.Abs(this.CalculateTaxOnTax(this.LineItem.RetailTransaction)); break; case TaxLimitBase.UnitWithoutVat: case TaxLimitBase.UnitWithVat: // if this tax's Limit is per-unit, then we need to convert the existing tax amounts from per-line to per-unit decimal quantity = (this.LineItem.Quantity == decimal.Zero) ? decimal.One : this.LineItem.Quantity; calculationBase = Math.Abs(this.CalculateTaxOnTax()) / Math.Abs(quantity); break; default: calculationBase = Math.Abs(this.CalculateTaxOnTax()); break; } break; case TaxBase.PercentPerGross: // Base is the price + other taxes calculationBase = basePrice; // If the Limit base is NOT per-unit, then we need to factor in the line quanity if (TaxLimitBase != TaxLimitBase.UnitWithoutVat && TaxLimitBase != TaxLimitBase.UnitWithVat) { calculationBase *= Math.Abs(this.LineItem.Quantity); } if (!string.IsNullOrEmpty(this.TaxOnTax)) { // Base is the Price + the amount of a single other tax calculationBase += Math.Abs(this.CalculateTaxOnTax()); } else { // Base is the Price + all other taxes calculationBase += Math.Abs(TaxCode.SumAllTaxAmounts(this.LineItem)); } break; case TaxBase.AmountByUnit: calculationBase = AmountPerUnitCalculationBase; break; case TaxBase.PercentPerNet: case TaxBase.PercentGrossOnNet: default: // Base is the Price calculationBase = basePrice; // If the Limit base is NOT per-unit, then we need to factor in the line quanity if (TaxLimitBase != TaxLimitBase.UnitWithoutVat && TaxLimitBase != TaxLimitBase.UnitWithVat) { calculationBase *= Math.Abs(this.LineItem.Quantity); } break; } //3. Set Limit Base if (this.TaxBase == TaxBase.AmountByUnit) { // Base for limits/intervals is base-quantity * price limitBase = calculationBase * basePrice; // Convert limit base to Tax currency, if different if (!taxInStoreCurrency) { limitBase = TaxService.Tax.InternalApplication.Services.Currency.CurrencyToCurrency( ApplicationSettings.Terminal.StoreCurrency, this.Currency, limitBase); } // If the tax is calculated in a different UOM, then convert if possible // this is only applicable for lineItem taxes. BaseSaleItem saleLineItem = this.LineItem as BaseSaleItem; if (saleLineItem != null && !string.Equals(this.Unit, this.LineItem.SalesOrderUnitOfMeasure, StringComparison.OrdinalIgnoreCase)) { UnitOfMeasureData uomData = new UnitOfMeasureData( ApplicationSettings.Database.LocalConnection, ApplicationSettings.Database.DATAAREAID, ApplicationSettings.Terminal.StorePrimaryId, TaxService.Tax.InternalApplication); UnitQtyConversion uomConversion = uomData.GetUOMFactor(this.LineItem.SalesOrderUnitOfMeasure, this.Unit, saleLineItem); calculationBase *= uomConversion.GetFactorForQty(this.LineItem.Quantity); } } else { // Convert base to Tax currency, if different if (!taxInStoreCurrency) { calculationBase = TaxService.Tax.InternalApplication.Services.Currency.CurrencyToCurrency( ApplicationSettings.Terminal.StoreCurrency, this.Currency, calculationBase); } // Base for limits/intervals is same for Calculations limitBase = calculationBase; } }
/// <summary> /// Calculate the tax bases calculationBase and limitBase (which is zero for India). /// </summary> /// <param name="basePrice">The base price.</param> /// <param name="taxInStoreCurrency">if set to <c>true</c> [tax in store currency].</param> /// <param name="calculateBasePrice">if set to <c>true</c> [Calculate the base price].</param> /// <param name="calculationBase">The calculation base.</param> /// <param name="limitBase">The limit base.</param> protected override void GetBases(ReadOnlyCollection <TaxCode> codes, bool taxInStoreCurrency, bool calculateBasePrice, out decimal calculationBase, out decimal limitBase) { limitBase = decimal.Zero; // For amount by unit calculation base is just the quantity. if (this.TaxBase == TaxBase.AmountByUnit) { calculationBase = LineItem.Quantity; // If the tax is calculated in a different UOM, then convert if possible // this is only applicable for lineItem taxes. BaseSaleItem saleLineItem = this.LineItem as BaseSaleItem; if (saleLineItem != null && !string.Equals(this.Unit, this.LineItem.SalesOrderUnitOfMeasure, StringComparison.OrdinalIgnoreCase)) { UnitOfMeasureData uomData = new UnitOfMeasureData( ApplicationSettings.Database.LocalConnection, ApplicationSettings.Database.DATAAREAID, ApplicationSettings.Terminal.StorePrimaryId, TaxService.Tax.InternalApplication); UnitQtyConversion uomConversion = uomData.GetUOMFactor(this.LineItem.SalesOrderUnitOfMeasure, this.Unit, saleLineItem); calculationBase *= uomConversion.GetFactorForQty(this.LineItem.Quantity); } return; } // Determine the starting calculation base (includes the line price or not) switch (Formula.TaxableBasis) { case TaxableBases.LineAmount: calculationBase = this.LineItem.NetAmountWithAllInclusiveTaxPerUnit; break; case TaxableBases.MRP: calculationBase = GetMRP(); break; default: calculationBase = decimal.Zero; break; } if (this.TaxIncludedInPrice) { calculationBase = GetBasePriceForTaxIncluded(calculationBase, codes, Formula); } calculationBase *= Math.Abs(this.LineItem.Quantity); // Calculation expression is of the form: +[BCD]+[CVD]+[E-CESS_CVD]+[PE-C_CVD]+[SHE-C_CVD] // where the brackets are replaced with the delimiter char(164) // and BCD, CVD ... are tax codes. // The operator may be + - / *. string[] tokens = Formula.ParseExpression(); for (int index = 1; index < tokens.Length; index += 2) { ITaxItem taxItem = (from line in this.LineItem.TaxLines where line.TaxCode == tokens[index] select line).FirstOrDefault(); if (taxItem != null) { this.IsTaxOnTax = true; this.TaxCodesInFormula.Add(taxItem.TaxCode); } decimal amount = taxItem == null ? decimal.Zero : taxItem.Amount * Math.Sign(this.LineItem.Quantity); switch (tokens[index - 1]) { case "+": calculationBase += amount; break; case "-": calculationBase -= amount; break; case "*": calculationBase *= amount; break; case "/": calculationBase = (amount == decimal.Zero ? calculationBase : calculationBase /= amount); break; default: NetTracer.Error("GetBases(): Invalid operator in formula. tokens[{0}]: {1}", index - 1, tokens[index - 1]); System.Diagnostics.Debug.Fail("Invalid operator in formula"); break; } } // Knock any abatement off of the taxable basis calculationBase *= (100 - AbatementPercent) / 100; }