public Map modifyCart()

in applications/order/src/main/java/org/apache/ofbiz/order/shoppingcart/ShoppingCartHelper.java [715:1031]


    public Map<String, Object> modifyCart(Security security, GenericValue userLogin, Map<String, ? extends Object> context, boolean removeSelected,
                                          String[] selectedItems, Locale locale) {
        Map<String, Object> result = null;
        if (locale == null) {
            locale = this.cart.getLocale();
        }

        List<ShoppingCartItem> deleteList = new ArrayList<>();
        List<String> errorMsgs = new ArrayList<>();

        BigDecimal oldQuantity;
        String oldDescription = "";
        String oldItemComment = "";
        BigDecimal oldPrice = BigDecimal.ONE.negate();

        if (this.cart.isReadOnlyCart()) {
            String errMsg = UtilProperties.getMessage(RES_ERROR, "cart.cart_is_in_read_only_mode", this.cart.getLocale());
            errorMsgs.add(errMsg);
            result = ServiceUtil.returnError(errorMsgs);
            return result;
        }

        // TODO: This should be refactored to use UtilHttp.parseMultiFormData(parameters)
        for (Entry<String, ? extends Object> entry : context.entrySet()) {
            String parameterName = entry.getKey();
            int underscorePos = parameterName.lastIndexOf('_');

            // ignore localized date input elements, just use their counterpart without the _i18n suffix
            if (underscorePos >= 0 && (!parameterName.endsWith("_i18n"))) {
                try {
                    String indexStr = parameterName.substring(underscorePos + 1);
                    int index = Integer.parseInt(indexStr);
                    String quantString = (String) entry.getValue();
                    BigDecimal quantity = BigDecimal.ONE.negate();
                    String itemDescription = "";
                    String itemComment = "";
                    if (quantString != null) {
                        quantString = quantString.trim();
                    }

                    // get the cart item
                    ShoppingCartItem item = this.cart.findCartItem(index);
                    if (parameterName.toUpperCase(Locale.getDefault()).startsWith("OPTION")) {
                        if (quantString.toUpperCase(Locale.getDefault()).startsWith("NO^")) {
                            if (quantString.length() > 2) { // the length of the prefix
                                String featureTypeId = this.getRemoveFeatureTypeId(parameterName);
                                if (featureTypeId != null) {
                                    item.removeAdditionalProductFeatureAndAppl(featureTypeId);
                                }
                            }
                        } else {
                            GenericValue featureAppl = this.getFeatureAppl(item.getProductId(), parameterName, quantString);
                            if (featureAppl != null) {
                                item.putAdditionalProductFeatureAndAppl(featureAppl);
                            }
                        }
                    } else if (parameterName.toUpperCase(Locale.getDefault()).startsWith("DESCRIPTION")) {
                        itemDescription = quantString;  // the quantString is actually the description if the field name starts with DESCRIPTION
                    } else if (parameterName.toUpperCase(Locale.getDefault()).startsWith("COMMENT")) {
                        itemComment = quantString;  // the quantString is actually the comment if the field name starts with COMMENT
                    } else if (parameterName.startsWith("reservStart")) {
                        if (quantString.isEmpty()) {
                            // should have format: yyyy-mm-dd hh:mm:ss.fffffffff
                            quantString += " 00:00:00.000000000";
                        }
                        if (item != null) {
                            Timestamp reservStart = Timestamp.valueOf(quantString);
                            item.setReservStart(reservStart);
                        }
                    } else if (parameterName.startsWith("reservLength")) {
                        if (item != null) {
                            BigDecimal reservLength = (BigDecimal) ObjectType.simpleTypeOrObjectConvert(quantString, "BigDecimal", null, locale);
                            item.setReservLength(reservLength);
                        }
                    } else if (parameterName.startsWith("reservPersons")) {
                        if (item != null) {
                            BigDecimal reservPersons = (BigDecimal) ObjectType.simpleTypeOrObjectConvert(quantString, "BigDecimal", null, locale);
                            item.setReservPersons(reservPersons);
                        }
                    } else if (parameterName.startsWith("shipBeforeDate")) {
                        if (UtilValidate.isNotEmpty(quantString)) {
                            // input is either yyyy-mm-dd or a full timestamp
                            if (quantString.length() == 10) {
                                quantString += " 00:00:00.000";
                            }
                            item.setShipBeforeDate(Timestamp.valueOf(quantString));
                        }
                    } else if (parameterName.startsWith("shipAfterDate")) {
                        if (UtilValidate.isNotEmpty(quantString)) {
                            // input is either yyyy-mm-dd or a full timestamp
                            if (quantString.length() == 10) {
                                quantString += " 00:00:00.000";
                            }
                            item.setShipAfterDate(Timestamp.valueOf(quantString));
                        }
                    } else if (parameterName.startsWith("amount")) {
                        if (UtilValidate.isNotEmpty(quantString)) {
                            BigDecimal amount = new BigDecimal(quantString);
                            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                                String errMsg = UtilProperties.getMessage(RES_ERROR, "cart.amount_not_positive_number", this.cart.getLocale());
                                errorMsgs.add(errMsg);
                                result = ServiceUtil.returnError(errorMsgs);
                                return result;
                            }
                            item.setSelectedAmount(amount);
                        }
                    } else if (parameterName.startsWith("itemType")) {
                        if (UtilValidate.isNotEmpty(quantString)) {
                            item.setItemType(quantString);
                        }
                    } else {
                        quantity = (BigDecimal) ObjectType.simpleTypeOrObjectConvert(quantString, "BigDecimal", null, locale);
                        //For quantity we should test if we allow to add decimal quantity for this product an productStore :
                        // if not and if quantity is in decimal format then return error.
                        if (!ProductWorker.isDecimalQuantityOrderAllowed(delegator, item.getProductId(), cart.getProductStoreId())
                                && parameterName.startsWith("update")) {
                            BigDecimal remainder = quantity.remainder(BigDecimal.ONE);
                            if (remainder.compareTo(BigDecimal.ZERO) != 0) {
                                String errMsg = UtilProperties.getMessage(RES_ERROR, "cart.addToCart.quantityInDecimalNotAllowed",
                                        this.cart.getLocale());
                                errorMsgs.add(errMsg);
                                result = ServiceUtil.returnError(errorMsgs);
                                return result;
                            }
                            quantity = quantity.setScale(0, UtilNumber.getRoundingMode("order.rounding"));
                        } else {
                            quantity = quantity.setScale(UtilNumber.getBigDecimalScale("order.decimals"),
                                    UtilNumber.getRoundingMode("order.rounding"));
                        }
                        if (quantity.compareTo(BigDecimal.ZERO) < 0) {
                            String errMsg = UtilProperties.getMessage(RES_ERROR, "cart.quantity_not_positive_number", this.cart.getLocale());
                            errorMsgs.add(errMsg);
                            result = ServiceUtil.returnError(errorMsgs);
                            return result;
                        }
                    }

                    // perhaps we need to reset the ship groups' before and after dates based on new dates for the items
                    if (parameterName.startsWith("shipAfterDate") || parameterName.startsWith("shipBeforeDate")) {
                        this.cart.setShipGroupShipDatesFromItem(item);
                    }

                    if (parameterName.toUpperCase(Locale.getDefault()).startsWith("UPDATE")) {
                        if (quantity.compareTo(BigDecimal.ZERO) == 0) {
                            deleteList.add(item);
                        } else {
                            if (item != null) {
                                try {
                                    oldItemComment = item.getItemComment();
                                    // if, on a purchase order, the quantity has changed, get the new SupplierProduct entity for this quantity level.
                                    if ("PURCHASE_ORDER".equals(cart.getOrderType())) {
                                        oldQuantity = item.getQuantity();
                                        if (oldQuantity.compareTo(quantity) != 0) {
                                            // save the old description and price, in case the user wants to change those as well
                                            oldDescription = item.getName(this.dispatcher);
                                            oldPrice = item.getBasePrice();

                                            if (UtilValidate.isNotEmpty(item.getProductId())) {
                                                GenericValue supplierProduct = this.cart.getSupplierProduct(item.getProductId(), quantity,
                                                        this.dispatcher);
                                                if (supplierProduct == null) {
                                                    if ("_NA_".equals(cart.getPartyId())) {
                                                        // no supplier does not require the supplier product
                                                        item.setQuantity(quantity, dispatcher, this.cart);
                                                        item.setName(item.getProduct().getString("internalName"));
                                                    } else {
                                                        // in this case, the user wanted to purchase a quantity which is not available
                                                        // (probably below minimum)
                                                        String errMsg = UtilProperties.getMessage(RES_ERROR, "cart.product_not_valid_for_supplier",
                                                                this.cart.getLocale());
                                                        errMsg = errMsg + " (" + item.getProductId() + ", " + quantity + ", " + cart.getCurrency()
                                                                + ")";
                                                        errorMsgs.add(errMsg);
                                                    }
                                                } else {
                                                    item.setSupplierProductId(supplierProduct.getString("supplierProductId"));
                                                    item.setQuantity(quantity, dispatcher, this.cart);
                                                    item.setBasePrice(supplierProduct.getBigDecimal("lastPrice"));
                                                    item.setName(ShoppingCartItem.getPurchaseOrderItemDescription(item.getProduct(), supplierProduct,
                                                            cart.getLocale(), dispatcher));
                                                }
                                            } else {
                                                item.setQuantity(quantity, dispatcher, this.cart);
                                            }
                                        }
                                    } else {
                                        BigDecimal minQuantity = ShoppingCart.getMinimumOrderQuantity(delegator, item.getBasePrice(),
                                                item.getProductId());
                                        oldQuantity = item.getQuantity();
                                        if (oldQuantity.compareTo(quantity) != 0) {
                                            GenericValue product = item.getProduct();
                                            //Reset shipment method information in cart only if shipping applies on product.
                                            if (UtilValidate.isNotEmpty(product) && ProductWorker.shippingApplies(product)) {
                                                for (int shipGroupIndex = 0; shipGroupIndex < cart.getShipGroupSize(); shipGroupIndex++) {
                                                    String shipContactMechId = cart.getShippingContactMechId(shipGroupIndex);
                                                    if (UtilValidate.isNotEmpty(shipContactMechId)) {
                                                        cart.setShipmentMethodTypeId(shipGroupIndex, null);
                                                    }
                                                }
                                            }
                                        }
                                        if (quantity.compareTo(minQuantity) < 0) {
                                            quantity = minQuantity;
                                        }
                                        item.setQuantity(quantity, dispatcher, this.cart, true, false);
                                        cart.setItemShipGroupQty(item, quantity, 0);
                                    }
                                } catch (CartItemModifyException e) {
                                    errorMsgs.add(e.getMessage());
                                }
                            }
                        }
                    }

                    if (parameterName.toUpperCase(Locale.getDefault()).startsWith("DESCRIPTION")) {
                        if (!oldDescription.equals(itemDescription)) {
                            if (security.hasEntityPermission("ORDERMGR", "_CREATE", userLogin)) {
                                if (item != null) {
                                    item.setName(itemDescription);
                                }
                            }
                        }
                    }

                    if (parameterName.toUpperCase(Locale.getDefault()).startsWith("COMMENT")) {
                        if (!oldItemComment.equals(itemComment)) {
                            if (security.hasEntityPermission("ORDERMGR", "_CREATE", userLogin)) {
                                if (item != null) {
                                    item.setItemComment(itemComment);
                                }
                            }
                        }
                    }

                    if (parameterName.toUpperCase(Locale.getDefault()).startsWith("PRICE")) {
                        NumberFormat pf = NumberFormat.getCurrencyInstance(locale);
                        String tmpQuantity = pf.format(quantity);
                        String tmpOldPrice = pf.format(oldPrice);
                        if (!tmpOldPrice.equals(tmpQuantity)) {
                            if (security.hasEntityPermission("ORDERMGR", "_CREATE", userLogin)) {
                                if (item != null) {
                                    item.setBasePrice(quantity); // this is quantity because the parsed number variable is the same as quantity
                                    item.setDisplayPrice(quantity); // or the amount shown the cart items page won't be right
                                }
                            }
                        }
                    }

                    if (parameterName.toUpperCase(Locale.getDefault()).startsWith("DELETE")) {
                        deleteList.add(this.cart.findCartItem(index));
                    }
                } catch (NumberFormatException nfe) {
                    Debug.logWarning(nfe, UtilProperties.getMessage(RES_ERROR, "OrderCaughtNumberFormatExceptionOnCartUpdate", cart.getLocale()));
                } catch (GeneralException e) {
                    Debug.logWarning(e, UtilProperties.getMessage(RES_ERROR, "OrderCaughtExceptionOnCartUpdate", cart.getLocale()));
                }
            } // else not a parameter we need
        }

        // get a list of the items to delete
        if (removeSelected) {
            for (String indexStr : selectedItems) {
                ShoppingCartItem item = null;
                try {
                    int index = Integer.parseInt(indexStr);
                    item = this.cart.findCartItem(index);
                } catch (Exception e) {
                    Debug.logWarning(e, UtilProperties.getMessage(RES_ERROR, "OrderProblemsGettingTheCartItemByIndex", cart.getLocale()));
                }
                if (item != null) {
                    deleteList.add(item);
                }
            }
        }

        for (ShoppingCartItem item : deleteList) {
            int itemIndex = this.cart.getItemIndex(item);

            if (Debug.infoOn()) {
                Debug.logInfo("Removing item index: " + itemIndex, MODULE);
            }
            try {
                this.cart.removeCartItem(itemIndex, dispatcher);
                GenericValue product = item.getProduct();
                //Reset shipment method information in cart only if shipping applies on product.
                if (UtilValidate.isNotEmpty(product) && ProductWorker.shippingApplies(product)) {
                    for (int shipGroupIndex = 0; shipGroupIndex < cart.getShipGroupSize(); shipGroupIndex++) {
                        String shipContactMechId = cart.getShippingContactMechId(shipGroupIndex);
                        if (UtilValidate.isNotEmpty(shipContactMechId)) {
                            cart.setShipmentMethodTypeId(shipGroupIndex, null);
                        }
                    }
                }

            } catch (CartItemModifyException e) {
                result = ServiceUtil.returnError(new ArrayList<String>());
                errorMsgs.add(e.getMessage());
            }
        }

        if (context.containsKey("alwaysShowcart")) {
            this.cart.setViewCartOnAdd(true);
        } else {
            this.cart.setViewCartOnAdd(false);
        }

        // Promotions are run again.
        ProductPromoWorker.doPromotions(this.cart, dispatcher);

        if (!errorMsgs.isEmpty()) {
            result = ServiceUtil.returnError(errorMsgs);
            return result;
        }

        result = ServiceUtil.returnSuccess();
        return result;
    }