Author: jleroux
Date: Wed Dec  3 10:15:20 2014
New Revision: 1643077

URL: http://svn.apache.org/r1643077
Log:
Implements "Allow to edit ship groups contents after and order has been 
created" https://issues.apache.org/jira/browse/OFBIZ-5761

>From an UI perspective this adds a "View ship group by order item" button 
>which allows to create new ship groups by order items and to move the quantity 
>of the order item between ship groups.
This is the adaptation of the "oisg-management" addon for R12.04 to the trunk. 
Thanks to Nicolas and Leila from Nereides for their help

For more information refer to the Jira issue.

Modified:
    ofbiz/trunk/applications/commonext/webapp/ordermgr-js/OrderShippingInfo.js
    ofbiz/trunk/applications/order/config/OrderErrorUiLabels.xml
    ofbiz/trunk/applications/order/config/OrderUiLabels.xml
    
ofbiz/trunk/applications/order/script/org/ofbiz/order/order/OrderServices.xml
    
ofbiz/trunk/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml
    ofbiz/trunk/applications/order/servicedef/services.xml
    
ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java
    
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java
    
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
    
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java
    ofbiz/trunk/applications/order/testdef/ShoppingCartTests.xml
    ofbiz/trunk/applications/order/webapp/ordermgr/WEB-INF/controller.xml
    ofbiz/trunk/applications/order/webapp/ordermgr/order/editorderitems.ftl
    ofbiz/trunk/applications/order/webapp/ordermgr/order/ordershippinginfo.ftl

Modified: 
ofbiz/trunk/applications/commonext/webapp/ordermgr-js/OrderShippingInfo.js
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/commonext/webapp/ordermgr-js/OrderShippingInfo.js?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/commonext/webapp/ordermgr-js/OrderShippingInfo.js 
(original)
+++ ofbiz/trunk/applications/commonext/webapp/ordermgr-js/OrderShippingInfo.js 
Wed Dec  3 10:15:20 2014
@@ -31,4 +31,137 @@ jQuery(document).ready( function() {
         // Populate state list based on default country
         getAssociatedStateList('countryGeoId', 'stateProvinceGeoId', 
'advice-required-stateProvinceGeoId', 'states');
     }
-});
\ No newline at end of file
+});
+
+function showEdit(edit, index) {
+    var sufix = index;
+    if (sufix == '-1') {
+       sufix = "";
+    }
+
+    //display / hide edit element
+    var element = document.getElementById("edit" + sufix);
+    if (element != null) {
+       var objBranch = element.style;
+       if ("edit" == edit) {
+         objBranch.display = "block";
+       } else {
+         objBranch.display = "none";
+       }
+    }
+    var element = document.getElementById("display" + sufix);
+    if (element != null) { 
+       var objBranch = element.style;
+       if (edit == "display") {
+          objBranch.display = "block";
+       } else {
+          objBranch.display = "none";
+       }
+    }
+
+    var next = true;
+    for(var i = 0; next ; i++) {
+      //hide / show display quantity
+      var element = document.getElementById("displayQuantity" + sufix + i);
+      if (element != null) { 
+        var objBranch = element.style;
+        if (edit == "display") {
+          objBranch.display = "block";
+        } else {
+          objBranch.display = "none";
+        }
+      }
+
+      //hide / show edit quantity
+      var element = document.getElementById("editQuantity" + sufix + i);
+      if (element != null) { 
+        var objBranch = element.style;
+        if (edit == "edit") {
+          objBranch.display = "block";
+        } else {
+          objBranch.display = "none";
+        }
+      }
+      if (element == null) {
+         next = false;
+      }
+    }
+
+    //Hide display OISG edit view
+    var element = document.getElementById("OISGEdit" + sufix);
+    if (element != null) {
+      var objBranch = element.style;
+      if (edit == "edit") {
+        objBranch.display = "block";
+      }
+      else {
+        objBranch.display = "none";
+      }
+    }
+}
+
+function restoreEditField(index) {
+    var sufix = index;
+    if (sufix == '-1')
+      sufix = "";
+
+    //display / hide edit element
+    var next = true;
+    for(var i = 0; next ; i++) {
+      var editElement = document.getElementById("edit" + index + "_o_" + i);
+      if (editElement == null) {
+         next = false;
+      } else {
+         editElement.value = editElement.title;
+      }
+    }
+}
+
+function showShipByDate(e, id) {
+    var element = document.getElementById(id);
+    if (e.value == "new") {
+       element.style.display = "block"; 
+    } else {
+       element.style.display = "none";
+    }
+}
+
+function showView(view, index) {
+    var sufix = index;
+    if (sufix == '-1') {
+       sufix = "";
+    }
+    //display / hide buttonDisplay element
+    var element = document.getElementById("display" + sufix);
+    if (element != null) {  
+      var objBranch = element.style;
+      if ("view" == view) {
+        objBranch.display = "none";
+      } else {
+        objBranch.display = "block";
+      }
+
+      //display / hide buttonEdit element
+      var element = document.getElementById("view" + sufix);
+      if (element != null) {  
+        var objBranch = element.style;
+        if ("view" == view) {
+          objBranch.display = "block";
+        } else {
+          objBranch.display = "none";
+        }
+      }
+
+      //Hide display OISG show view
+      var element = document.getElementById("OISGView" + sufix);
+      if (element != null) {
+        var objBranch = element.style;
+        if (view == "view") {
+          objBranch.display = "block";
+        }
+        else {
+          objBranch.display = "none";
+        }
+      }
+    }
+}

