svn commit: r1643778 [3/5] - in /ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23: ./ applications/accounting/script/org/ofbiz/accounting/budget/ applications/accounting/servicedef/ applications/commonext/webapp/ordermgr-js/ applications/conten...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1643778 [3/5] - in /ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23: ./ applications/accounting/script/org/ofbiz/accounting/budget/ applications/accounting/servicedef/ applications/commonext/webapp/ordermgr-js/ applications/conten...

jleroux@apache.org
Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml Mon Dec  8 10:21:56 2014
@@ -25,7 +25,24 @@ under the License.
         <entity-one entity-name="UserLogin" value-field="userLogin">
             <field-map field-name="userLoginId" value="system"/>
         </entity-one>
+        
+        <set field="map.userLogin" from="userLogin"/>
+        
+        <call-service service-name="testCreateShoppinCartAndOrder" in-map-name="map">
+            <result-to-field result-name="orderMap"/>
+        </call-service>
+        
+        <if-not-empty field="orderMap">
+            <log level="info" message="------------ ORDERID : [${orderMap.orderId}] ------------"/>
+        </if-not-empty>
+
+        <assert><not><if-empty field="orderMap.orderId"/></not></assert>
+        <check-errors/>
+    </simple-method>
 
+    <simple-method method-name="testCreateShoppinCartAndOrder" short-description="Create an order using a shopping cart">
+        <set field="userLogin" from="parameters.userLogin"/>
+        
         <!-- Shopping Cart new Instance -->
         <set field="delegator" from-field="parameters.delegator" type="Object"/>
         <set field="dispatcher" from-field="parameters.dispatcher" type="Object"/>
@@ -80,7 +97,7 @@ under the License.
         <set field="prodCatalogId" value="DemoCatalog" type="String"/>
         <set field="index" value="0" type="Integer"/>
         <set field="productId" value="GZ-2644" type="String"/>
-        <set field="quantity" value="1" type="BigDecimal"/>
+        <set field="quantity" value="5" type="BigDecimal"/>
         <set field="selectedAmount" value="0" type="BigDecimal"/>
         <set field="unitPrice" value="38.4" type="BigDecimal"/>
         <set field="itemType" value="PRODUCT_ORDER_ITEM" type="String"/>
@@ -245,20 +262,15 @@ under the License.
         <!-- Shopping Cart checkout and create order -->
         <call-bsh><![CDATA[
             checkOutHelper = new org.ofbiz.order.shoppingcart.CheckOutHelper(dispatcher, delegator, shoppingCart);
-            java.util.Map orderCreate = checkOutHelper.createOrder(userLogin);
-            parameters.put("orderMap", orderCreate);
-        ]]></call-bsh>
-
+            java.util.Map orderMap = checkOutHelper.createOrder(userLogin);
+            parameters.put("orderMap", orderMap);]]>
+        </call-bsh>
+        
         <!-- Clear Shopping Cart -->
         <call-object-method method-name="clear" obj-field="shoppingCart"/>
-
-        <set field="orderMap" from-field="parameters.orderMap"/>
-        <if-not-empty field="orderMap">
-            <log level="info" message="------------ ORDERID : [${orderMap.orderId}] ------------"/>
-        </if-not-empty>
-
-        <assert><not><if-empty field="orderMap.orderId"/></not></assert>
-        <check-errors/>
+        
+        <field-to-result field="parameters.orderMap" result-name="orderMap"/>
+        
     </simple-method>
 
     <simple-method method-name="testCreateOrderRentalProduct" short-description="Test create order rental of product" login-required="false">
@@ -671,5 +683,76 @@ under the License.
         <assert><not><if-empty field="orderId"/></not></assert>
         <check-errors/>
     </simple-method>
+    
+    
+    <simple-method method-name="testOrderMoveItemBetweenShipGoups" login-required="false"
+        short-description="Create an order with 2 ship groups and 3 items and move items between ship groups">
+        <entity-one entity-name="UserLogin" value-field="userLogin">
+            <field-map field-name="userLoginId" value="system"/>
+        </entity-one>
+                
+        <set field="map.userLogin" from="userLogin"/>
+        <call-service service-name="testCreateShoppinCartAndOrder" in-map-name="map">
+            <result-to-field result-name="orderMap"/>
+        </call-service>
+
+        <assert><not><if-empty field="orderMap.orderId"/></not></assert>
+        <check-errors/>
+        
+        <entity-and entity-name="OrderItem" list="orderItems">
+            <field-map field-name="orderId" from-field="orderMap.orderId"/>
+            <field-map field-name="productId" value="GZ-2644"/>
+        </entity-and>
+        <first-from-list entry="orderItem" list="orderItems"/>
+        
+        <set field="map.orderId" from="orderMap.orderId"/>
+        <set field="map.contactMechId" value="9015"/>
+        <set field="map.carrierPartyId" value="UPS"/>
+        <set field="map.shipmentMethodTypeId" value="NEXT_DAY"/>
+        <call-service service-name="createOrderItemShipGroup" in-map-name="map"/>
+        
+        <clear-field field="map"/>
+        <set field="map.userLogin" from="userLogin" type="GenericValue"/>
+        <set field="map.orderId" from="orderMap.orderId"/>
+        <set field="map.orderItemSeqId" from="orderItem.orderItemSeqId"/>
+        <set field="map.fromGroupIndex" value="00001"/>
+        <set field="map.toGroupIndex" value="00002"/>
+        <set field="map.quantity" value="2" type="BigDecimal"/>
+        <call-service service-name="MoveItemBetweenShipGroups" in-map-name="map"/>
+        
+        <entity-one entity-name="OrderItemShipGroupAssoc" value-field="orderItemShipGroupAssoc1">
+            <field-map field-name="orderId" from-field="orderMap.orderId"/>
+            <field-map field-name="orderItemSeqId" from-field="orderItem.orderItemSeqId"/>
+            <field-map field-name="shipGroupSeqId" value="00001"/>
+        </entity-one>
+        <assert><if-compare field="orderItemShipGroupAssoc1.quantity" operator="equals" value="3"></if-compare></assert>
+        <check-errors/>
 
+        <entity-one entity-name="OrderItemShipGroupAssoc" value-field="orderItemShipGroupAssoc2">
+            <field-map field-name="orderId" from-field="orderMap.orderId"/>
+            <field-map field-name="orderItemSeqId" from-field="orderItem.orderItemSeqId"/>
+            <field-map field-name="shipGroupSeqId" value="00002"/>
+        </entity-one>
+        <assert><if-compare field="orderItemShipGroupAssoc2.quantity" operator="equals" value="2"></if-compare></assert>
+        <check-errors/>
+        
+        <clear-field field="map"/>
+        <set field="map.userLogin" from="userLogin" type="GenericValue"/>
+        <set field="map.orderId" from="orderMap.orderId"/>
+        <set field="map.orderItemSeqId" from="orderItem.orderItemSeqId"/>
+        <set field="map.shipGroupSeqId" value="00002"/>
+        <call-service service-name="deleteOrderItemShipGroupAssoc" in-map-name="map"/>
+        
+        <clear-field field="map"/>
+        <set field="map.userLogin" from="userLogin" type="GenericValue"/>
+        <set field="map.orderId" from="orderMap.orderId"/>
+        <set field="map.shipGroupSeqId" value="00002"/>
+        <call-service service-name="deleteOrderItemShipGroup" in-map-name="map"/>
+        <entity-count entity-name="OrderItemShipGroup" count-field="orderItemShipGroupCount">
+            <condition-expr field-name="orderId" from-field="orderMap.orderId"/>
+        </entity-count>
+        <assert><if-compare field="orderItemShipGroupCount" operator="equals" value="1"></if-compare></assert>
+        <check-errors/>
+    </simple-method>
+    
 </simple-methods>

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/servicedef/services.xml?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/servicedef/services.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/servicedef/services.xml Mon Dec  8 10:21:56 2014
@@ -1069,6 +1069,42 @@ under the License.
         <attribute name="availabalityList" type="List" mode="OUT"/>
     </service>
     
+    <service name="addOrderItemShipGroup" engine="java" auth="true" default-entity-name="OrderItemShipGroup"
+             location="org.ofbiz.order.order.OrderServices" invoke="addOrderItemShipGroup">
+        <description>Creates a new OrderItemShipGroup with maySplit and isGift filled.</description>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+        <override name="shipGroupSeqId" mode="INOUT" optional="true"/>
+    </service>
+    <service name="deleteOrderItemShipGroup" engine="java" auth="true" default-entity-name="OrderItemShipGroup"
+             location="org.ofbiz.order.order.OrderServices"
+             invoke="deleteOrderItemShipGroup">
+        <description>delete Order Item Ship Group </description>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+    </service>
+
+    <service name="addOrderItemShipGroupAssoc" engine="java" auth="true" default-entity-name="OrderItemShipGroupAssoc"
+             location="org.ofbiz.order.order.OrderServices"
+             invoke="addOrderItemShipGroupAssoc">
+        <description>add Order Item Ship Group Assoc and if order item ship group not exit, create it before</description>
+        <implements service="addOrderItemShipGroup" optional="true"/>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+    </service>
+    <service name="updateOrderItemShipGroupAssoc" engine="java" auth="true" default-entity-name="OrderItemShipGroupAssoc"
+             location="org.ofbiz.order.order.OrderServices"
+             invoke="updateOrderItemShipGroupAssoc">
+        <description>update OrderItem from OISG, totalQuantity is used only if controller is a multi services </description>
+        <auto-attributes include="all" mode="IN" optional="true"/>
+        <attribute name="totalQuantity" type="BigDecimal"  mode="INOUT"  optional="true"/>
+        <attribute name="rowCount" type="Integer" mode="IN" optional="true"/>
+        <attribute name="rowNumber" type="Integer" mode="INOUT" optional="true"/>
+    </service>
+    <service name="deleteOrderItemShipGroupAssoc" engine="entity-auto" auth="true" default-entity-name="OrderItemShipGroupAssoc" invoke="delete">
+        <description>delete Order Item Ship Group Assoc</description>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+    </service>
+
     <service name="createQuoteTerm" engine="simple" default-entity-name="QuoteTerm"
         location="component://order/script/org/ofbiz/order/quote/QuoteServices.xml" invoke="createQuoteTerm">
         <description>
