Search in sources :

Example 11 with ShoppingCartItem

use of org.apache.ofbiz.order.shoppingcart.ShoppingCartItem in project ofbiz-framework by apache.

the class ProductDisplayWorker method getRandomCartProductAssoc.

/* ========================================================================================*/
/* ============================= Special Data Retrieval Methods ===========================*/
public static List<GenericValue> getRandomCartProductAssoc(ServletRequest request, boolean checkViewAllow) {
    Delegator delegator = (Delegator) request.getAttribute("delegator");
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    ShoppingCart cart = (ShoppingCart) httpRequest.getSession().getAttribute("shoppingCart");
    if (cart == null || cart.size() <= 0) {
        return null;
    }
    List<GenericValue> cartAssocs = null;
    try {
        Map<String, GenericValue> products = new HashMap<>();
        Iterator<ShoppingCartItem> cartiter = cart.iterator();
        while (cartiter != null && cartiter.hasNext()) {
            ShoppingCartItem item = cartiter.next();
            // since ProductAssoc records have a fromDate and thruDate, we can filter by now so that only assocs in the date range are included
            List<GenericValue> complementProducts = EntityQuery.use(delegator).from("ProductAssoc").where("productId", item.getProductId(), "productAssocTypeId", "PRODUCT_COMPLEMENT").cache(true).filterByDate().queryList();
            List<GenericValue> productsCategories = EntityQuery.use(delegator).from("ProductCategoryMember").where("productId", item.getProductId()).cache(true).filterByDate().queryList();
            if (productsCategories != null) {
                for (GenericValue productsCategoryMember : productsCategories) {
                    GenericValue productsCategory = productsCategoryMember.getRelatedOne("ProductCategory", true);
                    if ("CROSS_SELL_CATEGORY".equals(productsCategory.getString("productCategoryTypeId"))) {
                        List<GenericValue> curPcms = productsCategory.getRelated("ProductCategoryMember", null, null, true);
                        if (curPcms != null) {
                            for (GenericValue curPcm : curPcms) {
                                if (!products.containsKey(curPcm.getString("productId"))) {
                                    GenericValue product = curPcm.getRelatedOne("Product", true);
                                    products.put(product.getString("productId"), product);
                                }
                            }
                        }
                    }
                }
            }
            if (UtilValidate.isNotEmpty(complementProducts)) {
                for (GenericValue productAssoc : complementProducts) {
                    if (!products.containsKey(productAssoc.getString("productIdTo"))) {
                        GenericValue product = productAssoc.getRelatedOne("AssocProduct", true);
                        products.put(product.getString("productId"), product);
                    }
                }
            }
        }
        // remove all products that are already in the cart
        cartiter = cart.iterator();
        while (cartiter != null && cartiter.hasNext()) {
            ShoppingCartItem item = cartiter.next();
            products.remove(item.getProductId());
        }
        // if desired check view allow category
        if (checkViewAllow) {
            String currentCatalogId = CatalogWorker.getCurrentCatalogId(request);
            String viewProductCategoryId = CatalogWorker.getCatalogViewAllowCategoryId(delegator, currentCatalogId);
            if (viewProductCategoryId != null) {
                List<GenericValue> tempList = new LinkedList<>();
                tempList.addAll(products.values());
                tempList = CategoryWorker.filterProductsInCategory(delegator, tempList, viewProductCategoryId, "productId");
                cartAssocs = new LinkedList<>();
                cartAssocs.addAll(tempList);
            }
        }
        if (cartAssocs == null) {
            cartAssocs = new LinkedList<>();
            cartAssocs.addAll(products.values());
        }
        // randomly remove products while there are more than 3
        while (cartAssocs.size() > 3) {
            int toRemove = (int) (Math.random() * cartAssocs.size());
            cartAssocs.remove(toRemove);
        }
    } catch (GenericEntityException e) {
        Debug.logWarning(e, module);
    }
    if (UtilValidate.isNotEmpty(cartAssocs)) {
        return cartAssocs;
    }
    return null;
}
Also used : GenericValue(org.apache.ofbiz.entity.GenericValue) HashMap(java.util.HashMap) LinkedList(java.util.LinkedList) HttpServletRequest(javax.servlet.http.HttpServletRequest) Delegator(org.apache.ofbiz.entity.Delegator) ShoppingCart(org.apache.ofbiz.order.shoppingcart.ShoppingCart) GenericEntityException(org.apache.ofbiz.entity.GenericEntityException) ShoppingCartItem(org.apache.ofbiz.order.shoppingcart.ShoppingCartItem)

Example 12 with ShoppingCartItem

use of org.apache.ofbiz.order.shoppingcart.ShoppingCartItem in project ofbiz-framework by apache.

the class ProductPromoWorker method distributeDiscountAmount.