Modified: ofbiz/trunk/applications/order/config/OrderErrorUiLabels.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/config/OrderErrorUiLabels.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/config/OrderErrorUiLabels.xml (original)
+++ ofbiz/trunk/applications/order/config/OrderErrorUiLabels.xml Wed Dec  3 
10:15:20 2014
@@ -211,11 +211,15 @@
         <value xml:lang="zh">无
法更新;设置OrderShipmentPreference时出现问题</value>
         <value 
xml:lang="zh_TW">無法更新;設置OrderShipmentPreference時出現問題</value>
     </property>
+    <property key="OrderCartShipGroupAssocNotFound">
+        <value xml:lang="en">Cart ship group association not found</value>
+        <value xml:lang="fr">Association avec le groupe d'expédition non 
trouvée</value>
+    </property>
     <property key="OrderCartShipGroupNotFound">
         <value xml:lang="de">Warenkorb-Versandgruppe nicht gefunden [ 
${groupIndex} ]</value>
         <value xml:lang="en">Cart ship group not found [ ${groupIndex} 
]</value>
         <value xml:lang="es">Grupo de envío del carro no encontrado [ 
${groupIndex} ]</value>
-        <value xml:lang="fr">Groupe de chariots non trouvé [ ${groupIndex} 
]</value>
+        <value xml:lang="fr">Groupe d'expédition non trouvé [ ${groupIndex} 
]</value>
         <value xml:lang="it">Gruppo Spedizione Carrello non trovato [ 
${groupIndex} ]</value>
         <value 
xml:lang="ja">買い物かご発送グループが見つかりません [ 
${groupIndex} ]</value>
         <value xml:lang="nl">Winkelwagen verzendgroep niet gevinden [ 
${groupIndex} ]</value>
@@ -227,6 +231,18 @@
         <value xml:lang="zh">没有找到购物车运输组 [ ${groupIndex} 
]</value>
         <value xml:lang="zh_TW">沒有找到購物車運輸組 [ ${groupIndex} 
]</value>
     </property>
+    <property key="OrderCartShipGroupSeqIdIsMandatory">
+        <value xml:lang="en">Cart shipGroupSeqId is mandatory</value>
+        <value xml:lang="fr">La reference du groupe d'expédition est 
obligatoire</value>
+    </property>
+    <property key="OrderCartShipGroupPartyCarrierNotFound">
+        <value xml:lang="en">No Party Carrier found for [${partyId}]</value>
+        <value xml:lang="fr">Aucun transporteur trouvé pour la reference 
[${partyId}]</value>
+    </property>
+    <property key="OrderCartShipGroupShipmentMethodNotFound">
+        <value xml:lang="en">No Shipment Method found for 
[${shipmentMethodTypeId}]</value>
+        <value xml:lang="fr">Aucun mode d'expedition trouvé pour la reference 
[${shipmentMethodTypeId}]</value>
+    </property>
     <property key="OrderCaughtExceptionOnCartUpdate">
         <value xml:lang="de">Fehler bei Änderung des Warenkorbes. </value>
         <value xml:lang="en">Caught exception on cart update. </value>
@@ -323,7 +339,7 @@
     </property>
     <property key="OrderCouldNotFindRelatedFixedAssetForTheProduct">
         <value xml:lang="de">Zugehörige Anlage zu Produkt ${productId} konnte 
nicht gefunden werden</value>
-        <value xml:lang="en">Could not find related Fixed Asset for the 
product : ${productId}</value>
+        <value xml:lang="en">Could not find related Fixed Asset for the 
product: ${productId}</value>
         <value xml:lang="es">No se puede encontrar el activo fijo relacionado 
