/// <summary>
 /// Only support:
 /// codes that are of the supported tax basis.
 /// and codes that are defined in the formula (Id > 0)
 /// and codes that are of either ServiceTax or VAT or SalesTax
 /// </summary>
 /// <param name="codeIndia"></param>
 /// <returns></returns>
 private bool SupportedTax(TaxCodeIndia codeIndia)
 {
     return(codeIndia.Formula.SupportedTaxBasis && (codeIndia.Formula.Id > 0) &&
            (((codeIndia.TaxType == TaxTypes.ServiceTax) && taxParameterServiceIn) ||
             ((codeIndia.TaxType == TaxTypes.VAT) && taxParameterVatIn) ||
             ((codeIndia.TaxType == TaxTypes.SalesTax) && taxParameterSalesIn)));
 }
 protected override System.Collections.ObjectModel.ReadOnlyCollection <TaxCode> SortCodes(IEnumerable <TaxCode> codes)
 {
     // Return codes to be processed in the following order:
     // Non-India codes
     // India codes ordered by Id
     return(new ReadOnlyCollection <TaxCode>(
                codes.OrderBy(code =>
     {
         TaxCodeIndia codeIndia = code as TaxCodeIndia;
         if (codeIndia != null)
         {
             return codeIndia.Formula.Id + MaxPriorityTaxCode + 1;
         }
         else
         {
             return TaxCodeProvider.TaxCodePriority(code);
         }
     }).ToList()));
 }
        /// <summary>
        /// Back calculates the base price for items with included taxes.  Based off of the class in AX
        /// Tax.calcBaseAmtExclTax_IN
        /// </summary>
        /// <param name="lineItem">The line item.</param>
        /// <param name="codes">The tax codes.</param>
        /// <param name="formula">The formula val.</param>
        /// <returns>base price</returns>
        private static decimal GetBasePriceForTaxIncluded(decimal baseLine, ReadOnlyCollection <TaxCode> codes, Formula formula)
        {
            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);
                    }
                    else
                    {
                        CalculateTaxAmounts(code, ref amtPerUnitVal, ref taxVal);
                    }
                    code.TaxValue        = taxVal;
                    code.AmtPerUnitValue = 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 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;
            }
        }