private static void distributeDiscountAmount(BigDecimal discountAmountTotal, BigDecimal totalAmount, List<ShoppingCartItem> cartItemsUsed, GenericValue productPromoAction, Delegator delegator) {
    BigDecimal discountAmount = discountAmountTotal;
    // distribute the discount evenly weighted according to price over the order items that the individual quantities came from; avoids a number of issues with tax/shipping calc, inclusion in the sub-total for other promotions, etc
    Iterator<ShoppingCartItem> cartItemsUsedIter = cartItemsUsed.iterator();
    while (cartItemsUsedIter.hasNext()) {
        ShoppingCartItem cartItem = cartItemsUsedIter.next();
        // to minimize rounding issues use the remaining total for the last one, otherwise use a calculated value
        if (cartItemsUsedIter.hasNext()) {
            BigDecimal quantityUsed = cartItem.getPromoQuantityCandidateUseActionAndAllConds(productPromoAction);
            BigDecimal ratioOfTotal = quantityUsed.multiply(cartItem.getBasePrice()).divide(totalAmount, generalRounding);
            BigDecimal weightedAmount = ratioOfTotal.multiply(discountAmountTotal);
            // round the weightedAmount to 3 decimal places, we don't want an exact number cents/whatever because this will be added up as part of a subtotal which will be rounded to 2 decimal places
            weightedAmount = weightedAmount.setScale(3, RoundingMode.HALF_UP);
            discountAmount = discountAmount.subtract(weightedAmount);
            doOrderItemPromoAction(productPromoAction, cartItem, weightedAmount, "amount", delegator);
        } else {
            // last one, just use discountAmount
            doOrderItemPromoAction(productPromoAction, cartItem, discountAmount, "amount", delegator);
        }
    }
// this is the old way that causes problems: doOrderPromoAction(productPromoAction, cart, discountAmount, "amount", delegator);
}
Also used : ShoppingCartItem(org.apache.ofbiz.order.shoppingcart.ShoppingCartItem) BigDecimal(java.math.BigDecimal)

Example 13 with ShoppingCartItem

use of org.apache.ofbiz.order.shoppingcart.ShoppingCartItem in project ofbiz-framework by apache.

the class ProductPromoWorker method prepareDeltaProductUsageInfoMap.

private static Map<ShoppingCartItem, BigDecimal> prepareDeltaProductUsageInfoMap(Map<ShoppingCartItem, BigDecimal> oldMap, Map<ShoppingCartItem, BigDecimal> newMap) {
    Map<ShoppingCartItem, BigDecimal> deltaUsageInfoMap = new HashMap<>(newMap);
    for (Entry<ShoppingCartItem, BigDecimal> entry : oldMap.entrySet()) {
        ShoppingCartItem key = entry.getKey();
        BigDecimal oldUsed = entry.getValue();
        BigDecimal newUsed = entry.getValue();
        if (newUsed.compareTo(oldUsed) > 0) {
            deltaUsageInfoMap.put(key, newUsed.add(oldUsed.negate()));
        } else {
            deltaUsageInfoMap.remove(key);
        }
    }
    return deltaUsageInfoMap;
}
Also used : HashMap(java.util.HashMap) ShoppingCartItem(org.apache.ofbiz.order.shoppingcart.ShoppingCartItem) BigDecimal(java.math.BigDecimal)

Example 14 with ShoppingCartItem

use of org.apache.ofbiz.order.shoppingcart.ShoppingCartItem in project ofbiz-framework by apache.

the class ProductPromoWorker method prepareProductUsageInfoMap.

private static Map<ShoppingCartItem, BigDecimal> prepareProductUsageInfoMap(ShoppingCart cart) {
    Map<ShoppingCartItem, BigDecimal> usageInfoMap = new HashMap<>();
    List<ShoppingCartItem> lineOrderedByBasePriceList = cart.getLineListOrderedByBasePrice(false);
    for (ShoppingCartItem cartItem : lineOrderedByBasePriceList) {
        BigDecimal used = cartItem.getPromoQuantityUsed();
        if (used.compareTo(BigDecimal.ZERO) != 0) {
            usageInfoMap.put(cartItem, used);
        }
    }
    return usageInfoMap;
}
Also used : HashMap(java.util.HashMap) ShoppingCartItem(org.apache.ofbiz.order.shoppingcart.ShoppingCartItem) BigDecimal(java.math.BigDecimal)

Example 15 with ShoppingCartItem

use of org.apache.ofbiz.order.shoppingcart.ShoppingCartItem in project ofbiz-framework by apache.

the class ProductPromoWorker method runProductPromoRules.

