java.lang.Object
com.broadleafcommerce.billing.job.service.impl.DefaultDelegatingTaxService<P,Q,R>
All Implemented Interfaces:
TaxService<P,Q,R>

public class DefaultDelegatingTaxService<P extends BillingEventItem,Q extends BillingTaxDetail,R extends BillingProcessingRequestWithBillingEventDTO> extends Object implements TaxService<P,Q,R>
This implementation of TaxService calls TaxDelegate, which has a discovery process to determine the best TaxProvider implementation based on configured properties, the provided TaxCalculationRequest, and the ContextInfo.
Author:
Kelly Tisdell (ktisdell), Chris Kittrell (ckittrell)
  • Field Details

  • Constructor Details

    • DefaultDelegatingTaxService

      public DefaultDelegatingTaxService(@NonNull @NonNull com.broadleafcommerce.tax.delegate.TaxDelegate<?,?> taxDelegate, @NonNull @NonNull com.broadleafcommerce.common.extension.TypeFactory typeFactory)
  • Method Details

    • calculateTaxForBillingEventItems

      public Map<P,List<Q>> calculateTaxForBillingEventItems(R billingProcessingRequestWithBillingEventDTO, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Specified by:
      calculateTaxForBillingEventItems in interface TaxService<P extends BillingEventItem,Q extends BillingTaxDetail,R extends BillingProcessingRequestWithBillingEventDTO>
    • setAllTaxToZero

      protected void setAllTaxToZero(BillingEvent billingEvent, List<P> billingEventItems, javax.money.CurrencyUnit expectedCurrency, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Sets all item tax totals to 0 with the given currency. It also sets the billing event tax total to 0 of the given currency.
    • mapDoesNotContainTaxDetails

      protected boolean mapDoesNotContainTaxDetails(Map<P,List<Q>> itemsWithTaxDetailsMap)
      Determines whether the tax calculation was successful. If the given map is empty or does not contain any tax details, it must not have been.
      Parameters:
      itemsWithTaxDetailsMap - map of items with their tax details after tax calculation
      Returns:
      whether this map contains tax details, and by extension, had its taxes calculated successfully
    • buildEmptyTaxMap

      protected Map<P,List<Q>> buildEmptyTaxMap(List<P> billingEventItems)
    • canCalculateTaxes

      protected boolean canCalculateTaxes(@Nullable BillingEvent billingEvent, @NonNull @NonNull List<P> billingEventItems, @Nullable BillingEventAddress billingEventAddress, javax.money.CurrencyUnit expectedCurrency, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • isPreTaxBillingEventTotalGreaterThanZeroOrNull

      protected boolean isPreTaxBillingEventTotalGreaterThanZeroOrNull(BillingEvent billingEvent, javax.money.CurrencyUnit expectedCurrency, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • billingEventAddressHasSufficientData

      protected boolean billingEventAddressHasSufficientData(@Nullable BillingEventAddress billingEventAddress, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • hasTaxItems

      protected boolean hasTaxItems(com.broadleafcommerce.tax.domain.TaxCalculationRequest request, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Determine if there are tax items on the given request.
      Parameters:
      request - The TaxCalculationRequest to check.
      contextInfo - The context of this request.
      Returns:
      FALSE if there are no Tax Items on the request. TRUE if there are any present.
    • groupBillingEventItemsByNexus

      protected Map<String,List<P>> groupBillingEventItemsByNexus(@NonNull @NonNull List<P> billingEventItems)
    • createRequest

      protected com.broadleafcommerce.tax.domain.TaxCalculationRequest createRequest(BillingEvent billingEvent, List<P> billingEventItems, Map<P,List<BillingEventItemAdjustment>> billingEventItemsWithAdjustments, BillingEventAddress billingEventAddress, javax.money.CurrencyUnit expectedCurrency, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • determineBillingEventId

      protected String determineBillingEventId(BillingEvent billingEvent, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      We require the BillingEvent.getId(), in most cases. However, if, for some reason, there is no ID available on the event, then we provide a UUID. The BillingEvent ID is generally used to tie requests together in some Tax Provider systems.
    • determinePreferredProviderId

      @Nullable protected String determinePreferredProviderId(BillingEvent billingEvent, List<P> billingEventItems, BillingEventAddress billingEventAddress, boolean estimate, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      This method returns the "preferred" Tax Provider ID, which is determined by TaxProvider.getProviderId(). By default, this will be null. This provides a hook point to allow someone to specify the Tax Provider that should be prioritized for use. For example, you may wish to return SimpleTaxProvider.SIMPLE_TAX_PROVIDER_ID for estimates. In this case you could override this method to do so if the estimate argument is true, and return null otherwise. To be clear, this does not guarantee that the TaxProvider specified will be used; only that it will be prioritized for use. If there is no TaxProvider registered with that ID, then it will be ignored. Or, if the TaxProvider exists with that ID, but it cannot handle the request, then it will be ignored.
    • shouldCalculateItemTaxes

      protected boolean shouldCalculateItemTaxes(BillingEvent billingEvent, P billingEventItem, List<BillingEventItemAdjustment> itemAdjustments, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • calculatePreTaxItemTotal

      protected javax.money.MonetaryAmount calculatePreTaxItemTotal(P billingEventItem, List<BillingEventItemAdjustment> itemAdjustments, javax.money.CurrencyUnit currency)
      This adds up the item total for a given item prior to taxes. It adjusts the unit price with the total sum of all active adjustments for this item. Then, that adjusted price is multiplied by item quantity and returned.

      Note that event-level adjustments are prorated into each item's BillingEventItemAdjustment when the billing event is created in DefaultBillingEventService.generateProratedEventItemAdjustments(List, List).

    • buildTaxItemForBillingEventItem

      protected com.broadleafcommerce.tax.domain.TaxItem buildTaxItemForBillingEventItem(BillingEvent billingEvent, P billingEventItem, List<BillingEventItemAdjustment> itemAdjustments, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • itemIncludesTaxes

      protected boolean itemIncludesTaxes(BillingEvent billingEvent, P billingEventItem, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      In some situations, especially in European countries, for example, merchants are required to display all prices including tax. This is especially common with VAT. So, in some situations the price of an item will include Value Added Taxes. Some providers (e.g. Avalara) will attempt to back-calculate the taxes from the price of the item if we indicate that tax is included in the price. While the customer does not need to pay additional taxes, this allows us to calculate taxes owed for this item, which we can store on the tax details for informational purposes and remediation. NOTE: By default, this method returns false. Broadleaf Commerce does not currently provide a mechanism to determine if tax is included because catalogs, products, variants, and even pricing can be shared across applications and countries. Implementors may wish to override this method to return true under certain circumstances. For example, if the destination country is a European country (e.g. GB or FR) and/or the currency is a European currency, then you may wish to return true. The ContextInfo (i.e. the tenant or application) may also inform this decision.
    • buildTaxCalculationGroups

      protected List<com.broadleafcommerce.tax.domain.TaxCalculationGroup> buildTaxCalculationGroups(BillingEvent billingEvent, BillingEventAddress billingEventAddress, List<com.broadleafcommerce.tax.domain.TaxItem> taxItems, com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Builds a list of groups, which is used to calculate taxes for a group of items being shipped to or fulfilled at a particular Address.

      Some tax providers desire requests to be sent in particular groups, such as ones from the same country or for a single business entity. This method serves as a hook-point to be extended to create such a customization.

    • buildTaxCalculationGroup

      protected com.broadleafcommerce.tax.domain.TaxCalculationGroup buildTaxCalculationGroup(BillingEvent billingEvent, BillingEventAddress billingEventAddress, @NonNull @NonNull List<com.broadleafcommerce.tax.domain.TaxItem> taxItems, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Builds a TaxCalculationGroup, which is used to calculate taxes for a group of items being shipped to or fulfilled at a particular Address.
    • buildTaxAddress

      protected com.broadleafcommerce.tax.domain.TaxAddress buildTaxAddress(BillingEventAddress billingEventAddress)
    • executeTaxCalculation

      protected com.broadleafcommerce.tax.domain.TaxCalculationResponse executeTaxCalculation(@NonNull @NonNull com.broadleafcommerce.tax.domain.TaxCalculationRequest request, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • applyTaxResponses

      protected Map<P,List<Q>> applyTaxResponses(@NonNull @NonNull com.broadleafcommerce.tax.domain.TaxCalculationResponse response, BillingEvent billingEvent, Map<P,List<Q>> itemsWithTaxDetails, javax.money.CurrencyUnit expectedCurrency, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • applyTaxDetails

      protected Map<P,List<Q>> applyTaxDetails(BillingEvent billingEvent, Map<P,List<Q>> itemsWithTaxDetails, com.broadleafcommerce.tax.domain.TaxResponseGroup taxResponseGroup, javax.money.MonetaryAmount totalGroupTax, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
    • debugLogTrimmedTaxResponse

      protected void debugLogTrimmedTaxResponse(@NotNull @NotNull com.broadleafcommerce.tax.domain.TaxCalculationResponse response)
    • getTaxItemIdForBillingEventItem

      protected String getTaxItemIdForBillingEventItem(BillingEvent billingEvent, P billingEventItem)
      Extension point to modify the TaxItem.getItemId() for tax items. For some TaxProviders, there may be an affix like FR (for freight) to add to the BillingEventItem.getId(). Alternatively, some providers may combine the item id with the billing event id.
      Parameters:
      billingEvent - billing event from which to derive an id
      billingEventItem - item from which to derive an id
      Returns:
      TaxItem.getItemId() for billing event item tax items
    • buildItemTaxes

      protected List<Q> buildItemTaxes(@NonNull @NonNull com.broadleafcommerce.tax.domain.TaxInfo taxInfo, @NonNull P billingEventItem, @Nullable com.broadleafcommerce.data.tracking.core.context.ContextInfo contextInfo)
      Add BillingTaxDetails to the billing event item.
      Parameters:
      taxInfo - The tax info
      billingEventItem - The billing event item
      contextInfo - the contextInfo for this request
    • buildTaxDetailWithNonNumericalFields

      protected Q buildTaxDetailWithNonNumericalFields(com.broadleafcommerce.tax.domain.TaxDetail taxDetail, P billingEventItem)
    • getTypeFactory

      protected com.broadleafcommerce.common.extension.TypeFactory getTypeFactory()
    • getTaxDelegate

      protected com.broadleafcommerce.tax.delegate.TaxDelegate<?,?> getTaxDelegate()
    • getMapper

      protected com.fasterxml.jackson.databind.ObjectMapper getMapper()
    • setMapper

      @Autowired public void setMapper(com.fasterxml.jackson.databind.ObjectMapper mapper)