예제 #1
0
            /// <summary>
            /// Calculates the tax for the last item.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            private static CalculateTaxServiceResponse CalculateTax(CalculateTaxServiceRequest request)
            {
                ThrowIf.Null(request, "request");

                TaxHelpers.SetSalesTaxGroup(request.RequestContext, request.Transaction);
                SalesTaxOverrideHelper.CalculateTaxOverrides(request.RequestContext, request.Transaction);

                // Consider active (non-void) lines for tax.
                // Need to recalculate tax on return-by-receipt lines because we cannot reconstruct tax lines from return transaction lines alone.
                // A few key information like IsExempt, IsTaxInclusive, TaxCode are not available on return transaction line.
                foreach (var saleItem in request.Transaction.ActiveSalesLines)
                {
                    saleItem.TaxRatePercent = 0;
                    saleItem.TaxLines.Clear();
                }

                var totaler = new SalesTransactionTotaler(request.Transaction);

                totaler.CalculateTotals(request.RequestContext);

                ClearChargeTaxLines(request.Transaction);

                TaxContext taxContext = new TaxContext(request.RequestContext);

                TaxCodeProvider defaultProvider = GetTaxProvider(request.RequestContext, taxContext);

                defaultProvider.CalculateTax(request.RequestContext, request.Transaction);

                return(new CalculateTaxServiceResponse(request.Transaction));
            }
예제 #2
0
        public AddTaxViewModel(IEventAggregator ea, IOfficeContext context)
        {
            eventAggregator = ea;
            this.context    = context;

            TaxDTO  = new TaxContext();
            TaxList = new ObservableCollection <TaxContext>();

            LoadTaxList();
        }
예제 #3
0
 public VatControllers(TaxContext dbContext)
 {
     db = dbContext;
     if (db.Vats.Count() == 0)
     {
         db.Vats.Add(new Vat {
             VatId      = 7,
             EffectDate = DateTime.Now
         });
         db.SaveChanges();
     }
     taxRepo = new Repository(db);
 }
예제 #4
0
        private static async Task Main(string[] args)
        {
            double principleAmount = 1000;

            var taxContext = new TaxContext();

            double taxValue = await taxContext.TaxCalculation(Tax.GST, principleAmount);

            Console.WriteLine($"GST : {taxValue}");

            taxValue = await taxContext.TaxCalculation(Tax.VAT, principleAmount);

            Console.WriteLine($"Vat : {taxValue}");
        }
예제 #5
0
            /// <summary>
            /// Get the tax code provider.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="taxContext">Tax context.</param>
            /// <returns>The tax code provider.</returns>
            private static TaxCodeProvider GetTaxProvider(RequestContext context, TaxContext taxContext)
            {
                TaxCodeProvider taxCodeProvider;

                switch (context.GetChannelConfiguration().CountryRegionISOCode)
                {
                case CountryRegionISOCode.IN:
                    taxCodeProvider = new TaxCodeProviderIndia(taxContext);
                    break;

                default:
                    taxCodeProvider = new TaxCodeProvider(taxContext);
                    break;
                }

                return(taxCodeProvider);
            }
예제 #6
0
            /// <summary>
            /// Keeps track of totals aggregated by tax codes and rounds current value accordingly.
            /// </summary>
            /// <param name="taxContext">The tax context.</param>
            /// <param name="taxCode">The tax code. Used to get rounding configuration.</param>
            /// <param name="groupKey">The tax code grouping key, such as tax code (net invoice) or tax code combination.</param>
            /// <param name="taxCodeAmountNonRounded">The non-rounded tax code amount.</param>
            /// <returns>The rounded value of tax code amount.</returns>
            internal decimal Round(TaxContext taxContext, TaxCode taxCode, string groupKey, decimal taxCodeAmountNonRounded)
            {
                // Adjustments after roundings on accrued totals are needed for following cases.
                if (taxCode.TaxGroupRounding || taxCode.TaxLimitBase == TaxLimitBase.InvoiceWithoutVat)
                {
                    // Calculate current TaxCode.TotalAmount by summing up all non-rounded, [all previous and current] taxLines.taxCode.Amounts.
                    // That’s what we supposed to collect as a Tax for a given tax code (or combination).
                    Totals groupTotals;

                    if (this.currentTotals.TryGetValue(groupKey, out groupTotals))
                    {
                        decimal previousTotalRoundedValue = groupTotals.TotalRoundedValue;

                        groupTotals.TotalNonRoundedValue += taxCodeAmountNonRounded;
                        decimal newRoundedTotal         = taxContext.TaxCurrencyOperations.Round(groupTotals.TotalNonRoundedValue, taxCode.RoundingOff, taxCode.RoundingOffType);
                        decimal newTaxCodeAmountRounded = newRoundedTotal - previousTotalRoundedValue;

                        groupTotals.TotalRoundedValue = newRoundedTotal;

                        return(newTaxCodeAmountRounded);
                    }
                    else
                    {
                        groupTotals = new Totals
                        {
                            TotalNonRoundedValue = taxCodeAmountNonRounded,
                            TotalRoundedValue    = taxContext.TaxCurrencyOperations.Round(taxCodeAmountNonRounded, taxCode.RoundingOff, taxCode.RoundingOffType)
                        };

                        this.currentTotals.Add(groupKey, groupTotals);

                        // no further adjustments needed since there are no previous lines for the tax code.
                        return(groupTotals.TotalRoundedValue);
                    }
                }
                else
                {
                    // line (non-invoice) level, no tax code combination rounding is straight forward for given tax codes.
                    return(taxContext.TaxCurrencyOperations.Round(taxCodeAmountNonRounded, taxCode.RoundingOff, taxCode.RoundingOffType));
                }
            }
예제 #7
0
 public TaxRepository(TaxContext context)
 {
     _context = context ?? throw new ArgumentNullException(nameof(context));
 }
예제 #8
0
            /// <summary>
            /// Initializes a new instance of the <see cref="TaxCode"/> class.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="lineItem">The taxable line item.</param>
            /// <param name="interval">The tax code interval.</param>
            /// <param name="taxContext">Tax context.</param>
            /// <param name="transaction">Current transaction.</param>
            public TaxCode(RequestContext context, TaxableItem lineItem, TaxCodeInterval interval, TaxContext taxContext, SalesTransaction transaction)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                if (interval == null)
                {
                    throw new ArgumentNullException("interval");
                }

                this.Code                 = interval.TaxCode;
                this.TaxableEntity        = lineItem;
                this.TaxGroup             = interval.TaxItemGroup;
                this.Currency             = interval.TaxCurrencyCode;
                this.Exempt               = interval.IsTaxExempt;
                this.TaxBase              = (TaxBase)interval.TaxBase;
                this.TaxLimitBase         = (TaxLimitBase)interval.TaxLimitBase;
                this.TaxCalculationMethod = (TaxCalculationMode)interval.TaxCalculationMethod;
                this.TaxOnTax             = interval.TaxOnTax;
                this.Unit                 = interval.TaxUnit;
                this.RoundingOff          = interval.TaxRoundOff;
                this.RoundingOffType      = Rounding.ConvertRoundOffTypeToRoundingMethod(interval.TaxRoundOffType);
                this.CollectLimitMax      = interval.TaxMaximum;
                this.CollectLimitMin      = interval.TaxMinimum;
                this.TaxGroupRounding     = interval.IsGroupRounding;
                this.IsTaxIncludedInTax   = interval.IsTaxIncludedInTax;

                this.TaxIntervals = new Collection <TaxInterval>(new List <TaxInterval>(1));

                // should this be removed in favor of intervals?
                this.Value          = interval.TaxValue;
                this.TaxLimitMin    = interval.TaxLimitMinimum;
                this.TaxLimitMax    = interval.TaxLimitMaximum;
                this.RequestContext = context;
                this.Transaction    = transaction;
                this.TaxIntervals.Add(new TaxInterval(interval.TaxLimitMinimum, interval.TaxLimitMaximum, interval.TaxValue));

                this.TaxContext = taxContext;
            }
