📄 productpromoworker.java
字号:
if (promoDescBuf.length() > 0) { // remove any trailing space if (promoDescBuf.charAt(promoDescBuf.length() - 1) == ' ') promoDescBuf.deleteCharAt(promoDescBuf.length() - 1); // add a period promoDescBuf.append(". "); // capitalize the first letter promoDescBuf.setCharAt(0, Character.toUpperCase(promoDescBuf.charAt(0))); } if ("Y".equals(productPromo.getString("requireCode"))) { promoDescBuf.append("Requires code to use. "); } if (productPromo.getLong("useLimitPerOrder") != null) { promoDescBuf.append("Limit "); promoDescBuf.append(productPromo.getLong("useLimitPerOrder")); promoDescBuf.append(" per order. "); } if (productPromo.getLong("useLimitPerCustomer") != null) { promoDescBuf.append("Limit "); promoDescBuf.append(productPromo.getLong("useLimitPerCustomer")); promoDescBuf.append(" per customer. "); } if (productPromo.getLong("useLimitPerPromotion") != null) { promoDescBuf.append("Limit "); promoDescBuf.append(productPromo.getLong("useLimitPerPromotion")); promoDescBuf.append(" per promotion. "); } return promoDescBuf.toString(); } protected static boolean runProductPromoRules(ShoppingCart cart, boolean cartChanged, Long useLimit, boolean requireCode, String productPromoCodeId, Long codeUseLimit, long maxUseLimit, GenericValue productPromo, List productPromoRules, LocalDispatcher dispatcher, GenericDelegator delegator, Timestamp nowTimestamp) throws GenericEntityException, UseLimitException { String productPromoId = productPromo.getString("productPromoId"); while ((useLimit == null || useLimit.longValue() > cart.getProductPromoUseCount(productPromoId)) && (!requireCode || UtilValidate.isNotEmpty(productPromoCodeId)) && (codeUseLimit == null || codeUseLimit.longValue() > cart.getProductPromoCodeUse(productPromoCodeId))) { boolean promoUsed = false; double totalDiscountAmount = 0; double quantityLeftInActions = 0; Iterator promoRulesIter = productPromoRules.iterator(); while (promoRulesIter != null && promoRulesIter.hasNext()) { GenericValue productPromoRule = (GenericValue) promoRulesIter.next(); // if apply then performActions when no conditions are false, so default to true boolean performActions = true; // loop through conditions for rule, if any false, set allConditionsTrue to false List productPromoConds = delegator.findByAndCache("ProductPromoCond", UtilMisc.toMap("productPromoId", productPromo.get("productPromoId")), UtilMisc.toList("productPromoCondSeqId")); productPromoConds = EntityUtil.filterByAnd(productPromoConds, UtilMisc.toMap("productPromoRuleId", productPromoRule.get("productPromoRuleId"))); // using the other method to consolodate cache entries because the same cache is used elsewhere: List productPromoConds = productPromoRule.getRelatedCache("ProductPromoCond", null, UtilMisc.toList("productPromoCondSeqId")); if (Debug.verboseOn()) Debug.logVerbose("Checking " + productPromoConds.size() + " conditions for rule " + productPromoRule, module); Iterator productPromoCondIter = UtilMisc.toIterator(productPromoConds); while (productPromoCondIter != null && productPromoCondIter.hasNext()) { GenericValue productPromoCond = (GenericValue) productPromoCondIter.next(); boolean condResult = checkCondition(productPromoCond, cart, delegator, dispatcher, nowTimestamp); // any false condition will cause it to NOT perform the action if (condResult == false) { performActions = false; break; } } if (performActions) { // perform all actions, either apply or unapply List productPromoActions = productPromoRule.getRelatedCache("ProductPromoAction", null, UtilMisc.toList("productPromoActionSeqId")); if (Debug.verboseOn()) Debug.logVerbose("Performing " + productPromoActions.size() + " actions for rule " + productPromoRule, module); Iterator productPromoActionIter = UtilMisc.toIterator(productPromoActions); while (productPromoActionIter != null && productPromoActionIter.hasNext()) { GenericValue productPromoAction = (GenericValue) productPromoActionIter.next(); // Debug.logInfo("Doing action: " + productPromoAction, module); try { ActionResultInfo actionResultInfo = performAction(productPromoAction, cart, delegator, dispatcher, nowTimestamp); totalDiscountAmount += actionResultInfo.totalDiscountAmount; quantityLeftInActions += actionResultInfo.quantityLeftInAction; // only set if true, don't set back to false: implements OR logic (ie if ANY actions change content, redo loop) boolean actionChangedCart = actionResultInfo.ranAction; if (actionChangedCart) { promoUsed = true; cartChanged = true; } } catch (CartItemModifyException e) { Debug.logError("Error modifying the cart while performing promotion action [" + productPromoAction.getPrimaryKey() + "]: " + e.toString(), module); } } } } if (promoUsed) { cart.addProductPromoUse(productPromo.getString("productPromoId"), productPromoCodeId, totalDiscountAmount, quantityLeftInActions); } else { // the promotion was not used, don't try again until we finish a full pass and come back to see the promo conditions are now satisfied based on changes to the cart break; } if (cart.getProductPromoUseCount(productPromoId) > maxUseLimit) { throw new UseLimitException("ERROR: While calculating promotions the promotion [" + productPromoId + "] action was applied more than " + maxUseLimit + " times, so the calculation has been ended. This should generally never happen unless you have bad rule definitions."); } } return cartChanged; } protected static boolean checkCondition(GenericValue productPromoCond, ShoppingCart cart, GenericDelegator delegator, LocalDispatcher dispatcher, Timestamp nowTimestamp) throws GenericEntityException { String condValue = productPromoCond.getString("condValue"); String otherValue = productPromoCond.getString("otherValue"); String inputParamEnumId = productPromoCond.getString("inputParamEnumId"); String operatorEnumId = productPromoCond.getString("operatorEnumId"); String partyId = cart.getPartyId(); GenericValue userLogin = cart.getUserLogin(); if (userLogin == null) { userLogin = cart.getAutoUserLogin(); } if (Debug.verboseOn()) Debug.logVerbose("Checking promotion condition: " + productPromoCond, module); Integer compareBase = null; if ("PPIP_PRODUCT_AMOUNT".equals(inputParamEnumId)) { // for this type of promo force the operatorEnumId = PPC_EQ, effectively ignore that setting because the comparison is implied in the code operatorEnumId = "PPC_EQ"; // this type of condition requires items involved to not be involved in any other quantity consuming cond/action, and does not pro-rate the price, just uses the base price double amountNeeded = 0.0; if (UtilValidate.isNotEmpty(condValue)) { amountNeeded = Double.parseDouble(condValue); } // Debug.logInfo("Doing Amount Cond with Value: " + amountNeeded, module); Set productIds = ProductPromoWorker.getPromoRuleCondProductIds(productPromoCond, delegator, nowTimestamp); List lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false); Iterator lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator(); while (amountNeeded > 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")))) { double basePrice = cartItem.getBasePrice(); // get a rough price, round it up to an integer double quantityNeeded = Math.ceil(amountNeeded / basePrice); // reduce amount still needed to qualify for promo (amountNeeded) double quantity = cartItem.addPromoQuantityCandidateUse(quantityNeeded, productPromoCond, false); // get pro-rated amount based on discount amountNeeded -= (quantity * basePrice); } } // Debug.logInfo("Doing Amount Cond with Value after finding applicable cart lines: " + amountNeeded, module); // if amountNeeded > 0 then the promo condition failed, so remove candidate promo uses and increment the promoQuantityUsed to restore it if (amountNeeded > 0) { // failed, reset the entire rule, ie including all other conditions that might have been done before cart.resetPromoRuleUse(productPromoCond.getString("productPromoId"), productPromoCond.getString("productPromoRuleId")); compareBase = new Integer(-1); } else { // we got it, the conditions are in place... compareBase = new Integer(0); // NOTE: don't confirm promo rule use here, wait until actions are complete for the rule to do that } } else if ("PPIP_PRODUCT_TOTAL".equals(inputParamEnumId)) { // this type of condition allows items involved to be involved in other quantity consuming cond/action, and does pro-rate the price Double amountNeeded = Double.valueOf(condValue); double amountAvailable = 0; // Debug.logInfo("Doing Amount Not Counted Cond with Value: " + amountNeeded, module); Set productIds = ProductPromoWorker.getPromoRuleCondProductIds(productPromoCond, delegator, nowTimestamp); List lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false); Iterator lineOrderedByBasePriceIter = lineOrderedByBasePriceList.iterator(); while (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")))) { // just count the entire sub-total of the item amountAvailable += cartItem.getItemSubTotal(); } } // Debug.logInfo("Doing Amount Not Counted Cond with Value after finding applicable cart lines: " + amountNeeded, module); compareBase = new Integer(new Double(amountAvailable).compareTo(amountNeeded)); } else if ("PPIP_PRODUCT_QUANT".equals(inputParamEnumId)) { // for this type of promo force the operatorEnumId = PPC_EQ, effectively ignore that setting because the comparison is implied in the code operatorEnumId = "PPC_EQ"; double quantityNeeded = 1.0; if (UtilValidate.isNotEmpty(condValue)) { quantityNeeded = Double.parseDouble(condValue); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -