/// <summary> /// Back calculates the base price for items with included taxes. Based off of the class in AX /// <c>Tax.calcBaseAmtExclTax_IN</c>. /// </summary> /// <param name="baseLine">The base line amount.</param> /// <param name="codes">The tax codes.</param> /// <param name="formula">The formula value.</param> /// <param name="context">The request context.</param> /// <returns>The base price.</returns> private static decimal GetBasePriceForTaxIncluded(decimal baseLine, ReadOnlyCollection <TaxCode> codes, FormulaIndia formula, RequestContext context) { decimal taxVal; // A summarized tax rate for this code computed from the formula decimal taxValLine; // The summed tax rates for all codes for this line decimal amtPerUnitVal; // A summarized amount per unit contribution for this code computed from the formula decimal amtPerUnitLine; // The summed amount per unit contributions for all codes for this line. taxValLine = decimal.Zero; amtPerUnitLine = decimal.Zero; foreach (var code in codes) { taxVal = decimal.Zero; amtPerUnitVal = decimal.Zero; if (code.TaxIncludedInPrice) { // Handle codes differently based on whether they are India or not. TaxCodeIndia codeIndia = code as TaxCodeIndia; if (codeIndia != null) { CalculateTaxAmountsIndia(codes, codeIndia, ref amtPerUnitVal, ref taxVal, formula, context); } else { CalculateTaxAmounts(code, ref amtPerUnitVal, ref taxVal); } code.TaxValue = taxVal; code.AmountPerUnitValue = amtPerUnitVal; } taxValLine += taxVal; amtPerUnitLine += amtPerUnitVal; } // Back compute and set the price from price with tax (baseLine). return((Math.Abs(baseLine) - amtPerUnitLine) / (1 + taxValLine)); }
/// <summary> /// Calculates the tax amounts india. /// </summary> /// <param name="codes">The codes.</param> /// <param name="codeIndia">The code india.</param> /// <param name="amtPerUnitVal">The value of the amount per unit.</param> /// <param name="taxVal">The tax value.</param> /// <param name="formula">The formula value.</param> /// <param name="context">The request context.</param> private static void CalculateTaxAmountsIndia(ReadOnlyCollection <TaxCode> codes, TaxCodeIndia codeIndia, ref decimal amtPerUnitVal, ref decimal taxVal, FormulaIndia formula, RequestContext context) { decimal amtPerUnit = decimal.Zero; decimal taxCodeValue = decimal.Zero; decimal taxValueLoc; taxVal = decimal.Zero; amtPerUnitVal = decimal.Zero; if (codeIndia.Formula.TaxableBasis != TaxableBasisIndia.ExclusiveLineAmount && codeIndia.Formula.TaxableBasis != formula.TaxableBasis) { return; } string[] tokens = codeIndia.Formula.ParseExpression(); if (tokens.Length > 1) { GetTaxCodeFormulaIndiaDataRequest dataRequest = new GetTaxCodeFormulaIndiaDataRequest(codeIndia.TaxGroup, tokens[1]); FormulaIndia basisFormula = context.Execute <SingleEntityDataServiceResponse <FormulaIndia> >(dataRequest).Entity; 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; if (!codeIndia.taxCodesInFormula.Contains(basisCode.Code)) { 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.AmountPerUnitValue; } else { taxCodeValue -= basisCode.TaxValue; } break; case "+": if (basisCode.TaxBase == TaxBase.AmountByUnit) { amtPerUnit += basisCode.AmountPerUnitValue; } else { taxCodeValue += basisCode.TaxValue; } break; default: RetailLogger.Log.CrtServicesTaxCodeIndiaTaxServiceNotSupportedOperatorFoundInTaxAmountCalculation(tokens[index - 1]); break; } } } } } taxValueLoc = codeIndia.Value; if (codeIndia.TaxBase == TaxBase.AmountByUnit) { taxVal = decimal.Zero; amtPerUnitVal = taxValueLoc; } else { if (codeIndia.Formula.TaxableBasis != TaxableBasisIndia.ExclusiveLineAmount) { taxVal = ((1 + taxCodeValue) * taxValueLoc) / 100; } else { taxVal = (taxCodeValue * taxValueLoc) / 100; } taxVal *= (100 - codeIndia.AbatementPercent) / 100; amtPerUnitVal = amtPerUnit * taxValueLoc / 100; } }
/// <summary> /// Calculates tax for this code for the line item. /// Updates the line item by adding a new Tax Item. /// </summary> /// <param name="codes">The tax codes collection.</param> /// <param name="taxCodeAmountRounder">The current, accrued totals for this tax code.</param> /// <returns>The calculated amount of tax.</returns> public override decimal CalculateTaxAmount(ReadOnlyCollection <TaxCode> codes, TaxCodeAmountRounder taxCodeAmountRounder) { if (codes == null) { return(decimal.Zero); } decimal taxAmount = decimal.Zero; this.TaxableEntity.ItemTaxGroupId = this.TaxGroup; taxAmount = this.TaxIncludedInPrice ? this.CalculateTaxIncluded(codes) : this.CalculateTaxExcluded(codes); string groupRoundingKey = string.Empty; if (this.TaxGroupRounding) { // tax codes already sorted for this taxable item. foreach (var code in codes) { groupRoundingKey += code.Code + "@:$"; } } else if (this.TaxLimitBase == TaxLimitBase.InvoiceWithoutVat) { // total tax required for whole invoice by this tax code only. groupRoundingKey = this.Code; } // rounding required for above cases and when tax is not zero (not exempted). if (taxAmount != decimal.Zero) { // Adjust tax code amount. taxAmount = taxCodeAmountRounder.Round(this.TaxContext, this, groupRoundingKey, taxAmount); } // Record amounts on line item TaxLineIndia taxLine = new TaxLineIndia(); taxLine.Amount = taxAmount; taxLine.Percentage = this.Value; taxLine.TaxCode = this.Code; taxLine.TaxGroup = this.TaxGroup; taxLine.IsExempt = this.Exempt; taxLine.IsIncludedInPrice = this.TaxIncludedInPrice; taxLine.TaxComponent = this.GetTaxComponent(); taxLine.IsTaxOnTax = this.IsTaxOnTax; foreach (string codeInFormula in this.TaxCodesInFormula) { if (!taxLine.TaxCodesInFormula.Contains(codeInFormula)) { taxLine.TaxCodesInFormula.Add(codeInFormula); } } switch (this.Formula.TaxableBasis) { case TaxableBasisIndia.MaxRetailPrice: taxLine.IsIncludedInPrice = false; break; case TaxableBasisIndia.ExclusiveLineAmount: string[] tokens = this.Formula.ParseExpression(); // Iterate through the formula if (tokens.Length > 1) { GetTaxCodeFormulaIndiaDataRequest dataRequest = new GetTaxCodeFormulaIndiaDataRequest(this.TaxGroup, tokens[1]); FormulaIndia basisFormula = this.RequestContext.Execute <SingleEntityDataServiceResponse <FormulaIndia> >(dataRequest).Entity; if (basisFormula != null && basisFormula.TaxableBasis == TaxableBasisIndia.MaxRetailPrice) { taxLine.IsIncludedInPrice = false; } } break; default: break; } taxLine.TaxBasis = this.TaxBasis; this.TaxableEntity.TaxLines.Add(taxLine); return(taxAmount); }