📄 productpromoworker.java
字号:
agreementItem = EntityUtil.getFirst(agreementItems); } catch (GenericEntityException e) { Debug.logError(e, "Error looking up agreement items for agreement with id " + agreementId, module); } if (agreementItem == null) { Debug.logWarning(UtilProperties.getMessage(resource_error,"OrderNoAgreementItemFoundForAgreementWithIdNotDoingPromotions", UtilMisc.toMap("agreementId", agreementId), cart.getLocale()), module); return productPromoList; } try { // loop through promotions and get a list of all of the rules... List agreementPromoApplsList = agreementItem.getRelatedCache("AgreementPromoAppl", null, UtilMisc.toList("sequenceNum")); agreementPromoApplsList = EntityUtil.filterByDate(agreementPromoApplsList, nowTimestamp); if (agreementPromoApplsList == null || agreementPromoApplsList.size() == 0) { if (Debug.verboseOn()) Debug.logVerbose("Not doing promotions, none applied to agreement with ID " + agreementId, module); } Iterator agreementPromoAppls = UtilMisc.toIterator(agreementPromoApplsList); while (agreementPromoAppls != null && agreementPromoAppls.hasNext()) { GenericValue agreementPromoAppl = (GenericValue) agreementPromoAppls.next(); GenericValue productPromo = agreementPromoAppl.getRelatedOneCache("ProductPromo"); productPromoList.add(productPromo); } } catch (GenericEntityException e) { Debug.logError(e, "Error looking up promotion data while doing promotions", module); } return productPromoList; } public static void doPromotions(ShoppingCart cart, LocalDispatcher dispatcher) { ProductPromoWorker.doPromotions(cart, null, dispatcher); } public static void doPromotions(ShoppingCart cart, List productPromoList, LocalDispatcher dispatcher) { // this is called when a user logs in so that per customer limits are honored, called by cart when new userlogin is set // there is code to store ProductPromoUse information when an order is placed // ProductPromoUses are ignored if the corresponding order is cancelled // limits sub total for promos to not use gift cards (products with a don't use in promo indicator), also exclude gift cards from all other promotion considerations including subTotals for discounts, etc // TODO: (not done, delay, still considering...) add code to check ProductPromoUse limits per promo (customer, promo), and per code (customer, code) to avoid use of promos or codes getting through due to multiple carts getting promos applied at the same time, possibly on totally different servers GenericDelegator delegator = cart.getDelegator(); Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); // start out by clearing all existing promotions, then we can just add all that apply cart.clearAllPromotionInformation(); // there will be a ton of db access, so just do a big catch entity exception block try { if (productPromoList == null) { if (cart.getOrderType().equals("SALES_ORDER")) { productPromoList = ProductPromoWorker.getProductStorePromotions(cart, nowTimestamp, dispatcher); } else { productPromoList = ProductPromoWorker.getAgreementPromotions(cart, nowTimestamp, dispatcher); } } // do a calculate only run through the promotions, then order by descending totalDiscountAmount for each promotion // NOTE: on this run, with isolatedTestRun passed as false it should not apply any adjustments // or track which cart items are used for which promotions, but it will track ProductPromoUseInfo and // useLimits; we are basicly just trying to run each promo "independently" to see how much each is worth runProductPromos(productPromoList, cart, delegator, dispatcher, nowTimestamp, true); // NOTE: after that first pass we could remove any that have a 0 totalDiscountAmount from the run list, but we won't because by the time they are run the cart may have changed enough to get them to go; also, certain actions like free shipping should always be run even though we won't know what the totalDiscountAmount is at the time the promotion is run // each ProductPromoUseInfo on the shopping cart will contain it's total value, so add up all totals for each promoId and put them in a List of Maps // create a List of Maps with productPromo and totalDiscountAmount, use the Map sorter to sort them descending by totalDiscountAmount // before sorting split into two lists and sort each list; one list for promos that have a order total condition, and the other list for all promos that don't; then we'll always run the ones that have no condition on the order total first List productPromoDiscountMapList = FastList.newInstance(); List productPromoDiscountMapListOrderTotal = FastList.newInstance(); Iterator productPromoIter = productPromoList.iterator(); while (productPromoIter.hasNext()) { GenericValue productPromo = (GenericValue) productPromoIter.next(); Map productPromoDiscountMap = UtilMisc.toMap("productPromo", productPromo, "totalDiscountAmount", new Double(cart.getProductPromoUseTotalDiscount(productPromo.getString("productPromoId")))); if (hasOrderTotalCondition(productPromo, delegator)) { productPromoDiscountMapListOrderTotal.add(productPromoDiscountMap); } else { productPromoDiscountMapList.add(productPromoDiscountMap); } } // sort the Map List, do it ascending because the discount amounts will be negative, so the lowest number is really the highest discount productPromoDiscountMapList = UtilMisc.sortMaps(productPromoDiscountMapList, UtilMisc.toList("+totalDiscountAmount")); productPromoDiscountMapListOrderTotal = UtilMisc.sortMaps(productPromoDiscountMapListOrderTotal, UtilMisc.toList("+totalDiscountAmount")); productPromoDiscountMapList.addAll(productPromoDiscountMapListOrderTotal); List sortedProductPromoList = new ArrayList(productPromoDiscountMapList.size()); Iterator productPromoDiscountMapIter = productPromoDiscountMapList.iterator(); while (productPromoDiscountMapIter.hasNext()) { Map productPromoDiscountMap = (Map) productPromoDiscountMapIter.next(); GenericValue productPromo = (GenericValue) productPromoDiscountMap.get("productPromo"); sortedProductPromoList.add(productPromo); if (Debug.verboseOn()) Debug.logVerbose("Sorted Promo [" + productPromo.getString("productPromoId") + "] with total discount: " + productPromoDiscountMap.get("totalDiscountAmount"), module); } // okay, all ready, do the real run, clearing the temporary result first... cart.clearAllPromotionInformation(); runProductPromos(sortedProductPromoList, cart, delegator, dispatcher, nowTimestamp, false); } catch (NumberFormatException e) { Debug.logError(e, "Number not formatted correctly in promotion rules, not completed...", module); } catch (GenericEntityException e) { Debug.logError(e, "Error looking up promotion data while doing promotions", module); } catch (Exception e) { Debug.logError(e, "Error running promotions, will ignore: " + e.toString(), module); } } protected static boolean hasOrderTotalCondition(GenericValue productPromo, GenericDelegator delegator) throws GenericEntityException { boolean hasOtCond = false; List productPromoConds = delegator.findByAndCache("ProductPromoCond", UtilMisc.toMap("productPromoId", productPromo.get("productPromoId")), UtilMisc.toList("productPromoCondSeqId")); Iterator productPromoCondIter = productPromoConds.iterator(); while (productPromoCondIter.hasNext()) { GenericValue productPromoCond = (GenericValue) productPromoCondIter.next(); String inputParamEnumId = productPromoCond.getString("inputParamEnumId"); if ("PPIP_ORDER_TOTAL".equals(inputParamEnumId)) { hasOtCond = true; break; } } return hasOtCond; } protected static void runProductPromos(List productPromoList, ShoppingCart cart, GenericDelegator delegator, LocalDispatcher dispatcher, Timestamp nowTimestamp, boolean isolatedTestRun) throws GeneralException { String partyId = cart.getPartyId(); // this is our safety net; we should never need to loop through the rules more than a certain number of times, this is that number and may have to be changed for insanely large promo sets... long maxIterations = 1000; // part of the safety net to avoid infinite iteration long numberOfIterations = 0; // set a max limit on how many times each promo can be run, for cases where there is no use limit this will be the use limit //default to 2 times the number of items in the cart long maxUseLimit = 2 * Math.round(cart.getTotalQuantity()); try { // repeat until no more rules to run: either all rules are run, or no changes to the cart in a loop boolean cartChanged = true; while (cartChanged) { cartChanged = false; numberOfIterations++; if (numberOfIterations > maxIterations) { Debug.logError("ERROR: While calculating promotions the promotion rules where run more than " + maxIterations + " times, so the calculation has been ended. This should generally never happen unless you have bad rule definitions.", module); break; } Iterator productPromoIter = productPromoList.iterator(); while (productPromoIter.hasNext()) { GenericValue productPromo = (GenericValue) productPromoIter.next(); String productPromoId = productPromo.getString("productPromoId"); List productPromoRules = productPromo.getRelatedCache("ProductPromoRule", null, null); if (productPromoRules != null && productPromoRules.size() > 0) { // always have a useLimit to avoid unlimited looping, default to 1 if no other is specified Long candidateUseLimit = getProductPromoUseLimit(productPromo, partyId, delegator); Long useLimit = candidateUseLimit; if (Debug.verboseOn()) Debug.logVerbose("Running promotion [" + productPromoId + "], useLimit=" + useLimit + ", # of rules=" + productPromoRules.size(), module); boolean requireCode = "Y".equals(productPromo.getString("requireCode")); // check if promo code required if (requireCode) { Set enteredCodes = cart.getProductPromoCodesEntered(); if (enteredCodes.size() > 0) { // get all promo codes entered, do a query with an IN condition to see if any of those are related EntityCondition codeCondition = new EntityExpr(new EntityExpr("productPromoId", EntityOperator.EQUALS, productPromoId), EntityOperator.AND, new EntityExpr("productPromoCodeId", EntityOperator.IN, enteredCodes)); // may want to sort by something else to decide which code to use if there is more than one candidate List productPromoCodeList = delegator.findByCondition("ProductPromoCode", codeCondition, null, UtilMisc.toList("productPromoCodeId")); Iterator productPromoCodeIter = productPromoCodeList.iterator(); // support multiple promo codes for a single promo, ie if we run into a use limit for one code see if we can find another for this promo // check the use limit before each pass so if the promo use limit has been hit we don't keep on trying for the promo code use limit, if there is one of course while ((useLimit == null || useLimit.longValue() > cart.getProductPromoUseCount(productPromoId)) && productPromoCodeIter.hasNext()) { GenericValue productPromoCode = (GenericValue) productPromoCodeIter.next(); String productPromoCodeId = productPromoCode.getString("productPromoCodeId"); Long codeUseLimit = getProductPromoCodeUseLimit(productPromoCode, partyId, delegator); if (runProductPromoRules(cart, cartChanged, useLimit, true, productPromoCodeId, codeUseLimit, maxUseLimit, productPromo, productPromoRules, dispatcher, delegator, nowTimestamp)) { cartChanged = true; } if (cart.getProductPromoUseCount(productPromoId) > maxUseLimit) { Debug.logError("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.", module); break; } } } } else { try { if (runProductPromoRules(cart, cartChanged, useLimit, false, null, null, maxUseLimit, productPromo, productPromoRules, dispatcher, delegator, nowTimestamp)) { cartChanged = true; } } catch (RuntimeException e) { throw new GeneralException("Error running promotion with ID [" + productPromoId + "]", e); } } } // if this is an isolatedTestRun clear out adjustments and cart item promo use info if (isolatedTestRun) { cart.clearAllPromotionAdjustments(); cart.clearCartItemUseInPromoInfo(); } } // if this is an isolatedTestRun, then only go through it once, never retry if (isolatedTestRun) { cartChanged = false; } } } catch (UseLimitException e) { Debug.logError(e, e.toString(), module); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -