You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ja...@apache.org on 2009/05/30 02:35:10 UTC

svn commit: r780153 - in /ofbiz/trunk/specialpurpose/googlecheckout: ./ config/ data/ entitydef/ servicedef/ src/org/ofbiz/googlecheckout/ webapp/googlecheckout/WEB-INF/

Author: jaz
Date: Sat May 30 00:35:09 2009
New Revision: 780153

URL: http://svn.apache.org/viewvc?rev=780153&view=rev
Log:
1. re-implemented google checkout (send shopping cart) using the java API
2. enhanced the create order code
3. finished implementation of cancel, capture and ship notifications (Order Processing API to Google)
4. implemented order state change notification
5. added place holders for other notification messages
6. added controller event for processing incoming messages (/googlecheckout/control/handleMessage)
7. added new entity to map shipping methods to support w/ google and link them to internal shipping methods
8. added ecas to prevent certain order changes which cannot be support by Google (adding items, changng quanities)


Added:
    ofbiz/trunk/specialpurpose/googlecheckout/entitydef/
    ofbiz/trunk/specialpurpose/googlecheckout/entitydef/entitymodel.xml
Modified:
    ofbiz/trunk/specialpurpose/googlecheckout/config/googleCheckout.properties
    ofbiz/trunk/specialpurpose/googlecheckout/data/DemoGoogleCheckoutData.xml
    ofbiz/trunk/specialpurpose/googlecheckout/data/GoogleCheckoutTypeData.xml
    ofbiz/trunk/specialpurpose/googlecheckout/ofbiz-component.xml
    ofbiz/trunk/specialpurpose/googlecheckout/servicedef/secas.xml
    ofbiz/trunk/specialpurpose/googlecheckout/servicedef/services_request.xml
    ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutHelper.java
    ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutResponseEvents.java
    ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleRequestServices.java
    ofbiz/trunk/specialpurpose/googlecheckout/webapp/googlecheckout/WEB-INF/controller.xml