예제 #9
0
            /// <summary>
            /// Gets the base price for tax included.
            /// </summary>
            /// <param name="taxableItem">The taxable item.</param>
            /// <param name="codes">The codes.</param>
            /// <param name="taxContext">The tax context.</param>
            /// <returns>The base price for tax included.</returns>
            public static decimal GetBasePriceForTaxIncluded(TaxableItem taxableItem, ReadOnlyCollection <TaxCode> codes, TaxContext taxContext)
            {
                // check to see if we can do the 'simple' Inclusive algorithm
                bool simpleBasis = codes.All(c =>
                                             (c.TaxBase == TaxBase.PercentPerNet || c.TaxBase == TaxBase.PercentGrossOnNet) &&
                                             (c.TaxLimitMin == decimal.Zero && c.TaxLimitMax == decimal.Zero));
                bool collectLimits      = codes.Any(c => (c.CollectLimitMax != decimal.Zero || c.CollectLimitMin != decimal.Zero));
                bool multiplePercentage = codes.Any(c => (c.TaxIntervals.Count > 1));

                if (simpleBasis && !collectLimits && !multiplePercentage)
                {
                    // Get base price for Simple TaxInclusive calculation
                    return(GetBasePriceSimpleTaxIncluded(taxableItem, codes));
                }
                else
                {
                    // Get base price for Full TaxInclusive calculation
                    return(GetBasePriceAdvancedTaxIncluded(taxableItem, codes, collectLimits, taxContext));
                }
            }
예제 #10
0
 public TaxDataProvider()
 {
     _ctx = new TaxContext();
 }
