protected int applyLegacyAdjustments(
     int appliedItemOffersCount,
     PromotableCandidateItemOffer itemOffer,
     int beforeCount,
     PromotableOrderItem orderItem) {
   // legacy promotion
   if (!orderItem.isNotCombinableOfferApplied()) {
     if ((itemOffer.getOffer().isCombinableWithOtherOffers() && itemOffer.getOffer().isStackable())
         || !orderItem.isHasOrderItemAdjustments()) {
       applyOrderItemAdjustment(itemOffer, orderItem);
       appliedItemOffersCount++;
     }
   }
   // check if not combinable offer is better than sale price; if no, remove the not combinable
   // offer so
   // that another offer may be applied to the item
   if (!itemOffer.getOffer().isCombinableWithOtherOffers()
       && appliedItemOffersCount > beforeCount) {
     Money adjustmentTotal = new Money(0D);
     Money saleTotal = new Money(0D);
     adjustmentTotal =
         adjustmentTotal.add(orderItem.getCurrentPrice().multiply(orderItem.getQuantity()));
     saleTotal =
         saleTotal.add(
             orderItem.getPriceBeforeAdjustments(true).multiply(orderItem.getQuantity()));
     if (adjustmentTotal.greaterThanOrEqual(saleTotal)) {
       // adjustment price is not best price, remove adjustments for this item
       orderItem.removeAllAdjustments();
       appliedItemOffersCount--;
     }
   }
   return appliedItemOffersCount;
 }
 /**
  * Private method used by applyAllItemOffers to create an OrderItemAdjustment from a
  * CandidateItemOffer and associates the OrderItemAdjustment to the OrderItem.
  *
  * @param itemOffer a CandidateItemOffer to apply to an OrderItem
  */
 protected void applyOrderItemAdjustment(
     PromotableCandidateItemOffer itemOffer, PromotableOrderItem orderItem) {
   OrderItemAdjustment itemAdjustment = offerDao.createOrderItemAdjustment();
   itemAdjustment.init(
       orderItem.getDelegate(), itemOffer.getOffer(), itemOffer.getOffer().getName());
   // add to adjustment
   PromotableOrderItemAdjustment promotableOrderItemAdjustment =
       promotableItemFactory.createPromotableOrderItemAdjustment(itemAdjustment, orderItem);
   orderItem.addOrderItemAdjustment(
       promotableOrderItemAdjustment); // This is how we can tell if an item has been discounted
 }
  protected void applyItemQualifiersAndTargets(
      PromotableCandidateItemOffer itemOffer, PromotableOrder order) {
    Offer promotion = itemOffer.getOffer();
    OrderItemPriceComparator priceComparator =
        new OrderItemPriceComparator(promotion.getApplyDiscountToSalePrice());
    boolean matchFound = false;
    do {
      matchFound = false;
      int totalQualifiersNeeded = 0;
      for (OfferItemCriteria itemCriteria : itemOffer.getCandidateQualifiersMap().keySet()) {
        totalQualifiersNeeded += itemCriteria.getQuantity();
      }
      int receiveQtyNeeded = promotion.getTargetItemCriteria().getQuantity();

      checkAll:
      {
        for (OfferItemCriteria itemCriteria : itemOffer.getCandidateQualifiersMap().keySet()) {
          List<PromotableOrderItem> chargeableItems =
              itemOffer.getCandidateQualifiersMap().get(itemCriteria);

          // Sort the items so that the highest priced ones are at the top
          Collections.sort(chargeableItems, priceComparator);
          // Calculate the number of qualifiers needed that will not receive the promotion.
          // These will be reserved first before the target is assigned.
          int qualifierQtyNeeded = itemCriteria.getQuantity();

          for (PromotableOrderItem chargeableItem : chargeableItems) {

            // Mark Qualifiers
            if (qualifierQtyNeeded > 0) {
              int itemQtyAvailableToBeUsedAsQualifier =
                  chargeableItem.getQuantityAvailableToBeUsedAsQualifier(promotion);
              if (itemQtyAvailableToBeUsedAsQualifier > 0) {
                int qtyToMarkAsQualifier =
                    Math.min(qualifierQtyNeeded, itemQtyAvailableToBeUsedAsQualifier);
                qualifierQtyNeeded -= qtyToMarkAsQualifier;
                chargeableItem.addPromotionQualifier(itemOffer, itemCriteria, qtyToMarkAsQualifier);
              }
            }

            if (qualifierQtyNeeded == 0) {
              totalQualifiersNeeded -= itemCriteria.getQuantity();
              break;
            }
          }
          if (qualifierQtyNeeded != 0) {
            break checkAll;
          }
        }
        checkTargets:
        {
          List<PromotableOrderItem> chargeableItems = itemOffer.getCandidateTargets();
          Collections.sort(chargeableItems, priceComparator);
          for (PromotableOrderItem chargeableItem : chargeableItems) {
            // Mark Targets
            if (receiveQtyNeeded > 0) {
              int itemQtyAvailableToBeUsedAsTarget =
                  chargeableItem.getQuantityAvailableToBeUsedAsTarget(promotion);
              if (itemQtyAvailableToBeUsedAsTarget > 0) {
                if (promotion.getMaxUses() == 0 || itemOffer.getUses() < promotion.getMaxUses()) {
                  int qtyToMarkAsTarget =
                      Math.min(receiveQtyNeeded, itemQtyAvailableToBeUsedAsTarget);
                  receiveQtyNeeded -= qtyToMarkAsTarget;
                  // atLeastOneCriteriaMatched = true;
                  chargeableItem.addPromotionDiscount(
                      itemOffer, itemOffer.getOffer().getTargetItemCriteria(), qtyToMarkAsTarget);
                }
              }
            }

            if (receiveQtyNeeded == 0) {
              break checkTargets;
            }
          }
        }
      }
      boolean criteriaMatched = true;
      if (receiveQtyNeeded != 0 || totalQualifiersNeeded != 0) {
        // This ItemCriteria did not match.  Therefore, we need to clear all non-finalized
        // quantities.
        for (OfferItemCriteria itemCriteria : itemOffer.getCandidateQualifiersMap().keySet()) {
          List<PromotableOrderItem> chargeableItems =
              itemOffer.getCandidateQualifiersMap().get(itemCriteria);
          clearAllNonFinalizedQuantities(chargeableItems);
        }
        clearAllNonFinalizedQuantities(itemOffer.getCandidateTargets());
        criteriaMatched = false;
      }

      if (criteriaMatched) {
        matchFound = true;
        finalizeQuantities(order.getDiscountableDiscreteOrderItems());
      }
      // This promotion may be able to be applied multiple times if there is enough
      // product quantity in the order. Continue to loop through the order until
      // there are no more matches
    } while (matchFound);

    if (order.getSplitItems().size() == 0) {
      initializeSplitItems(order, order.getDiscountableDiscreteOrderItems());
    }
    List<PromotableOrderItem> allSplitItems = order.getAllSplitItems();
    for (PromotableOrderItem chargeableItem : allSplitItems) {
      if (itemOffer.getCandidateTargets().contains(chargeableItem)) {
        List<PromotableOrderItem> splitItems = chargeableItem.split();
        if (splitItems != null && splitItems.size() > 0) {
          // Remove this item from the list
          List<PromotableOrderItem> temp = order.searchSplitItems(chargeableItem);
          if (!CollectionUtils.isEmpty(temp)) {
            temp.remove(chargeableItem);
            temp.addAll(splitItems);
          }
        }
      }
    }
  }
 protected int applyAdjustments(
     PromotableOrder order,
     int appliedItemOffersCount,
     PromotableCandidateItemOffer itemOffer,
     int beforeCount) {
   boolean notCombinableOfferApplied = false;
   boolean offerApplied = false;
   List<PromotableOrderItem> allSplitItems = order.getAllSplitItems();
   for (PromotableOrderItem targetItem : allSplitItems) {
     notCombinableOfferApplied = targetItem.isNotCombinableOfferApplied();
     if (!offerApplied) {
       offerApplied = targetItem.isHasOrderItemAdjustments();
     }
     if (notCombinableOfferApplied) {
       break;
     }
   }
   if (!notCombinableOfferApplied
       && (((itemOffer.getOffer().isCombinableWithOtherOffers()
               || itemOffer.getOffer().isTotalitarianOffer() == null
               || !itemOffer.getOffer().isTotalitarianOffer())
           // && itemOffer.getOffer().isStackable()
           )
           || !offerApplied)) {
     // At this point, we should not have any official adjustment on the order
     // for this item.
     applyItemQualifiersAndTargets(itemOffer, order);
     allSplitItems = order.getAllSplitItems();
     for (PromotableOrderItem splitItem : allSplitItems) {
       for (PromotionDiscount discount : splitItem.getPromotionDiscounts()) {
         if (discount.getPromotion().equals(itemOffer.getOffer())) {
           applyOrderItemAdjustment(itemOffer, splitItem);
           appliedItemOffersCount++;
           break;
         }
       }
     }
   }
   // check if not combinable offer is better than sale price; if no, remove the not combinable
   // offer so
   // that another offer may be applied to the item
   if ((!itemOffer.getOffer().isCombinableWithOtherOffers()
           || (itemOffer.getOffer().isTotalitarianOffer() != null
               && itemOffer.getOffer().isTotalitarianOffer()))
       && appliedItemOffersCount > beforeCount) {
     Money adjustmentTotal = new Money(0D);
     Money saleTotal = new Money(0D);
     for (PromotableOrderItem splitItem : allSplitItems) {
       adjustmentTotal =
           adjustmentTotal.add(splitItem.getCurrentPrice().multiply(splitItem.getQuantity()));
       saleTotal =
           saleTotal.add(
               splitItem.getPriceBeforeAdjustments(true).multiply(splitItem.getQuantity()));
     }
     if (adjustmentTotal.greaterThanOrEqual(saleTotal)) {
       // adjustment price is not best price, remove adjustments for this item
       for (PromotableOrderItem splitItem : allSplitItems) {
         if (splitItem.isHasOrderItemAdjustments()) {
           appliedItemOffersCount--;
         }
       }
       order.getSplitItems().clear();
     }
   }
   return appliedItemOffersCount;
 }