/// <summary> /// Get the PercentRate for a given Tax (takes Gross Taxes into account) /// </summary> /// <param name="code"></param> /// <param name="taxBase"></param> /// <param name="otherCodes"></param> /// <returns></returns> private static decimal GetPercentPerTax(TaxCode code, decimal taxBase, ReadOnlyCollection <TaxCode> otherCodes) { decimal percent = decimal.Zero; if (code.TaxBase == TaxBase.PercentPerGross) { decimal otherPercents = decimal.Zero; foreach (TaxCode t in otherCodes.Where(c => (c.Code != code.Code && c.TaxBase != TaxBase.AmountByUnit))) { otherPercents += t.PercentPerTax(taxBase); } decimal grossPercent = code.PercentPerTax(taxBase); //Gross Percent needs to be expressed with respect to the original item price: // ActualPercent = GrossPercent * (full price + other taxes)/100 percent = grossPercent * (100 + otherPercents) / 100m; } else { percent = code.PercentPerTax(taxBase); } return(percent); }
/// <summary> /// Calculates the tax amounts for non India tax codes (simple tax codes only supported). /// </summary> /// <param name="code">The code.</param> /// <param name="amtPerUnitVal">The amt per unit val.</param> /// <param name="taxVal">The tax val.</param> private static void CalculateTaxAmounts(TaxCode code, ref decimal amtPerUnitVal, ref decimal taxVal) { if (code.TaxBase == TaxBase.AmountByUnit) { amtPerUnitVal = code.Value; taxVal = decimal.Zero; } else { amtPerUnitVal = decimal.Zero; taxVal = code.Value; } }
private void AddTaxCode(CacheKey cacheKey, SqlDataReader reader, ITaxableItem taxableItem, Dictionary <string, TaxCode> codes) { TaxCode code = GetTaxCode(reader, taxableItem); codes.Add(code.Code, code); if (!taxCodeCache.ContainsKey(cacheKey)) { taxCodeCache[cacheKey] = new List <TaxCode>() { code } } ; else { taxCodeCache[cacheKey].Add(code); } }
protected static int TaxCodePriority(TaxCode code) { // Return codes to be processed in the following order: // 1. Amount per unit & Percent of net & Percent Gross on net // 2. Percent of tax // 3. Percent of gross (single tax) // 4. Percent of gross (all taxes) switch (code.TaxBase) { case TaxBase.AmountByUnit: case TaxBase.PercentPerNet: case TaxBase.PercentGrossOnNet: return(1); case TaxBase.PercentPerTax: return(2); case TaxBase.PercentPerGross: return(string.IsNullOrEmpty(code.TaxOnTax) ? MaxPriorityTaxCode : 3); default: return(0); } }
/// <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> /// Whether or not a given TaxCode is in the Store Currency /// </summary> /// <param name="code"></param> /// <returns></returns> private static bool IsStoreCurrency(TaxCode code) { return(string.IsNullOrEmpty(code.Currency) || code.Currency.Equals(ApplicationSettings.Terminal.StoreCurrency, StringComparison.OrdinalIgnoreCase)); }
/// <summary> /// Calculates the tax amounts india. /// </summary> /// <param name="codes">The codes.</param> /// <param name="codeIndia">The code india.</param> /// <param name="amtPerUnitVal">The amt per unit val.</param> /// <param name="taxVal">The tax val.</param> /// <param name="formula">The formula val.</param> private static void CalculateTaxAmountsIndia(ReadOnlyCollection <TaxCode> codes, TaxCodeIndia codeIndia, ref decimal amtPerUnitVal, ref decimal taxVal, Formula formula) { decimal amtPerUnit = decimal.Zero; decimal taxCodeValue = decimal.Zero; decimal taxValueLoc; taxVal = decimal.Zero; amtPerUnitVal = decimal.Zero; if (codeIndia.Formula.TaxableBasis != TaxableBases.ExclAmount && codeIndia.Formula.TaxableBasis != formula.TaxableBasis) { return; } string[] tokens = codeIndia.Formula.ParseExpression(); if (tokens.Length > 1) { Formula basisFormula = FormulaData.GetFormula(codeIndia.TaxGroup, tokens[1]); if (basisFormula != null && basisFormula.TaxableBasis == formula.TaxableBasis) { // Iterate through the formula for (int index = 1; index < tokens.Length; index += 2) { TaxCode basisCode = (from c in codes where c.Code == tokens[index] select c).FirstOrDefault(); if ((basisCode != null) && !basisCode.Exempt) { codeIndia.IsTaxOnTax = true; codeIndia.TaxCodesInFormula.Add(basisCode.Code); // Either add or subtract the values based on the operator switch (tokens[index - 1]) { case "-": if (basisCode.TaxBase == TaxBase.AmountByUnit) { amtPerUnit -= basisCode.AmtPerUnitValue; } else { taxCodeValue -= basisCode.TaxValue; } break; case "+": if (basisCode.TaxBase == TaxBase.AmountByUnit) { amtPerUnit += basisCode.AmtPerUnitValue; } else { taxCodeValue += basisCode.TaxValue; } break; default: NetTracer.Error("CalculateTaxAmountsIndia(): Multiplication and division not currently supported in AX. tokens[{0}]: {1}", index - 1, tokens[index - 1]); Debug.Fail("Multiplication and division not currently supported in AX"); break; } } } } } taxValueLoc = codeIndia.Value; if (codeIndia.TaxBase == TaxBase.AmountByUnit) { taxVal = decimal.Zero; amtPerUnitVal = taxValueLoc; } else { if (codeIndia.Formula.TaxableBasis != TaxableBases.ExclAmount) { taxVal = ((1 + taxCodeValue) * taxValueLoc) / 100; } else { taxVal = (taxCodeValue * taxValueLoc) / 100; } taxVal *= (100 - codeIndia.AbatementPercent) / 100; amtPerUnitVal = amtPerUnit * taxValueLoc / 100; } }