// no product found to add as GWP, just return
return actionResultInfo;
}
// pass null for cartLocation to add to end of cart, pass false for doPromotions to avoid infinite recursion
ShoppingCartItem gwpItem = null;
try {
// just leave the prodCatalogId null, this line won't be associated with a catalog
String prodCatalogId = null;
gwpItem = ShoppingCartItem.makeItem(null, product, null, quantity, null, null, null, null, null, null, null, null, prodCatalogId, null, null, null, dispatcher, cart, Boolean.FALSE, Boolean.TRUE, null, Boolean.FALSE, Boolean.FALSE);
if (optionProductIds.size() > 0) {
gwpItem.setAlternativeOptionProductIds(optionProductIds);
} else {
gwpItem.setAlternativeOptionProductIds(null);
}
} catch (CartItemModifyException e) {
int gwpItemIndex = cart.getItemIndex(gwpItem);
cart.removeCartItem(gwpItemIndex, dispatcher);
throw e;
}
BigDecimal discountAmount = quantity.multiply(gwpItem.getBasePrice()).negate();
doOrderItemPromoAction(productPromoAction, gwpItem, discountAmount, "amount", delegator);
// set promo after create; note that to setQuantity we must clear this flag, setQuantity, then re-set the flag
gwpItem.setIsPromo(true);
if (Debug.verboseOn()) Debug.logVerbose("gwpItem adjustments: " + gwpItem.getAdjustments(), module);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = discountAmount;
}
} else if ("PROMO_FREE_SHIPPING".equals(productPromoActionEnumId)) {
// this may look a bit funny: on each pass all rules that do free shipping will set their own rule id for it,
// and on unapply if the promo and rule ids are the same then it will clear it; essentially on any pass
// through the promos and rules if any free shipping should be there, it will be there
cart.addFreeShippingProductPromoAction(productPromoAction);
// don't consider this as a cart change?
actionResultInfo.ranAction = true;
// should probably set the totalDiscountAmount to something, but we have no idea what it will be, so leave at 0, will still get run
} else if ("PROMO_PROD_DISC".equals(productPromoActionEnumId)) {
BigDecimal quantityDesired = productPromoAction.get("quantity") == null ? BigDecimal.ONE : productPromoAction.getBigDecimal("quantity");
BigDecimal startingQuantity = quantityDesired;
BigDecimal discountAmountTotal = BigDecimal.ZERO;
Set productIds = ProductPromoWorker.getPromoRuleActionProductIds(productPromoAction, delegator, nowTimestamp);
List lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false);
Iterator lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator();
while (quantityDesired.compareTo(BigDecimal.ZERO) > 0 && lineOrderedByBasePriceIter.hasNext()) {
ShoppingCartItem cartItem = (ShoppingCartItem) lineOrderedByBasePriceIter.next();
// only include if it is in the productId Set for this check and if it is not a Promo (GWP) item
GenericValue product = cartItem.getProduct();
String parentProductId = cartItem.getParentProductId();
if (!cartItem.getIsPromo() &&
(productIds.contains(cartItem.getProductId()) || (parentProductId != null && productIds.contains(parentProductId))) &&
(product == null || !"N".equals(product.getString("includeInPromotions")))) {
// reduce quantity still needed to qualify for promo (quantityNeeded)
BigDecimal quantityUsed = cartItem.addPromoQuantityCandidateUse(quantityDesired, productPromoAction, false);
if (quantityUsed.compareTo(BigDecimal.ZERO) > 0) {
quantityDesired = quantityDesired.subtract(quantityUsed);
// create an adjustment and add it to the cartItem that implements the promotion action
BigDecimal percentModifier = productPromoAction.get("amount") == null ? BigDecimal.ZERO : productPromoAction.getBigDecimal("amount").movePointLeft(2);
BigDecimal lineAmount = quantityUsed.multiply(cartItem.getBasePrice()).multiply(cartItem.getRentalAdjustment());
BigDecimal discountAmount = lineAmount.multiply(percentModifier).negate();
discountAmountTotal = discountAmountTotal.add(discountAmount);
// not doing this any more, now distributing among conditions and actions (see call below): doOrderItemPromoAction(productPromoAction, cartItem, discountAmount, "amount", delegator);
}
}
}
if (quantityDesired == startingQuantity || quantityDesired.compareTo(BigDecimal.ZERO) > 0) {
// couldn't find any (or enough) cart items to give a discount to, don't consider action run
actionResultInfo.ranAction = false;
// clear out any action uses for this so they don't become part of anything else
cart.resetPromoRuleUse(productPromoAction.getString("productPromoId"), productPromoAction.getString("productPromoRuleId"));
} else {
BigDecimal totalAmount = getCartItemsUsedTotalAmount(cart, productPromoAction);
if (Debug.verboseOn()) Debug.logVerbose("Applying promo [" + productPromoAction.getPrimaryKey() + "]\n totalAmount=" + totalAmount + ", discountAmountTotal=" + discountAmountTotal, module);
distributeDiscountAmount(discountAmountTotal, totalAmount, getCartItemsUsed(cart, productPromoAction), productPromoAction, delegator);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = discountAmountTotal;
actionResultInfo.quantityLeftInAction = quantityDesired;
}
} else if ("PROMO_PROD_AMDISC".equals(productPromoActionEnumId)) {
BigDecimal quantityDesired = productPromoAction.get("quantity") == null ? BigDecimal.ONE : productPromoAction.getBigDecimal("quantity");
BigDecimal startingQuantity = quantityDesired;
BigDecimal discountAmountTotal = BigDecimal.ZERO;
Set productIds = ProductPromoWorker.getPromoRuleActionProductIds(productPromoAction, delegator, nowTimestamp);
List lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false);
Iterator lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator();
while (quantityDesired.compareTo(BigDecimal.ZERO) > 0 && lineOrderedByBasePriceIter.hasNext()) {
ShoppingCartItem cartItem = (ShoppingCartItem) lineOrderedByBasePriceIter.next();
// only include if it is in the productId Set for this check and if it is not a Promo (GWP) item
String parentProductId = cartItem.getParentProductId();
GenericValue product = cartItem.getProduct();
if (!cartItem.getIsPromo() &&
(productIds.contains(cartItem.getProductId()) || (parentProductId != null && productIds.contains(parentProductId))) &&
(product == null || !"N".equals(product.getString("includeInPromotions")))) {
// reduce quantity still needed to qualify for promo (quantityNeeded)
BigDecimal quantityUsed = cartItem.addPromoQuantityCandidateUse(quantityDesired, productPromoAction, false);
quantityDesired = quantityDesired.subtract(quantityUsed);
// create an adjustment and add it to the cartItem that implements the promotion action
BigDecimal discount = productPromoAction.get("amount") == null ? BigDecimal.ZERO : productPromoAction.getBigDecimal("amount");
// don't allow the discount to be greater than the price
if (discount.compareTo(cartItem.getBasePrice().multiply(cartItem.getRentalAdjustment())) > 0) {
discount = cartItem.getBasePrice().multiply(cartItem.getRentalAdjustment());
}
BigDecimal discountAmount = quantityUsed.multiply(discount).negate();
discountAmountTotal = discountAmountTotal.add(discountAmount);
// not doing this any more, now distributing among conditions and actions (see call below): doOrderItemPromoAction(productPromoAction, cartItem, discountAmount, "amount", delegator);
}
}
if (quantityDesired == startingQuantity) {
// couldn't find any cart items to give a discount to, don't consider action run
actionResultInfo.ranAction = false;
} else {
BigDecimal totalAmount = getCartItemsUsedTotalAmount(cart, productPromoAction);
if (Debug.verboseOn()) Debug.logVerbose("Applying promo [" + productPromoAction.getPrimaryKey() + "]\n totalAmount=" + totalAmount + ", discountAmountTotal=" + discountAmountTotal, module);
distributeDiscountAmount(discountAmountTotal, totalAmount, getCartItemsUsed(cart, productPromoAction), productPromoAction, delegator);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = discountAmountTotal;
actionResultInfo.quantityLeftInAction = quantityDesired;
}
} else if ("PROMO_PROD_PRICE".equals(productPromoActionEnumId)) {
// with this we want the set of used items to be one price, so total the price for all used items, subtract the amount we want them to cost, and create an adjustment for what is left
BigDecimal quantityDesired = productPromoAction.get("quantity") == null ? BigDecimal.ONE : productPromoAction.getBigDecimal("quantity");
BigDecimal desiredAmount = productPromoAction.get("amount") == null ? BigDecimal.ZERO : productPromoAction.getBigDecimal("amount");
BigDecimal totalAmount = BigDecimal.ZERO;
Set productIds = ProductPromoWorker.getPromoRuleActionProductIds(productPromoAction, delegator, nowTimestamp);
List cartItemsUsed = FastList.newInstance();
List lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false);
Iterator lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator();
while (quantityDesired.compareTo(BigDecimal.ZERO) > 0 && lineOrderedByBasePriceIter.hasNext()) {
ShoppingCartItem cartItem = (ShoppingCartItem) lineOrderedByBasePriceIter.next();
// only include if it is in the productId Set for this check and if it is not a Promo (GWP) item
String parentProductId = cartItem.getParentProductId();
GenericValue product = cartItem.getProduct();
if (!cartItem.getIsPromo() && (productIds.contains(cartItem.getProductId()) || (parentProductId != null && productIds.contains(parentProductId))) &&
(product == null || !"N".equals(product.getString("includeInPromotions")))) {
// reduce quantity still needed to qualify for promo (quantityNeeded)
BigDecimal quantityUsed = cartItem.addPromoQuantityCandidateUse(quantityDesired, productPromoAction, false);
if (quantityUsed.compareTo(BigDecimal.ZERO) > 0) {
quantityDesired = quantityDesired.subtract(quantityUsed);
totalAmount = totalAmount.add(quantityUsed.multiply(cartItem.getBasePrice()).multiply(cartItem.getRentalAdjustment()));
cartItemsUsed.add(cartItem);
}
}
}
if (totalAmount.compareTo(desiredAmount) > 0 && quantityDesired.compareTo(BigDecimal.ZERO) == 0) {
BigDecimal discountAmountTotal = totalAmount.subtract(desiredAmount).negate();
distributeDiscountAmount(discountAmountTotal, totalAmount, cartItemsUsed, productPromoAction, delegator);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = discountAmountTotal;
// no use setting the quantityLeftInAction because that does not apply for buy X for $Y type promotions, it is all or nothing
} else {
actionResultInfo.ranAction = false;
// clear out any action uses for this so they don't become part of anything else
cart.resetPromoRuleUse(productPromoAction.getString("productPromoId"), productPromoAction.getString("productPromoRuleId"));
}
} else if ("PROMO_ORDER_PERCENT".equals(productPromoActionEnumId)) {
BigDecimal percentage = (productPromoAction.get("amount") == null ? BigDecimal.ZERO : (productPromoAction.getBigDecimal("amount").movePointLeft(2))).negate();
BigDecimal amount = cart.getSubTotalForPromotions().multiply(percentage);
if (amount.compareTo(BigDecimal.ZERO) != 0) {
doOrderPromoAction(productPromoAction, cart, amount, "amount", delegator);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = amount;
}
} else if ("PROMO_ORDER_AMOUNT".equals(productPromoActionEnumId)) {
BigDecimal amount = (productPromoAction.get("amount") == null ? BigDecimal.ZERO : productPromoAction.getBigDecimal("amount")).negate();
// if amount is greater than the order sub total, set equal to order sub total, this normally wouldn't happen because there should be a condition that the order total be above a certain amount, but just in case...
BigDecimal subTotal = cart.getSubTotalForPromotions();
if (amount.negate().compareTo(subTotal) > 0) {
amount = subTotal.negate();
}
if (amount.compareTo(BigDecimal.ZERO) != 0) {
doOrderPromoAction(productPromoAction, cart, amount, "amount", delegator);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = amount;
}
} else if ("PROMO_PROD_SPPRC".equals(productPromoActionEnumId)) {
// if there are productIds associated with the action then restrict to those productIds, otherwise apply for all products
Set productIds = ProductPromoWorker.getPromoRuleActionProductIds(productPromoAction, delegator, nowTimestamp);
// go through the cart items and for each product that has a specialPromoPrice use that price
Iterator cartItemIter = cart.items().iterator();
while (cartItemIter.hasNext()) {
ShoppingCartItem cartItem = (ShoppingCartItem) cartItemIter.next();
String itemProductId = cartItem.getProductId();
if (UtilValidate.isEmpty(itemProductId)) {
continue;
}
if (productIds.size() > 0 && !productIds.contains(itemProductId)) {
continue;
}
if (cartItem.getSpecialPromoPrice() == null) {
continue;
}
// get difference between basePrice and specialPromoPrice and adjust for that
BigDecimal difference = cartItem.getBasePrice().multiply(cartItem.getRentalAdjustment()).subtract(cartItem.getSpecialPromoPrice()).negate();
if (difference.compareTo(BigDecimal.ZERO) != 0) {
BigDecimal quantityUsed = cartItem.addPromoQuantityCandidateUse(cartItem.getQuantity(), productPromoAction, false);
if (quantityUsed.compareTo(BigDecimal.ZERO) > 0) {
BigDecimal amount = difference.multiply(quantityUsed);
doOrderItemPromoAction(productPromoAction, cartItem, amount, "amount", delegator);
actionResultInfo.ranAction = true;
actionResultInfo.totalDiscountAmount = amount;