Class DefaultItemOfferProcessor
- 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 Summary
Fields Modifier and Type Field Description protected OrderAndItemOfferHelperhelperprotected PotentialSavingsCalculatorpotentialSavingsCalculatorprotected QualifierAndTargetMarkerqualifierAndTargetMarker
-
Constructor Summary
Constructors Constructor Description DefaultItemOfferProcessor(PotentialSavingsCalculator potentialSavingsCalculator, QualifierAndTargetMarker qualifierAndTargetMarker, OrderAndItemOfferHelper helper, boolean isForFulfillment)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description protected voidaddFreeGiftsToResult(OfferProcessingContext context, ItemOfferPermutationResult result)protected voidaddOrderCodeToAdjustmentIfUsed(@NonNull Offer offer, @NonNull com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment adjustment, @NonNull Set<String> allOrderCodes)Adds an offer code to the givenAdjustmentif it is present on the order.protected voidapplyAdjustments(EnhancedOrder order, CandidateItemOffer itemOffer)protected voidapplyCandidateOffers(EnhancedOrder order, List<CandidateItemOffer> candidateOffers)protected voidapplyFreeGift(EnhancedOrder order, CandidateItemOffer itemOffer)Builds and adds aFreeGiftItemtoEnhancedOrder.getFreeGiftItems()based onCandidateItemOffer.getCandidateQualifiersMap()if the givenitemOfferis a free gift offer.voidapplyItemAdjustments(OfferProcessingContext context, ItemOfferPermutationResult result)For item processing, the adjustments are stored onLineItemOfferDetailrecords.protected voidapplyItemOffer(EnhancedOrder order, CandidateItemOffer itemOffer)protected voidapplyItemQualifiersAndTargets(EnhancedOrder order, CandidateItemOffer itemOffer)protected voidapplyLineItemAdjustment(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail, OfferDiscount offerDiscount)Adds anItemOfferAdjustmentto the givenLineItemOfferDetail.protected voidassertCandidateOffersNotNull(CandidateOffers candidateOffers)protected voidassertCommonParamsNotNull(EnhancedOrder order, CandidateOffers candidateOffers)protected com.broadleafcommerce.promotion.offer.client.web.context.info.AdjustmentbuildAdjustmentForFreeGift(EnhancedOrder order, CandidateItemOffer itemOffer)Builds anAdjustmentfor aFreeGiftItem.protected com.broadleafcommerce.promotion.offer.client.web.context.info.FreeGiftItembuildFreeGiftItem(Offer offer, int quantityToAdd, com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment adjustment)Builds aFreeGiftItemfrom the givenOffer, quantity, and qualifier item ids.protected voidcalculatePotentialSavings(EnhancedOrder order, List<CandidateItemOffer> candidateItemOffers)protected javax.money.MonetaryAmountcalculatePriceForBundleRatio(LineItemOfferDetail detail)protected booleancanOfferBeApplied(EnhancedOrder order, CandidateItemOffer itemOffer, List<LineItemOfferDetail> itemDetails)Determines whether theOffercan be applied by making sure it iscombinableand that all other offers applied to anyLineItemsare also combinable by checking theirEnhancedLineItem.offerDetails.protected voidchooseSaleOrStandardAdjustments(EnhancedOrder order)SomeOfferscan only apply to theEnhancedLineItem.getStandardPrice().protected voidclearStateBetweenPermutations(EnhancedOrder order, List<CandidateItemOffer> candidateOffers)protected ItemOfferPermutationResultcomputeOfferPermutationValue(OfferProcessingContext context, List<CandidateItemOffer> candidateItemOffers, OrderTotals orderTotals)protected javax.money.MonetaryAmountcomputeSaleAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)protected javax.money.MonetaryAmountcomputeStandardAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)protected com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetailcreateOfferItemDetail(CandidateItemOffer itemOffer, String itemId, int quantityPerUsage)Creates anOfferItemDetailbased on the given fields.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.voidfindBestItemOffersForPermutation(OfferProcessingContext context, CombinedTypesOfferPermutation ctop)protected Optional<List<CandidateItemOffer>>findBestPermutation(EnhancedOrder order, List<List<CandidateItemOffer>> permutations)Determines the best permutation by comparing the resulting total discounts of each permutations.protected List<CandidateItemOffer>getCandidateItemOffers(OfferProcessingContext context)protected javax.money.MonetaryAmountgetEstimatedFreeGiftValue(EnhancedOrder order, Offer offer)protected intgetFreeGiftQuantityToAdd(CandidateItemOffer itemOffer)Gets the quantity of the free gift items to be added from the givenCandidateItemOffer.protected List<CandidateItemOffer>getPermutationByComparator(List<CandidateItemOffer> rootPremutation, Comparator<CandidateItemOffer> comparator)Uses aComparatorto sortcandidate offers.protected List<com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetail>getQualifierDetails(CandidateItemOffer itemOffer)Gets a list ofOfferItemDetailsrepresenting qualifiers.protected booleanisAdjustmentGoodEnough(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.protected voidlogIfDebugOn(String message, Object... formatArgs)Checks ifdebug is enabled, then wraps the message inString.format(String, Object...)with the givenformatArgsand logs it.protected voidlogIfTraceOn(String message, Object... formatArgs)Checks ifLog.isTraceEnabled()trace is enabled}, then wraps the message inString.format(String, Object...)with the givenformatArgsand logs it.protected voidmergePriceDetails(EnhancedOrder order)Checks to see if anyLineItemOfferDetailsneed to be combined and if so, combines them.voidprepareForItemOfferProcessing(EnhancedOrder order, List<CandidateItemOffer> candidateItemOffers)Item offer processing can benefit from setup activities that are used by all of the permutations.protected voidremoveDuplicatePermutations(List<List<CandidateItemOffer>> permutations)A duplicate permutation means that the permutations have the same offers in the same order.protected voidsetCandidateItemOffers(CandidateOffers candidateOffers, List<CandidateItemOffer> candidateItemOffers)protected voidsort(List<CandidateItemOffer> candidateItemOffers)The default based on theCandidateItemOfferComparatorprotected voidsplitDetailsIfNecessary(List<LineItemOfferDetail> offerDetails)Checks if the discount quantity matches the detail quantity.protected voidupdateBestPermutation(CombinedTypesOfferPermutation ctop, ItemOfferPermutationResult bestPermutation)
-
-
-
Field Detail
-
potentialSavingsCalculator
protected final PotentialSavingsCalculator potentialSavingsCalculator
-
qualifierAndTargetMarker
protected final QualifierAndTargetMarker qualifierAndTargetMarker
-
helper
protected final OrderAndItemOfferHelper helper
-
-
Constructor Detail
-
DefaultItemOfferProcessor
public DefaultItemOfferProcessor(PotentialSavingsCalculator potentialSavingsCalculator, QualifierAndTargetMarker qualifierAndTargetMarker, OrderAndItemOfferHelper helper, boolean isForFulfillment)
-
-
Method Detail
-
findBestItemOffersForPermutation
public void findBestItemOffersForPermutation(OfferProcessingContext context, CombinedTypesOfferPermutation ctop)
- Specified by:
findBestItemOffersForPermutationin interfaceItemOfferProcessor
-
updateBestPermutation
protected void updateBestPermutation(CombinedTypesOfferPermutation ctop, ItemOfferPermutationResult bestPermutation)
-
applyItemAdjustments
public void applyItemAdjustments(OfferProcessingContext context, ItemOfferPermutationResult result)
Description copied from interface:ItemOfferProcessorFor item processing, the adjustments are stored onLineItemOfferDetailrecords. These detail records are stored in theItemOfferPermutationResult.getLineItemDetailMap()- Specified by:
applyItemAdjustmentsin interfaceItemOfferProcessor
-
prepareForItemOfferProcessing
public void prepareForItemOfferProcessing(EnhancedOrder order, List<CandidateItemOffer> candidateItemOffers)
Description copied from interface:ItemOfferProcessorItem 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:
prepareForItemOfferProcessingin interfaceItemOfferProcessor
-
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 theCandidateItemOfferComparator- Parameters:
candidateItemOffers-
-
applyCandidateOffers
protected void applyCandidateOffers(@NonNull EnhancedOrder order, @NonNull List<CandidateItemOffer> candidateOffers)
-
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.
- 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 aComparatorto sortcandidate offers. The default comparators to use areItemOfferQtyOneComparatorandItemOfferWeightedPercentSavedComparator. Each ordering is considered its own permutation since the order in which offers are applied affects the end price.
-
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 compatibleCandidateItemOffers
-
findBestPermutation
protected Optional<List<CandidateItemOffer>> findBestPermutation(EnhancedOrder order, List<List<CandidateItemOffer>> permutations)
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)
Determines whether theOffercan be applied by making sure it iscombinableand that all other offers applied to anyLineItemsare also combinable by checking theirEnhancedLineItem.offerDetails.- Returns:
- whether the offer can be applied.
-
applyItemQualifiersAndTargets
protected void applyItemQualifiersAndTargets(EnhancedOrder order, CandidateItemOffer itemOffer)
-
splitDetailsIfNecessary
protected void splitDetailsIfNecessary(List<LineItemOfferDetail> offerDetails)
Checks if the discount quantity matches the detail quantity. If not, splits the price detail.
-
applyAdjustments
protected void applyAdjustments(EnhancedOrder order, CandidateItemOffer itemOffer)
-
calculatePriceForBundleRatio
protected javax.money.MonetaryAmount calculatePriceForBundleRatio(LineItemOfferDetail detail)
-
applyFreeGift
protected void applyFreeGift(EnhancedOrder order, CandidateItemOffer itemOffer)
Builds and adds aFreeGiftItemtoEnhancedOrder.getFreeGiftItems()based onCandidateItemOffer.getCandidateQualifiersMap()if the givenitemOfferis a free gift offer.- Parameters:
order- order to apply the free gift offers toitemOffer- offer to build theFreeGiftItemand get the qualifiers from
-
getFreeGiftQuantityToAdd
protected int getFreeGiftQuantityToAdd(CandidateItemOffer itemOffer)
Gets the quantity of the free gift items to be added from the givenCandidateItemOffer.- Parameters:
itemOffer- thefree gift offerto 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 aFreeGiftItemfrom the givenOffer, quantity, and qualifier item ids.- Parameters:
offer- the free gift offer to build theFreeGiftItemfromquantityToAdd- the quantity of theFreeGiftItemadjustment- theItemAdjustmentof theFreeGiftItem- Returns:
FreeGiftItemfrom the givenOffer, quantity, and adjustment
-
buildAdjustmentForFreeGift
protected com.broadleafcommerce.promotion.offer.client.web.context.info.Adjustment buildAdjustmentForFreeGift(EnhancedOrder order, CandidateItemOffer itemOffer)
Builds anAdjustmentfor aFreeGiftItem.- Parameters:
order- theEnhancedOrdertheFreeGiftItemwill be added toitemOffer- theCandidateItemOfferfor the free gift- Returns:
- an
Adjustmentfor 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 givenAdjustmentif it is present on the order.- Parameters:
offer-Offerfrom which theadjustmentis derived.adjustment- Adjustment TheAdjustmentfor which an offer code may applyallOrderCodes- 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 anyAdjustments.
-
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.
-
applyLineItemAdjustment
protected void applyLineItemAdjustment(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail, OfferDiscount offerDiscount)
Adds anItemOfferAdjustmentto the givenLineItemOfferDetail.- Parameters:
itemOffer- theCandidateItemOfferto build theItemOfferAdjustmentfromofferDetail- theLineItemOfferDetailto add theItemOfferAdjustmenttoofferDiscount- theOfferDiscountto get the target criteria rule from
-
getQualifierDetails
protected List<com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetail> getQualifierDetails(CandidateItemOffer itemOffer)
Gets a list ofOfferItemDetailsrepresenting qualifiers.- Parameters:
itemOffer- theCandidateItemOfferto get the qualifier items from- Returns:
- a list of
OfferItemDetailsrepresenting qualifiers
-
createOfferItemDetail
protected com.broadleafcommerce.promotion.offer.client.web.context.info.OfferItemDetail createOfferItemDetail(CandidateItemOffer itemOffer, String itemId, int quantityPerUsage)
Creates anOfferItemDetailbased on the given fields.- Parameters:
itemOffer- theCandidateItemOfferto build the details fromitemId- the item idquantityPerUsage- the quantity per usage- Returns:
- an
OfferItemDetailbased on the given fields
-
computeStandardAdjustmentValue
protected javax.money.MonetaryAmount computeStandardAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)
-
computeSaleAdjustmentValue
protected javax.money.MonetaryAmount computeSaleAdjustmentValue(CandidateItemOffer itemOffer, LineItemOfferDetail offerDetail)
-
chooseSaleOrStandardAdjustments
protected void chooseSaleOrStandardAdjustments(EnhancedOrder order)
SomeOfferscan only apply to theEnhancedLineItem.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 anyLineItemOfferDetailsneed 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)
-
logIfDebugOn
protected void logIfDebugOn(String message, Object... formatArgs)
Checks ifdebug is enabled, then wraps the message inString.format(String, Object...)with the givenformatArgsand logs it.
-
logIfTraceOn
protected void logIfTraceOn(String message, Object... formatArgs)
Checks ifLog.isTraceEnabled()trace is enabled}, then wraps the message inString.format(String, Object...)with the givenformatArgsand logs it.
-
-