para el producto: ${productId}</value>
         <value xml:lang="fr">Vous ne pouvez pas trouver le Fixed Asset pour 
l'article : ${productId}</value>
         <value xml:lang="it">Non è possibile trovare Cespite per il prodotto 
: ${productId}</value>
@@ -1167,6 +1183,10 @@
         <value 
xml:lang="zh">错误:订单明细和/或订单头不存在</value>
         <value xml:lang="zh_TW">錯誤:訂單明細和/或訂單é 
­ä¸å­˜åœ¨</value>
     </property>
+    <property key="OrderErrorOrderItemAlreadyRelatedToShipGroup">
+        <value xml:lang="en">Order Item is already related To This OISG</value>
+        <value xml:lang="fr">La ligne de commande est déja associée au 
groupe d'expédition</value>
+    </property>
     <property key="OrderErrorOrderItemCantBeModified">
         <value xml:lang="de">FEHLER : Auftragsposition kann nicht geändert 
werden</value>
         <value xml:lang="en">ERROR : OrderItem can't be modified</value>
@@ -2886,6 +2906,18 @@
         <value xml:lang="zh">产品店铺不存在</value>
         <value xml:lang="zh_TW">產品店鋪不存在</value>
     </property>
+    <property key="OrderQuantityAssociatedCannotBeNullOrNegative">
+        <value xml:lang="en">Quantity associated can not be null or 
negative.</value>
+        <value xml:lang="fr">La quantité associée ne peut être négative ou 
nulle.</value>
+    </property>
+    <property key="OrderQuantityAssociatedIsBiggerThanOrderItemQuantity">
+        <value xml:lang="en">Quantity associated is bigger than order item 
quantity.</value>
+        <value xml:lang="fr">La quantité associée est plus grande que celle 
commandée.</value>
+    </property>
+    <property key="OrderQuantityAssociatedIsLessThanOrderItemQuantity">
+        <value xml:lang="en">Quantity associated is less than order item 
quantity.</value>
+        <value xml:lang="fr">La quantité totale associée aux groupe(s) 
d'expédition(s) est plus petite que celle commandée.</value>
+    </property>
     <property key="OrderQuickAddOrderItemError">
         <value xml:lang="de">Schnelles Hinzufügen von 
Auftragspositionen</value>
         <value xml:lang="en">Quick  Add  Order  Item</value>
@@ -4178,6 +4210,10 @@
         <value xml:lang="zh">获得订单明细的运输组相å…
³èµ„源列表时出现问题</value>
         <value 
xml:lang="zh_TW">獲得訂單明細的運輸組相關資源列表時出現問題</value>
     </property>
+    <property key="OrderUnableToAddItemToOISG">
+        <value xml:lang="en">Unable to add order item to ship group: </value>
+        <value xml:lang="fr">Impossible d'ajouter la ligne de commande au 
groupe d'expédition : </value>
+    </property>
     <property key="OrderUnableToAddItemToShoppingList">
         <value xml:lang="de">Fehler beim Hinzufügen einer Position zur 
Einkaufsliste - ${shoppingListId}</value>
         <value xml:lang="en">Unable to add item to shopping list - 
${shoppingListId}</value>
@@ -4193,6 +4229,10 @@
         <value xml:lang="zh">无法把明细添加到购物列表 - 
${shoppingListId}</value>
         <value xml:lang="zh_TW">無法把明細添加到購物列表 - 
${shoppingListId}</value>
     </property>
+    <property key="OrderUnableToAddOISGToOrder">
+        <value xml:lang="en">Unable to add ship group to order: </value>
+        <value xml:lang="fr">Impossible d'ajouter le groupe d'expédition : 
</value>
+    </property>
     <property key="OrderUnableToCancelItemInventoryReservation">
         <value xml:lang="de">Fehler beim Stornieren einer 
Bestandsreservierung</value>
         <value xml:lang="en">Unable to cancel item inventory 
reservation</value>
@@ -4477,6 +4517,10 @@
         <value xml:lang="zh">不能更新明细的评论</value>
         <value xml:lang="zh_TW">不能更新明細的評論</value>
     </property>
+    <property key="OrderUnableToUpdateOrderItemFromOISG">
+        <value xml:lang="en">Unable to update order item from the ship group: 
</value>
+        <value xml:lang="fr">Impossible de mettre à jour la ligne de commande 
depuis le groupe d'expédition : </value>
+    </property>
     <property key="OrderUnableToUpdateInventoryReservations">
         <value xml:lang="de">Bestandsreservierungen können nicht aktualisiert 
