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;
}