/// <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)); }
public AddTaxViewModel(IEventAggregator ea, IOfficeContext context) { eventAggregator = ea; this.context = context; TaxDTO = new TaxContext(); TaxList = new ObservableCollection <TaxContext>(); LoadTaxList(); }
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); }
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}"); }
/// <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); }
/// <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)); } }
public TaxRepository(TaxContext context) { _context = context ?? throw new ArgumentNullException(nameof(context)); }
/// <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; }
/// <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)); } }
public TaxDataProvider() { _ctx = new TaxContext(); }
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); }
/// <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>(); }
public FinanceRepo(TaxContext c) { context = c; }
/// <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>(); }
/// <summary> /// Initializes a new instance of the <see cref="TaxCodeProviderIndia"/> class. /// </summary> /// <param name="taxContext">Tax context.</param> internal TaxCodeProviderIndia(TaxContext taxContext) : base(taxContext) { }
public TaxDataProvider(TaxContext context) { _ctx = context; }
public MunicipalityDataProvider() { _ctx = new TaxContext(); }
public MunicipalityDataProvider(TaxContext context) { _ctx = context; }
public MunicipalityTaxService(TaxContext context) { _context = context; }