@@ -1102,8 +1138,14 @@ under the License.
     </service>
     
     <service name="createTestOrderRentalProduct" engine="simple" auth="true"
-         location="component://order/script/org/ofbiz/order/test/ShoppingCartTests.xml" invoke="testCreateOrderRentalProduct">
-         <description>Create Test Order Rental of an asset which is shipped from and returned to inventory</description>
+        location="component://order/script/org/ofbiz/order/test/ShoppingCartTests.xml" invoke="testCreateOrderRentalProduct">
+        <description>Create Test Order Rental of an asset which is shipped from and returned to inventory</description>
+    </service>
+    
+    <service name="testCreateShoppinCartAndOrder" engine="simple" auth="true"
+        location="component://order/script/org/ofbiz/order/test/ShoppingCartTests.xml" invoke="testCreateShoppinCartAndOrder">
+        <description>Create an order using a shopping cart - only used internally in ShoppingCartTests.xml for test purpose</description>
+        <attribute name="orderMap" type="Map" mode="OUT"/>
     </service>
     
     <!-- Order Item Attribute -->
@@ -1135,4 +1177,14 @@ under the License.
         <attribute name="quantity" type="BigDecimal" mode="IN" optional="false"/>
     </service>
     
+    <service name="MoveItemBetweenShipGroups" engine="simple"
+        location="component://order/script/org/ofbiz/order/order/OrderServices.xml" invoke="MoveItemBetweenShipGroups">
+        <description>Move order items between ship groups</description>
+        <attribute name="orderId" type="String" mode="IN"/>
+        <attribute name="orderItemSeqId" type="String" mode="IN"/>
+        <attribute name="fromGroupIndex" type="String" mode="IN"/>
+        <attribute name="toGroupIndex" type="String" mode="IN"/>
+        <attribute name="quantity" type="BigDecimal" mode="IN"/>
+    </service>
+    
 </services>

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/OrderManagerEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/OrderManagerEvents.java?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/OrderManagerEvents.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/OrderManagerEvents.java Mon Dec  8 10:21:56 2014
@@ -76,7 +76,7 @@ public class OrderManagerEvents {
                 placingCustomer = EntityQuery.use(delegator).from("OrderRole").where("orderId", orderId, "roleTypeId", "PLACING_CUSTOMER").queryFirst();
             } catch (GenericEntityException e) {
                 Debug.logError(e, "Problems looking up order payment preferences", module);
-                request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderErrorProcessingOfflinePayments", locale));
+                request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderErrorProcessingOfflinePayments", locale));
                 return "error";
             }
             if (paymentPrefs != null) {
@@ -110,7 +110,7 @@ public class OrderManagerEvents {
                     delegator.storeAll(toBeStored);
                 } catch (GenericEntityException e) {
                     Debug.logError(e, "Problems storing payment information", module);
-                    request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemStoringReceivedPaymentInformation", locale));
+                    request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemStoringReceivedPaymentInformation", locale));
                     return "error";
                 }
 
@@ -137,7 +137,7 @@ public class OrderManagerEvents {
             orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne();
         } catch (GenericEntityException e) {
             Debug.logError(e, "Problems reading order header from datasource.", module);
-            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemsReadingOrderHeaderInformation", locale));
+            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemsReadingOrderHeaderInformation", locale));
             return "error";
         }
 
@@ -153,12 +153,12 @@ public class OrderManagerEvents {
             paymentMethodTypes = EntityQuery.use(delegator).from("PaymentMethodType").where(EntityCondition.makeCondition("paymentMethodTypeId", EntityOperator.NOT_EQUAL, "EXT_OFFLINE")).queryList();
         } catch (GenericEntityException e) {
             Debug.logError(e, "Problems getting payment types", module);
-            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemsWithPaymentTypeLookup", locale));
+            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemsWithPaymentTypeLookup", locale));
             return "error";
         }
 
         if (paymentMethodTypes == null) {
-            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemsWithPaymentTypeLookup", locale));
+            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemsWithPaymentTypeLookup", locale));
             return "error";
         }
 
@@ -168,7 +168,7 @@ public class OrderManagerEvents {
             paymentMethods = EntityQuery.use(delegator).from("PaymentMethod").where("partyId", partyId).queryList();
         } catch (GenericEntityException e) {
             Debug.logError(e, "Problems getting payment methods", module);
-            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemsWithPaymentMethodLookup", locale));
+            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemsWithPaymentMethodLookup", locale));
             return "error";
         }
 
@@ -177,7 +177,7 @@ public class OrderManagerEvents {
             placingCustomer = EntityQuery.use(delegator).from("OrderRole").where("orderId", orderId, "roleTypeId", "PLACING_CUSTOMER").queryFirst();
         } catch (GenericEntityException e) {
             Debug.logError(e, "Problems looking up order payment preferences", module);
-            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderErrorProcessingOfflinePayments", locale));
+            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderErrorProcessingOfflinePayments", locale));
             return "error";
         }
 
@@ -188,9 +188,9 @@ public class OrderManagerEvents {
             if (!UtilValidate.isEmpty(paymentMethodAmountStr)) {
                 BigDecimal paymentMethodAmount = BigDecimal.ZERO;
                 try {
-                 paymentMethodAmount = (BigDecimal) ObjectType.simpleTypeConvert(paymentMethodAmountStr, "BigDecimal", null, locale);
+                    paymentMethodAmount = (BigDecimal) ObjectType.simpleTypeConvert(paymentMethodAmountStr, "BigDecimal", null, locale);
                 } catch (GeneralException e) {
-                    request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemsPaymentParsingAmount", locale));
+                    request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemsPaymentParsingAmount", locale));
                     return "error";
                 }
                 if (paymentMethodAmount.compareTo(BigDecimal.ZERO) > 0) {
@@ -199,8 +199,8 @@ public class OrderManagerEvents {
                     try {
                         results = dispatcher.runSync("createPaymentFromOrder",
                             UtilMisc.toMap("orderId", orderId,
-                             "paymentMethodId", paymentMethodId,
-                             "paymentRefNum", paymentMethodReference,
+                                    "paymentMethodId", paymentMethodId,
+                                    "paymentRefNum", paymentMethodReference,
                                     "comments", "Payment received offline and manually entered.",
                                     "userLogin", userLogin));
                     } catch (GenericServiceException e) {
@@ -214,14 +214,12 @@ public class OrderManagerEvents {
                         request.setAttribute("_ERROR_MESSAGE_", results.get(ModelService.ERROR_MESSAGE));
                         return "error";
                     }
-                
                 }
                 OrderChangeHelper.approveOrder(dispatcher, userLogin, orderId);
                 return "success";
             }
         }
-        
-        
+
         List<GenericValue> toBeStored = FastList.newInstance();
         for (GenericValue paymentMethodType : paymentMethodTypes) {
             String paymentMethodTypeId = paymentMethodType.getString("paymentMethodTypeId");
@@ -232,13 +230,13 @@ public class OrderManagerEvents {
                 try {
                     paymentTypeAmount = (BigDecimal) ObjectType.simpleTypeConvert(amountStr, "BigDecimal", null, locale);
                 } catch (GeneralException e) {
-                    request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemsPaymentParsingAmount", locale));
+                    request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemsPaymentParsingAmount", locale));
                     return "error";
                 }
                 if (paymentTypeAmount.compareTo(BigDecimal.ZERO) > 0) {
                     // create the OrderPaymentPreference
                     // TODO: this should be done with a service
-                    Map<String, String> prefFields = UtilMisc.<String, String>toMap("orderPaymentPreferenceId", delegator.getNextSeqId("OrderPaymentPreference"));
+                    Map<String, String> prefFields = UtilMisc.<String, String> toMap("orderPaymentPreferenceId", delegator.getNextSeqId("OrderPaymentPreference"));
                     GenericValue paymentPreference = delegator.makeValue("OrderPaymentPreference", prefFields);
                     paymentPreference.set("paymentMethodTypeId", paymentMethodType.getString("paymentMethodTypeId"));
                     paymentPreference.set("maxAmount", paymentTypeAmount);
@@ -287,7 +285,7 @@ public class OrderManagerEvents {
                     EntityCondition.makeCondition("orderId", EntityOperator.EQUALS, orderId),
                     EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "PAYMENT_CANCELLED")),
                     EntityOperator.AND);
-            currentPrefs = delegator.findList("OrderPaymentPreference", ecl, null, null, null, false);
+            currentPrefs = EntityQuery.use(delegator).from("OrderPaymentPreference").where(ecl).queryList();
         } catch (GenericEntityException e) {
             Debug.logError(e, "ERROR: Unable to get existing payment preferences from order", module);
         }
@@ -322,7 +320,7 @@ public class OrderManagerEvents {
             delegator.storeAll(toBeStored);
         } catch (GenericEntityException e) {
             Debug.logError(e, "Problems storing payment information", module);
-            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error,"OrderProblemStoringReceivedPaymentInformation", locale));
+            request.setAttribute("_ERROR_MESSAGE_", UtilProperties.getMessage(resource_error, "OrderProblemStoringReceivedPaymentInformation", locale));
             return "error";
         }
 

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java Mon Dec  8 10:21:56 2014
@@ -1391,15 +1391,12 @@ public class OrderReadHelper {
         try {
             orderDeliverySchedule = EntityQuery.use(delegator).from("OrderDeliverySchedule").where("orderId", orderId, "orderItemSeqId", "_NA_").queryOne();
         } catch (GenericEntityException e) {
+            if (Debug.infoOn()) Debug.logInfo(" OrderDeliverySchedule not found for order " + orderId, module);
+            return false;
         }
-        Timestamp estimatedShipDate = null;
-        if (orderDeliverySchedule != null && orderDeliverySchedule.get("estimatedReadyDate") != null) {
-            estimatedShipDate = orderDeliverySchedule.getTimestamp("estimatedReadyDate");
-        }
-        if (estimatedShipDate != null && UtilDateTime.nowTimestamp().after(estimatedShipDate)) {
-            return true;
-        }
-        return false;
+        if (orderDeliverySchedule == null) return false;
+        Timestamp estimatedShipDate = orderDeliverySchedule.getTimestamp("estimatedReadyDate");
+        return estimatedShipDate != null && UtilDateTime.nowTimestamp().after(estimatedShipDate);
     }
 
     public boolean getRejectedOrderItems() {
@@ -1985,6 +1982,38 @@ public class OrderReadHelper {
                 BigDecimal issueQty = issue.getBigDecimal("quantity");
                 BigDecimal cancelQty = issue.getBigDecimal("cancelQuantity");
                 if (cancelQty == null) {
+                    cancelQty = ZERO;
+                }
+                if (issueQty == null) {
+                    issueQty = ZERO;
+                }
+                quantityShipped = quantityShipped.add(issueQty.subtract(cancelQty)).setScale(scale, rounding);
+            }
+        }
+        return quantityShipped.setScale(scale, rounding);
+    }
+
+    public BigDecimal getItemShipGroupAssocShippedQuantity(GenericValue orderItem, String shipGroupSeqId) {
+        BigDecimal quantityShipped = ZERO;
+
+        if (orderItem == null) return null;
+        if (this.orderItemIssuances == null) {
+            Delegator delegator = orderItem.getDelegator();
+            try {
+                orderItemIssuances = EntityQuery.use(delegator).from("ItemIssuance").where("orderId", orderItem.get("orderId"), "shipGroupSeqId", shipGroupSeqId).queryList();                
+            } catch (GenericEntityException e) {
+                Debug.logWarning(e, "Trouble getting ItemIssuance(s)", module);
+            }
+        }
+
+        // filter the issuance
+        Map<String, Object> filter = UtilMisc.toMap("orderItemSeqId", orderItem.get("orderItemSeqId"), "shipGroupSeqId", shipGroupSeqId);
+        List<GenericValue> issuances = EntityUtil.filterByAnd(orderItemIssuances, filter);
+        if (UtilValidate.isNotEmpty(issuances)) {
+            for (GenericValue issue : issuances) {
+                BigDecimal issueQty = issue.getBigDecimal("quantity");
+                BigDecimal cancelQty = issue.getBigDecimal("cancelQuantity");
+                if (cancelQty == null) {
                     cancelQty = ZERO;
                 }
                 if (issueQty == null) {

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderServices.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderServices.java?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderServices.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/order/OrderServices.java Mon Dec  8 10:21:56 2014
@@ -44,7 +44,6 @@ import org.ofbiz.base.util.GeneralExcept
 import org.ofbiz.base.util.GeneralRuntimeException;
 import org.ofbiz.base.util.ObjectType;
 import org.ofbiz.base.util.UtilDateTime;
-import org.ofbiz.base.util.UtilFormatOut;
 import org.ofbiz.base.util.UtilGenerics;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilNumber;
@@ -96,6 +95,7 @@ public class OrderServices {
     public static final String resource = "OrderUiLabels";
     public static final String resource_error = "OrderErrorUiLabels";
     public static final String resourceProduct = "ProductUiLabels";
+    public static final String resourceCommon = "CommonUiLabels";
 
     public static Map<String, String> salesAttributeRoleMap = FastMap.newInstance();
     public static Map<String, String> purchaseAttributeRoleMap = FastMap.newInstance();
@@ -572,7 +572,7 @@ public class OrderServices {
         // before processing orderItems process orderItemGroups so that they'll be in place for the foreign keys and what not
         List<GenericValue> orderItemGroups = UtilGenerics.checkList(context.get("orderItemGroups"));
         if (UtilValidate.isNotEmpty(orderItemGroups)) {
-            for (GenericValue orderItemGroup : orderItemGroups){
+            for (GenericValue orderItemGroup : orderItemGroups) {
                 orderItemGroup.set("orderId", orderId);
                 toBeStored.add(orderItemGroup);
             }
@@ -1196,7 +1196,7 @@ public class OrderServices {
             countProductQuantityOrdered(ctx, context);
         }
         return ServiceUtil.returnSuccess();
-    }            
+    }
 
     public static void reserveInventory(Delegator delegator, LocalDispatcher dispatcher, GenericValue userLogin, Locale locale, List<GenericValue> orderItemShipGroupInfo, List<String> dropShipGroupIds, Map<String, GenericValue> itemValuesBySeqId, String orderTypeId, String productStoreId, List<String> resErrorMessages) throws GeneralException {
         boolean isImmediatelyFulfilled = false;
@@ -2128,6 +2128,17 @@ public class OrderServices {
                                 "OrderUnableToSetCancelQuantity", UtilMisc.toMap("itemMsgInfo",itemMsgInfo), locale));
                     }
 
+                    Map<String, Object> localCtx = UtilMisc.toMap("userLogin", userLogin,
+                            "orderId", orderItem.getString("orderId"),
+                            "orderItemSeqId", orderItem.getString("orderItemSeqId"),
+                            "shipGroupSeqId", orderItemShipGroupAssoc.getString("shipGroupSeqId"));
+                    try {
+                        dispatcher.runSync("deleteOrderItemShipGroupAssoc", localCtx);
+                    } catch (GenericServiceException e) {
+                        Debug.logError(e, module);
+                        return ServiceUtil.returnError(e.getMessage());
+                    }
+
                     //  create order item change record
                     if (!"Y".equals(orderItem.getString("isPromo"))) {
                         String reasonEnumId = null;
@@ -3577,6 +3588,8 @@ public class OrderServices {
                     "OrderShoppingCartEmpty", locale));
         }
 
+        shipGroupIdx = cart.getShipInfoIndex(shipGroupSeqId);
+
         // add in the new product
         try {
             if ("PURCHASE_ORDER".equals(cart.getOrderType())) {
@@ -3611,6 +3624,9 @@ public class OrderServices {
 
                 // set the item in the selected ship group
                 item.setDesiredDeliveryDate(itemDesiredDeliveryDate);
+                shipGroupIdx = cart.getShipInfoIndex(shipGroupSeqId);
+                int itemId = cart.getItemIndex(item);
+                cart.positionItemToGroup(itemId, quantity, cart.getItemShipGroupIndex(itemId), shipGroupIdx, false);
                 cart.clearItemShipInfo(item);
                 cart.setItemShipGroupQty(item, item.getQuantity(), shipGroupIdx);
             }
@@ -3845,10 +3861,13 @@ public class OrderServices {
             // set the group qty
             ShoppingCartItem cartItem = cart.findCartItem(itemInfo[0]);
             if (cartItem != null) {
-            Debug.logInfo("Shipping info (before) for group #" + (groupIdx-1) + " [" + cart.getShipmentMethodTypeId(groupIdx-1) + " / " + cart.getCarrierPartyId(groupIdx-1) + "]", module);
-            cart.setItemShipGroupQty(cartItem, groupQty, groupIdx - 1);
-            Debug.logInfo("Set ship group qty: [" + itemInfo[0] + " / " + itemInfo[1] + " (" + (groupIdx-1) + ")] " + groupQty, module);
-            Debug.logInfo("Shipping info (after) for group #" + (groupIdx-1) + " [" + cart.getShipmentMethodTypeId(groupIdx-1) + " / " + cart.getCarrierPartyId(groupIdx-1) + "]", module);
+                int shipGroupIndex = cart.getShipInfoIndex(itemInfo[1]);
+                if (Debug.infoOn()) Debug.logInfo("Shipping info (before) for group #" + (shipGroupIndex) + " [" + cart.getShipmentMethodTypeId(shipGroupIndex) + " / " + cart.getCarrierPartyId(shipGroupIndex) + "]", module);
+                cart.setItemShipGroupQty(cartItem, groupQty, shipGroupIndex);
+                if (Debug.infoOn()) {
+                    Debug.logInfo("Set ship group qty: [" + itemInfo[0] + " / " + itemInfo[1] + " (" + (shipGroupIndex) + ")] " + groupQty, module);
+                    Debug.logInfo("Shipping info (after) for group #" + (shipGroupIndex) + " [" + cart.getShipmentMethodTypeId(shipGroupIndex) + " / " + cart.getCarrierPartyId(shipGroupIndex) + "]", module);
+                }
             }
         }
 
@@ -4049,7 +4068,33 @@ public class OrderServices {
             exprs.add(EntityCondition.makeCondition("orderAdjustmentTypeId", EntityOperator.EQUALS, "VAT_PRICE_CORRECT"));
             adjExprs.add(EntityCondition.makeCondition(exprs, EntityOperator.OR));
             EntityCondition cond = EntityCondition.makeCondition(adjExprs, EntityOperator.AND);
-            delegator.removeByCondition("OrderAdjustment", cond);
+            List<GenericValue> orderAdjustmentsToDelete = EntityQuery.use(delegator).from("OrderAdjustment").where(cond).queryList();
+            List<GenericValue> orderAdjustmentsToStore = new LinkedList<GenericValue>();
+            List<GenericValue> orderAdjustmentsToRemove = new LinkedList<GenericValue>();
+            if (UtilValidate.isNotEmpty(orderAdjustmentsToDelete)) {
+                for (GenericValue orderAdjustment : orderAdjustmentsToDelete) {
+                    //check if the adjustment has a related entry in entity OrderAdjustmentBilling
+                    List<GenericValue> oaBilling = orderAdjustment.getRelated("OrderAdjustmentBilling", null, null, false);
+                    if (UtilValidate.isNotEmpty(oaBilling)) {
+                        orderAdjustmentsToRemove.add(orderAdjustment);
+                        if ("SALES_TAX".equals(orderAdjustment.get("orderAdjustmentTypeId"))) {
+                            //if the orderAdjustment is  a sale tax, set the amount to 0 to avoid amount addition
+                            orderAdjustmentsToStore.add(orderAdjustment);
+                        }
+                    }
+                }
+            }
+            //then remove order Adjustment of the list
+            if (UtilValidate.isNotEmpty(orderAdjustmentsToDelete)) {
+                orderAdjustmentsToDelete.removeAll(orderAdjustmentsToRemove);
+                delegator.removeAll(orderAdjustmentsToDelete);
+            }
+            if (UtilValidate.isNotEmpty(orderAdjustmentsToStore)) {
+                for (GenericValue orderAdjustment : orderAdjustmentsToStore) {
+                    orderAdjustment.set("amount", BigDecimal.ZERO);
+                }
+                delegator.storeAll(orderAdjustmentsToStore);
+            }
         } catch (GenericEntityException e) {
             Debug.logError(e, module);
             throw new GeneralException(e.getMessage());
@@ -4091,9 +4136,13 @@ public class OrderServices {
     private static void saveUpdatedCartToOrder(LocalDispatcher dispatcher, Delegator delegator, ShoppingCart cart,
             Locale locale, GenericValue userLogin, String orderId, Map<String, Object> changeMap, boolean calcTax,
             boolean deleteItems) throws GeneralException {
-        // get/set the shipping estimates.  if it's a SALES ORDER, then return an error if there are no ship estimates
-        int shipGroups = cart.getShipGroupSize();
-        for (int gi = 0; gi < shipGroups; gi++) {
+        // get/set the shipping estimates. If it's a SALES ORDER, then return an error if there are no ship estimates
+        int shipGroupsSize = cart.getShipGroupSize();
+        int realShipGroupsSize = (new OrderReadHelper(delegator, orderId)).getOrderItemShipGroups().size();
+        // If an empty csi has initially been added to cart.shipInfo by ShoppingCart.setItemShipGroupQty() (called indirectly by ShoppingCart.setUserLogin() and then ProductPromoWorker.doPromotions(), etc.)
+        //  shipGroupsSize > realShipGroupsSize are different (+1 for shipGroupsSize), then simply bypass the 1st empty csi!
+        int origin = realShipGroupsSize == shipGroupsSize ? 0 : 1;
+        for (int gi = origin; gi < shipGroupsSize; gi++) {
             String shipmentMethodTypeId = cart.getShipmentMethodTypeId(gi);
             String carrierPartyId = cart.getCarrierPartyId(gi);
             Debug.logInfo("Getting ship estimate for group #" + gi + " [" + shipmentMethodTypeId + " / " + carrierPartyId + "]", module);
@@ -4152,18 +4201,15 @@ public class OrderServices {
         toStore.addAll(cart.makeOrderItems());
         toStore.addAll(cart.makeAllAdjustments());
 
-        String shipGroupSeqId = null;
         long groupIndex = cart.getShipInfoSize();
         if (!deleteItems) {
             for (long itr = 1; itr <= groupIndex; itr++) {
-                shipGroupSeqId = UtilFormatOut.formatPaddedNumber(itr, 5);
                 List<GenericValue> removeList = new ArrayList<GenericValue>();
                 for (GenericValue stored: toStore) {
                     if ("OrderAdjustment".equals(stored.getEntityName())) {
                         if (("SHIPPING_CHARGES".equals(stored.get("orderAdjustmentTypeId")) ||
                                "SALES_TAX".equals(stored.get("orderAdjustmentTypeId"))) &&
-                                stored.get("orderId").equals(orderId) &&
-                                stored.get("shipGroupSeqId").equals(shipGroupSeqId)) {
+                                stored.get("orderId").equals(orderId)) {
                             // Removing objects from toStore list for old Shipping and Handling Charges Adjustment and Sales Tax Adjustment.
                             removeList.add(stored);
                         }
@@ -5637,6 +5683,442 @@ public class OrderServices {
                 "OrderRunSubscriptionAutoReorders", UtilMisc.toMap("count", count), locale));
     }
 
+    /**
+     * Create an OrderItemShipGroup record
+     * @param ctx
+     * @param context
+     * @return
+     * @throws GenericEntityException
+     */
+    public static Map<String, Object> addOrderItemShipGroup(DispatchContext dctx, Map<String, Object> context) {
+        Delegator delegator = dctx.getDelegator();
+        Locale locale = (Locale) context.get("locale" );
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+        String orderId = (String) context.get("orderId");
+
+        //main message error
+        String mainErrorMessage = UtilProperties.getMessage(resource_error, "OrderUnableToAddOISGToOrder", locale);
+        Map<String, Object> createOrderItemShipGroupMap = null;
+        try {
+            createOrderItemShipGroupMap = dctx.makeValidContext("createOrderItemShipGroup", "IN", context);
+        } catch (GenericServiceException gse) {
+            String errMsg = mainErrorMessage + gse.toString();
+            return ServiceUtil.returnError(errMsg);
+        }
+
+        try {
+            //test if party is a valid carrier
+            String carrierPartyId = (String) context.get("carrierPartyId");
+            GenericValue carrierRole = EntityQuery.use(delegator).from("PartyRole").where("partyId", carrierPartyId, "roleTypeId", "CARRIER").cache().queryOne();
+            if (UtilValidate.isNotEmpty(carrierPartyId) && UtilValidate.isEmpty(carrierRole)) {
+                String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderCartShipGroupPartyCarrierNotFound", UtilMisc.toMap("partyId", carrierPartyId), locale);
+                return ServiceUtil.returnError(errMsg);
+            }
+
+            //test if shipmentMethodTypeId is available for carrier party
+            String shipmentMethodTypeId = (String) context.get("shipmentMethodTypeId");
+            if (UtilValidate.isNotEmpty(shipmentMethodTypeId)) {
+                // carrierPartyId is not in shipmentMethodTypeId
+                if (shipmentMethodTypeId.indexOf("_o_" ) == -1) {
+                    GenericValue shipmentMethod = EntityQuery.use(delegator).from("CarrierShipmentMethod").where("partyId", carrierPartyId, "roleTypeId", "CARRIER", "shipmentMethodTypeId", shipmentMethodTypeId).cache().queryOne();
+                    if (UtilValidate.isEmpty(shipmentMethod)) {
+                        String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderCartShipGroupShipmentMethodNotFound", UtilMisc.toMap("shipmentMethodTypeId", shipmentMethodTypeId), locale);
+                        return ServiceUtil.returnError(errMsg);
+                    }
+                } else {
+                    // carrierPartyId is in shipmentMethodTypeId
+                    String[] carrierShipmentMethod = shipmentMethodTypeId.split("_o_");
+                    if (carrierShipmentMethod.length == 2) {
+                        shipmentMethodTypeId = carrierShipmentMethod[0];
+                        carrierPartyId = carrierShipmentMethod[1];
+                    }
+                    context.put("carrierPartyId", carrierPartyId);
+                    context.put("shipmentMethodTypeId", shipmentMethodTypeId);
+                }
+            }
+
+            List<GenericValue> oisgs = EntityQuery.use(delegator).from("OrderItemShipGroup").where("orderId", orderId).orderBy("shipGroupSeqId DESC").queryList();
+            if (UtilValidate.isNotEmpty(oisgs)) {
+                GenericValue oisg = EntityUtil.getFirst(oisgs);
+                // set shipmentMethodTypeId, carrierPartyId, carrierRoleTypeId, contactMechId when shipmentMethodTypeId and carrierPartyId are empty
+                if (UtilValidate.isEmpty(carrierPartyId) && UtilValidate.isEmpty(shipmentMethodTypeId)) {
+                    createOrderItemShipGroupMap.put("shipmentMethodTypeId", oisg.get("shipmentMethodTypeId"));
+                    createOrderItemShipGroupMap.put("carrierPartyId", oisg.get("carrierPartyId"));
+                    createOrderItemShipGroupMap.put("carrierRoleTypeId", oisg.get("carrierRoleTypeId"));
+                    createOrderItemShipGroupMap.put("contactMechId", oisg.get("contactMechId"));
+                }
+            }
+        } catch (GenericEntityException gee) {
+            String errMsg = mainErrorMessage + gee.toString();
+            return ServiceUtil.returnError(errMsg);
+        }
+
+        // set maySplit and isGift for the new oisg to No if they are not present
+        if (UtilValidate.isEmpty(createOrderItemShipGroupMap.get("maySplit"))) {
+            createOrderItemShipGroupMap.put("maySplit", "N");
+        }
+        if (UtilValidate.isEmpty(createOrderItemShipGroupMap.get("isGift"))) {
+            createOrderItemShipGroupMap.put("isGift", "N");
+        }
+
+        //create new oisg
+        try {
+            result = dctx.getDispatcher().runSync("createOrderItemShipGroup", createOrderItemShipGroupMap);
+        } catch (GenericServiceException gse) {
+            String errMsg = mainErrorMessage + gse.toString();
+            return ServiceUtil.returnError(errMsg);
+        }
+
+        if (ServiceUtil.isError(result)) {
+            String errMsg = UtilProperties.getMessage(resource, mainErrorMessage + result.get("errorMessage"), locale);
+            return ServiceUtil.returnError(errMsg);
+        }
+        return result;
+    }
+
+    /**
+     * Remove an OrderItemShipGroup record
+     * @param ctx
+     * @param context: a map containing in paramaters
+     * @return result: a map containing out parameters
+     * @throws GenericEntityException
+     */
+    public static Map deleteOrderItemShipGroup(DispatchContext ctx, Map context) throws GenericEntityException {
+        Delegator delegator = ctx.getDelegator();
+        Map<String, Object> result = new HashMap<String, Object>();
+        
+        GenericValue orderItemShipGroup = (GenericValue) context.get("orderItemShipGroup");
+        if (UtilValidate.isEmpty(orderItemShipGroup)) {
+            String orderId= (String) context.get("orderId");
+            GenericValue orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne();
+            String shipGroupSeqId= (String) context.get("shipGroupSeqId");
+            if (UtilValidate.isNotEmpty(orderHeader) && UtilValidate.isNotEmpty(shipGroupSeqId)) {
+                orderItemShipGroup = EntityQuery.use(delegator).from("OrderItemShipGroup").where("orderId", orderId, "shipGroupSeqId", shipGroupSeqId).queryOne();
+                if (UtilValidate.isEmpty(orderItemShipGroup)) {
+                    return ServiceUtil.returnError("OrderItemShipGroup Does Not Exist");
+                }
+            }
+        }
+        if (UtilValidate.isNotEmpty(orderItemShipGroup)) {
+            orderItemShipGroup.remove();
+            result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
+        }
+        return result;
+    }
+
+    /**
+     * Create orderItem and shipGroup association
+     * @param dctx
+     * @param context
+     * @return
+     * @throws GenericEntityException
+     */
+    public static Map addOrderItemShipGroupAssoc(DispatchContext dctx, Map<String, Object> context) throws GenericEntityException {
+        Delegator delegator = dctx.getDelegator();
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+        Locale locale = (Locale) context.get("locale" );
+        String orderId = (String) context.get("orderId");
+        String orderItemSeqId = (String) context.get("orderItemSeqId");
+        String shipGroupSeqId = (String) context.get("shipGroupSeqId");
+        BigDecimal quantity = (BigDecimal) context.get("quantity");
+
+        //main message error
+        String mainErrorMessage = UtilProperties.getMessage(resource_error, "OrderUnableToAddItemToOISG", locale);
+        //test orderItem and check status
+        GenericValue orderItem = EntityQuery.use(delegator).from("OrderItem").where("orderId", orderId, "orderItemSeqId", orderItemSeqId).queryOne();
+        if (orderItem == null) {
+            String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderErrorOrderItemNotFound", UtilMisc.toMap("orderId", orderId, "orderItemSeqId", orderItemSeqId), locale);
+            return ServiceUtil.returnError(errMsg);
+        }
+        String statusId = orderItem.getString("statusId");
+        // add OISG only if orderItem is not already prepared
+        if ("ITEM_CREATED".equals(statusId) || "ITEM_APPROVED".equals(statusId)) {
+            //find OISG
+            //by default create a new orderItemShipGroup if null with default carrier and contact from the first OISG
+            if ("new".equals(shipGroupSeqId)) {
+                try {
+                    Map<String, Object> addOrderItemShipGroupMap = dctx.makeValidContext("addOrderItemShipGroup", "IN", context);
+                    addOrderItemShipGroupMap.remove("shipGroupSeqId");
+                    //get default OrderItemShipGroup value for carrier and contact data  
+                    List<GenericValue> oisgas = orderItem.getRelated("OrderItemShipGroupAssoc", null, null, false);
+                    if (UtilValidate.isNotEmpty(oisgas)) {
+                        GenericValue oisga = EntityUtil.getFirst(oisgas);
+                        GenericValue oisg = oisga.getRelatedOne("OrderItemShipGroup", false);
+                        if (UtilValidate.isNotEmpty(oisg)) {
+                            addOrderItemShipGroupMap.put("shipmentMethodTypeId", oisg.get("shipmentMethodTypeId"));
+                            addOrderItemShipGroupMap.put("carrierPartyId", oisg.get("carrierPartyId"));
+                            addOrderItemShipGroupMap.put("carrierRoleTypeId", oisg.get("carrierRoleTypeId"));
+                            addOrderItemShipGroupMap.put("contactMechId", oisg.get("contactMechId"));
+                        }
+                    }
+                    //call  service to create new oisg
+                    Map<String, Object> result = null;
+                    result = dispatcher.runSync("addOrderItemShipGroup", addOrderItemShipGroupMap);
+                    if (result.containsKey("shipGroupSeqId")) {
+                        shipGroupSeqId = (String) result.get("shipGroupSeqId");
+                    }
+                } catch (GenericServiceException e) {
+                    String errMsg = UtilProperties.getMessage(resource, mainErrorMessage, locale);
+                    return ServiceUtil.returnError(errMsg);
+                }
+            }
+            GenericValue orderItemShipGroup = EntityQuery.use(delegator).from("OrderItemShipGroup").where("orderId", orderId, "shipGroupSeqId", shipGroupSeqId).queryOne();
+            if (UtilValidate.isEmpty(orderItemShipGroup)) {
+                String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderCartShipGroupNotFound", UtilMisc.toMap("groupIndex", shipGroupSeqId), locale);
+                return ServiceUtil.returnError(errMsg);
+            }
+            //now test quantity parameter
+            //if quantity is null or negative then display error
+            if (quantity == null || quantity.compareTo(BigDecimal.ZERO) == -1) {
+                String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderQuantityAssociatedCannotBeNullOrNegative", locale);
+                return ServiceUtil.returnError(errMsg);
+            }
+            //test if this association already exist if yes display error
+            GenericValue oisgAssoc = EntityQuery.use(delegator).from("OrderItemShipGroupAssoc").where("orderId", orderId, "orderItemSeqId", orderItem.get("orderItemSeqId"), "shipGroupSeqId", shipGroupSeqId).queryOne();
+            if (UtilValidate.isNotEmpty(oisgAssoc)) {
+                String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderErrorOrderItemAlreadyRelatedToShipGroup", locale);
+                return ServiceUtil.returnError(errMsg);
+            }
+            //no error, create OISGA
+            oisgAssoc = delegator.makeValue("OrderItemShipGroupAssoc", UtilMisc.toMap("orderId", orderId, "orderItemSeqId", orderItem.get("orderItemSeqId"), "shipGroupSeqId", shipGroupSeqId));
+            oisgAssoc.set("quantity", quantity);
+            oisgAssoc.create();
+            return ServiceUtil.returnSuccess();
+        } else {
+            String errMsg = UtilProperties.getMessage(resource, mainErrorMessage + orderItem, locale);
+            return ServiceUtil.returnError(errMsg);
+        }
+    }
+
+    /**
+     * Update orderItem and shipgroup association
+     * @param ctx
+     * @param context
+     * @return
+     * @throws GeneralException
+     */
+    public static Map updateOrderItemShipGroupAssoc(DispatchContext dctx, Map context) throws GeneralException{
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+        String message = null;
+        Delegator delegator = dctx.getDelegator();
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+        Locale locale = (Locale) context.get("locale" );
+        GenericValue userLogin = (GenericValue) context.get("userLogin" );
+
+        String orderId = (String) context.get("orderId");
+        String orderItemSeqId = (String) context.get("orderItemSeqId");
+        String shipGroupSeqId = (String) context.get("shipGroupSeqId");
+        BigDecimal quantity = (BigDecimal) context.get("quantity");
+        if (UtilValidate.isEmpty(quantity)) {
+            quantity = BigDecimal.ZERO;
+        }
+        BigDecimal totalQuantity = (BigDecimal) context.get("totalQuantity");
+        if (UtilValidate.isEmpty(totalQuantity)) {
+            totalQuantity = BigDecimal.ZERO;
+        }
+
+        //main message error
+        String mainErrorMessage = UtilProperties.getMessage(resource_error, "OrderUnableToUpdateOrderItemFromOISG", locale);
+        Integer rowCount = (Integer) context.get("rowCount");
+        Integer rowNumber = (Integer) context.get("rowNumber"); //total row number
+
+        if (rowNumber == null) {
+            Long count = EntityQuery.use(delegator).from("OrderItemShipGroupAssoc").where("orderId", orderId, "orderItemSeqId", orderItemSeqId).queryCount();
+            if (count != null) {
+                rowNumber = new Integer(count.intValue());
+                result.put("rowNumber", rowNumber);
+            }
+        }
+
+        //find OISG Assoc
+        GenericValue oisga = EntityQuery.use(delegator).from("OrderItemShipGroupAssoc").where("orderId", orderId, "orderItemSeqId", orderItemSeqId, "shipGroupSeqId", shipGroupSeqId).queryOne();
+        if (UtilValidate.isEmpty(oisga)) {
+            String errMsg = mainErrorMessage + " : Order Item Ship Group Assoc Does Not Exist";
+            Debug.logError(errMsg, module);
+            return ServiceUtil.returnError(errMsg);
+        }
+
+        // find OISG associated with oisga
+        GenericValue oisg = EntityQuery.use(delegator).from("OrderItemShipGroup").where("orderId", orderId, "shipGroupSeqId", shipGroupSeqId).queryOne();
+        //find OrderItem
+        GenericValue orderItem = EntityQuery.use(delegator).from("OrderItem").where("orderId", orderId, "orderItemSeqId", orderItemSeqId).queryOne();
+        if (UtilValidate.isEmpty(orderItem)) {
+            String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderErrorOrderItemNotFound", UtilMisc.toMap("orderId", orderId, "orderItemSeqId", orderItemSeqId), locale);
+            return ServiceUtil.returnError(errMsg);
+        }
+
+        // update OISGA  
+        if (oisg != null) {
+            //if quantity is 0, delete this association only if there is several oisgaoc
+            if (ZERO.compareTo(quantity) == 0) {
+                // test if  there is only one oisgaoc then display errror
+                if (rowNumber.intValue() == 1) {
+                    String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderQuantityAssociatedCannotBeNullOrNegative", locale);
+                    Debug.logError(errMsg, module);
+                    return ServiceUtil.returnError(errMsg);
+                }
+                try {
+                    Map<String, Object> cancelOrderInventoryReservationMap = dctx.makeValidContext("cancelOrderInventoryReservation", "IN", context);
+                    Map<String, Object> localResult = dispatcher.runSync("cancelOrderInventoryReservation", cancelOrderInventoryReservationMap);
+                    if (ServiceUtil.isError(localResult)) return localResult;
+                    Map<String, Object> deleteOrderItemShipGroupAssocMap = dctx.makeValidContext("deleteOrderItemShipGroupAssoc", "IN", context);
+                    localResult = dispatcher.runSync("deleteOrderItemShipGroupAssoc", deleteOrderItemShipGroupAssocMap);
+                    if (ServiceUtil.isError(localResult)) return localResult;
+                } catch (GenericServiceException e) {
+                    return ServiceUtil.returnError(e.toString());
+                }
+                //Only for multi service calling and the last row : test if orderItem quantity equals OrderItemShipGroupAssocs quantitys
+                if (rowCount != null && rowNumber != null ) {
+                    int rowCountInt = rowCount .intValue();
+                    int rowNumberInt = rowNumber .intValue();
+                    if (rowCountInt == rowNumberInt - 1) {
+                        try {
+                            message = validateOrderItemShipGroupAssoc(delegator, dispatcher, orderItem, totalQuantity, oisga, userLogin, locale);
+                        }
+                        catch (Exception e) {
+                            String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderQuantityAssociatedIsLessThanOrderItemQuantity", locale);
+                            Debug.logError(errMsg, module);
+                            return ServiceUtil.returnError(errMsg);
+                        }
+                    }
+                }
+                result.put("totalQuantity", totalQuantity);
+                if (UtilValidate.isNotEmpty(message)) {
+                    result.put("successMessage", message);
+                }
+                return result;
+           }
+
+           BigDecimal actualQuantity = totalQuantity.add(quantity);
+           BigDecimal qty = (BigDecimal) orderItem.get("quantity");
+           if (UtilValidate.isEmpty(qty)) {
+               qty = BigDecimal.ZERO;
+           }
+           BigDecimal cancelQty = (BigDecimal) orderItem.get("cancelQuantity");
+           if (UtilValidate.isEmpty(cancelQty)) {
+               cancelQty = BigDecimal.ZERO;
+           }
+           BigDecimal orderItemQuantity = qty.subtract(cancelQty);
+            if (actualQuantity.compareTo(orderItemQuantity ) > 0) {
+                String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderQuantityAssociatedIsBiggerThanOrderItemQuantity", locale);
+                Debug.logError(errMsg, module);
+                return ServiceUtil.returnError(errMsg);
+            }
+
+            //if quantity is bigger than OI then display error
+            if (quantity.compareTo(orderItemQuantity) > 0) {
+                String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderQuantityAssociatedIsBiggerThanOrderItemQuantity", locale);
+                Debug.logError(errMsg, module);
+                return ServiceUtil.returnError(errMsg);
+            }
+            oisga.set("quantity", quantity);
+            //store new values
+            oisga.store();
+            // reserve the inventory
+            GenericValue orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne();
+            if (UtilValidate.isNotEmpty(orderHeader)) {
+                Map<String, Object> cancelResp = dispatcher.runSync("cancelOrderInventoryReservation", UtilMisc.toMap("userLogin", userLogin, "orderId", orderId, "orderItemSeqId", orderItemSeqId, "shipGroupSeqId", shipGroupSeqId ));
+                if (ServiceUtil.isError(cancelResp)) {
+                    throw new GeneralException(ServiceUtil.getErrorMessage(cancelResp));
+                }
+                String productStoreId = orderHeader.getString("productStoreId");
+                String orderTypeId = orderHeader.getString("orderTypeId");
+                List<String> resErrorMessages = new LinkedList<String>();
+                if (Debug.infoOn()) Debug.logInfo("Calling reserve inventory...", module);
+                reserveInventory(delegator, dispatcher, userLogin, locale, UtilMisc.toList(oisga), null, UtilMisc.<String, GenericValue>toMap(orderItemSeqId, orderItem), orderTypeId, productStoreId, resErrorMessages);
+            }
+
+            //update totalQuantity
+            totalQuantity = totalQuantity.add(quantity);
+            result.put("totalQuantity", totalQuantity);
+
+            //Only for multi service calling and the last row : test if orderItem quantity equals OrderItemShipGroupAssocs quantitys
+            if (rowCount != null && rowNumber != null ) {
+                int rowCountInt = rowCount .intValue();
+                int rowNumberInt = rowNumber .intValue();
+                if (rowCountInt == rowNumberInt - 1) {
+                    try {
+                        message = validateOrderItemShipGroupAssoc(delegator, dispatcher, orderItem, totalQuantity,  oisga, userLogin, locale);
+                    }
+                    catch (GeneralException e) {
+                        String errMsg = mainErrorMessage + UtilProperties.getMessage(resource_error, "OrderQuantityAssociatedIsLessThanOrderItemQuantity", locale);
+                        Debug.logError(errMsg, module);
+                        return ServiceUtil.returnError(errMsg);
+                    }
+                }
+                if (UtilValidate.isNotEmpty(message)) {
+                    result.put("successMessage", message);
+                }
+            }
+        } else {
+            //update totalQuantity
+            totalQuantity = totalQuantity.add(quantity);
+            result.put("totalQuantity", totalQuantity);
+        }
+        return result;
+    }
+
+    /**
+     * Validate OrderItemShipGroupAssoc quantity
+     * This service should be called after updateOrderItemShipGroupAssoc
+     * test if orderItem quantity equals OrderItemShipGroupAssocs quantities
+     * if not then get the last orderItemShipgroupAssoc estimated shipDate and add quantity to this OrderItemShipGroupAssoc
+     * @param ctx
+     * @param context
+     * @return
+     * @throws GeneralException
+     */
+    private static String validateOrderItemShipGroupAssoc(Delegator delegator, LocalDispatcher dispatcher, GenericValue orderItem, BigDecimal totalQuantity, GenericValue lastOISGAssoc, GenericValue userLogin, Locale locale)
+           throws GeneralException {
+        String result = null;
+        BigDecimal qty = (BigDecimal) orderItem.get("quantity");
+        if (UtilValidate.isEmpty(qty)) {
+            qty = BigDecimal.ZERO;
+        }
+        BigDecimal cancelQty = (BigDecimal) orderItem.get("cancelQuantity");
+        if (UtilValidate.isEmpty(cancelQty)) {
+            cancelQty = BigDecimal.ZERO;
+        }
+
+        BigDecimal orderItemQuantity = qty.subtract(cancelQty);
+        if (totalQuantity.compareTo(orderItemQuantity) < 0) {
+            //if quantity in orderItem is bigger than in totalQUantity then added missing quantity in ShipGroupAssoc
+            BigDecimal adjustementQuantity = orderItemQuantity.subtract( totalQuantity);
+            BigDecimal lastOISGAssocQuantity = (BigDecimal) lastOISGAssoc.get("quantity");
+            if (UtilValidate.isEmpty(lastOISGAssocQuantity)) {
+                lastOISGAssocQuantity = BigDecimal.ZERO;
+            }
+            BigDecimal oisgaQty = lastOISGAssocQuantity.add(adjustementQuantity);
+            lastOISGAssoc.set("quantity", oisgaQty);
+            lastOISGAssoc.store();
+
+            // reserve the inventory
+            GenericValue orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", lastOISGAssoc.get("orderId")).queryOne();
+            if (UtilValidate.isNotEmpty(orderHeader)) {
+                Map<String, Object> cancelOrderInventoryReservationMap = UtilMisc.toMap("userLogin", userLogin, "locale", locale);
+                cancelOrderInventoryReservationMap.put("orderId", lastOISGAssoc.get("orderId"));
+                cancelOrderInventoryReservationMap.put("orderItemSeqId", lastOISGAssoc.get("orderItemSeqId"));
+                cancelOrderInventoryReservationMap.put("shipGroupSeqId", lastOISGAssoc.get("shipGroupSeqId"));
+                Map<String, Object> cancelResp = dispatcher.runSync("cancelOrderInventoryReservation", cancelOrderInventoryReservationMap);
+                if (ServiceUtil.isError(cancelResp)) {
+                    throw new GeneralException(ServiceUtil.getErrorMessage(cancelResp));
+                }
+                String productStoreId = orderHeader.getString("productStoreId");
+                String orderTypeId = orderHeader.getString("orderTypeId");
+                List<String> resErrorMessages = new LinkedList<String>();
+                if (Debug.infoOn()) Debug.logInfo("Calling reserve inventory...", module);
+                reserveInventory(delegator, dispatcher, userLogin, locale, UtilMisc.toList(lastOISGAssoc), null, UtilMisc.<String, GenericValue>toMap(lastOISGAssoc.getString("orderItemSeqId"), orderItem), orderTypeId, productStoreId, resErrorMessages);
+            }
+
+            //return warning message
+            Map<String, Object> messageParameters = new HashMap<String, Object>();
+            messageParameters.put("shipByDate", lastOISGAssoc.getRelatedOne("OrderItemShipGroup", false).getString("shipByDate"));
+            messageParameters.put("adjustementQuantity", adjustementQuantity);
+            return "Order OISG Assoc Quantity Auto Completed";
+        }
+        return result;
+    }
+
     public static Map<String, Object> setShippingInstructions(DispatchContext dctx, Map<String, ? extends Object> context) {
         Delegator delegator = dctx.getDelegator();
         String orderId = (String) context.get("orderId");

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java Mon Dec  8 10:21:56 2014
@@ -960,6 +960,7 @@ public class ShoppingCart implements Ite
     }
 
     /** Returns an iterator of cart items. */
+    @Override
     public Iterator<ShoppingCartItem> iterator() {
         return cartLines.iterator();
     }
@@ -2209,6 +2210,39 @@ public class ShoppingCart implements Ite
         }
     }
 
+    public int getShipInfoIndex (String shipGroupSeqId) {
+        int idx = -1;
+        for (int i=0; i<shipInfo.size(); i++) {
+            CartShipInfo csi = shipInfo.get(i);
+            if (shipGroupSeqId.equals(csi.shipGroupSeqId)) {
+                idx = i;
+                break;
+            }
+        }
+        return idx;
+    }
+
+    /**
+    * Return index of the ship group where the item is located
+    * @return
+    */
+    public int getItemShipGroupIndex(int itemId) {
+    int shipGroupIndex = this.getShipGroupSize() - 1;
+    ShoppingCartItem item = this.findCartItem(itemId);
+    int result=0;
+    for (int i = 0; i <(shipGroupIndex + 1); i++) {
+       CartShipInfo csi = this.getShipInfo(i);
+       Iterator it = csi.shipItemInfo.keySet().iterator();
+        while (it.hasNext()) {
+            ShoppingCartItem item2 = (ShoppingCartItem) it.next();
+            if (item.equals(item2) ) {
+                result = i;
+            }
+        }
+    }
+    return result;
+    }
+
     /** Sets the shipping contact mech id. */
     public void setShippingContactMechId(int idx, String shippingContactMechId) {
         CartShipInfo csi = this.getShipInfo(idx);
@@ -3922,7 +3956,12 @@ public class ShoppingCart implements Ite
         List<GenericValue> groups = new LinkedList<GenericValue>();
         long seqId = 1;
         for (CartShipInfo csi : this.shipInfo) {
-            groups.addAll(csi.makeItemShipGroupAndAssoc(this.getDelegator(), this, seqId));
+            String shipGroupSeqId = csi.shipGroupSeqId;
+            if (shipGroupSeqId != null) {
+                groups.addAll(csi.makeItemShipGroupAndAssoc(this.getDelegator(), this, shipGroupSeqId));
+            } else {
+                groups.addAll(csi.makeItemShipGroupAndAssoc(this.getDelegator(), this, UtilFormatOut.formatPaddedNumber(seqId, 5), true));
+            }
             seqId++;
         }
         return groups;
@@ -4289,6 +4328,7 @@ public class ShoppingCart implements Ite
             this.ascending = ascending;
         }
 
+        @Override
         public int compare(java.lang.Object obj, java.lang.Object obj1) {
             ShoppingCartItem cartItem = (ShoppingCartItem) obj;
             ShoppingCartItem cartItem1 = (ShoppingCartItem) obj1;
@@ -4418,6 +4458,7 @@ public class ShoppingCart implements Ite
             }
         }
 
+        @Override
         public int compareTo(ProductPromoUseInfo other) {
             return other.getUsageWeight().compareTo(getUsageWeight());
         }
@@ -4505,8 +4546,11 @@ public class ShoppingCart implements Ite
             }
         }
 
-        public List<GenericValue> makeItemShipGroupAndAssoc(Delegator delegator, ShoppingCart cart, long groupIndex) {
-            shipGroupSeqId = UtilFormatOut.formatPaddedNumber(groupIndex, 5);
+        public List<GenericValue> makeItemShipGroupAndAssoc(Delegator delegator, ShoppingCart cart, String shipGroupSeqId) {
+            return makeItemShipGroupAndAssoc(delegator, cart, shipGroupSeqId, false);
+        }
+
+        public List<GenericValue> makeItemShipGroupAndAssoc(Delegator delegator, ShoppingCart cart, String shipGroupSeqId, boolean newShipGroup) {
             List<GenericValue> values = new LinkedList<GenericValue>();
 
             // create order contact mech for shipping address
@@ -4937,6 +4981,7 @@ public class ShoppingCart implements Ite
             return values;
         }
 
+        @Override
         public int compareTo(Object o) {
             CartPaymentInfo that = (CartPaymentInfo) o;
             Debug.logInfo("Compare [" + this.toString() + "] to [" + that.toString() + "]", module);

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java Mon Dec  8 10:21:56 2014
@@ -191,8 +191,7 @@ public class ShoppingCartItem implements
         if (product == null) {
             Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productId", productId);
 
-            String excMsg = UtilProperties.getMessage(resource_error, "item.product_not_found",
-                                          messageMap , cart.getLocale());
+            String excMsg = UtilProperties.getMessage(resource_error, "item.product_not_found", messageMap , cart.getLocale());
 
             Debug.logWarning(excMsg, module);
             throw new ItemNotFoundException(excMsg);
@@ -201,11 +200,9 @@ public class ShoppingCartItem implements
 
         // check to see if product is virtual
         if ("Y".equals(product.getString("isVirtual"))) {
-            Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productName", product.getString("productName"),
-                                            "productId", product.getString("productId"));
+            Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productName", product.getString("productName"), "productId", product.getString("productId"));
 
-            String excMsg = UtilProperties.getMessage(resource_error, "item.cannot_add_product_virtual",
-                                          messageMap , cart.getLocale());
+            String excMsg = UtilProperties.getMessage(resource_error, "item.cannot_add_product_virtual", messageMap , cart.getLocale());
 
             Debug.logWarning(excMsg, module);
             throw new CartItemModifyException(excMsg);
@@ -216,11 +213,9 @@ public class ShoppingCartItem implements
         // check to see if the product is fully configured
         if ("AGGREGATED".equals(product.getString("productTypeId")) || "AGGREGATED_SERVICE".equals(product.getString("productTypeId"))) {
             if (configWrapper == null || !configWrapper.isCompleted()) {
-                Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productName", product.getString("productName"),
-                                                "productId", product.getString("productId"));
+                Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productName", product.getString("productName"), "productId", product.getString("productId"));
 
-                String excMsg = UtilProperties.getMessage(resource_error, "item.cannot_add_product_not_configured_correctly",
-                                              messageMap , cart.getLocale());
+                String excMsg = UtilProperties.getMessage(resource_error, "item.cannot_add_product_not_configured_correctly", messageMap , cart.getLocale());
 
                 Debug.logWarning(excMsg, module);
                 throw new CartItemModifyException(excMsg);
@@ -403,11 +398,9 @@ public class ShoppingCartItem implements
 
         // check to see if product is virtual
         if ("Y".equals(product.getString("isVirtual"))) {
-            Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productName", product.getString("productName"),
-                                            "productId", product.getString("productId"));
+            Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productName", product.getString("productName"), "productId", product.getString("productId"));
 
-            String excMsg = UtilProperties.getMessage(resource_error, "item.cannot_add_product_virtual",
-                                          messageMap , cart.getLocale());
+            String excMsg = UtilProperties.getMessage(resource_error, "item.cannot_add_product_virtual", messageMap , cart.getLocale());
 
             Debug.logWarning(excMsg, module);
             throw new CartItemModifyException(excMsg);
@@ -422,21 +415,18 @@ public class ShoppingCartItem implements
         // check to see if the product is a rental item
         if ("ASSET_USAGE".equals(product.getString("productTypeId")) || "ASSET_USAGE_OUT_IN".equals(product.getString("productTypeId"))) {
             if (reservStart == null)    {
-                String excMsg = UtilProperties.getMessage(resource_error, "item.missing_reservation_starting_date",
-                                              cart.getLocale());
+                String excMsg = UtilProperties.getMessage(resource_error, "item.missing_reservation_starting_date", cart.getLocale());
                 throw new CartItemModifyException(excMsg);
             }
 
             if (reservStart.before(UtilDateTime.nowTimestamp()))    {
-                String excMsg = UtilProperties.getMessage(resource_error, "item.reservation_from_tomorrow",
-                                              cart.getLocale());
+                String excMsg = UtilProperties.getMessage(resource_error, "item.reservation_from_tomorrow", cart.getLocale());
                 throw new CartItemModifyException(excMsg);
             }
             newItem.setReservStart(reservStart);
 
             if (reservLength.compareTo(BigDecimal.ONE) < 0)    {
-                String excMsg = UtilProperties.getMessage(resource_error, "item.number_of_days",
-                                              cart.getLocale());
+                String excMsg = UtilProperties.getMessage(resource_error, "item.number_of_days", cart.getLocale());
                 throw new CartItemModifyException(excMsg);
             }
             newItem.setReservLength(reservLength);
@@ -444,10 +434,8 @@ public class ShoppingCartItem implements
             if (product.get("reservMaxPersons") != null) {
                 BigDecimal reservMaxPersons = product.getBigDecimal("reservMaxPersons");
                  if (reservMaxPersons.compareTo(reservPersons) < 0)    {
-                     Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("reservMaxPersons", product.getString("reservMaxPersons"),
-                                                     "reservPersons", reservPersons);
-                     String excMsg = UtilProperties.getMessage(resource_error, "item.maximum_number_of_person_renting",
-                                                   messageMap, cart.getLocale());
+                     Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("reservMaxPersons", product.getString("reservMaxPersons"), "reservPersons", reservPersons);
+                     String excMsg = UtilProperties.getMessage(resource_error, "item.maximum_number_of_person_renting", messageMap, cart.getLocale());
 
                      Debug.logInfo(excMsg,module);
                      throw new CartItemModifyException(excMsg);
@@ -468,10 +456,8 @@ public class ShoppingCartItem implements
             // check to see if the related fixed asset is available for rent
             String isAvailable = checkAvailability(product.getString("productId"), quantity, reservStart, reservLength, cart);
             if (isAvailable.compareTo("OK") != 0) {
-                Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productId", product.getString("productId"),
-                                                "availableMessage", isAvailable);
-                String excMsg = UtilProperties.getMessage(resource_error, "item.product_not_available",
-                                              messageMap, cart.getLocale());
+                Map<String, Object> messageMap = UtilMisc.<String, Object>toMap("productId", product.getString("productId"), "availableMessage", isAvailable);
+                String excMsg = UtilProperties.getMessage(resource_error, "item.product_not_available", messageMap, cart.getLocale());
                 Debug.logInfo(excMsg, module);
                 throw new CartItemModifyException(isAvailable);
             }
@@ -1073,6 +1059,11 @@ public class ShoppingCartItem implements
 
         // set the item ship group
         if (resetShipGroup) {
+            int itemId = cart.getItemIndex(this);
+            int shipGroupIndex = 0;
+            if (itemId != -1) {
+                shipGroupIndex = cart.getItemShipGroupIndex(itemId);
+            }
             cart.clearItemShipInfo(this);
 
             /*
@@ -1132,7 +1123,7 @@ public class ShoppingCartItem implements
             }
             cart.setItemShipGroupQty(this, quantity, shipGroupIndex);
             */
-            cart.setItemShipGroupQty(this, quantity, 0);
+            cart.setItemShipGroupQty(this, quantity, shipGroupIndex);
         }
     }
 
@@ -2020,7 +2011,7 @@ public class ShoppingCartItem implements
     }
 
     public void setListPrice(BigDecimal listPrice) {
-     this.listPrice = listPrice;
+        this.listPrice = listPrice;
     }
 
     /** Returns isModifiedPrice */

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java Mon Dec  8 10:21:56 2014
@@ -30,7 +30,6 @@ import java.util.Map;
 import javolution.util.FastList;
 import javolution.util.FastMap;
 
-import org.apache.commons.lang.math.NumberUtils;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
 import org.ofbiz.base.util.UtilDateTime;
@@ -312,6 +311,7 @@ public class ShoppingCartServices {
             int newShipInfoIndex = cart.addShipInfo();
 
             // shouldn't be gaps in it but allow for that just in case
+            /*
             String cartShipGroupIndexStr = orderItemShipGroup.getString("shipGroupSeqId");
             int cartShipGroupIndex = NumberUtils.toInt(cartShipGroupIndexStr);
 
@@ -321,6 +321,7 @@ public class ShoppingCartServices {
                     newShipInfoIndex = cart.addShipInfo();
                 }
             }
+            */
 
             CartShipInfo cartShipInfo = cart.getShipInfo(newShipInfoIndex);
 
@@ -564,6 +565,9 @@ public class ShoppingCartServices {
                     List<GenericValue> orderItemAdjustments = orh.getOrderItemAdjustments(item);
                     // set the item's ship group info
                     List<GenericValue> shipGroupAssocs = orh.getOrderItemShipGroupAssocs(item);
+                    if (UtilValidate.isNotEmpty(shipGroupAssocs)) {
+                        shipGroupAssocs = EntityUtil.orderBy(shipGroupAssocs, UtilMisc.toList("-shipGroupSeqId"));
+                    }
                     for (int g = 0; g < shipGroupAssocs.size(); g++) {
                         GenericValue sgAssoc = shipGroupAssocs.get(g);
                         BigDecimal shipGroupQty = OrderReadHelper.getOrderItemShipGroupQuantity(sgAssoc);
@@ -572,9 +576,7 @@ public class ShoppingCartServices {
                         }
 
                         String cartShipGroupIndexStr = sgAssoc.getString("shipGroupSeqId");
-                        int cartShipGroupIndex = NumberUtils.toInt(cartShipGroupIndexStr);
-                        cartShipGroupIndex = cartShipGroupIndex - 1;
-
+                        int cartShipGroupIndex = cart.getShipInfoIndex(cartShipGroupIndexStr);
                         if (cartShipGroupIndex > 0) {
                             cart.positionItemToGroup(itemIndex, shipGroupQty, 0, cartShipGroupIndex, false);
                         }
@@ -593,13 +595,13 @@ public class ShoppingCartServices {
                                     "] to ship group with index [" + itemIndex + "]; group quantity is [" + shipGroupQty +
                                     "] item quantity is [" + (cartItem != null ? cartItem.getQuantity() : "no cart item") +
                                     "] cartShipGroupIndex is [" + cartShipGroupIndex + "], csi.shipItemInfo.size(): " +
-                                    csi.shipItemInfo.size(), module);
+                                    (cartShipGroupIndex < 0 ? 0 : csi.shipItemInfo.size()), module);
                         } else {
                             cart.setItemShipGroupQty(itemIndex, shipGroupQty, cartShipGroupIndex);
                         }
 
                         List<GenericValue> shipGroupItemAdjustments = EntityUtil.filterByAnd(orderItemAdjustments, UtilMisc.toMap("shipGroupSeqId", cartShipGroupIndexStr));
-                        if (cartItem == null) {
+                        if (cartItem == null || cartShipGroupIndex < 0) {
                             Debug.logWarning("In loadCartFromOrder could not find cart item for itemIndex=" + itemIndex + ", for orderId=" + orderId, module);
                         } else {
                             CartShipItemInfo cartShipItemInfo = csi.getShipItemInfo(cartItem);

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/testdef/ShoppingCartTests.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/testdef/ShoppingCartTests.xml?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/testdef/ShoppingCartTests.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/testdef/ShoppingCartTests.xml Mon Dec  8 10:21:56 2014
@@ -40,4 +40,8 @@ under the License.
     <test-case case-name="configurableServiceOrder-test">
         <simple-method-test location="component://order/script/org/ofbiz/order/test/ShoppingCartTests.xml" name="testCreateOrderConfigurableServiceProduct"/>
     </test-case>
+
+    <test-case case-name="testOrderMoveItemBetweenShipGoups">
+        <simple-method-test location="component://order/script/org/ofbiz/order/test/ShoppingCartTests.xml" name="testOrderMoveItemBetweenShipGoups"/>
+    </test-case>
 </test-suite>

Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/webapp/ordermgr/WEB-INF/controller.xml
URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/webapp/ordermgr/WEB-INF/controller.xml?rev=1643778&r1=1643777&r2=1643778&view=diff
==============================================================================
--- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/webapp/ordermgr/WEB-INF/controller.xml (original)
+++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/order/webapp/ordermgr/WEB-INF/controller.xml Mon Dec  8 10:21:56 2014
@@ -1731,6 +1731,38 @@ under the License.
         <response name="success" type="view" value="product"/>
     </request-map>
 
+    <request-map uri="AddOrderItemShipGroup">
+        <security auth="true" https="true"/>
+        <event type="service" path="" invoke="addOrderItemShipGroup"/>
+        <response name="success" type="view" value="orderview"/>
+        <response name="error" type="view" value="orderview"/>
+    </request-map>
+    <request-map uri="DeleteOrderItemShipGroup">
+        <security auth="true" https="true"/>
+        <event type="service" path="" invoke="deleteOrderItemShipGroup"/>
+        <response name="success" type="view" value="orderview"/>
+        <response name="error" type="view" value="orderview"/>
+    </request-map>
+
+    <request-map uri="AddOrderItemShipGroupAssoc">
+        <security auth="true" https="true"/>
+        <event type="service" invoke="addOrderItemShipGroupAssoc"/>
+        <response name="success" type="view" value="orderview"/>
+        <response name="error" type="view" value="orderview"/>
+    </request-map>
+    <request-map uri="UpdateOrderItemShipGroupAssoc">
+        <security auth="true" https="true"/>
+        <event type="service-multi" invoke="updateOrderItemShipGroupAssoc"/>
+        <response name="success" type="view" value="orderview"/>
+        <response name="error" type="view" value="orderview"/>
+    </request-map>
+    <request-map uri="DeleteOrderItemShipGroupAssoc">
+        <security auth="true" https="true"/>
+        <event type="service" invoke="deleteOrderItemShipGroupAssoc"/>
+        <response name="success" type="view" value="orderview"/>
+        <response name="error" type="view" value="orderview"/>
+    </request-map>
+
     <!-- Lookup request mappings -->
     <request-map uri="LookupPerson"><security https="true" auth="true"/><response name="success" type="view" value="LookupPerson"/></request-map>
     <request-map uri="LookupPartyGroup"><security https="true" auth="true"/><response name="success" type="view" value="LookupPartyGroup"/></request-map>