public TaxCalculator(int[] intervals, double[] rates) { if (intervals.Length != rates.Length - 1) { throw new ArgumentException("You must specify rates for each interval"); } if (intervals.Distinct().Count() != intervals.Count()) { throw new ArgumentException("The values of the passed list of intervals are not unique"); } Array.Sort(intervals); Length = rates.Length; this.intervals = new TaxInterval[Length]; for (int i = 0; i < intervals.Length; i++) { this[i] = new TaxInterval(intervals[i], rates[i]); } this[intervals.Length] = new TaxInterval(int.MaxValue, rates[intervals.Length]); }
/// <summary> /// Gets the basic rate for this tax. /// </summary> /// <param name="limitBase">The limit base.</param> /// <returns>The basic rate.</returns> public decimal PercentPerTax(decimal limitBase) { // Find the interval for this limitBase TaxInterval interval = this.TaxIntervals.Find(limitBase); decimal intervalRate = interval.Value; switch (this.TaxBase) { case TaxBase.PercentPerTax: if (!string.IsNullOrEmpty(this.TaxOnTax) && this.TaxOnTaxInstance != null) { return((intervalRate * this.TaxOnTaxInstance.Value) / 100); } return(decimal.Zero); case TaxBase.PercentPerGross: if (!string.IsNullOrEmpty(this.TaxOnTax) && this.TaxOnTaxInstance != null) { return(intervalRate + ((intervalRate * this.TaxOnTaxInstance.Value) / 100)); } return(intervalRate); case TaxBase.PercentGrossOnNet: return(PercentGrossOnNet(intervalRate)); case TaxBase.AmountByUnit: case TaxBase.PercentPerNet: default: return(intervalRate); } }
protected virtual ReadOnlyCollection <TaxCode> GetTaxCodes(TaxableItem taxableItem, RequestContext context, SalesTransaction transaction) { ThrowIf.Null(taxableItem, "taxableItem"); ThrowIf.Null(context, "context"); try { Dictionary <string, TaxCode> codes = new Dictionary <string, TaxCode>(); // If the line has an EndDate specified (usually because it's a Returned line), // then use that value to calculate taxes, otherwise use BeginDate TaxDateAndGroups key = new TaxDateAndGroups(this.GetTaxDate(taxableItem), taxableItem.SalesTaxGroupId, taxableItem.ItemTaxGroupId); ReadOnlyCollection <TaxCodeInterval> taxCodeIntervals = null; if (key.IsNoTax) { taxCodeIntervals = new List <TaxCodeInterval>().AsReadOnly(); } else if (!this.TaxContext.TaxCodeInternalsLookup.TryGetValue(key, out taxCodeIntervals)) { // Shouldn't get here. taxCodeIntervals = this.GetTaxCodeIntervals(context, taxableItem.SalesTaxGroupId, taxableItem.ItemTaxGroupId, key.TaxDate); } foreach (TaxCodeInterval taxCodeInterval in taxCodeIntervals) { if (codes.ContainsKey(taxCodeInterval.TaxCode)) { // Add a new 'value' entry for an existing tax code var taxInterval = new TaxInterval(taxCodeInterval.TaxLimitMinimum, taxCodeInterval.TaxLimitMaximum, taxCodeInterval.TaxValue); codes[taxCodeInterval.TaxCode].TaxIntervals.Add(taxInterval); } else { this.AddTaxCode(context, taxableItem, taxCodeInterval, codes, transaction); } } // Link any taxes which rely on other taxes foreach (TaxCode tax in codes.Values) { if (!string.IsNullOrEmpty(tax.TaxOnTax) && (tax.TaxBase == TaxBase.PercentPerTax || tax.TaxBase == TaxBase.PercentPerGross) && codes.Keys.Contains(tax.TaxOnTax)) { tax.TaxOnTaxInstance = codes[tax.TaxOnTax]; } } return(this.SortCodes(codes)); } catch (Exception ex) { RetailLogger.Log.CrtServicesTaxCodeProviderTaxServiceGetTaxCodesFailure(ex); throw; } }
/// <summary> /// Determine whether any portion of the given amount is within the given interval. /// </summary> /// <param name="interval">The interval.</param> /// <param name="amount">The amount.</param> /// <returns>A value indicating whether the amount is in the tax interval.</returns> /// <example> /// Interval = $25 - $100. /// Amount = $10 returns FALSE. /// Amount = $50 returns TRUE. /// Amount = $150 returns TRUE. /// </example> /// <remarks>This belongs to TaxInterval.</remarks> public static bool AmountInInterval(this TaxInterval interval, decimal amount) { return((interval.TaxLimitMin == decimal.Zero) || (interval.TaxLimitMin < amount)); }
/// <summary> /// Determine whether the given amount is wholly within the interval. /// </summary> /// <param name="interval">The interval.</param> /// <param name="amount">The amount.</param> /// <returns>A value indicating whether the amount is entirely within the tax interval.</returns> /// <example> /// Interval = $25 - $100. /// Amount = $10 returns FALSE. /// Amount = $50 returns TRUE. /// Amount = $150 returns FALSE. /// </example> /// <remarks>This belongs to TaxInterval.</remarks> public static bool WholeAmountInInterval(this TaxInterval interval, decimal amount) { // return if the amount is in within the interval or equal to either end. return((interval.TaxLimitMin == decimal.Zero || interval.TaxLimitMin <= amount) && (interval.TaxLimitMax == decimal.Zero || interval.TaxLimitMax >= amount)); }