java.lang.Object
com.broadleafcommerce.promotion.offer.service.engine.application.processor.DefaultItemOfferProcessor
All Implemented Interfaces:
ItemOfferProcessor

public class DefaultItemOfferProcessor extends Object implements ItemOfferProcessor
Author:
Chad Harchar (charchar)
  • Field Details

  • Constructor Details

  • Method Details

    • findBestItemOffersForPermutation

      public void findBestItemOffersForPermutation(OfferProcessingContext context, CombinedTypesOfferPermutation ctop)
      Specified by:
      findBestItemOffersForPermutation in interface ItemOfferProcessor
    • determineBestPermutationGivenEqualAdjustmentValues

      protected ItemOfferPermutationResult determineBestPermutationGivenEqualAdjustmentValues(AtomicReference<ItemOfferPermutationResult> bestPermutation, ItemOfferPermutationResult result)
      Hook point where both permutations offering the same discount, which permutation should be chosen. By default, this returns the existing best permutation.
      Parameters:
      bestPermutation - Current best permutation result during evaluation
      result - The permutation result to check against the best permutation
      Returns:
      The determined best permutation
    • updateBestPermutation

      protected void updateBestPermutation(CombinedTypesOfferPermutation ctop, ItemOfferPermutationResult bestPermutation)
    • applyItemAdjustments

      public void applyItemAdjustments(OfferProcessingContext context, ItemOfferPermutationResult result)
      Description copied from interface: ItemOfferProcessor
      For item processing, the adjustments are stored on LineItemOfferDetail records. These detail records are stored in the ItemOfferPermutationResult.getLineItemDetailMap()
      Specified by:
      applyItemAdjustments in interface ItemOfferProcessor
    • prepareForItemOfferProcessing

      public void prepareForItemOfferProcessing(EnhancedOrder order, List<CandidateItemOffer> candidateItemOffers)
      Description copied from interface: ItemOfferProcessor
      Item offer processing can benefit from setup activities that are used by all of the permutations. Most notably, finding the maximum savings for a given offer which can be used to prioritize the order in which offers are attempted within a cart.
      Specified by:
      prepareForItemOfferProcessing in interface ItemOfferProcessor
    • clearStateBetweenPermutations

      protected void clearStateBetweenPermutations(EnhancedOrder order, List<CandidateItemOffer> candidateOffers)
    • computeOfferPermutationValue

      protected ItemOfferPermutationResult computeOfferPermutationValue(OfferProcessingContext context, List<CandidateItemOffer> candidateItemOffers, OrderTotals orderTotals)
    • calculatePotentialSavings

      protected void calculatePotentialSavings(EnhancedOrder order, List<CandidateItemOffer> candidateItemOffers)
    • sort

      protected void sort(List<CandidateItemOffer> candidateItemOffers)
      The default based on the CandidateItemOfferComparator
      Parameters:
      candidateItemOffers -
    • applyCandidateOffers

      protected void applyCandidateOffers(@NonNull EnhancedOrder order, @NonNull List<CandidateItemOffer> candidateOffers, ItemOfferPermutationResult result)
    • applyCandidateOffers

      @Deprecated(since="1.8.0", forRemoval=true) protected void applyCandidateOffers(@NonNull EnhancedOrder order, @NonNull List<CandidateItemOffer> candidateOffers)
      Deprecated, for removal: This API element is subject to removal in a future version.
    • expandPermutations

      protected List<List<CandidateItemOffer>> expandPermutations(List<CandidateItemOffer> itemOffers)

      This method takes a list of item offers that are compatible with each other and share the same combinability characteristics with other types like order offers and builds additional permutations that influence the order that the offers will be run.

      Even though two offers are compatible to be in the same offer, the results of the offer engine can be different depending on the order they are applied due to complexities involving qualifiers and bundle offers.

      For most scenarios, these complexities can be managed with using explicit priorities, exclusions and stacking rules.

      <By default, this method expands the included permutation into at most three additional permutations as follows:

      • A permutation based on default sorting rules and potential savings
      • A permutation based on considering savings on weighted potential savings
      • A permutation based on savings tied to qty 1
    • getPermutationByComparator

      protected List<CandidateItemOffer> getPermutationByComparator(List<CandidateItemOffer> rootPremutation, Comparator<CandidateItemOffer> comparator)
      Uses a Comparator to sort candidate offers. The default comparators to use are ItemOfferQtyOneComparator and ItemOfferWeightedPercentSavedComparator. Each ordering is considered its own permutation since the order in which offers are applied affects the end price.
      See Also:
    • removeDuplicatePermutations

      protected void removeDuplicatePermutations(List<List<CandidateItemOffer>> permutations)
      A duplicate permutation means that the permutations have the same offers in the same order.
      Parameters:
      permutations - contains lists of compatible CandidateItemOffers
    • findBestPermutation

      @Deprecated(since="Offer Service 3.1.0", forRemoval=true) protected Optional<List<CandidateItemOffer>> findBestPermutation(EnhancedOrder order, List<List<CandidateItemOffer>> permutations)
      Deprecated, for removal: This API element is subject to removal in a future version.
      Unused.
      Determines the best permutation by comparing the resulting total discounts of each permutations.
    • applyItemOffer

      protected void applyItemOffer(EnhancedOrder order, CandidateItemOffer itemOffer)
    • canOfferBeApplied

      protected boolean canOfferBeApplied(EnhancedOrder order, CandidateItemOffer itemOffer, List<LineItemOfferDetail> itemDetails, ItemOfferPermutationResult result)
      Determines whether the Offer can be applied by making sure it is the order meets the total requirements.
      Returns:
      whether the offer can be applied.
    • canOfferBeApplied

      protected boolean canOfferBeApplied(EnhancedOrder order, CandidateItemOffer itemOffer, List<LineItemOfferDetail> itemDetails)
    • applyItemQualifiersAndTargets

      protected void applyItemQualifiersAndTargets(EnhancedOrder order, CandidateItemOffer itemOffer)
    • splitDetailsIfNecessary

      protected void splitDetailsIfNecessary(List<LineItemOfferDetail> offerDetails, CandidateItemOffer itemOffer)
      Checks if the discount quantity matches the detail quantity. If not, splits the price detail.
    • calculatePartialSavingsAmountForDiscount

      protected javax.money.MonetaryAmount calculatePartialSavingsAmountForDiscount(CandidateItemOffer itemOffer, OfferDiscount discount)
    • applyAdjustments

      protected void applyAdjustments(EnhancedOrder order, CandidateItemOffer itemOffer)
    • compatibleWithSegment

      protected boolean compatibleWithSegment(String offerSegment, String itemSegment)
    • calculatePriceForBundleRatio

      protected javax.money.MonetaryAmount calculatePriceForBundleRatio(LineItemOfferDetail detail)
    • applyFreeGift

      protected void applyFreeGift(EnhancedOrder order, CandidateItemOffer itemOffer)
      Builds and adds a FreeGiftItem to EnhancedOrder.getFreeGiftItems() based on CandidateItemOffer.getCandidateQualifiersMap() if the given itemOffer is a free gift offer.
      Parameters:
      order - order to apply the free gift offers to
      itemOffer - offer to build the FreeGiftItem and get the qualifiers from
    • getFreeGiftQuantityToAdd

      protected int getFreeGiftQuantityToAdd(CandidateItemOffer itemOffer)
      Gets the quantity of the free gift items to be added from the given CandidateItemOffer.

      If the Offer.hasItemQualifierCriteriaRules() is false, the quantity of free gift items should default to 1 since no qualifier items would be marked.

      Parameters:
      itemOffer - the free gift offer to calculate the quantity of free gift items for
      Returns:
      the quantity of the free gift items to be added
    • buildFreeGiftItem

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.FreeGiftItem buildFreeGiftItem(Offer offer, int quantityToAdd, com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment adjustment)
      Builds a FreeGiftItem from the given Offer, quantity, and qualifier item ids.
      Parameters:
      offer - the free gift offer to build the FreeGiftItem from
      quantityToAdd - the quantity of the FreeGiftItem
      adjustment - the ItemAdjustment of the FreeGiftItem
      Returns:
      FreeGiftItem from the given Offer, quantity, and adjustment
    • buildGiftItemWithFee

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.FreeGiftItem buildGiftItemWithFee(Offer offer, int quantityToAdd, com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment adjustment)
      Builds a FreeGiftItem from the given Offer, quantity, and qualifier item ids.
      Parameters:
      offer - the free gift offer to build the FreeGiftItem from
      quantityToAdd - the quantity of the FreeGiftItem
      Returns:
      FreeGiftItem from the given Offer, quantity, and adjustment
    • buildReducedFeeGiftDetail

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.ItemProrationDetail buildReducedFeeGiftDetail(Offer offer, int quantityToAdd)
    • getFreeGiftObject

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.FreeGiftItem getFreeGiftObject(Offer offer, int quantityToAdd, com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment adjustment)
    • buildAdjustmentForFreeGift

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment buildAdjustmentForFreeGift(EnhancedOrder order, CandidateItemOffer itemOffer)
      Builds an Adjustment for a FreeGiftItem.
      Parameters:
      order - the EnhancedOrder the FreeGiftItem will be added to
      itemOffer - the CandidateItemOffer for the free gift
      Returns:
      an Adjustment for then free gift offer
    • addOrderCodeToAdjustmentIfUsed

      protected void addOrderCodeToAdjustmentIfUsed(@NonNull @NonNull Offer offer, @NonNull @NonNull com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment adjustment, @NonNull @NonNull Set<String> allOrderCodes)
      Adds an offer code to the given Adjustment if it is present on the order.
      Parameters:
      offer - Offer from which the adjustment is derived.
      adjustment - Adjustment The Adjustment for which an offer code may apply
      allOrderCodes - Set of all of the shared or campaign codes set on the order. These may have been used to apply an offer and should be recorded on any Adjustments.
    • isAdjustmentGoodEnough

      protected boolean isAdjustmentGoodEnough(CandidateItemOffer itemOffer, LineItemOfferDetail detail)
      Checking to make sure that an offer's adjustment to an item's price is actually better than the original price, especially if the item is on sale since not all offers can apply to a sale price. If the offer can apply to the sale price, it must be good enough to apply.
    • isRecurringAdjustmentGoodEnough

      protected boolean isRecurringAdjustmentGoodEnough(@NonNull @NonNull CandidateItemOffer itemOffer, @NonNull @NonNull EnhancedLineItem lineItem)
      isAdjustmentGoodEnough(CandidateItemOffer, LineItemOfferDetail) delegates to this method to handle whether a recurring (a.k.a., subscription) adjustment is good enough to keep considering.
      Parameters:
      itemOffer - The candidate offer
      lineItem - The target item
      Returns:
      Whether the offer is good enough to keep.
      Since:
      Offer Service 3.1.0, Release Train 2.2.0
    • applyLineItemAdjustment

      protected void applyLineItemAdjustment(@NonNull @NonNull CandidateItemOffer itemOffer, @NonNull @NonNull LineItemOfferDetail offerDetail, @NonNull @NonNull OfferDiscount offerDiscount)
      Parameters:
      itemOffer - the CandidateItemOffer to build the ItemOfferAdjustment from
      offerDetail - the LineItemOfferDetail to add the ItemOfferAdjustment to
      offerDiscount - the OfferDiscount to get the target criteria rule from
    • computeAdjustmentValue

      protected javax.money.MonetaryAmount computeAdjustmentValue(@NonNull @NonNull CandidateItemOffer itemOffer, @NonNull @NonNull LineItemOfferDetail offerDetail, boolean useSalePrice)
      Computes the adjustment value taking into account whether the sale price is discountable and whether a recurring price should be discounted rather than the upfront.
      Parameters:
      itemOffer - The offer to apply
      offerDetail - The details about the item being discounted
      useSalePrice - Whether to use the sale price in the computation.
      Returns:
      The adjustment value.
    • computeNumberOfPeriodsToDiscount

      protected int computeNumberOfPeriodsToDiscount(@NonNull @NonNull CandidateItemOffer itemOffer, @NonNull @NonNull LineItemOfferDetail offerDetail, boolean useSalePrice)
      Determines the number of periods to discount for DefaultAdjustmentType.RECURRING_DISCOUNT adjustments. Returns 1 if the offer is not a subscription discount—this value will not matter in that case.
      Parameters:
      itemOffer - The offer to apply.
      offerDetail - The details about the line item receiving the offer.
      useSalePrice - Whether to calculate the result based on the sale price.
      Returns:
      The number of periods to discount.
    • getQualifierDetails

      protected List<com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetail> getQualifierDetails(@NonNull @NonNull CandidateItemOffer itemOffer, @Nullable OfferDiscount offerDiscount)
      Gets a list of OfferItemDetails representing qualifiers.
      Parameters:
      itemOffer - the CandidateItemOffer to get the qualifier items from
      offerDiscount - optional offer discount in order to filter usage details
      Returns:
      a list of OfferItemDetails representing qualifiers
    • itemHasQualifierOfferDetails

      protected boolean itemHasQualifierOfferDetails(@NonNull @NonNull EnhancedLineItem item, @NonNull @NonNull CandidateItemOffer itemOffer, @Nullable OfferDiscount offerDiscount)
      Determines whether the given EnhancedLineItem has any OfferItemDetails that has any OfferQualifiers matching the given CandidateItemOffer.
      Parameters:
      item - the EnhancedLineItem to check against
      itemOffer - the CandidateItemOffer to match
      offerDiscount - optional offer discount in order to filter usage details
      Returns:
      true if the given EnhancedLineItem has any OfferItemDetails that has any OfferQualifiers matching the given CandidateItemOffer, otherwise false
    • createOfferItemDetailAndDetermineQualifierQuantity

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetail createOfferItemDetailAndDetermineQualifierQuantity(@NonNull @NonNull CandidateItemOffer itemOffer, @NonNull @NonNull EnhancedLineItem lineItem, @Nullable OfferDiscount offerDiscount, int quantityPerUsage)
      Creates an OfferItemDetail based on the given fields.
      Parameters:
      itemOffer - the CandidateItemOffer to build the details from
      lineItem - the qualifier item candidate
      offerDiscount - optional offer discount in order to filter on usage details
      quantityPerUsage - the quantity per usage
      Returns:
      an OfferItemDetail based on the given fields
    • createOfferItemDetail

      protected com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetail createOfferItemDetail(CandidateItemOffer itemOffer, String itemId, int quantityPerUsage)
      Creates an OfferItemDetail based on the given fields.
      Parameters:
      itemOffer - the CandidateItemOffer to build the details from
      itemId - the item id
      quantityPerUsage - the quantity per usage
      Returns:
      an OfferItemDetail based on the given fields
    • computeStandardAdjustmentValue

      protected javax.money.MonetaryAmount computeStandardAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)
    • computeRecurringStandardAdjustmentValue

      protected javax.money.MonetaryAmount computeRecurringStandardAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)
    • computeSaleAdjustmentValue

      protected javax.money.MonetaryAmount computeSaleAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)
    • computeRecurringSaleAdjustmentValue

      protected javax.money.MonetaryAmount computeRecurringSaleAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)
    • chooseSaleOrStandardAdjustments

      protected void chooseSaleOrStandardAdjustments(EnhancedOrder order)
      Some Offers can only apply to the EnhancedLineItem.getStandardPrice(). This method determines whether standard-price-only promotions should be used instead of those that can apply to the sale price as well.
    • addFreeGiftsToResult

      protected void addFreeGiftsToResult(OfferProcessingContext context, ItemOfferPermutationResult result)
    • getEstimatedFreeGiftValue

      protected javax.money.MonetaryAmount getEstimatedFreeGiftValue(EnhancedOrder order, Offer offer)
    • mergePriceDetails

      protected void mergePriceDetails(EnhancedOrder order)
      Checks to see if any LineItemOfferDetails need to be combined and if so, combines them.
    • getCandidateItemOffers

      protected List<CandidateItemOffer> getCandidateItemOffers(OfferProcessingContext context)
    • setCandidateItemOffers

      protected void setCandidateItemOffers(CandidateOffers candidateOffers, List<CandidateItemOffer> candidateItemOffers)
    • assertCommonParamsNotNull

      protected void assertCommonParamsNotNull(EnhancedOrder order, CandidateOffers candidateOffers)
    • assertCandidateOffersNotNull

      protected void assertCandidateOffersNotNull(CandidateOffers candidateOffers)
    • addCodeResponseToPermutationResult

      protected void addCodeResponseToPermutationResult(EnhancedOrder order, Offer offer, ItemOfferPermutationResult result, com.broadleafcommerce.promotion.offer.client.web.context.discounts.CodeResponse codeResponse)
      Adds the CodeResponse to the ItemOfferPermutationResult for the provided offer.
      Parameters:
      order - provides context information around offers and offer codes
      offer - the offer to add the code responses for
      result - the permutation result to add the code response to
      codeResponse - the code response to be added
    • logIfDebugOn

      protected void logIfDebugOn(String message, Object... formatArgs)
      Checks if debug is enabled, then wraps the message in String.format(String, Object...) with the given formatArgs and logs it.
    • logIfTraceOn

      protected void logIfTraceOn(String message, Object... formatArgs)
      Checks if Log.isTraceEnabled() trace is enabled}, then wraps the message in String.format(String, Object...) with the given formatArgs and logs it.