예제 #11
0
            private static decimal GetBasePriceAdvancedTaxIncluded(
                TaxableItem taxableItem, ReadOnlyCollection <TaxCode> codes, bool collectLimits, TaxContext taxContext)
            {
                // accumulation of amount based tax
                decimal fullLineUnitTax      = decimal.Zero;
                decimal nonExemptLineUnitTax = decimal.Zero;
                decimal codeValue            = decimal.Zero;

                // AX variables
                decimal endAmount = taxableItem.NetAmountWithAllInclusiveTaxPerUnit; // endAmount will be the final price w/o tax
                int     sign      = 1;

                // 3.
                decimal taxLimitMax = decimal.Zero;
                decimal taxLimitMin = decimal.Zero;
                decimal startAmount = decimal.Zero;

                // 3a...
                decimal taxCalc = decimal.Zero;
                decimal baseCur;

                // Tax Amount deducted for a given Code
                Dictionary <string, decimal> deductedTax = new Dictionary <string, decimal>();

                // 3b ...
                decimal percentTotal;
                decimal tmpBase;

                // 3c..
                // Whether or not a Code needs to be removed from the sum of percent rates
                Dictionary <string, bool> removePercent = new Dictionary <string, bool>();

                // 3d.
                decimal totalTax = decimal.Zero;

                // Whether or not the Code needs to be calculated
                Dictionary <string, bool> calcTax = new Dictionary <string, bool>();

                string storeCurrency = taxContext.ChannelCurrency;

                // Begin Tax included calculation
                // 0. Initialize the supporting collections
                foreach (TaxCode code in codes)
                {
                    deductedTax[code.Code]   = decimal.Zero;
                    removePercent[code.Code] = false;
                    calcTax[code.Code]       = true;
                }

                // 1. Remove all AmountByUnit taxes
                foreach (TaxCode code in codes.Where(c => c.TaxBase == TaxBase.AmountByUnit))
                {
                    codeValue             = code.Calculate(codes, false); // Reference dev item 5748.
                    fullLineUnitTax      += codeValue;
                    nonExemptLineUnitTax += code.Exempt ? decimal.Zero : codeValue;
                    calcTax[code.Code]    = false;
                }

                endAmount -= Math.Abs(nonExemptLineUnitTax);

                // 2. Record the sign, and then continue using the magnitude of endAmount
                sign      = (endAmount < decimal.Zero) ? -1 : 1;
                endAmount = Math.Abs(endAmount);

                // 3.
                while (startAmount < endAmount)
                {
                    // 3a Consider interval limits
                    taxCalc     = decimal.Zero;
                    taxLimitMax = decimal.Zero;

                    foreach (TaxCode code in codes)
                    {
                        if (code.TaxCalculationMethod == TaxCalculationMode.FullAmounts)
                        {
                            taxLimitMax = decimal.Zero;
                        }
                        else
                        {
                            if (code.IsStoreCurrency)
                            {
                                baseCur = taxContext.TaxCurrencyOperations.ConvertCurrency(storeCurrency, code.Currency, taxLimitMin);
                            }
                            else
                            {
                                baseCur = taxLimitMin;
                            }

                            baseCur += 1;

                            // if 'baseCur' falls into an interval
                            if (code.TaxIntervals.Exists(baseCur))
                            {
                                // get the Upper limit of the interval that 'baseCur'/'taxLimitMin' falls into
                                decimal amount = code.TaxIntervals.Find(taxLimitMin + 1).TaxLimitMax;
                                taxLimitMax = (amount != decimal.Zero && amount < endAmount) ? amount : endAmount;
                            }
                        }

                        taxCalc += deductedTax[code.Code];
                    }

                    // 3b. Sum up all the Tax Percentage Rates
                    percentTotal = 0;
                    tmpBase      = (taxLimitMax > decimal.Zero) ? taxLimitMax : endAmount;

                    foreach (TaxCode code in codes.Where(c => calcTax[c.Code]))
                    {
                        percentTotal += GetPercentPerTax(code, tmpBase, codes);
                    }

                    decimal taxMax;
                    decimal baseInclTax;
                    decimal baseExclTax;

                    // 3c.
                    // if this is the last interval??
                    if (taxLimitMax == decimal.Zero)
                    {
                        // Forward calculate taxes to see if we exceed the CollectLimit
                        foreach (TaxCode code in codes.Where(c => calcTax[c.Code]))
                        {
                            taxMax      = code.CollectLimitMax;
                            baseInclTax = endAmount - taxLimitMin - taxCalc;
                            baseExclTax = baseInclTax * 100 / (100 + percentTotal);

                            if (taxMax != decimal.Zero)
                            {
                                tmpBase = endAmount;

                                decimal percent = GetPercentPerTax(code, tmpBase, codes);

                                if ((deductedTax[code.Code] + (baseExclTax * percent / 100)) > taxMax)
                                {
                                    deductedTax[code.Code]   = taxMax;
                                    removePercent[code.Code] = true;
                                }
                            }
                        }

                        // 3d.
                        // Now remove any rates that exceed their LimitMax
                        foreach (TaxCode code in codes)
                        {
                            if (removePercent[code.Code] && calcTax[code.Code])
                            {
                                tmpBase            = endAmount;
                                percentTotal      -= GetPercentPerTax(code, tmpBase, codes);
                                calcTax[code.Code] = false;
                            }

                            taxCalc += deductedTax[code.Code];
                        }
                    }

                    // 4. Compute tax adjusted for limits
                    totalTax = decimal.Zero;
                    foreach (TaxCode code in codes.Where(c => c.TaxBase != TaxBase.AmountByUnit))
                    {
                        if (calcTax[code.Code])
                        {
                            tmpBase = (taxLimitMax > decimal.Zero) ? taxLimitMax : endAmount;

                            decimal percent = GetPercentPerTax(code, tmpBase, codes);

                            if (taxLimitMax > decimal.Zero && taxLimitMax < endAmount)
                            {
                                deductedTax[code.Code] += (taxLimitMax - taxLimitMin) * percent / 100;
                            }
                            else
                            {
                                baseInclTax             = endAmount - taxLimitMin - taxCalc;
                                baseExclTax             = baseInclTax * 100 / (100 + percentTotal);
                                deductedTax[code.Code] += baseExclTax * percent / 100;
                            }

                            taxMax = code.CollectLimitMax;

                            if (taxMax > decimal.Zero && deductedTax[code.Code] > taxMax)
                            {
                                deductedTax[code.Code] = taxMax;
                            }
                        }

                        totalTax += deductedTax[code.Code];
                    }

                    if (taxLimitMax > decimal.Zero)
                    {
                        taxLimitMin = taxLimitMax;
                        startAmount = taxLimitMin + totalTax;
                    }
                    else
                    {
                        startAmount = endAmount;
                    }
                } // END if( startAmount < endAmount)

                // 5a. Total up taxes
                foreach (TaxCode code in codes)
                {
                    if (collectLimits && (deductedTax[code.Code] < code.CollectLimitMin))
                    {
                        totalTax -= deductedTax[code.Code];
                        deductedTax[code.Code] = decimal.Zero;
                    }

                    if (code.IsStoreCurrency)
                    {
                        taxCalc = Rounding.RoundToUnit(deductedTax[code.Code], code.RoundingOff, code.RoundingOffType);
                    }
                    else
                    {
                        taxCalc = deductedTax[code.Code];
                    }

                    totalTax += taxCalc - deductedTax[code.Code];
                    deductedTax[code.Code] = taxCalc;
                }

                // 5b. Determine base price
                return((endAmount - totalTax) * sign);
            }