Modified: ofbiz/trunk/specialpurpose/googlecheckout/config/googleCheckout.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/config/googleCheckout.properties?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/config/googleCheckout.properties (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/config/googleCheckout.properties Sat May 30 00:35:09 2009
@@ -30,13 +30,13 @@
 
 ####Required Parameters:####
 ##your merchantId - sandbox will be different than live
-merchantId =
+merchantId = 634321449957567
 #your merchantKey - sandbox will be different than live
-merchantKey =
+merchantKey = DAnyTJLnPzhhK_CuCaQOCg
 ## URL to edit cart
-editCartUrl =
+editCartUrl = http://localhost:8080/ecommerce/control/view/showcart
 ## continue shopping url after payment
-continueShoppingUrl =
+continueShoppingUrl = http://localhost:8080/ecommerce/control/main
 
 ####Integration Parameters####
 ##location of template
@@ -57,6 +57,18 @@
 request = /request
 diagnose = /diagnose
 
+### Notification API and Order Processing API URLs -- NOTE: we should migrate the above urls to build upon these instead
+
+# use Sandbox or Production
+environment.mode = Sandbox
+
+production.root.url = https://checkout.google.com/api/checkout/v2
+sandbox.root.url = https://sandbox.google.com/checkout/api/checkout/v2
+
+merchant.checkout.command = merchantCheckout
+checkout.command = checkout
+request.command = request
+
 
 
 

Modified: ofbiz/trunk/specialpurpose/googlecheckout/data/DemoGoogleCheckoutData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/data/DemoGoogleCheckoutData.xml?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/data/DemoGoogleCheckoutData.xml (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/data/DemoGoogleCheckoutData.xml Sat May 30 00:35:09 2009
@@ -20,4 +20,8 @@
 
 <entity-engine-xml>
     <WebSite webSiteId="GOOGLECHECKOUT" productStoreId="9000" />
+    
+    <GoogleShippingMethods methodTypeEnumId="GOOGLE_FLAT_RATE" shipmentMethodName="Express" productStoreId="9000" amount="20.00" carrierPartyId="UPS" shipmentMethodTypeId="AIR"/>
+    <GoogleShippingMethods methodTypeEnumId="GOOGLE_FLAT_RATE" shipmentMethodName="Standard" productStoreId="9000" amount="10.00" carrierPartyId="UPS" shipmentMethodTypeId="GROUND"/>
+    <GoogleShippingMethods methodTypeEnumId="GOOGLE_FLAT_RATE" shipmentMethodName="Free" productStoreId="9000" amount="0.00" carrierPartyId="USPS" shipmentMethodTypeId="STANDARD"/>    
 </entity-engine-xml>
\ No newline at end of file

Modified: ofbiz/trunk/specialpurpose/googlecheckout/data/GoogleCheckoutTypeData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/data/GoogleCheckoutTypeData.xml?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/data/GoogleCheckoutTypeData.xml (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/data/GoogleCheckoutTypeData.xml Sat May 30 00:35:09 2009
@@ -22,4 +22,10 @@
     <Enumeration description="Google Checkout Channel" enumCode="GC_CHANNEL" enumId="GC_SALES_CHANNEL" sequenceId="01" enumTypeId="ORDER_SALES_CHANNEL"/>
     <PaymentMethodType description="Google Checkout" paymentMethodTypeId="EXT_GOOGLE_CHECKOUT"/>
     <WebSite webSiteId="GOOGLECHECKOUT" siteName="Google Checkout Application" visualThemeSetId="BACKOFFICE"/>
+    
+    <EnumerationType description="Google Checkout Ship Types" enumTypeId="GOOGLE_SHIP_TYPE" hasTable="N" parentTypeId=""/>
+    <Enumeration description="Flat Rate Shipping" enumCode="FLAT_RATE" enumId="GOOGLE_FLAT_RATE" sequenceId="01" enumTypeId="GOOGLE_SHIP_TYPE"/>
+    <Enumeration description="Merchant Calculated Shipping" enumCode="MERCHANT_CALC" enumId="GOOGLE_MERCHANT_CALC" sequenceId="02" enumTypeId="GOOGLE_SHIP_TYPE"/>
+    <Enumeration description="Carrier Calculated Shipping" enumCode="CARRIER_CALC" enumId="GOOGLE_CARRIER_CALC" sequenceId="03" enumTypeId="GOOGLE_SHIP_TYPE"/>    
+    <Enumeration description="Pickup Shipping" enumCode="PICKUP" enumId="GOOGLE_PICKUP" sequenceId="04" enumTypeId="GOOGLE_SHIP_TYPE"/>    
 </entity-engine-xml>
\ No newline at end of file

Added: ofbiz/trunk/specialpurpose/googlecheckout/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/entitydef/entitymodel.xml?rev=780153&view=auto
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/entitydef/entitymodel.xml (added)
+++ ofbiz/trunk/specialpurpose/googlecheckout/entitydef/entitymodel.xml Sat May 30 00:35:09 2009
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<entitymodel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/entitymodel.xsd">
+    
+    <!-- ========================================================= -->
+    <!-- ======================== Defaults ======================= -->
+    <!-- ========================================================= -->
+    <title>Entity of an Open For Business Project Component</title>
+    <description>None</description>
+    <copyright>Copyright 2001-2009 The Apache Software Foundation</copyright>
+    <author>None</author>
+    <version>1.0</version>
+    
+    <!-- ========================================================= -->
+    <!-- ======================== Data Model ===================== -->
+    <!-- The modules in this file are as follows:                  -->
+    <!--  - org.ofbiz.googlecheckout.shipping -->  
+    <!-- ========================================================= -->
+    
+    <!-- ========================================================= -->
+    <!-- org.ofbiz.googlecheckout.shipping -->
+    <!-- ========================================================= -->
+    
+    <entity entity-name="GoogleShippingMethods"
+            package-name="org.ofbiz.accounting.budget"
+            title="Budget Entity">
+      <field name="shipmentMethodName" type="id-ne"></field>
+      <field name="productStoreId" type="id-ne"></field>
+      <field name="amount" type="currency-amount"></field>
+      <field name="additionalAmount" type="currency-amount"></field>
+      <field name="additionalPercent" type="fixed-point"></field>
+      <field name="methodTypeEnumId" type="id-ne"></field>
+      <field name="carrierPartyId" type="id-ne"></field>
+      <field name="shipmentMethodTypeId" type="id-ne"></field>      
+      <prim-key field="shipmentMethodName"/>
+      <prim-key field="productStoreId"/>
+      <relation type="one" fk-name="GSM_PROD_STORE" rel-entity-name="ProductStore">
+        <key-map field-name="productStoreID"/>
+      </relation>
+      <relation type="one" fk-name="GSM_TYPE_ENUM" rel-entity-name="Enumeration">
+        <key-map field-name="methodTypeEnumId" rel-field-name="enumId"/>
+      </relation>
+      <relation type="one" fk-name="GSM_CARRIER_PARTY" rel-entity-name="Party">
+        <key-map field-name="carrierPartyId" rel-field-name="partyId"/>
+      </relation>
+      <relation type="one" fk-name="GSM_SHIPMETH_TYPE" rel-entity-name="ShipmentMethodType">
+        <key-map field-name="shipmentMethodTypeId"/>
+      </relation>
+    </entity>
+</entitymodel>
\ No newline at end of file

Modified: ofbiz/trunk/specialpurpose/googlecheckout/ofbiz-component.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/ofbiz-component.xml?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/ofbiz-component.xml (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/ofbiz-component.xml Sat May 30 00:35:09 2009
@@ -26,10 +26,13 @@
     <classpath type="jar" location="lib/*"/>
     <classpath type="jar" location="build/lib/*"/>
 
+    <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>
     <entity-resource type="data" reader-name="seed" loader="main" location="data/GoogleCheckoutTypeData.xml"/>
     <entity-resource type="data" reader-name="demo" loader="main" location="data/DemoGoogleCheckoutData.xml"/>
     
+    <service-resource type="model" loader="main" location="servicedef/services_request.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services.xml"/>
+    <service-resource type="eca" loader="main" location="servicedef/secas.xml"/>
     
     <webapp name="googlecheckout"
         title="GoogleCheckout"

Modified: ofbiz/trunk/specialpurpose/googlecheckout/servicedef/secas.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/servicedef/secas.xml?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/servicedef/secas.xml (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/servicedef/secas.xml Sat May 30 00:35:09 2009
@@ -20,10 +20,7 @@
 <service-eca xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/service-eca.xsd">
     
-    <!-- payment related services -->
-    <eca service="authOrderPayments" event="commit" run-on-failure="false" run-on-error="false"> 
-        <action service="sendGoogleAuthorizeRequest" mode="sync"/>
-    </eca>
+    <!-- payment related services -->    
     <eca service="captureOrderPayments" event="commit" run-on-failure="false" run-on-error="false">
         <action service="sendGoogleChargeRequest" mode="sync"/>
     </eca>
@@ -39,11 +36,13 @@
     </eca>
      
     <!-- return related services -->
+    <!-- enable once method is implemented
     <eca service="updateReturnHeader" event="in-validate" run-on-failure="false" run-on-error="false">
         <condition field-name="statusId" operator="equals" value="RETURN_COMPLETED"/>
         <condition field-name="currentStatusId" operator="not-equals" value="RETURN_COMPLETED"/>
         <action service="sendGoogleReturnRequest" mode="sync"/>
     </eca>   
+    -->
       
     <!-- shipment related services -->
     <eca service="updateShipment" event="commit" run-on-failure="false" run-on-error="false">
@@ -51,4 +50,21 @@
         <condition field-name="statusId" operator="equals" value="SHIPMENT_SHIPPED"/>
         <action service="sendGoogleShipRequest" mode="sync"/>
     </eca>
+    
+    <!-- edit order catches -->
+    <eca service="updateOrderItems" event="in-validate" run-on-failure="false">
+        <action service="catchEditGoogleOrder" mode="sync" result-to-context="true" ignore-failure="false"/>
+    </eca>
+    <eca service="appendOrderItem" event="in-validate" run-on-failure="false">
+        <action service="catchEditGoogleOrder" mode="sync" result-to-context="true" ignore-failure="false"/>
+    </eca>
+    <eca service="recalcShippingTotal" event="in-validate" run-on-failure="false">
+        <action service="catchEditGoogleOrder" mode="sync" result-to-context="true" ignore-failure="false"/>
+    </eca>
+    <eca service="recalcTaxTotal" event="in-validate" run-on-failure="false">
+        <action service="catchEditGoogleOrder" mode="sync" result-to-context="true" ignore-failure="false"/>
+    </eca>
+    <eca service="createOrderAdjustment" event="in-validate" run-on-failure="false">
+        <action service="catchEditGoogleOrder" mode="sync" result-to-context="true" ignore-failure="false"/>
+    </eca>
  </service-eca>
\ No newline at end of file

Modified: ofbiz/trunk/specialpurpose/googlecheckout/servicedef/services_request.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/servicedef/services_request.xml?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/servicedef/services_request.xml (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/servicedef/services_request.xml Sat May 30 00:35:09 2009
@@ -21,10 +21,18 @@
 <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/services.xsd">
 
+    <!-- checkout request -->
+    <service name="sendGoogleCheckoutRequest" engine="java" auth="false"
+            location="org.ofbiz.googlecheckout.GoogleRequestServices" invoke="sendShoppingCartRequest">
+        <attribute name="shoppingCart" type="org.ofbiz.order.shoppingcart.ShoppingCart" mode="IN" optional="false"/>
+        <attribute name="productStoreId" type="String" mode="IN" optional="false"/>
+        <attribute name="redirect" type="String" mode="OUT" optional="false"/>
+    </service>
+    
     <!-- create order request notification -->
     <service name="sendGoogleOrderNumberRequest" engine="java" invoke="sendOrderNumberRequest"
             location="org.ofbiz.googlecheckout.GoogleRequestServices">
-        <attribute name="orderId" type="String" mode="IN" optional="false"/>
+        <attribute name="orderId" type="String" mode="IN" optional="false"/>        
     </service>
     
     <!-- payment notifications -->
@@ -35,6 +43,7 @@
     <service name="sendGoogleChargeRequest" engine="java" invoke="sendChargeRequest"
             location="org.ofbiz.googlecheckout.GoogleRequestServices">
         <attribute name="orderId" type="String" mode="IN" optional="false"/>
+        <attribute name="captureAmount" type="Double" mode="IN" optional="false"/>
     </service>
     
     <!-- returns -->
@@ -70,4 +79,9 @@
         <attribute name="orderId" type="String" mode="IN" optional="false"/>
     </service>
     
+    <!-- catch editing orders; return error -->
+    <service name="catchEditGoogleOrder" engine="java" invoke="catchEditGoogleOrder"
+            location="org.ofbiz.googlecheckout.GoogleRequestServices">
+        <attribute name="orderId" type="String" mode="IN" optional="false"/>   
+    </service>
  </services>
\ No newline at end of file

Modified: ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutHelper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutHelper.java?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutHelper.java (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutHelper.java Sat May 30 00:35:09 2009
@@ -34,6 +34,8 @@
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.entity.util.EntityUtil;
 import org.ofbiz.order.order.OrderChangeHelper;
 import org.ofbiz.order.shoppingcart.CheckOutHelper;
@@ -44,20 +46,26 @@
 import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.service.ServiceUtil;
 
-import com.google.checkout.CheckoutException;
 import com.google.checkout.checkout.Item;
 import com.google.checkout.notification.Address;
+import com.google.checkout.notification.AuthorizationAmountNotification;
+import com.google.checkout.notification.ChargeAmountNotification;
+import com.google.checkout.notification.ChargebackAmountNotification;
+import com.google.checkout.notification.FinancialOrderState;
 import com.google.checkout.notification.MerchantCodes;
 import com.google.checkout.notification.NewOrderNotification;
 import com.google.checkout.notification.OrderAdjustment;
+import com.google.checkout.notification.OrderStateChangeNotification;
+import com.google.checkout.notification.RefundAmountNotification;
+import com.google.checkout.notification.RiskInformationNotification;
 import com.google.checkout.notification.Shipping;
 import com.google.checkout.notification.StructuredName;
-import com.google.checkout.orderprocessing.AddMerchantOrderNumberRequest;
 
 public class GoogleCheckoutHelper {
 
     private static final String module = GoogleCheckoutHelper.class.getName();
-
+    private static final boolean errorOnUnknownItem = true; // set to false to simply ignore the item
+    
     public static final String SALES_CHANNEL = "GC_SALES_CHANNEL";
     public static final String ORDER_TYPE = "SALES_ORDER";
     public static final String PAYMENT_METHOD = "EXT_GOOGLE_CHECKOUT";
@@ -65,8 +73,8 @@
     public static final int SHIPPING_ADDRESS = 10;
     public static final int BILLING_ADDRESS = 50;
 
-   protected LocalDispatcher dispatcher;
-   protected GenericDelegator delegator;
+    protected LocalDispatcher dispatcher;
+    protected GenericDelegator delegator;
     protected GenericValue system;
 
     public GoogleCheckoutHelper(LocalDispatcher dispatcher, GenericDelegator delegator) {
@@ -84,6 +92,71 @@
         }
     }
 
+    public void processStateChange(OrderStateChangeNotification info) throws GeneralException {
+        String externalId = info.getGoogleOrderNumber();
+        GenericValue order = null;
+        try {
+            List<GenericValue> orders = delegator.findByAnd("OrderHeader", UtilMisc.toMap("externalId", externalId, "salesChannelEnumId" , SALES_CHANNEL));
+            order = EntityUtil.getFirst(orders);
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        
+        if (order != null) {
+            String orderId = order.getString("orderId");
+            
+            // check for a financial state change
+            FinancialOrderState oldFin = info.getPreviousFinancialOrderState();
+            FinancialOrderState newFin = info.getNewFinancialOrderState();
+            if (!oldFin.equals(newFin)) {
+                // financial state change
+                if (newFin.equals(FinancialOrderState.CANCELLED) || newFin.equals(FinancialOrderState.CANCELLED_BY_GOOGLE)) {
+                    // cancel the order
+                    if (!"ORDER_CANCELLED".equals(order.getString("statusId"))) {
+                        OrderChangeHelper.cancelOrder(dispatcher, system, orderId);
+                    }
+                } else if (newFin.equals(FinancialOrderState.CHARGEABLE) && oldFin.equals(FinancialOrderState.REVIEWING)) {
+                    // approve the order 
+                    if (!"ORDER_APPROVED".equals(order.getString("statusId"))) {
+                        OrderChangeHelper.approveOrder(dispatcher, system, orderId, hasHoldOrderNotes(orderId));
+                    }
+                } else if (newFin.equals(FinancialOrderState.PAYMENT_DECLINED)) {
+                    // reject the order
+                    if (!"ORDER_REJECTED".equals(order.getString("statusId"))) {
+                        OrderChangeHelper.rejectOrder(dispatcher, system, orderId);
+                    }
+                }
+                // TODO: look at how to implement the other state changes
+                // CHARGED, CHARGING
+            }           
+        }        
+    }
+            
+    public void processRiskNotification(RiskInformationNotification info) throws GeneralException {
+        // TODO implement me (if desired)
+        return; // the notification will be accepted
+    }
+    
+    public void processAuthNotification(AuthorizationAmountNotification info) throws GeneralException {
+        // TODO implement me (if desired)
+        return; // the notification will be accepted                        
+    }
+    
+    public void processChargeNotification(ChargeAmountNotification info) throws GeneralException {
+        // TODO: implement me (if desired)
+        return; // the notification will be accepted
+    }
+    
+    public void processRefundNotification(RefundAmountNotification info) throws GeneralException {
+        // TODO: implement me (if desired)
+        return; // the notification will be accepted
+    }
+    
+    public void processChargeBackNotification(ChargebackAmountNotification info) throws GeneralException {
+        // TODO: implement me (if desired)
+        return; // the notification will be accepted
+    }
+    
     @SuppressWarnings("unchecked")
     public void createOrder(NewOrderNotification info, String productStoreId, String websiteId, String currencyUom, Locale locale) throws GeneralException {
         // get the google order number
@@ -92,7 +165,9 @@
         // check and make sure this order doesn't already exist
         List<GenericValue> existingOrder = delegator.findByAnd("OrderHeader", UtilMisc.toMap("externalId", externalId));
         if (existingOrder != null && existingOrder.size() > 0) {
-            throw new GeneralException("Google order #" + externalId + " already exists.");
+            //throw new GeneralException("Google order #" + externalId + " already exists.");
+            Debug.logWarning("Google order #" + externalId + " already exists.", module);
+            return;
         }
 
         // Initialize the shopping cart
@@ -105,8 +180,8 @@
 
         Debug.logInfo("Created shopping cart for Google order: ", module);
         Debug.logInfo("-- WebSite : " + websiteId, module);
-       Debug.logInfo("-- Product Store : " + productStoreId, module);
-       Debug.logInfo("-- Locale : " + locale.toString(), module);
+        Debug.logInfo("-- Product Store : " + productStoreId, module);
+        Debug.logInfo("-- Locale : " + locale.toString(), module);
         Debug.logInfo("-- Google Order # : " + externalId, module);
 
         // set the customer information
@@ -144,9 +219,12 @@
         for (Item item : items) {
             try {
                 addItem(cart, item, null, 0);
-            } catch (ItemNotFoundException e) {
-                // TODO: handle items not found
+            } catch (ItemNotFoundException e) {                
                 Debug.logWarning(e, "Item was not found : " + item.getMerchantItemId(), module);
+                // throwing this exception tell google the order failed; it will continue to retry  
+                if (errorOnUnknownItem) {
+                    throw new GeneralException("Invalid item requested from Google Checkout - " + item.getMerchantItemId());
+                }
             }
         }
 
@@ -156,10 +234,10 @@
 
         // ship group info
         Shipping shipping = info.getOrderAdjustment().getShipping();
-        addShipInfo(cart, shipping);
+        addShipInfo(cart, shipping, partyInfo[1]);
 
         // set the cart payment method
-        cart.addPayment(PAYMENT_METHOD);
+        cart.addPaymentAmount(PAYMENT_METHOD, cart.getGrandTotal());
 
         // validate the payment methods
         CheckOutHelper coh = new CheckOutHelper(dispatcher, delegator, cart);
@@ -174,19 +252,13 @@
         if (ServiceUtil.isError(createResp)) {
             throw new GeneralException(ServiceUtil.getErrorMessage(createResp));
         }
-
-        // approve the order
-        OrderChangeHelper.approveOrder(dispatcher, system, orderId, cart.getHoldOrder());
-
+        
         // notify google of our order number
-        // TODO: enable this
-        /*
         try {
-            dispatcher.runAsync("sendGoogleOrderNumberRequest", true, UtilMisc.toMap("orderId", orderId));
+            dispatcher.runAsync("sendGoogleOrderNumberRequest", UtilMisc.toMap("orderId", orderId), true);
         } catch (GeneralException e) {
             Debug.logError(e, module);
-        } 
-        */
+        }         
     }
 
     protected void addItem(ShoppingCart cart, Item item, String productCatalogId, int groupIdx) throws GeneralException {
@@ -233,7 +305,7 @@
         GenericValue taxAdj = delegator.makeValue("OrderAdjustment", FastMap.newInstance());
         taxAdj.set("orderAdjustmentTypeId", "SALES_TAX");
         taxAdj.set("amount", taxAmount);
-       cart.addAdjustment(taxAdj);
+        cart.addAdjustment(taxAdj);
 
         // handle promotions
         Collection<MerchantCodes> merchantCodes = adjustment.getMerchantCodes();
@@ -247,19 +319,24 @@
         }
     }
 
-    protected void addShipInfo(ShoppingCart cart, Shipping shipping) {
-        String shippingName = shipping.getShippingName();
-
-        // TODO parse the shipping method and get a valid OFBiz shipping method
-        // FOR NOW - Just use some dummy info
-        String shipmentMethodTypeId = shippingName;
-        String carrierPartyId = "_NA_";
-        Boolean maySplit = Boolean.FALSE;
-
-        if (shipmentMethodTypeId != null) {
+    protected void addShipInfo(ShoppingCart cart, Shipping shipping, String shipContactMechId) {        
+        String shippingName = shipping.getShippingName();        
+        GenericValue googleShipping = null;        
+        try {
+            googleShipping = delegator.findOne("GoogleShippingMethods", UtilMisc.toMap("shipmentMethodName", shippingName, 
+                    "productStoreId", cart.getProductStoreId()), false);
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        if (googleShipping != null) {
+            String shipmentMethodTypeId = googleShipping.getString("shipmentMethodTypeId");
+            String carrierPartyId = googleShipping.getString("carrierPartyId");
+            Boolean maySplit = Boolean.FALSE; 
+            
             cart.setShipmentMethodTypeId(shipmentMethodTypeId);
             cart.setCarrierPartyId(carrierPartyId);
             cart.setMaySplit(maySplit);
+            cart.setShippingContactMechId(shipContactMechId);
         } else {
             Debug.logWarning("No valid fulfillment method found! No shipping info set!", module);
         }
@@ -273,8 +350,9 @@
 	    // look for an existing shipping address
 	    List<GenericValue> shipInfo = PartyWorker.findMatchingPartyAndPostalAddress(delegator, shipAddr.getAddress1(), 
 	            (UtilValidate.isEmpty(shipAddr.getAddress2()) ? null : shipAddr.getAddress2()), shipAddr.getCity(), shipAddr.getRegion(), 
-	            shipAddr.getPostalCode(), null, shipAddr.getCountryCode(), shipAddr.getStructuredName().getFirstName(), 
+	            shipAddr.getPostalCode(), null, getCountryGeoId(shipAddr.getCountryCode()), shipAddr.getStructuredName().getFirstName(), 
 	            null, shipAddr.getStructuredName().getLastName());
+	    
 	    if (shipInfo != null && shipInfo.size() > 0) {
 	        GenericValue first = EntityUtil.getFirst(shipInfo);
 	        shipCmId = first.getString("contactMechId");
@@ -285,8 +363,9 @@
 	    // look for an existing billing address
 	    List<GenericValue> billInfo = PartyWorker.findMatchingPartyAndPostalAddress(delegator, billAddr.getAddress1(), 
 	            (UtilValidate.isEmpty(billAddr.getAddress2()) ? null : billAddr.getAddress2()), billAddr.getCity(), billAddr.getRegion(), 
-	            billAddr.getPostalCode(), null, billAddr.getCountryCode(), billAddr.getStructuredName().getFirstName(), 
+	            billAddr.getPostalCode(), null, getCountryGeoId(billAddr.getCountryCode()), billAddr.getStructuredName().getFirstName(), 
 	            null, billAddr.getStructuredName().getLastName());
+	    
         if (billInfo != null && billInfo.size() > 0) {
             GenericValue first = EntityUtil.getFirst(billInfo);
             billCmId = first.getString("contactMechId");
@@ -318,8 +397,9 @@
             // check the billing address again (in case it was just created)
             billInfo = PartyWorker.findMatchingPartyAndPostalAddress(delegator, billAddr.getAddress1(), 
                     billAddr.getAddress2(), billAddr.getCity(), billAddr.getRegion(), 
-                    billAddr.getPostalCode(), null, billAddr.getCountryCode(), billAddr.getStructuredName().getFirstName(), 
+                    billAddr.getPostalCode(), null, getCountryGeoId(billAddr.getCountryCode()), billAddr.getStructuredName().getFirstName(), 
                     null, billAddr.getStructuredName().getLastName());
+            
             if (billInfo != null && billInfo.size() > 0) {
                 GenericValue first = EntityUtil.getFirst(billInfo);
                 billCmId = first.getString("contactMechId");
@@ -366,7 +446,7 @@
         addrMap.put("address2", addr.getAddress2());
         addrMap.put("city", addr.getCity());
         addrMap.put("stateProvinceGeoId",addr.getRegion());
-        addrMap.put("countryGeoId", addr.getCountryCode());
+        addrMap.put("countryGeoId", getCountryGeoId(addr.getCountryCode()));
         addrMap.put("postalCode", postalCode);
         addrMap.put("postalCodeExt", postalCodeExt);
         addrMap.put("allowSolicitation", "Y");
@@ -485,5 +565,33 @@
         }
     }
 	
-	// uses a unique order number each time so that the duplicate order check doesn't kick in
+	protected String getCountryGeoId(String geoCode) {
+	    if (geoCode != null && geoCode.length() == 3) {
+	        return geoCode;
+	    }
+        List<GenericValue> geos = null;
+        try {
+            geos = delegator.findByAnd("Geo", UtilMisc.toMap("geoCode", geoCode, "geoTypeId", "COUNTRY"));
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        if (geos != null && geos.size() > 0) {
+            return EntityUtil.getFirst(geos).getString("geoId");
+        } else {
+            return "_NA_";
+        }
+    }
+	
+	protected boolean hasHoldOrderNotes(String orderId) {
+	    EntityCondition idCond = EntityCondition.makeCondition("orderId", EntityOperator.EQUALS, orderId);
+	    EntityCondition content = EntityCondition.makeCondition("noteInfo", EntityOperator.LIKE, "%Order is held%");
+	    EntityCondition mainCond = EntityCondition.makeCondition(UtilMisc.toList(idCond, content), EntityOperator.AND);
+	    List<GenericValue> holdOrderNotes = null;	    
+	    try {
+	        holdOrderNotes = delegator.findList("OrderHeaderNoteView", mainCond, null, null, null, false);
+	    } catch (GenericEntityException e) {
+	        Debug.logError(e, module);
+	    }
+	    return UtilValidate.isNotEmpty(holdOrderNotes);
+	}
 }
\ No newline at end of file

Modified: ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutResponseEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutResponseEvents.java?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutResponseEvents.java (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleCheckoutResponseEvents.java Sat May 30 00:35:09 2009
@@ -18,9 +18,7 @@
 **/
 package org.ofbiz.googlecheckout;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.Locale;
 
@@ -30,7 +28,6 @@
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
 import org.ofbiz.base.util.UtilMisc;
-import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
@@ -38,7 +35,13 @@
 import org.w3c.dom.Document;
 
 import com.google.checkout.CheckoutException;
+import com.google.checkout.notification.AuthorizationAmountNotification;
+import com.google.checkout.notification.ChargeAmountNotification;
+import com.google.checkout.notification.ChargebackAmountNotification;
 import com.google.checkout.notification.NewOrderNotification;
+import com.google.checkout.notification.OrderStateChangeNotification;
+import com.google.checkout.notification.RefundAmountNotification;
+import com.google.checkout.notification.RiskInformationNotification;
 import com.google.checkout.util.Utils;
 
 public class GoogleCheckoutResponseEvents {
@@ -50,14 +53,17 @@
         GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
           
         GoogleCheckoutHelper helper = new GoogleCheckoutHelper(dispatcher, delegator);
-        //String xmlString = helper.getTestResponseString(); // TODO: make this work with the info sent to the event
-        String xmlString = processGoogleCheckoutResponse(request,response);
+        
         // check and parse the document
         Document document = null;
         try {
-            document = Utils.newDocumentFromString(xmlString);
+            document = Utils.newDocumentFromInputStream(request.getInputStream());            
         } catch (CheckoutException e) {
             Debug.logError(e, module);
+            sendResponse(response, null, true);
+        } catch (IOException e) {
+            Debug.logError(e, module);
+            sendResponse(response, null, true);
         }
         
         // check the document type and process 
@@ -75,6 +81,72 @@
                     sendResponse(response, serialNumber, true);
                     return null;
                 }
+            } else if ("order-state-change-notification".equals(nodeValue)) {
+                OrderStateChangeNotification info = new OrderStateChangeNotification(document);
+                String serialNumber = info.getSerialNumber();
+                try {
+                    helper.processStateChange(info);
+                    sendResponse(response, serialNumber, false);
+                } catch (GeneralException e) {
+                    Debug.logError(e, module);
+                    sendResponse(response, serialNumber, true);
+                    return null;
+                }
+            } else if ("risk-information-notification".equals(nodeValue)) {
+                RiskInformationNotification info = new RiskInformationNotification(document);
+                String serialNumber = info.getSerialNumber();
+                try {
+                    helper.processRiskNotification(info);
+                    sendResponse(response, serialNumber, false);                    
+                } catch (GeneralException e) {
+                    Debug.logError(e, module);
+                    sendResponse(response, serialNumber, true);
+                    return null;
+                }
+            } else if ("authorization-amount-notification".equals(nodeValue)) {
+                AuthorizationAmountNotification info = new AuthorizationAmountNotification(document);
+                String serialNumber = info.getSerialNumber();
+                try {
+                    helper.processAuthNotification(info);
+                    sendResponse(response, serialNumber, false);                    
+                } catch (GeneralException e) {
+                    Debug.logError(e, module);
+                    sendResponse(response, serialNumber, true);
+                    return null;
+                } 
+            } else if ("charge-amount-notification".equals(nodeValue)) {
+                ChargeAmountNotification info = new ChargeAmountNotification(document);
+                String serialNumber = info.getSerialNumber();
+                try {
+                    helper.processChargeNotification(info);
+                    sendResponse(response, serialNumber, false);                    
+                } catch (GeneralException e) {
+                    Debug.logError(e, module);
+                    sendResponse(response, serialNumber, true);
+                    return null;
+                }  
+            } else if ("chargeback-amount-notification".equals(nodeValue)) {
+                ChargebackAmountNotification info = new ChargebackAmountNotification(document);
+                String serialNumber = info.getSerialNumber();
+                try {
+                    helper.processChargeBackNotification(info);
+                    sendResponse(response, serialNumber, false);                    
+                } catch (GeneralException e) {
+                    Debug.logError(e, module);
+                    sendResponse(response, serialNumber, true);
+                    return null;
+                }             
+            } else if ("refund-amount-notification".equals(nodeValue)) {
+                RefundAmountNotification info = new RefundAmountNotification(document);
+                String serialNumber = info.getSerialNumber();
+                try {
+                    helper.processRefundNotification(info);
+                    sendResponse(response, serialNumber, false);                    
+                } catch (GeneralException e) {
+                    Debug.logError(e, module);
+                    sendResponse(response, serialNumber, true);
+                    return null;
+                }  
             } else {
                 Debug.logWarning("Unsupported document type submitted by Google; [" + nodeValue + "] has not yet been implemented.", module);
             }
@@ -82,25 +154,7 @@
         
         return null;
     }
-    public static String processGoogleCheckoutResponse(HttpServletRequest request, HttpServletResponse response) {
-        StringBuffer xmlBuff = new StringBuffer();
-        try {
-            BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
-            String inputLine;
-            while ((inputLine = in.readLine()) != null) {
-                xmlBuff.append(inputLine);
-            }
-            in.close();
-        } catch (IOException e) {
-            Debug.logError(e, "Problems sending verification message", module);
-        }
-        
-        if(UtilValidate.isNotEmpty(xmlBuff.toString())) {
-            return xmlBuff.toString();
-        } else {
-            return "error";
-        }
-    }
+            
     private static void sendResponse(HttpServletResponse response, String serialNumber, boolean error) {
         if (error) {
             try {

Modified: ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleRequestServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleRequestServices.java?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleRequestServices.java (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/src/org/ofbiz/googlecheckout/GoogleRequestServices.java Sat May 30 00:35:09 2009
@@ -19,28 +19,37 @@
 
 package org.ofbiz.googlecheckout;
 
+import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
 import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
 import org.ofbiz.entity.util.EntityUtil;
+import org.ofbiz.order.shoppingcart.ShoppingCart;
+import org.ofbiz.order.shoppingcart.ShoppingCartItem;
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.ServiceUtil;
 
 import com.google.checkout.CheckoutException;
+import com.google.checkout.CheckoutResponse;
+import com.google.checkout.EnvironmentType;
 import com.google.checkout.MerchantInfo;
+import com.google.checkout.checkout.CarrierPickup;
+import com.google.checkout.checkout.CheckoutShoppingCartRequest;
+import com.google.checkout.checkout.Item;
+import com.google.checkout.checkout.TaxArea;
 import com.google.checkout.orderprocessing.AddMerchantOrderNumberRequest;
 import com.google.checkout.orderprocessing.ArchiveOrderRequest;
 import com.google.checkout.orderprocessing.AuthorizeOrderRequest;
 import com.google.checkout.orderprocessing.CancelOrderRequest;
 import com.google.checkout.orderprocessing.ChargeOrderRequest;
-import com.google.checkout.orderprocessing.RefundOrderRequest;
 import com.google.checkout.orderprocessing.UnarchiveOrderRequest;
 import com.google.checkout.orderprocessing.lineitem.CancelItemsRequest;
 import com.google.checkout.orderprocessing.lineitem.ShipItemsRequest;
@@ -49,20 +58,142 @@
     
     private static final String module = GoogleRequestServices.class.getName();
     
+    @SuppressWarnings("unchecked")
+    public static Map<String, Object> sendShoppingCartRequest(DispatchContext dctx, Map<String, ? extends Object> context) {        
+        ShoppingCart cart = (ShoppingCart) context.get("shoppingCart");  
+        String productStoreId = (String) context.get("productStoreId");        
+        GenericDelegator delegator = dctx.getDelegator();
+        MerchantInfo mInfo = getMerchantInfo();
+        if (mInfo == null) {
+            Debug.logError("Invalid Google Chechout Merchant settings, check your configuration!", module);
+            return ServiceUtil.returnError("Google checkout configuration error");
+        }
+        
+        // the checkout request object
+        CheckoutShoppingCartRequest req = new CheckoutShoppingCartRequest(mInfo, 300);
+        req.setRequestInitialAuthDetails(true); // send the auth notification
+        
+        // add the items
+        List<ShoppingCartItem> items = cart.items();
+        for (ShoppingCartItem item : items) {                        
+            Item i = new Item();            
+            i.setItemName(item.getName());
+            i.setItemDescription(item.getDescription());
+            i.setMerchantItemId(item.getProductId());
+            i.setQuantity(item.getQuantity().intValue());
+            i.setUnitPriceAmount(item.getItemSubTotal(new BigDecimal(1)).floatValue());
+            i.setUnitPriceCurrency(cart.getCurrency());            
+            //i.setItemWeight(item.getWeight().floatValue()); // must convert weight to Lb 
+            if (!item.taxApplies()) {
+                i.setTaxTableSelector("tax_exempt");
+            }
+            req.addItem(i);
+        }
+                        
+        // flow support URLs
+        String contShoppingUrl = UtilProperties.getPropertyValue("googleCheckout.properties", "continueShoppingUrl");
+        String editCartUrl = UtilProperties.getPropertyValue("googleCheckout.properties", "editCartUrl");
+        req.setContinueShoppingUrl(contShoppingUrl);
+        req.setEditCartUrl(editCartUrl);
+        
+        // setup exempt tax support
+        TaxArea exemptArea = new TaxArea();
+        exemptArea.addWorldArea();
+        req.addAlternateTaxRule("tax_exempt", true, 0, exemptArea);
+        
+        // setup default tax table
+        // TODO: implement this; for now use the tax table in Google Checkout Settings
+        
+        // setup shipping options support
+        List<GenericValue> shippingOptions = null;
+        try {
+            shippingOptions = delegator.findByAnd("GoogleShippingMethods", UtilMisc.toMap("productStoreId", productStoreId));
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        if (UtilValidate.isNotEmpty(shippingOptions)) {
+            for (GenericValue option : shippingOptions) {
+                String shippingName = option.getString("shipmentMethodName");
+                Double amount = option.getDouble("amount");
+                if (amount == null) {
+                    amount = 0.0;
+                }
+                if ("GOOGLE_FLAT_RATE".equals(option.getString("methodTypeEnumId"))) {
+                    req.addFlatRateShippingMethod(shippingName, amount.floatValue());
+                } else if ("GOOGLE_MERCHANT_CALC".equals(option.getString("methodTypeEnumId"))) {                    
+                    req.addMerchantCalculatedShippingMethod(shippingName, amount.floatValue());
+                } else if ("GOOGLE_PICKUP".equals(option.getString("methodTypeEnumId"))) {
+                    req.addPickupShippingMethod(shippingName, amount.floatValue());     
+                } else if ("GOOGLE_CARRIER_CALC".equals(option.getString("methodTypeEnumId"))) {
+                    String carrierPartyId = option.getString("carrierPartyId");
+                    
+                    Double additionalAmount = option.getDouble("additionalAmount");
+                    Double additionalPercent = option.getDouble("additionalPercent");
+                    if (additionalAmount == null) {
+                        additionalAmount = 0.0;
+                    }
+                    if (additionalPercent == null) {
+                        additionalPercent = 0.0;
+                    }
+                    
+                    String shippingCompany = null;
+                    if ("ups".equalsIgnoreCase(carrierPartyId)) {
+                        shippingCompany = "UPS";
+                    } else if ("fedex".equalsIgnoreCase(carrierPartyId)) {
+                        shippingCompany = "FedEx";                        
+                    } else if ("usps".equalsIgnoreCase(carrierPartyId)) {
+                        shippingCompany = "USPS";
+                    }
+                    if (shippingCompany == null) {
+                        return ServiceUtil.returnError("Invalid Google Checkout Shipping Configuration! Carriers can only be UPS, FedEx or USPS.");
+                    }
+                    req.addCarrierCalculatedShippingOption(amount.floatValue(), shippingCompany, CarrierPickup.REGULAR_PICKUP,
+                             shippingName, additionalAmount.floatValue(), additionalPercent.floatValue());                              
+                }
+            }
+        }
+        
+        // merchant stuff
+        //req.setAcceptMerchantCoupons(false); // disable coupons through google
+        //req.setAcceptMerchantGiftCertificates(false); // disable gift certs through google
+        req.setRequestBuyerPhoneNumber(true);
+        
+        // send the request
+        CheckoutResponse resp = null;
+        try {
+            Debug.logInfo("Sending XML to Google:\n\n" + req.getXmlPretty() + "\n\n", module);
+            resp = req.send();
+        } catch (CheckoutException e) {
+            Debug.logError(e, module);
+            return ServiceUtil.returnError(e.getMessage());
+        }
+        if (resp == null) {
+            return ServiceUtil.returnError("Checkout response was null");
+        }
+        if (!resp.isValidRequest()) {
+            Debug.logError("Error returned from Google: " + resp.getErrorMessage(), module);
+            return ServiceUtil.returnError(resp.getErrorMessage());
+        }
+        
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+        result.put("redirect", resp.getRedirectUrl());
+        return result;
+    }
+    
     public static Map<String, Object> sendOrderNumberRequest(DispatchContext dctx, Map<String, ? extends Object> context) {
         GenericDelegator delegator = dctx.getDelegator();
         String orderId = (String) context.get("orderId");
         GenericValue order = findGoogleOrder(delegator, orderId);
         if (order != null) {
             MerchantInfo mInfo = getMerchantInfo();
-            String externalId = order.getString("externalId");
-            if (UtilValidate.isNotEmpty(externalId)) {
+            if (mInfo != null) {
+                String externalId = order.getString("externalId");                
                 AddMerchantOrderNumberRequest aor = new AddMerchantOrderNumberRequest(mInfo, externalId, orderId);
                 try {
                     aor.send();
                 } catch (CheckoutException e) {
                     Debug.logError(e, module);
-                }
+                }                
             }
         }
         
@@ -75,14 +206,14 @@
         GenericValue order = findGoogleOrder(delegator, orderId);
         if (order != null) {
             MerchantInfo mInfo = getMerchantInfo();
-            String externalId = order.getString("externalId");
-            if (UtilValidate.isNotEmpty(externalId)) {  
+            if (mInfo != null) {
+                String externalId = order.getString("externalId");
                 AuthorizeOrderRequest aor = new AuthorizeOrderRequest(mInfo, externalId);
                 try {
                     aor.send();
                 } catch (CheckoutException e) {
                     Debug.logError(e, module);
-                }
+                }                
             }
         }
         
@@ -96,15 +227,19 @@
         GenericValue order = findGoogleOrder(delegator, orderId);
         if (order != null) {
             MerchantInfo mInfo = getMerchantInfo();
-            String externalId = order.getString("externalId");
-            if (UtilValidate.isNotEmpty(externalId)) {
+            if (mInfo != null) {
+                String externalId = order.getString("externalId");
                 Double amountToCharge = (Double) context.get("captureAmount");
-                
-                ChargeOrderRequest cor = new ChargeOrderRequest(mInfo, externalId, amountToCharge.floatValue());
-                try {
-                    cor.send();
-                } catch (CheckoutException e) {
-                    Debug.logError(e, module);
+                if (amountToCharge == null || amountToCharge == 0) {
+                    amountToCharge = order.getDouble("grandTotal"); // captureAmount 0 means capture all??
+                }
+                if (amountToCharge > 0) {
+                    ChargeOrderRequest cor = new ChargeOrderRequest(mInfo, externalId, amountToCharge.floatValue());
+                    try {
+                        cor.send();
+                    } catch (CheckoutException e) {
+                        Debug.logError(e, module);
+                    }
                 }
             }
         }
@@ -124,12 +259,14 @@
     public static Map<String, Object> sendShipRequest(DispatchContext dctx, Map<String, ? extends Object> context) {
         GenericDelegator delegator = dctx.getDelegator();
         String shipmentId = (String) context.get("shipmentId");
-        try {
-            sendItemsShipped(delegator, shipmentId);
-        } catch (GeneralException e) {
-            // TODO: handle the error
-        }
-                
+        MerchantInfo mInfo = getMerchantInfo();
+        if (mInfo != null) {
+            try {
+                sendItemsShipped(delegator, shipmentId, mInfo);
+            } catch (GeneralException e) {
+                // TODO: handle the error
+            }
+        }                
         return ServiceUtil.returnSuccess();
     }
     
@@ -139,14 +276,14 @@
         GenericValue order = findGoogleOrder(delegator, orderId);
         if (order != null) {
             MerchantInfo mInfo = getMerchantInfo();
-            String externalId = order.getString("externalId");
-            if (UtilValidate.isNotEmpty(externalId)) {
+            if (mInfo != null) {
+                String externalId = order.getString("externalId");                
                 CancelOrderRequest cor = new CancelOrderRequest(mInfo, externalId, "Order Cancelled", ""); // TODO: configure the reason and comment
                 try {
                     cor.send();
                 } catch (CheckoutException e) {
                     Debug.logError(e, module);
-                }
+                }                
             }
         }
         
@@ -168,15 +305,15 @@
             
             if (orderItem != null) {
                 MerchantInfo mInfo = getMerchantInfo();
-                String externalId = order.getString("externalId");
-                if (UtilValidate.isNotEmpty(externalId)) {
+                if (mInfo != null) {
+                    String externalId = order.getString("externalId");                    
                     CancelItemsRequest cir = new CancelItemsRequest(mInfo, externalId, "Item Cancelled", ""); // TODO: configure the reason and comment
                     cir.addItem(orderItem.getString("productId"));
                     try {
                         cir.send();
                     } catch (CheckoutException e) {
                         Debug.logError(e, module);
-                    }
+                    }                    
                 }
             }
         }
@@ -190,8 +327,8 @@
         GenericValue order = findGoogleOrder(delegator, orderId);
         if (order != null) {
             MerchantInfo mInfo = getMerchantInfo();
-            String externalId = order.getString("externalId");
-            if (UtilValidate.isNotEmpty(externalId)) {   
+            if (mInfo != null) {
+                String externalId = order.getString("externalId");                
                 ArchiveOrderRequest aor = new ArchiveOrderRequest(mInfo, externalId);
                 try {
                     aor.send();
@@ -210,8 +347,8 @@
         GenericValue order = findGoogleOrder(delegator, orderId);
         if (order != null) {
             MerchantInfo mInfo = getMerchantInfo();
-            String externalId = order.getString("externalId");
-            if (UtilValidate.isNotEmpty(externalId)) {   
+            if (mInfo != null) {
+                String externalId = order.getString("externalId");
                 UnarchiveOrderRequest uor = new UnarchiveOrderRequest(mInfo, externalId);
                 try {
                     uor.send();
@@ -224,17 +361,31 @@
         return ServiceUtil.returnSuccess();
     }
     
-    private static void sendItemsShipped(GenericDelegator delegator, String shipmentId) throws GeneralException {
+    // special service to tigger off of events which prevent editing orders
+    public static Map<String, Object> catchEditGoogleOrder(DispatchContext dctx, Map<String, ? extends Object> context) {
+        GenericDelegator delegator = dctx.getDelegator();
+        String orderId = (String) context.get("orderId");
+        GenericValue order = findGoogleOrder(delegator, orderId);
+        if (order != null) {
+            Debug.log("Returning FAILURE; this IS an Google Checkout order and cannot be modified as requested!", module);
+            return ServiceUtil.returnFailure("Google Checkout orders cannot be modified. You may cancel orders/items only!");
+        }
+        return ServiceUtil.returnSuccess();        
+    }    
+    
+    private static void sendItemsShipped(GenericDelegator delegator, String shipmentId, MerchantInfo mInfo) throws GeneralException {
         List<GenericValue> issued = delegator.findByAnd("ItemIssuance", UtilMisc.toMap("shipmentId", shipmentId));
         if (issued != null && issued.size() > 0) {
             for (GenericValue issue : issued) {
+                GenericValue orderItem = issue.getRelatedOne("OrderItem");
                 String shipmentItemSeqId = issue.getString("shipmentItemSeqId"); 
-                String productId = issue.getString("productId");
+                String productId = orderItem.getString("productId");
                 String orderId = issue.getString("orderId");
                 GenericValue order = findGoogleOrder(delegator, orderId);
-                String externalId = order.getString("externalId");
-                  
-                if (externalId != null) {
+                                 
+                if (order != null) {
+                    String externalId = order.getString("externalId");
+                    
                     // locate the shipment package content record
                     Map<String, ? extends Object> spcLup = UtilMisc.toMap("shipmentId", shipmentId, "shipmentItemSeqId", shipmentItemSeqId);
 
@@ -261,7 +412,7 @@
                                     }
 
                                     try {
-                                        ShipItemsRequest isr = new ShipItemsRequest(getMerchantInfo(), externalId);
+                                        ShipItemsRequest isr = new ShipItemsRequest(mInfo, externalId);
                                         isr.addItemShippingInformation(productId, carrier, track);
                                         isr.send();
                                     } catch (CheckoutException e) {
@@ -287,18 +438,52 @@
         
         if (order != null) {
             String salesChannel = order.getString("salesChannelEnumId");
-            if (GoogleCheckoutHelper.SALES_CHANNEL.equals(salesChannel)) {
+            String externalId = order.getString("externalId");
+            if (GoogleCheckoutHelper.SALES_CHANNEL.equals(salesChannel) && UtilValidate.isNotEmpty(externalId)) {
                 return order;
             }
         }
         
         return null;
     }
-               
+                           
     public static MerchantInfo getMerchantInfo() {
-        // TODO: implement this to pull data from the properties file
-        MerchantInfo info = null;
-        
-        return info;
-    }
+        // merchant information
+        String merchantId = UtilProperties.getPropertyValue("googleCheckout.properties", "merchantId");
+        String merchantKey = UtilProperties.getPropertyValue("googleCheckout.properties", "merchantKey");
+        String environment = UtilProperties.getPropertyValue("googleCheckout.properties", "environment.mode", "Sandbox");
+        String currencyCode = "USD";
+        
+        if (UtilValidate.isEmpty(merchantId) || UtilValidate.isEmpty(merchantKey)) {
+            return null;
+        }
+        
+        // base URLs
+        String productionRoot = UtilProperties.getPropertyValue("googleCheckout.properties", "production.root.url");
+        String sandboxRoot = UtilProperties.getPropertyValue("googleCheckout.properties", "sandbox.root.url");
+        
+        // command strings
+        String merchantCheckoutCommand = UtilProperties.getPropertyValue("googleCheckout.properties", "merchant.checkout.command", "merchantCheckout");
+        String checkoutCommand = UtilProperties.getPropertyValue("googleCheckout.properties", "checkout.command", "checkout");        
+        String requestCommand = UtilProperties.getPropertyValue("googleCheckout.properties", "request.command", "request");
+
+        String checkoutUrl = "";
+        String merchantCheckoutUrl = "";
+        String requestUrl = "";
+
+        // build the URLs based on the Environment type
+        if (EnvironmentType.Sandbox.equals(environment)) {
+            merchantCheckoutUrl = sandboxRoot + "/" + merchantCheckoutCommand + "/Merchant/" + merchantId;
+            checkoutUrl = sandboxRoot + "/" + checkoutCommand + "/Merchant/" + merchantId;            
+            requestUrl = sandboxRoot + "/" + requestCommand + "/Merchant/" + merchantId;
+        } else if (EnvironmentType.Production.equals(environment)) {
+            merchantCheckoutUrl = productionRoot + "/" + merchantCheckoutCommand + "/Merchant/" + merchantId;
+            checkoutUrl = productionRoot + "/" + checkoutCommand + "/Merchant/" + merchantId;            
+            requestUrl = productionRoot + "/" + requestCommand + "/Merchant/" + merchantId;
+        } else {
+            Debug.logError("Environment must be one of " + EnvironmentType.Sandbox + " or " + EnvironmentType.Production + ".", module);
+            return null;
+        }
+        return new MerchantInfo(merchantId, merchantKey, environment, currencyCode, checkoutUrl, merchantCheckoutUrl, requestUrl);                
+    }                   
 }

Modified: ofbiz/trunk/specialpurpose/googlecheckout/webapp/googlecheckout/WEB-INF/controller.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/googlecheckout/webapp/googlecheckout/WEB-INF/controller.xml?rev=780153&r1=780152&r2=780153&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/googlecheckout/webapp/googlecheckout/WEB-INF/controller.xml (original)
+++ ofbiz/trunk/specialpurpose/googlecheckout/webapp/googlecheckout/WEB-INF/controller.xml Sat May 30 00:35:09 2009
@@ -22,12 +22,21 @@
         xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/site-conf.xsd">
 
     <description>Google Checkout Component Site Configuration File</description>
-
+    <owner>Copyright 2001-2009 The Apache Software Foundation</owner>
+    <errorpage>/error/error.jsp</errorpage>
+    <handler name="java" type="request" class="org.ofbiz.webapp.event.JavaEventHandler"/>
+    
     <request-map uri="main">
         <security https="true" auth="true"/>
         <response name="success" type="view" value="main"/>
     </request-map>
 
+    <request-map uri="handleMessage" track-serverhit="false" track-visit="false">
+        <security https="false" auth="false"/>
+        <event type="java" path="org.ofbiz.googlecheckout.GoogleCheckoutResponseEvents" invoke="checkNotification"/>
+        <response name="success" type="none"/>
+        <response name="error" type="none"/>
+    </request-map>
     <!-- end of request mappings -->
 
     <!-- View Mappings -->