private static boolean runProductPromoRules(ShoppingCart cart, Long useLimit, boolean requireCode, String productPromoCodeId, Long codeUseLimit, long maxUseLimit, GenericValue productPromo, List<GenericValue> productPromoRules, LocalDispatcher dispatcher, Delegator delegator, Timestamp nowTimestamp) throws GenericEntityException, UseLimitException {
    boolean cartChanged = false;
    Map<ShoppingCartItem, BigDecimal> usageInfoMap = prepareProductUsageInfoMap(cart);
    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;
        BigDecimal totalDiscountAmount = BigDecimal.ZERO;
        BigDecimal quantityLeftInActions = BigDecimal.ZERO;
        Iterator<GenericValue> promoRulesIter = productPromoRules.iterator();
        while (promoRulesIter != null && promoRulesIter.hasNext()) {
            GenericValue productPromoRule = 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<GenericValue> productPromoConds = EntityQuery.use(delegator).from("ProductPromoCond").where("productPromoId", productPromo.get("productPromoId")).orderBy("productPromoCondSeqId").cache(true).queryList();
            productPromoConds = EntityUtil.filterByAnd(productPromoConds, UtilMisc.toMap("productPromoRuleId", productPromoRule.get("productPromoRuleId")));
            // using the other method to consolidate cache entries because the same cache is used elsewhere: List productPromoConds = productPromoRule.getRelated("ProductPromoCond", null, UtilMisc.toList("productPromoCondSeqId"), true);
            if (Debug.verboseOn()) {
                Debug.logVerbose("Checking " + productPromoConds.size() + " conditions for rule " + productPromoRule, module);
            }
            Iterator<GenericValue> productPromoCondIter = UtilMisc.toIterator(productPromoConds);
            while (productPromoCondIter != null && productPromoCondIter.hasNext()) {
                GenericValue productPromoCond = productPromoCondIter.next();
                boolean conditionSatisfied = checkCondition(productPromoCond, cart, delegator, dispatcher, nowTimestamp);
                // any false condition will cause it to NOT perform the action
                if (!conditionSatisfied) {
                    performActions = false;
                    break;
                }
            }
            if (performActions) {
                // perform all actions, either apply or unapply
                List<GenericValue> productPromoActions = productPromoRule.getRelated("ProductPromoAction", null, UtilMisc.toList("productPromoActionSeqId"), true);
                Iterator<GenericValue> productPromoActionIter = UtilMisc.toIterator(productPromoActions);
                while (productPromoActionIter != null && productPromoActionIter.hasNext()) {
                    GenericValue productPromoAction = productPromoActionIter.next();
                    try {
                        ActionResultInfo actionResultInfo = performAction(productPromoAction, cart, delegator, dispatcher, nowTimestamp);
                        totalDiscountAmount = totalDiscountAmount.add(actionResultInfo.totalDiscountAmount);
                        quantityLeftInActions = quantityLeftInActions.add(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(e, "Error modifying the cart while performing promotion action [" + productPromoAction.getPrimaryKey() + "]", module);
                    }
                }
            }
        }
        if (promoUsed) {
            // Get product use information from the cart
            Map<ShoppingCartItem, BigDecimal> newUsageInfoMap = prepareProductUsageInfoMap(cart);
            Map<ShoppingCartItem, BigDecimal> deltaUsageInfoMap = prepareDeltaProductUsageInfoMap(usageInfoMap, newUsageInfoMap);
            usageInfoMap = newUsageInfoMap;
            cart.addProductPromoUse(productPromo.getString("productPromoId"), productPromoCodeId, totalDiscountAmount, quantityLeftInActions, deltaUsageInfoMap);
        } 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;
}
Also used : GenericValue(org.apache.ofbiz.entity.GenericValue) CartItemModifyException(org.apache.ofbiz.order.shoppingcart.CartItemModifyException) ShoppingCartItem(org.apache.ofbiz.order.shoppingcart.ShoppingCartItem) BigDecimal(java.math.BigDecimal)

Aggregations

ShoppingCartItem (org.apache.ofbiz.order.shoppingcart.ShoppingCartItem)16 BigDecimal (java.math.BigDecimal)12 GenericValue (org.apache.ofbiz.entity.GenericValue)11 HashMap (java.util.HashMap)8 GenericEntityException (org.apache.ofbiz.entity.GenericEntityException)8 CartItemModifyException (org.apache.ofbiz.order.shoppingcart.CartItemModifyException)8 Delegator (org.apache.ofbiz.entity.Delegator)7 ShoppingCart (org.apache.ofbiz.order.shoppingcart.ShoppingCart)7 GenericServiceException (org.apache.ofbiz.service.GenericServiceException)7 Locale (java.util.Locale)5 Map (java.util.Map)5 GeneralException (org.apache.ofbiz.base.util.GeneralException)5 LocalDispatcher (org.apache.ofbiz.service.LocalDispatcher)5 HashSet (java.util.HashSet)4 LinkedList (java.util.LinkedList)4 Timestamp (java.sql.Timestamp)3 CheckOutHelper (org.apache.ofbiz.order.shoppingcart.CheckOutHelper)3 ItemNotFoundException (org.apache.ofbiz.order.shoppingcart.ItemNotFoundException)3 Calendar (com.ibm.icu.util.Calendar)2 ArrayList (java.util.ArrayList)2