예제 #12
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TaxCodeProvider"/> class.
 /// </summary>
 /// <param name="taxContext">Tax context.</param>
 internal TaxCodeProvider(TaxContext taxContext)
 {
     this.TaxContext          = taxContext;
     this.Identifier          = "LSRetailPosis.TaxService.DefaultTaxProvider";
     this.transactionTaxCodes = new Collection <TaxCode>();
 }
예제 #13
0
 public FinanceRepo(TaxContext c)
 {
     context = c;
 }
예제 #14
0
            /// <summary>
            /// Initializes a new instance of the <see cref="TaxCodeIndia"/> class.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="taxableItem">The taxable line item.</param>
            /// <param name="taxCodeInterval">The tax code interval.</param>
            /// <param name="taxContext">Tax context.</param>
            /// <param name="transaction">Current transaction.</param>
            public TaxCodeIndia(
                RequestContext context, TaxableItem taxableItem, TaxCodeIntervalIndia taxCodeInterval, TaxContext taxContext, SalesTransaction transaction)
                : base(context, taxableItem, taxCodeInterval, taxContext, transaction)
            {
                if (context == null)
                {
                    throw new ArgumentNullException("context");
                }

                if (taxCodeInterval == null)
                {
                    throw new ArgumentNullException("taxCodeInterval");
                }

                this.TaxType           = taxCodeInterval.TaxType;
                this.AbatementPercent  = taxCodeInterval.AbatementPercent;
                this.taxCodesInFormula = new List <string>();
            }
예제 #15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TaxCodeProviderIndia"/> class.
 /// </summary>
 /// <param name="taxContext">Tax context.</param>
 internal TaxCodeProviderIndia(TaxContext taxContext)
     : base(taxContext)
 {
 }
예제 #16
0
 public TaxDataProvider(TaxContext context)
 {
     _ctx = context;
 }
예제 #17
0
 public MunicipalityDataProvider()
 {
     _ctx = new TaxContext();
 }
예제 #18
0
 public MunicipalityDataProvider(TaxContext context)
 {
     _ctx = context;
 }
 public MunicipalityTaxService(TaxContext context)
 {
     _context = context;
 }