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;
                }
            }
            private void FixTaxCodeIntervalsLookup(RequestContext context, List <TaxableItem> taxableItems)
            {
                foreach (TaxableItem taxableItem in taxableItems)
                {
                    TaxDateAndGroups key = new TaxDateAndGroups(this.GetTaxDate(taxableItem), taxableItem.SalesTaxGroupId, taxableItem.ItemTaxGroupId);

                    if (!key.IsNoTax)
                    {
                        if (!this.TaxContext.TaxCodeInternalsLookup.ContainsKey(key))
                        {
                            this.TaxContext.TaxCodeInternalsLookup.Add(key, this.GetTaxCodeIntervals(context, key.SalesTaxGroup, key.ItemTaxGroup, key.TaxDate));
                        }
                    }
                }
            }