werden: ${itemMsgInfo}</value>
         <value xml:lang="en">Unable to update inventory reservations : 
${itemMsgInfo}</value>

Modified: ofbiz/trunk/applications/order/config/OrderUiLabels.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/config/OrderUiLabels.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/config/OrderUiLabels.xml (original)
+++ ofbiz/trunk/applications/order/config/OrderUiLabels.xml Wed Dec  3 10:15:20 
2014
@@ -13230,6 +13230,26 @@
         <value xml:lang="zh">请稍候,正在处理订单...</value>
         <value xml:lang="zh_TW">請稍候,正在處理訂單...</value>
     </property>
+    <property key="DeleteOrderItemShipGroup">
+        <value xml:lang="en">Delete this ship group</value>
+        <value xml:lang="fr">Supprimer le groupe d'expédition</value>
+    </property>
+    <property key="OrderAddToshipGroup">
+        <value xml:lang="en">Add to ship group</value>
+        <value xml:lang="fr">Ajouter au groupe d'expédition</value>
+    </property>
+    <property key="OrderItemId">
+        <value xml:lang="en">Ref</value>
+        <value xml:lang="fr">N° ligne</value>
+    </property>
+    <property key="OrderShipmentInformationByOISG">
+        <value xml:lang="en">View by ship group</value>
+        <value xml:lang="fr">Voir par groupe d'expédition</value>
+    </property>
+    <property key="OrderShipmentInformationByOrderItem">
+        <value xml:lang="en">View ship group by order item</value>
+        <value xml:lang="fr">Voir les groupes d'expédition par ligne de 
commandes</value>
+    </property>
     <property key="OrderSupplierData">
         <value xml:lang="de">Daten Lieferant</value>
         <value xml:lang="en">Supplier Data</value>

Modified: 
ofbiz/trunk/applications/order/script/org/ofbiz/order/order/OrderServices.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/script/org/ofbiz/order/order/OrderServices.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- 
ofbiz/trunk/applications/order/script/org/ofbiz/order/order/OrderServices.xml 
(original)
+++ 
ofbiz/trunk/applications/order/script/org/ofbiz/order/order/OrderServices.xml 
Wed Dec  3 10:15:20 2014
@@ -1459,4 +1459,49 @@ under the License.
             <call-service service-name="createPaymentApplication" 
in-map-name="createCtx"/>
         </if-not-empty>
     </simple-method>
+    
+    <simple-method method-name="MoveItemBetweenShipGroups" 
short-description="Move order items between ship groups">
+        <entity-one entity-name="OrderItemShipGroupAssoc" 
value-field="orderItemShipGroupAssoc">
+            <field-map field-name="orderId" from-field="parameters.orderId"/>
+            <field-map field-name="orderItemSeqId" 
from-field="parameters.orderItemSeqId"/>
+            <field-map field-name="shipGroupSeqId" 
from-field="parameters.toGroupIndex"/>
+        </entity-one>
+        <if-empty field="orderItemShipGroupAssoc">
+            <set-service-fields service-name="addOrderItemShipGroupAssoc" 
map="parameters" to-map="map"/>
+            <set field="map.quantity" value="0" type="BigDecimal"/>
+            <set field="map.shipGroupSeqId" from="parameters.toGroupIndex"/>
+            <call-service service-name="addOrderItemShipGroupAssoc" 
in-map-name="map"/>
+            <entity-one entity-name="OrderItemShipGroupAssoc" 
value-field="orderItemShipGroupAssoc">
+                <field-map field-name="orderId" 
from-field="parameters.orderId"/>
+                <field-map field-name="orderItemSeqId" 
from-field="parameters.orderItemSeqId"/>
+                <field-map field-name="shipGroupSeqId" 
from-field="parameters.toGroupIndex"/>
+            </entity-one>
+        </if-empty>
+        <clear-field field="map"/>
+        <set field="map.orderId" from-field="parameters.orderId"/>
+        <set field="map.orderItemSeqId" 
from-field="parameters.orderItemSeqId"/>
+        <set field="map.shipGroupSeqId" from-field="parameters.toGroupIndex"/>
+        <set field="map.quantity" value="${orderItemShipGroupAssoc.quantity + 
parameters.quantity}" type="BigDecimal"/>
+        <call-service service-name="updateOrderItemShipGroupAssoc" 
in-map-name="map"/>
+        
+        <entity-one entity-name="OrderItemShipGroupAssoc" 
value-field="orderItemShipGroupAssoc">
+            <field-map field-name="orderId" from-field="parameters.orderId"/>
+            <field-map field-name="orderItemSeqId" 
from-field="parameters.orderItemSeqId"/>
+            <field-map field-name="shipGroupSeqId" 
from-field="parameters.fromGroupIndex"/>
+        </entity-one>
+        <if-empty field="orderItemShipGroupAssoc">
+            <add-error>
+                <fail-message message="The orderItemShipGroupAssoc qualified 
by orderId=${parameters.orderId} orderItemSeqId=${parameters.orderItemSeqId} 
shipGroupSeqId=${parameters.fromGroupIndex} does not exist"/>
+            </add-error>
+        </if-empty>
+        <check-errors/>
+        
+        <clear-field field="map"/>
+        <set field="map.orderId" from-field="parameters.orderId"/>
+        <set field="map.orderItemSeqId" 
from-field="parameters.orderItemSeqId"/>
+        <set field="map.shipGroupSeqId" 
from-field="parameters.fromGroupIndex"/>
+        <set field="map.quantity" value="${orderItemShipGroupAssoc.quantity - 
parameters.quantity}" type="BigDecimal"/>
+        <call-service service-name="updateOrderItemShipGroupAssoc" 
in-map-name="map"/>
+    </simple-method>
+    
 </simple-methods>

Modified: 
ofbiz/trunk/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- 
ofbiz/trunk/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml
 (original)
+++ 
ofbiz/trunk/applications/order/script/org/ofbiz/order/test/ShoppingCartTests.xml
 Wed Dec  3 10:15:20 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/trunk/applications/order/servicedef/services.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/servicedef/services.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/servicedef/services.xml (original)
+++ ofbiz/trunk/applications/order/servicedef/services.xml Wed Dec  3 10:15:20 
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/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- 
ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java 
(original)
+++ 
ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java 
Wed Dec  3 10:15:20 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/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java 
(original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderServices.java 
Wed Dec  3 10:15:20 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());
@@ -4152,18 +4197,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 +5679,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/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java
 (original)
+++ 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java
 Wed Dec  3 10:15:20 2014
@@ -2209,6 +2209,39 @@ public class ShoppingCart implements Ite
         }
     }
 
+    public int getShipInfoIndex (String shipGroupSeqId) {
+        int idx = -1;
+        for (int i=0; i<shipInfo.size(); i++) {
+            CartShipInfo csi = (CartShipInfo) shipInfo.get(i);
+            if (csi.shipGroupSeqId.equals(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 +3955,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;
@@ -4505,8 +4543,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

Modified: 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
 (original)
+++ 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartItem.java
 Wed Dec  3 10:15:20 2014
@@ -1073,6 +1073,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 +1137,7 @@ public class ShoppingCartItem implements
             }
             cart.setItemShipGroupQty(this, quantity, shipGroupIndex);
             */
-            cart.setItemShipGroupQty(this, quantity, 0);
+            cart.setItemShipGroupQty(this, quantity, shipGroupIndex);
         }
     }
 

Modified: 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java
 (original)
+++ 
ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartServices.java
 Wed Dec  3 10:15:20 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);
 
@@ -337,6 +338,7 @@ public class ShoppingCartServices {
             
cartShipInfo.setVendorPartyId(orderItemShipGroup.getString("vendorPartyId"));
             
cartShipInfo.setShipGroupSeqId(orderItemShipGroup.getString("shipGroupSeqId"));
             
cartShipInfo.shipTaxAdj.addAll(orh.getOrderHeaderAdjustmentsTax(orderItemShipGroup.getString("shipGroupSeqId")));
+            cart.setShipGroupSeqId(newShipInfoIndex - 1, 
orderItemShipGroup.getString("shipGroupSeqId"));
         }
 
         List<GenericValue> orderItems = orh.getOrderItems();
@@ -564,6 +566,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 +577,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);
                         }

Modified: ofbiz/trunk/applications/order/testdef/ShoppingCartTests.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/testdef/ShoppingCartTests.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/testdef/ShoppingCartTests.xml (original)
+++ ofbiz/trunk/applications/order/testdef/ShoppingCartTests.xml Wed Dec  3 
10:15:20 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/trunk/applications/order/webapp/ordermgr/WEB-INF/controller.xml
URL: 
http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/webapp/ordermgr/WEB-INF/controller.xml?rev=1643077&r1=1643076&r2=1643077&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/webapp/ordermgr/WEB-INF/controller.xml 
(original)
+++ ofbiz/trunk/applications/order/webapp/ordermgr/WEB-INF/controller.xml Wed 
Dec  3 10:15:20 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>


Reply via email to