svn commit: r793866 - in /ofbiz/trunk: applications/accounting/config/ applications/accounting/data/ applications/accounting/entitydef/ applications/accounting/script/org/ofbiz/accounting/payment/ applications/accounting/servicedef/ applications/accoun...

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

svn commit: r793866 - in /ofbiz/trunk: applications/accounting/config/ applications/accounting/data/ applications/accounting/entitydef/ applications/accounting/script/org/ofbiz/accounting/payment/ applications/accounting/servicedef/ applications/accoun...

lektran
Author: lektran
Date: Tue Jul 14 11:43:21 2009
New Revision: 793866

URL: http://svn.apache.org/viewvc?rev=793866&view=rev
Log:
Initial implementation of the Payflow Pro version of PayPal's Express Checkout OFBIZ-934

Added:
    ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/
    ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java   (with props)
Modified:
    ofbiz/trunk/applications/accounting/config/AccountingErrorUiLabels.xml
    ofbiz/trunk/applications/accounting/data/AccountingTypeData.xml
    ofbiz/trunk/applications/accounting/entitydef/entitymodel.xml
    ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml
    ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml
    ofbiz/trunk/applications/accounting/servicedef/services_verisign.xml
    ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java
    ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/verisign/PayflowPro.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReadHelper.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReturnServices.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutEvents.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCart.java
    ofbiz/trunk/framework/base/src/org/ofbiz/base/util/HttpClient.java
    ofbiz/trunk/specialpurpose/ecommerce/data/DemoProduct.xml
    ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/controller.xml
    ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/paymentoptions.ftl
    ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/shipsettings.ftl

Modified: ofbiz/trunk/applications/accounting/config/AccountingErrorUiLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/config/AccountingErrorUiLabels.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/config/AccountingErrorUiLabels.xml (original)
+++ ofbiz/trunk/applications/accounting/config/AccountingErrorUiLabels.xml Tue Jul 14 11:43:21 2009
@@ -19,6 +19,12 @@
     under the License.
 -->
 <resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <property key="AccountingPayPalCommunicationError">
+        <value xml:lang="en">A problem occurred while communicating with PayPal, please try again or select a different checkout method</value>
+    </property>
+    <property key="AccountingPayPalShoppingCartIsEmpty">
+        <value xml:lang="en">Shopping cart is empty, cannot proceed with Express Checkout</value>
+    </property>
     <property key="payPalEvents.failedToExecuteServiceCreatePaymentFromPreference">
         <value xml:lang="en">Failed to execute service createPaymentFromPreference</value>
         <value xml:lang="fr">Echec à l'exécution du service createPaymentFromPreference</value>

Modified: ofbiz/trunk/applications/accounting/data/AccountingTypeData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/data/AccountingTypeData.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/data/AccountingTypeData.xml (original)
+++ ofbiz/trunk/applications/accounting/data/AccountingTypeData.xml Tue Jul 14 11:43:21 2009
@@ -685,7 +685,8 @@
     
     <PaymentGatewayConfigType paymentGatewayConfigTypeId="PAYFLOWPRO" hasTable="N" description="Payflow Pro Payment Gateway"/>
     <PaymentGatewayConfig paymentGatewayConfigId="PAYFLOWPRO_CONFIG" paymentGatewayConfigTypeId="PAYFLOWPRO" description="Payflow Pro Config"/>
-    <PaymentGatewayPayflowPro paymentGatewayConfigId="PAYFLOWPRO_CONFIG" certsPath="${sys:getProperty('ofbiz.home')}/applications/accounting/pfcerts" hostAddress="pilot-payflowpro.paypal.com" hostPort="443" timeout="80" proxyAddress="" proxyPort="80" proxyLogon="" proxyPassword="" vendor="[Vendor]" userId="[PayFlow UserID]" pwd="[PayFlow Password]" partner="[PayFlow Partner]" checkAvs="Y" checkCvv2="Y" preAuth="Y" enableTransmit="true" logFileName="${sys:getProperty('ofbiz.home')}/runtime/logs/payflow_java.log" loggingLevel="6" maxLogFileSize="1000000" stackTraceOn="N"/>
+    <PaymentGatewayPayflowPro paymentGatewayConfigId="PAYFLOWPRO_CONFIG" certsPath="${sys:getProperty('ofbiz.home')}/applications/accounting/pfcerts" hostAddress="pilot-payflowpro.paypal.com" hostPort="443" timeout="80" proxyAddress="" proxyPort="80" proxyLogon="" proxyPassword=""
+        vendor="[Vendor]" userId="[PayFlow UserID]" pwd="[PayFlow Password]" partner="[PayFlow Partner]" checkAvs="Y" checkCvv2="Y" preAuth="Y" enableTransmit="true" logFileName="${sys:getProperty('ofbiz.home')}/runtime/logs/payflow_java.log" loggingLevel="6" maxLogFileSize="1000000" stackTraceOn="N" returnUrl="[Express Checkout Return URL]" cancelReturnUrl="[Express Checkout Cancel Return URL]" redirectUrl="[Express Checkout Customer Redirect URL]"/>
     
     <PaymentGatewayConfigType paymentGatewayConfigTypeId="PAYPAL" hasTable="N" description="PayPal Payment Gateway"/>
     <PaymentGatewayConfig paymentGatewayConfigId="PAYPAL_CONFIG" paymentGatewayConfigTypeId="PAYPAL" description="PayPal Config"/>
@@ -719,6 +720,11 @@
     <CustomMethodType customMethodTypeId="GIFT_REFUND" parentTypeId="" hasTable="N" description="GIFT card refund methods"/>
     <CustomMethodType customMethodTypeId="GIFT_RELEASE" parentTypeId="" hasTable="N" description="GIFT card release methods"/>
     
+    <CustomMethodType customMethodTypeId="PAYPAL_AUTH" parentTypeId="" hasTable="N" description="PayPal authorize methods"/>
+    <CustomMethodType customMethodTypeId="PAYPAL_CAPTURE" parentTypeId="" hasTable="N" description="PayPal capture methods"/>
+    <CustomMethodType customMethodTypeId="PAYPAL_REFUND" parentTypeId="" hasTable="N" description="PayPal refund methods"/>
+    <CustomMethodType customMethodTypeId="PAYPAL_RELEASE" parentTypeId="" hasTable="N" description="PayPal release methods"/>
+
     <CustomMethod customMethodId="CC_AUTH_TEST" customMethodTypeId="CC_AUTH" customMethodName="testCCProcessor" description="CC Test authorize"/>
     <CustomMethod customMethodId="CC_AUTH_CAPTURE_TST" customMethodTypeId="CC_AUTH" customMethodName="testCCProcessorWithCapture" description="CC Test authorize and capture"/>
     <CustomMethod customMethodId="CC_AUTH_RANDOM_TEST" customMethodTypeId="CC_AUTH" customMethodName="testRandomAuthorize" description="CC Test random authorize"/>
@@ -796,6 +802,11 @@
     <CustomMethod customMethodId="GIFT_RELEASE_TEST" customMethodTypeId="GIFT_RELEASE" customMethodName="testGCRelease" description="GIFT card test release"/>
     <CustomMethod customMethodId="GIFT_RELEASE_VALUEL" customMethodTypeId="GIFT_RELEASE" customMethodName="valueLinkRelease" description="GIFT card ValueLink release"/>
     
+    <CustomMethod customMethodId="PAYPAL_AUTH_PFP" customMethodTypeId="PAYPAL_AUTH" customMethodName="payflowPayPalProcessor" description="Payflow PayPal payment authorize"/>
+    <CustomMethod customMethodId="PAYPAL_CAPTURE_PFP" customMethodTypeId="PAYPAL_CAPTURE" customMethodName="payflowPayPalCapture" description="Payflow PayPal payment capture"/>
+    <CustomMethod customMethodId="PAYPAL_REFUND_PFP" customMethodTypeId="PAYPAL_REFUND" customMethodName="payflowPayPalRefund" description="Payflow PayPal payment refund"/>
+    <CustomMethod customMethodId="PAYPAL_RELEASE_PFP" customMethodTypeId="PAYPAL_RELEASE" customMethodName="payflowPayPalVoid" description="CC Payflow Pro release"/>
+
     <!-- Credit Cart Types -->
     <EnumerationType description="Credit Card Type" enumTypeId="CREDIT_CARD_TYPE" hasTable="N" parentTypeId=""/>
     <Enumeration description="Visa" enumCode="Visa" enumId="CCT_VISA" sequenceId="01" enumTypeId="CREDIT_CARD_TYPE"/>

Modified: ofbiz/trunk/applications/accounting/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/entitydef/entitymodel.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/accounting/entitydef/entitymodel.xml Tue Jul 14 11:43:21 2009
@@ -3118,6 +3118,9 @@
       <field name="loggingLevel" type="numeric"><description>Logging level</description></field>
       <field name="maxLogFileSize" type="numeric"><description>Max log file size</description></field>
       <field name="stackTraceOn" type="indicator"><description>Stack trace on/off</description></field>
+      <field name="redirectUrl" type="value"><description>Express Checkout Redirect URL</description></field>
+      <field name="returnUrl" type="value"><description>Express Checkout Return URL</description></field>
+      <field name="cancelReturnUrl" type="value"><description>Express Checkout Return On Cancel URL</description></field>
       <prim-key field="paymentGatewayConfigId"/>
       <relation type="one" fk-name="PGPF_PGC" rel-entity-name="PaymentGatewayConfig">
         <key-map field-name="paymentGatewayConfigId"/>
@@ -3280,6 +3283,30 @@
       </relation>
     </entity>
 
+    <entity entity-name="PayPalPaymentMethod"
+            package-name="org.ofbiz.accounting.payment">
+      <description>PayPal Payment Method Details</description>
+      <field name="paymentMethodId" type="id-ne"></field>
+      <field name="payerId" type="id"></field>
+      <field name="expressCheckoutToken" type="short-varchar"></field>
+      <field name="payerStatus" type="short-varchar"></field>
+      <field name="avsAddr" type="indicator"></field>
+      <field name="avsZip" type="indicator"></field>
+      <field name="correlationId" type="id"></field>
+      <field name="contactMechId" type="id-ne"></field>
+      <field name="transactionId" type="short-varchar"></field>
+      <prim-key field="paymentMethodId"/>
+      <relation type="one" fk-name="PAYPAL_PMNTMETH" rel-entity-name="PaymentMethod">
+        <key-map field-name="paymentMethodId"/>
+      </relation>
+      <relation type="one" fk-name="PAYPAL_CMECH" rel-entity-name="ContactMech">
+        <key-map field-name="contactMechId"/>
+      </relation>
+      <relation type="one" fk-name="PAYPAL_PADDR" rel-entity-name="PostalAddress">
+        <key-map field-name="contactMechId"/>
+      </relation>
+    </entity>
+
     <entity entity-name="ValueLinkKey"
             package-name="org.ofbiz.accounting.payment"
             title="Value Link Key Store">

Modified: ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml (original)
+++ ofbiz/trunk/applications/accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml Tue Jul 14 11:43:21 2009
@@ -131,4 +131,28 @@
         <now-timestamp field="paymentGroupMember.thruDate"/>
         <store-value value-field="paymentGroupMember"/>
     </simple-method>
+    
+    <simple-method method-name="createPayPalPaymentMethod" short-description="Create a PayPal Payment Method">
+        <make-value value-field="newPaymentMethod" entity-name="PaymentMethod"/>
+        <set-pk-fields value-field="newPaymentMethod" map="parameters"/>
+        <if-empty field="newPaymentMethod.paymentMethodId">
+            <sequenced-id sequence-name="PaymentMethod" field="newPaymentMethod.paymentMethodId"/>
+        </if-empty>
+        <set-nonpk-fields value-field="newPaymentMethod" map="parameters"/>
+        <set field="newPaymentMethod.paymentMethodTypeId" value="EXT_PAYPAL"/>
+        <create-value value-field="newPaymentMethod"/>
+
+        <make-value value-field="newPayPalPaymentMethod" entity-name="PayPalPaymentMethod"/>
+        <set field="newPayPalPaymentMethod.paymentMethodId" from-field="newPaymentMethod.paymentMethodId"/>
+        <set-nonpk-fields value-field="newPayPalPaymentMethod" map="parameters"/>
+        <create-value value-field="newPayPalPaymentMethod"/>
+        <field-to-result result-name="paymentMethodId" field="newPaymentMethod.paymentMethodId"/>
+    </simple-method>
+
+    <simple-method method-name="updatePayPalPaymentMethod" short-description="Update a PayPal Payment Method">
+        <entity-one value-field="payPalPaymentMethod" entity-name="PayPalPaymentMethod"/>
+        <set-nonpk-fields value-field="payPalPaymentMethod" map="parameters"/>
+        <store-value value-field="payPalPaymentMethod"/>
+        <field-to-result result-name="paymentMethodId" field="payPalPaymentMethod.paymentMethodId"/>
+    </simple-method>
 </simple-methods>

Modified: ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml (original)
+++ ofbiz/trunk/applications/accounting/servicedef/services_paymentmethod.xml Tue Jul 14 11:43:21 2009
@@ -179,6 +179,22 @@
         <attribute name="oldContactMechId" type="String" mode="IN" optional="false"/>
         <attribute name="partyId" type="String" mode="IN" optional="true"/>
     </service>
+    <service name="createPayPalPaymentMethod" engine="simple"
+            location="component://accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml" invoke="createPayPalPaymentMethod" auth="true">
+        <description>Create a PayPal Payment Method</description>
+        <auto-attributes mode="INOUT" entity-name="PayPalPaymentMethod" include="pk" optional="true"/>
+        <auto-attributes mode="IN" entity-name="PayPalPaymentMethod" include="nonpk" optional="true"/>
+        <attribute name="partyId" type="String" mode="IN" optional="true"/>
+        <attribute name="description" type="String" mode="IN" optional="true"/>
+        <attribute name="fromDate" type="Timestamp" mode="IN" optional="true"/>
+        <attribute name="thruDate" type="Timestamp" mode="IN" optional="true"/>
+    </service>
+    <service name="updatePayPalPaymentMethod" engine="simple"
+            location="component://accounting/script/org/ofbiz/accounting/payment/PaymentMethodServices.xml" invoke="updatePayPalPaymentMethod" auth="true">
+        <description>Update a PayPal Payment Method</description>
+        <attribute name="paymentMethodId" mode="INOUT" type="String" optional="false"/>
+        <auto-attributes mode="IN" entity-name="PayPalPaymentMethod" include="nonpk" optional="true"/>
+    </service>
 
     <!-- Payment Auth/Capture Services -->
     <service name="manualForcedCcAuthTransaction" engine="java"
@@ -575,6 +591,41 @@
         <attribute name="eftAccount" type="org.ofbiz.entity.GenericValue" mode="IN" optional="false"/>
     </service>
 
+    <!-- PayPal Payment Interfaces -->
+    <service name="payPalProcessInterface" engine="interface" location="" invoke="">
+        <description>PayPal authorize Interface</description>
+        <implements service="paymentProcessInterface"/>
+        <attribute name="payPalPaymentMethod" type="org.ofbiz.entity.GenericValue" mode="IN" optional="false"/>
+    </service>
+    <service name="payPalCaptureInterface" engine="interface" location="" invoke="">
+        <description>PayPal Capture Interface</description>
+        <attribute name="orderPaymentPreference" type="org.ofbiz.entity.GenericValue" mode="IN" optional="false"/>
+        <attribute name="captureAmount" type="BigDecimal" mode="INOUT" optional="false"/>
+        <attribute name="currency" type="String" mode="IN" optional="true"/>
+        <attribute name="paymentConfig" type="String" mode="IN" optional="true"/>
+        <attribute name="authTrans" type="org.ofbiz.entity.GenericValue" mode="IN" optional="true"/>
+        <attribute name="paymentGatewayConfigId" type="String" mode="IN" optional="true"/>
+        <attribute name="captureResult" type="Boolean" mode="OUT" optional="true"/>
+        <attribute name="captureAltRefNum" type="String" mode="OUT" optional="true"/>
+        <attribute name="captureRefNum" type="String" mode="OUT" optional="false"/>
+        <attribute name="captureCode" type="String" mode="OUT" optional="true"/>
+        <attribute name="captureFlag" type="String" mode="OUT" optional="true"/>
+        <attribute name="captureMessage" type="String" mode="OUT" optional="true"/>
+        <attribute name="internalRespMsgs" type="List" mode="OUT" optional="true"/>
+    </service>
+    <service name="payPalSetExpressCheckoutInterface" engine="interface" location="" invoke="">
+        <description>Interface for services performing the PayPal getExpressCheckout operation</description>
+        <attribute name="cart" mode="IN" type="org.ofbiz.order.shoppingcart.ShoppingCart" optional="false"></attribute>
+    </service>
+    <service name="payPalGetExpressCheckoutInterface" engine="interface" location="" invoke="">
+        <description>Interface for services performing the PayPal getExpressCheckoutDetails operation</description>
+        <attribute name="cart" mode="IN" type="org.ofbiz.order.shoppingcart.ShoppingCart" optional="false"></attribute>
+    </service>
+    <service name="payPalDoExpressCheckoutInterface" engine="interface" location="" invoke="">
+        <description>Interface for services performing the PayPal doExpressCheckout operation</description>
+        <attribute name="orderPaymentPreference" mode="IN" type="GenericValue" optional="false"></attribute>
+    </service>
+
     <!-- Gift Card Interfaces -->
     <service name="giftCardProcessInterface" engine="interface" location="" invoke="">
         <description>Gift Card Processing Interface</description>

Modified: ofbiz/trunk/applications/accounting/servicedef/services_verisign.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/servicedef/services_verisign.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/servicedef/services_verisign.xml (original)
+++ ofbiz/trunk/applications/accounting/servicedef/services_verisign.xml Tue Jul 14 11:43:21 2009
@@ -48,4 +48,35 @@
         <description>Credit Card Refund</description>
         <implements service="paymentRefundInterface"/>
     </service>
+    
+    <service name="payflowSetExpressCheckout" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="setExpressCheckout">
+        <implements service="payPalSetExpressCheckoutInterface"/>
+    </service>
+    <service name="payflowGetExpressCheckout" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="getExpressCheckout">
+        <implements service="payPalGetExpressCheckoutInterface"/>
+    </service>
+    <service name="payflowDoExpressCheckout" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="doExpressCheckout">
+        <implements service="payPalDoExpressCheckoutInterface"/>
+    </service>
+    
+    <service name="payflowPayPalProcessor" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="ccProcessor">
+        <implements service="payPalProcessInterface"/>
+    </service>
+    <service name="payflowPayPalCapture" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="ccCapture">
+        <implements service="payPalCaptureInterface"/>
+    </service>
+    <service name="payflowPayPalVoid" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="ccVoid">
+        <description>Credit Card Void</description>
+        <implements service="paymentReleaseInterface"/>
+    </service>
+    <service name="payflowPayPalRefund" engine="java"
+             location="org.ofbiz.accounting.thirdparty.verisign.PayflowPro" invoke="ccRefund">
+        <implements service="paymentRefundInterface"/>
+    </service>
 </services>

Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java (original)
+++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/payment/PaymentGatewayServices.java Tue Jul 14 11:43:21 2009
@@ -92,7 +92,7 @@
 
     /**
      * Authorizes a single order preference with an option to specify an amount. The result map has the Booleans
-     * "errors" and "finished" which notify the user if there were any errors and if the authorizatoin was finished.
+     * "errors" and "finished" which notify the user if there were any errors and if the authorization was finished.
      * There is also a List "messages" for the authorization response messages and a BigDecimal, "processAmount" as the
      * amount processed.
      *
@@ -645,6 +645,9 @@
             toContext.put("orderItems", orderItems);
         } else if ("FIN_ACCOUNT".equals(paymentMethodTypeId)) {
             toContext.put("finAccountId", paymentPreference.getString("finAccountId"));
+        } else if ("EXT_PAYPAL".equals(paymentMethodTypeId)) {
+            GenericValue payPalPaymentMethod = paymentMethod.getRelatedOne("PayPalPaymentMethod");
+            toContext.put("payPalPaymentMethod", payPalPaymentMethod);
         } else {
             // add other payment types here; i.e. gift cards, etc.
             // unknown payment type; ignoring.
@@ -2690,18 +2693,27 @@
      * @return
      */
     public static GenericValue getAuthTransaction(GenericValue orderPaymentPreference) {
-        GenericValue authTrans = null;
+        return EntityUtil.getFirst(getAuthTransactions(orderPaymentPreference));
+    }
+    
+    /**
+     * Gets a chronologically ordered list of PaymentGatewayResponses from an OrderPaymentPreference which is either a PRDS_PAY_AUTH
+     * or PRDS_PAY_REAUTH.
+     * @param orderPaymentPreference
+     * @return
+     */
+    public static List<GenericValue> getAuthTransactions(GenericValue orderPaymentPreference) {
+        List<GenericValue> authTransactions = null;
         try {
             List<String> order = UtilMisc.toList("-transactionDate");
             List<GenericValue> transactions = orderPaymentPreference.getRelated("PaymentGatewayResponse", null, order);
             List<EntityExpr> exprs = UtilMisc.toList(EntityCondition.makeCondition("paymentServiceTypeEnumId", EntityOperator.EQUALS, AUTH_SERVICE_TYPE),
                     EntityCondition.makeCondition("paymentServiceTypeEnumId", EntityOperator.EQUALS, REAUTH_SERVICE_TYPE));
-            List<GenericValue> authTransactions = EntityUtil.filterByOr(transactions, exprs);
-            authTrans = EntityUtil.getFirst(authTransactions);
+            authTransactions = EntityUtil.filterByOr(transactions, exprs);
         } catch (GenericEntityException e) {
             Debug.logError(e, "ERROR: Problem getting authorization information from PaymentGatewayResponse", module);
         }
-        return authTrans;
+        return authTransactions;
     }
 
     public static Timestamp getAuthTime(GenericValue orderPaymentPreference) {

Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/verisign/PayflowPro.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/verisign/PayflowPro.java?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/verisign/PayflowPro.java (original)
+++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/verisign/PayflowPro.java Tue Jul 14 11:43:21 2009
@@ -18,20 +18,21 @@
  *******************************************************************************/
 package org.ofbiz.accounting.thirdparty.verisign;
 
-import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
-import java.net.URLEncoder;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
 import javolution.util.FastMap;
 
+import org.apache.commons.lang.StringUtils;
 import org.ofbiz.accounting.payment.PaymentGatewayServices;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.UtilDateTime;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilValidate;
@@ -39,7 +40,13 @@
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
+import org.ofbiz.order.order.OrderReadHelper;
+import org.ofbiz.order.shoppingcart.ShoppingCart;
+import org.ofbiz.order.shoppingcart.ShoppingCartItem;
+import org.ofbiz.product.store.ProductStoreWorker;
 import org.ofbiz.service.DispatchContext;
+import org.ofbiz.service.GenericServiceException;
+import org.ofbiz.service.LocalDispatcher;
 import org.ofbiz.service.ServiceUtil;
 
 import paypal.payflow.PayflowAPI;
@@ -66,71 +73,87 @@
         BigDecimal processAmount = (BigDecimal) context.get("processAmount");
         GenericValue party = (GenericValue) context.get("billToParty");
         GenericValue cc = (GenericValue) context.get("creditCard");
+        GenericValue payPalPaymentMethod = (GenericValue) context.get("payPalPaymentMethod");
         GenericValue ps = (GenericValue) context.get("billingAddress");
         String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
         String configString = (String) context.get("paymentConfig");
+
         if (configString == null) {
             configString = "payment.properties";
         }
 
-        if (authTrans == null) {
-            authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
+        boolean isPayPal = false;
+        // Are we doing a cc or a paypal payment?
+        if ("EXT_PAYPAL".equals(paymentPref.getString("paymentMethodTypeId"))) {
+            isPayPal = true;
         }
 
-        // set the orderId as comment1 so we can query in PF Manager
-        boolean isReAuth = false;
-        Map<String, String> data = UtilMisc.toMap("COMMENT1", orderId);
-        data.put("PONUM", orderId);
-        data.put("CUSTCODE", party.getString("partyId"));
+        Map<String, String> data = FastMap.newInstance();
 
-        // transaction type
-        if (comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "preAuth", configString, "payment.verisign.preAuth",  "Y")) {
+        boolean isReAuth = false;
+        if (isPayPal) {
             data.put("TRXTYPE", "A");
-            // only support re-auth for auth types; sale types don't do it
-            if (authTrans != null) {
-                String refNum = authTrans.getString("referenceNum");
-                data.put("ORIGID", refNum);
-                isReAuth = true;
-            }
+            data.put("TENDER", "P");
+            data.put("ORIGID", payPalPaymentMethod.getString("transactionId"));
         } else {
-            data.put("TRXTYPE", "S");
-        }
+            if (authTrans == null) {
+                authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
+            }
 
-        // credit card tender
-        data.put("TENDER", "C");
+            // set the orderId as comment1 so we can query in PF Manager
+            data.put("COMMENT1", orderId);
+            data.put("PONUM", orderId);
+            data.put("CUSTCODE", party.getString("partyId"));
+
+            // transaction type
+            if (comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "preAuth", configString, "payment.verisign.preAuth",  "Y")) {
+                data.put("TRXTYPE", "A");
+                // only support re-auth for auth types; sale types don't do it
+                if (authTrans != null) {
+                    String refNum = authTrans.getString("referenceNum");
+                    data.put("ORIGID", refNum);
+                    isReAuth = true;
+                }
+            } else {
+                data.put("TRXTYPE", "S");
+            }
 
-        // card security code
-        if (UtilValidate.isNotEmpty(cvv2)) {
-            data.put("CVV2", cvv2);
-        }
+            // credit card tender
+            data.put("TENDER", "C");
 
-        // set the amount
-        data.put("AMT", processAmount.toString());
+            // card security code
+            if (UtilValidate.isNotEmpty(cvv2)) {
+                data.put("CVV2", cvv2);
+            }
 
-        // get the payment information
-        data.put("ACCT", cc.getString("cardNumber"));
+            // get the payment information
+            data.put("ACCT", cc.getString("cardNumber"));
+
+            // name on card
+            String name = cc.getString("firstNameOnCard") + " " + cc.getString("lastNameOnCard");
+            data.put("FIRSTNAME", cc.getString("firstNameOnCard"));
+            data.put("LASTNAME", cc.getString("lastNameOnCard"));
+            data.put("COMMENT2", name);
+            if (cc.get("expireDate") != null) {
+                String exp = cc.getString("expireDate");
+                String expDate = exp.substring(0, 2);
+
+                expDate = expDate + exp.substring(exp.length() - 2);
+                data.put("EXPDATE", expDate);
+            }
 
-        // name on card
-        String name = cc.getString("firstNameOnCard") + " " + cc.getString("lastNameOnCard");
-        data.put("FIRSTNAME", cc.getString("firstNameOnCard"));
-        data.put("LASTNAME", cc.getString("lastNameOnCard"));
-        data.put("COMMENT2", name);
-        if (cc.get("expireDate") != null) {
-            String exp = cc.getString("expireDate");
-            String expDate = exp.substring(0, 2);
-
-            expDate = expDate + exp.substring(exp.length() - 2);
-            data.put("EXPDATE", expDate);
-        }
-
-        // gather the address info
-        if (ps != null) {
-            String street = ps.getString("address1") + (ps.get("address2") != null && ps.getString("address2").length() > 0 ? " " + ps.getString("address2") : "");
+            // gather the address info
+            if (ps != null) {
+                String street = ps.getString("address1") + (ps.get("address2") != null && ps.getString("address2").length() > 0 ? " " + ps.getString("address2") : "");
 
-            data.put("STREET", street);
-            data.put("ZIP", ps.getString("postalCode"));
+                data.put("STREET", street);
+                data.put("ZIP", ps.getString("postalCode"));
+            }
         }
 
+        // set the amount
+        data.put("AMT", processAmount.toString());
+
         PayflowAPI pfp = init(delegator, paymentGatewayConfigId, configString, context);
         
         // get the base params
@@ -151,10 +174,14 @@
         if (Debug.verboseOn()) {
             Debug.logVerbose("Response from Verisign: " + resp, module);
         }
+        if (isPayPal) {
+            // Attach the avs info returned in doExpressCheckout and stored in PayPalPaymentMethod
+            resp += "&AVSADDR=" + payPalPaymentMethod.getString("avsAddr") + "&AVSZIP=" + payPalPaymentMethod.getString("avsZip");
+        }
         
         // check the response
         Map<String, Object> result = ServiceUtil.returnSuccess();
-        parseAuthResponse(delegator, paymentGatewayConfigId, resp, result, configString, isReAuth);
+        parseAuthResponse(delegator, paymentGatewayConfigId, resp, result, configString, isReAuth, isPayPal);
         result.put("processAmount", processAmount);
         return result;
     }
@@ -170,6 +197,12 @@
             configString = "payment.properties";
         }
 
+        boolean isPayPal = false;
+        // Are we doing a cc or a paypal payment?
+        if ("EXT_PAYPAL".equals(paymentPref.getString("paymentMethodTypeId"))) {
+            isPayPal = true;
+        }
+
         if (authTrans == null) {
             authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
         }
@@ -185,12 +218,19 @@
         // tx type (Delayed Capture)
         data.put("TRXTYPE", "D");
 
-        // credit card tender
-        data.put("TENDER", "C");
+        if (isPayPal) {
+            // paypal tender
+            data.put("TENDER", "P");
+            data.put("CAPTURECOMPLETE", "N");
+        } else {
+            // credit card tender
+            data.put("TENDER", "C");
+
+            // get the orderID
+            String orderId = paymentPref.getString("orderId");
+            data.put("COMMENT1", orderId);
+        }
 
-        // get the orderID
-        String orderId = paymentPref.getString("orderId");
-        data.put("COMMENT1", orderId);
 
         // amount to capture
         data.put("AMT", amount.toString());
@@ -240,6 +280,12 @@
             return ServiceUtil.returnError("No authorization transaction found for the OrderPaymentPreference; cannot capture");
         }
 
+        boolean isPayPal = false;
+        // Are we doing a cc or a paypal payment?
+        if ("EXT_PAYPAL".equals(paymentPref.getString("paymentMethodTypeId"))) {
+            isPayPal = true;
+        }
+
         // auth ref number
         String refNum = authTrans.getString("referenceNum");
         Map<String, String> data = UtilMisc.toMap("ORIGID", refNum);
@@ -247,15 +293,23 @@
         // tx type (Void)
         data.put("TRXTYPE", "V");
 
-        // credit card tender
-        data.put("TENDER", "C");
-
         // get the orderID
         String orderId = paymentPref.getString("orderId");
-        data.put("COMMENT1", orderId);
 
-        // amount to capture
-        data.put("AMT", amount.toString());
+        if (isPayPal) {
+            data.put("TENDER", "P");
+
+            data.put("NOTE", orderId);
+        } else {
+            // credit card tender
+            data.put("TENDER", "C");
+
+            data.put("COMMENT1", orderId);
+
+            // amount to void
+            data.put("AMT", amount.toString());
+        }
+
 
         PayflowAPI pfp = init(delegator, paymentGatewayConfigId, configString, context);
 
@@ -299,6 +353,12 @@
             return ServiceUtil.returnError("No capture transaction found for the OrderPaymentPreference; cannot refund");
         }
 
+        boolean isPayPal = false;
+        // Are we doing a cc or a paypal payment?
+        if ("EXT_PAYPAL".equals(paymentPref.getString("paymentMethodTypeId"))) {
+            isPayPal = true;
+        }
+
         // auth ref number
         String refNum = captureTrans.getString("referenceNum");
         Map<String, String> data = UtilMisc.toMap("ORIGID", refNum);
@@ -306,12 +366,19 @@
         // tx type (Credit)
         data.put("TRXTYPE", "C");
 
-        // credit card tender
-        data.put("TENDER", "C");
-
         // get the orderID
         String orderId = paymentPref.getString("orderId");
-        data.put("COMMENT1", orderId);
+
+        if (isPayPal) {
+            data.put("TENDER", "P");
+
+            data.put("MEMO", orderId);
+        } else {
+            // credit card tender
+            data.put("TENDER", "C");
+
+            data.put("COMMENT1", orderId);
+        }
 
         // amount to capture
         data.put("AMT", amount.toString());
@@ -341,10 +408,255 @@
         result.put("refundAmount", amount);
         return result;
     }
+    
+    
+    public static Map<String, Object> setExpressCheckout(DispatchContext dctx, Map<String, ? extends Object> context) {
+        GenericDelegator delegator = dctx.getDelegator();
+        ShoppingCart cart = (ShoppingCart) context.get("cart");
+        Locale locale = cart.getLocale();
+        GenericValue payPalPaymentSetting = ProductStoreWorker.getProductStorePaymentSetting(delegator, cart.getProductStoreId(), "EXT_PAYPAL", null, true);
+        String paymentGatewayConfigId = payPalPaymentSetting.getString("paymentGatewayConfigId");
+        String configString = "payment.properties";
+        
+        if (cart == null || cart.items().size() <= 0) {
+            return ServiceUtil.returnError(UtilProperties.getMessage("AccountingErrorUiLabels", "AccountingPayPalShoppingCartIsEmpty", locale));
+        }
+
+        Map<String, String> data = FastMap.newInstance();
+
+        data.put("TRXTYPE", "O");
+        data.put("TENDER", "P");
+        data.put("ACTION", "S");
+        String token = (String) cart.getAttribute("payPalCheckoutToken");
+        if (UtilValidate.isNotEmpty(token)) {
+            data.put("TOKEN", token);
+        }
+        data.put("RETURNURL", getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "returnUrl", configString, "payment.verisign.returnUrl"));
+        data.put("CANCELURL", getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "cancelReturnUrl", configString, "payment.verisign.cancelReturnUrl"));
+        
+        try {
+            addCartDetails(data, cart);
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+            ServiceUtil.returnError("An error occurred while retreiving cart details");
+        }
+
+        PayflowAPI pfp = init(delegator, paymentGatewayConfigId, null, context);
+
+        // get the base params
+        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, null);
+
+        // parse the context parameters
+        params.append("&").append(parseContext(data));
+
+        // transmit the request
+        if (Debug.verboseOn()) Debug.logVerbose("Sending to Verisign: " + params.toString(), module);
+        String resp;
+        if (!comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "enableTransmit", configString, "payment.verisign.enable_transmit",  "false")) {
+            resp = pfp.submitTransaction(params.toString(), pfp.generateRequestId());
+        } else {
+            resp = "RESULT=0&TOKEN=" + (new Date()).getTime() + "&RESPMSG=Testing";
+        }
+
+        if (Debug.verboseOn()) Debug.logVerbose("Response from Verisign: " + resp, module);
+
+        Map<String, String> responseMap = parseResponse(resp);
+        String result = responseMap.get("RESULT");
+        if (!"0".equals(result)) {
+            String respMsg = responseMap.get("RESPMSG");
+            Debug.logError("A problem occurred while requesting an express checkout token from paypal: Result = " + result + ", Message = " + respMsg, module);
+            return ServiceUtil.returnError(UtilProperties.getMessage("AccountingErrorUiLabels", "AccountingPayPalCommunicationError", locale));
+        }
+        token = responseMap.get("TOKEN");
+        cart.setAttribute("payPalCheckoutToken", token);
+        return ServiceUtil.returnSuccess();
+    }
+
+    private static void addCartDetails(Map<String, String> parameterMap, ShoppingCart cart) throws GenericEntityException {
+        parameterMap.put("CURRENCY", cart.getCurrency());
+        int line = 0;
+        for (ShoppingCartItem item : cart.items()) {
+            //paramMap.put("L_NUMBER" + line, item.getProductId());
+            parameterMap.put("L_NAME" + line, item.getName());
+            parameterMap.put("L_DESC" + line, item.getDescription());
+            parameterMap.put("L_AMT" + line, item.getBasePrice().setScale(2).toPlainString());
+            parameterMap.put("L_QTY" + line, item.getQuantity().toBigInteger().toString());
+            line++;
+            BigDecimal otherAdjustments = item.getOtherAdjustments();
+            if (otherAdjustments.compareTo(BigDecimal.ZERO) != 0) {
+                parameterMap.put("L_NAME" + line, item.getName() + " Adjustments");
+                parameterMap.put("L_DESC" + line, "Adjustments for item: " + item.getName());
+                parameterMap.put("L_AMT" + line, otherAdjustments.setScale(2).toPlainString());
+                parameterMap.put("L_QTY" + line, "1");
+                line++;
+            }
+        }
+        BigDecimal otherAdjustments = cart.getOrderOtherAdjustmentTotal();
+        if (otherAdjustments.compareTo(BigDecimal.ZERO) != 0) {
+            parameterMap.put("L_NAME" + line, "Order Adjustments");
+            parameterMap.put("L_AMT" + line, otherAdjustments.setScale(2).toPlainString());
+            parameterMap.put("L_QTY" + line, "1");
+            line++;
+        }
+        parameterMap.put("ITEMAMT", cart.getSubTotal().add(otherAdjustments).setScale(2).toPlainString());
+        parameterMap.put("TAXAMT", cart.getTotalSalesTax().setScale(2).toPlainString());
+        parameterMap.put("FREIGHTAMT", cart.getTotalShipping().setScale(2).toPlainString());
+        parameterMap.put("AMT", cart.getGrandTotal().setScale(2).toPlainString());
+
+        if (!cart.shippingApplies()) {
+            parameterMap.put("NOSHIPPING", "1");
+        } else {
+            GenericValue shippingAddress = cart.getShippingAddress();
+            parameterMap.put("ADDROVERRIDE", "1");
+            parameterMap.put("SHIPTOSTREET", StringUtils.left(shippingAddress.getString("address1"), 30));
+            parameterMap.put("SHIPTOSTREET2", StringUtils.left(shippingAddress.getString("address2"), 30));
+            parameterMap.put("SHIPTOCITY", StringUtils.left(shippingAddress.getString("city"), 40));
+            if (shippingAddress.getString("stateProvinceGeoId") != null && !"_NA_".equals(shippingAddress.getString("stateProvinceGeoId"))) {
+                GenericValue stateProvinceGeo = shippingAddress.getRelatedOne("StateProvinceGeo");
+                parameterMap.put("SHIPTOSTATE", StringUtils.left(stateProvinceGeo.getString("geoCode"), 40));
+            }
+            parameterMap.put("SHIPTOZIP", StringUtils.left(shippingAddress.getString("postalCode"), 16));
+            GenericValue countryGeo = shippingAddress.getRelatedOne("CountryGeo");
+            parameterMap.put("SHIPTOCOUNTRY", StringUtils.left(countryGeo.getString("geoCode"), 2));
+        }
+    }
+    
+    public static Map<String, Object> getExpressCheckout(DispatchContext dctx, Map<String, Object> context) {
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+        GenericDelegator delegator = dctx.getDelegator();
+        ShoppingCart cart = (ShoppingCart) context.get("cart");
+        Locale locale = cart.getLocale();
+        GenericValue payPalPaymentSetting = ProductStoreWorker.getProductStorePaymentSetting(delegator, cart.getProductStoreId(), "EXT_PAYPAL", null, true);
+        String paymentGatewayConfigId = payPalPaymentSetting.getString("paymentGatewayConfigId");
+        String configString = "payment.properties";
+
+        Map<String, String> data = FastMap.newInstance();
+        data.put("TRXTYPE", "O");
+        data.put("TENDER", "P");
+        data.put("ACTION", "G");
+        String token = (String) cart.getAttribute("payPalCheckoutToken");
+        if (UtilValidate.isNotEmpty(token)) {
+            data.put("TOKEN", token);
+        }
+
+        PayflowAPI pfp = init(delegator, paymentGatewayConfigId, null, context);
+
+        // get the base params
+        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, null);
+
+        // parse the context parameters
+        params.append("&").append(parseContext(data));
 
-    private static void parseAuthResponse(GenericDelegator delegator, String paymentGatewayConfigId, String resp, Map<String, Object> result, String resource, boolean isReAuth) {
+        // transmit the request
+        if (Debug.verboseOn()) Debug.logVerbose("Sending to Verisign: " + params.toString(), module);
+        String resp;
+        if (!comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "enableTransmit", configString, "payment.verisign.enable_transmit",  "false")) {
+            resp = pfp.submitTransaction(params.toString(), pfp.generateRequestId());
+        } else {
+            resp = "RESULT=0&PAYERID=" + (new Date()).getTime() + "&RESPMSG=Testing";
+        }
+
+        Map<String, String> responseMap = parseResponse(resp);
+        if (!"0".equals(responseMap.get("RESULT"))) {
+            Debug.logError("A problem occurred while requesting the checkout details from paypal: Result = " + responseMap.get("RESULT") + ", Message = " + responseMap.get("RESPMSG"), module);
+            return ServiceUtil.returnError(UtilProperties.getMessage("AccountingErrorUiLabels", "AccountingPayPalCommunicationError", locale));
+        }
+        
+        Map<String, Object> inMap = FastMap.newInstance();
+        inMap.put("userLogin", cart.getUserLogin());
+        inMap.put("partyId", cart.getOrderPartyId());
+        inMap.put("contactMechId", cart.getShippingContactMechId());
+        inMap.put("fromDate", UtilDateTime.nowTimestamp());
+        inMap.put("payerId", responseMap.get("PAYERID"));
+        inMap.put("expressCheckoutToken", token);
+        inMap.put("payerStatus", responseMap.get("PAYERSTATUS"));
+        inMap.put("avsAddr", responseMap.get("AVSADDR"));
+        inMap.put("avsZip", responseMap.get("AVSZIP"));
+        inMap.put("correlationId", responseMap.get("CORRELATIONID"));
+        Map<String, Object> outMap = null;
+        try {
+            outMap = dispatcher.runSync("createPayPalPaymentMethod", inMap);
+        } catch (GenericServiceException e) {
+            Debug.logError(e, module);
+            return ServiceUtil.returnError(e.getMessage());
+        }
+        String paymentMethodId = (String) outMap.get("paymentMethodId");
+        
+        cart.clearPayments();
+        cart.addPaymentAmount(paymentMethodId, cart.getGrandTotal(), true);
+        
+        return ServiceUtil.returnSuccess();
+
+    }
+
+    public static Map<String, Object> doExpressCheckout(DispatchContext dctx, Map<String, Object> context) {
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+        GenericDelegator delegator = dctx.getDelegator();
+        GenericValue userLogin = (GenericValue) context.get("userLogin");
+        GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference");
+        OrderReadHelper orh = new OrderReadHelper(delegator, paymentPref.getString("orderId"));
+        GenericValue payPalPaymentSetting = ProductStoreWorker.getProductStorePaymentSetting(delegator, orh.getProductStoreId(), "EXT_PAYPAL", null, true);
+        String paymentGatewayConfigId = payPalPaymentSetting.getString("paymentGatewayConfigId");
+        String configString = "payment.properties";
+        GenericValue payPalPaymentMethod = null;
+        try {
+            payPalPaymentMethod = paymentPref.getRelatedOne("PaymentMethod");
+            payPalPaymentMethod = payPalPaymentMethod.getRelatedOne("PayPalPaymentMethod");
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+            return ServiceUtil.returnError(e.getMessage());
+        }
+        BigDecimal processAmount = paymentPref.getBigDecimal("maxAmount");
+
+        Map<String, String> data = FastMap.newInstance();
+        data.put("TRXTYPE", "O");
+        data.put("TENDER", "P");
+        data.put("PAYERID", payPalPaymentMethod.getString("payerId"));
+        data.put("TOKEN", payPalPaymentMethod.getString("expressCheckoutToken"));
+        data.put("ACTION", "D");
+        // set the amount
+        data.put("AMT", processAmount.setScale(2).toPlainString());
+
+        PayflowAPI pfp = init(delegator, paymentGatewayConfigId, null, context);
+
+        // get the base params
+        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, null);
+
+        // parse the context parameters
+        params.append("&").append(parseContext(data));
+
+        // transmit the request
+        if (Debug.verboseOn()) Debug.logVerbose("Sending to Verisign: " + params.toString(), module);
+        String resp;
+        if (!comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "enableTransmit", configString, "payment.verisign.enable_transmit",  "false")) {
+            resp = pfp.submitTransaction(params.toString(), pfp.generateRequestId());
+        } else {
+            resp = "RESULT=0&PAYERID=" + (new Date()).getTime() + "&RESPMSG=Testing";
+        }
+
+        Map<String, String> responseMap = parseResponse(resp);
+
+        Map<String, Object> inMap = FastMap.newInstance();
+        inMap.put("userLogin", userLogin);
+        inMap.put("paymentMethodId", payPalPaymentMethod.get("paymentMethodId"));
+        inMap.put("transactionId", responseMap.get("PNREF"));
+        Map<String, Object> outMap = null;
+        try {
+            outMap = dispatcher.runSync("updatePayPalPaymentMethod", inMap);
+        } catch (GenericServiceException e) {
+            Debug.logError(e, module);
+            return ServiceUtil.returnError(e.getMessage());
+        }
+        if (ServiceUtil.isError(outMap)) {
+            Debug.logError(ServiceUtil.getErrorMessage(outMap), module);
+            return outMap;
+        }
+        return ServiceUtil.returnSuccess();
+    }
+
+    private static Map<String, String> parseResponse(String resp) {
         Debug.logInfo("Verisign response string: " + resp, module);
-        Map<Object, Object> parameters = FastMap.newInstance();
+        Map<String, String> parameters = FastMap.newInstance();
         List<String> params = StringUtil.split(resp, "&");
         Iterator<String> i = params.iterator();
 
@@ -353,13 +665,17 @@
 
             if (str.length() > 0) {
                 List<String> kv = StringUtil.split(str, "=");
-                Object k = kv.get(0);
-                Object v = kv.get(1);
+                String k = kv.get(0);
+                String v = kv.get(1);
 
                 if (k != null && v != null)
                     parameters.put(k, v);
             }
         }
+        return parameters;
+    }
+    private static void parseAuthResponse(GenericDelegator delegator, String paymentGatewayConfigId, String resp, Map<String, Object> result, String resource, boolean isReAuth, boolean isPayPal) {
+        Map<String, String> parameters = parseResponse(resp);
 
         // txType
         boolean isSale = !comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "preAuth", resource, "payment.verisign.preAuth", "Y");
@@ -379,10 +695,10 @@
             }
         }
 
-        // cvv2 checking - ignore on re-auth
+        // cvv2 checking - ignore on re-auth or paypal
         boolean cvv2CheckOkay = true;
         String cvvCode = null;
-        if (!isReAuth) {
+        if (!isReAuth && !isPayPal) {
             boolean checkCvv2 = comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "checkCvv2", resource, "payment.verisign.checkCvv2", "Y");
             if (checkCvv2 && !isSale) {
                 cvvCode = (String) parameters.get("CVV2MATCH");
@@ -400,7 +716,9 @@
             Debug.logError(e, "Unable to parse response code; not a number!", module);
         }
 
+        
         result.put("authRefNum", parameters.get("PNREF"));
+
         if (codeInt == 0 && avsCheckOkay && cvv2CheckOkay) {
             result.put("authResult", Boolean.TRUE);
             result.put("authCode", parameters.get("AUTHCODE"));
@@ -432,22 +750,8 @@
     }
 
     private static void parseCaptureResponse(String resp, Map<String, Object> result) {
-        Map<Object, Object> parameters = FastMap.newInstance();
-        List<String> params = StringUtil.split(resp, "&");
-        Iterator<String> i = params.iterator();
-
-        while (i.hasNext()) {
-            String str = (String) i.next();
-
-            if (str.length() > 0) {
-                List<String> kv = StringUtil.split(str, "=");
-                Object k = kv.get(0);
-                Object v = kv.get(1);
-
-                if (k != null && v != null)
-                    parameters.put(k, v);
-            }
-        }
+        Map<String, String> parameters = parseResponse(resp);
+        
         String respCode = (String) parameters.get("RESULT");
         int codeInt = -999; // custom response code -- not from payflow docs
         try {
@@ -474,22 +778,8 @@
     }
 
     private static void parseVoidResponse(String resp, Map<String, Object> result) {
-        Map<Object, Object> parameters = FastMap.newInstance();
-        List<String> params = StringUtil.split(resp, "&");
-        Iterator<String> i = params.iterator();
-
-        while (i.hasNext()) {
-            String str = (String) i.next();
-
-            if (str.length() > 0) {
-                List<String> kv = StringUtil.split(str, "=");
-                Object k = kv.get(0);
-                Object v = kv.get(1);
-
-                if (k != null && v != null)
-                    parameters.put(k, v);
-            }
-        }
+        Map<String, String> parameters = parseResponse(resp);
+        
         String respCode = (String) parameters.get("RESULT");
         int codeInt = -999; // custom response code -- not from payflow docs
         try {
@@ -516,22 +806,8 @@
     }
 
     private static void parseRefundResponse(String resp, Map<String, Object> result) {
-        Map<Object, Object> parameters = FastMap.newInstance();
-        List<String> params = StringUtil.split(resp, "&");
-        Iterator<String> i = params.iterator();
-
-        while (i.hasNext()) {
-            String str = (String) i.next();
-
-            if (str.length() > 0) {
-                List<String> kv = StringUtil.split(str, "=");
-                Object k = kv.get(0);
-                Object v = kv.get(1);
-
-                if (k != null && v != null)
-                    parameters.put(k, v);
-            }
-        }
+        Map<String, String> parameters = parseResponse(resp);
+        
         String respCode = (String) parameters.get("RESULT");
         int codeInt = -999; // custom response code -- not from payflow docs
         try {
@@ -571,15 +847,7 @@
             } else {
                 String value = valueObj.toString();
 
-                // URL enocde each field to make sure it can pass to payflow properly
-                try {
-                    name = URLEncoder.encode(name, "UTF-8");
-                    value = URLEncoder.encode(value, "UTF-8");
-                } catch (UnsupportedEncodingException e) {
-                    Debug.logError(e, module);
-                    continue;
-                }
-
+                // Payflow expects an unencoded name/value pair string
                 buf.append(name).append("=");
                 buf.append(value);
                 if (i.hasNext())

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=793866&r1=793865&r2=793866&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 Tue Jul 14 11:43:21 2009
@@ -77,7 +77,7 @@
     protected List orderItemAndShipGrp = null;
     protected List orderItems = null;
     protected List adjustments = null;
-    protected List paymentPrefs = null;
+    protected List<GenericValue> paymentPrefs = null;
     protected List orderStatuses = null;
     protected List orderItemPriceInfos = null;
     protected List orderItemShipGrpInvResList = null;
@@ -191,7 +191,7 @@
         return adjustments;
     }
 
-    public List getPaymentPreferences() {
+    public List<GenericValue> getPaymentPreferences() {
         if (paymentPrefs == null) {
             try {
                 paymentPrefs = orderHeader.getRelated("OrderPaymentPreference", UtilMisc.toList("orderPaymentPreferenceId"));

Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReturnServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReturnServices.java?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReturnServices.java (original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/order/OrderReturnServices.java Tue Jul 14 11:43:21 2009
@@ -52,6 +52,7 @@
 import org.ofbiz.entity.condition.EntityConditionList;
 import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.entity.util.EntityUtil;
+import org.ofbiz.order.thirdparty.paypal.ExpressCheckoutEvents;
 import org.ofbiz.product.product.ProductContentWrapper;
 import org.ofbiz.product.product.ProductWorker;
 import org.ofbiz.product.store.ProductStoreWorker;
@@ -1300,7 +1301,14 @@
 
                 // This can be extended to support additional electronic types
                 List electronicTypes = UtilMisc.toList("CREDIT_CARD", "EFT_ACCOUNT", "FIN_ACCOUNT", "GIFT_CARD");
-
+                
+                // Figure out if EXT_PAYPAL should be considered as an electronic type
+                if (productStore != null) {
+                    ExpressCheckoutEvents.CheckoutType payPalType = ExpressCheckoutEvents.determineCheckoutType(delegator, productStore.getString("productStoreId"));
+                    if (!payPalType.equals(ExpressCheckoutEvents.CheckoutType.NONE)) {
+                        electronicTypes.add("EXT_PAYPAL");
+                    }
+                }
                 // This defines the ordered part of the sequence of refund processing
                 List orderedRefundPaymentMethodTypes = new ArrayList();
                 orderedRefundPaymentMethodTypes.add("EXT_BILLACT");

Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutEvents.java?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutEvents.java (original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutEvents.java Tue Jul 14 11:43:21 2009
@@ -629,6 +629,31 @@
         return result;
     }
 
+    public static String checkExternalCheckout(HttpServletRequest request, HttpServletResponse response) {
+        GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
+        ShoppingCart cart = ShoppingCartEvents.getCartObject(request);
+        GenericValue productStore = ProductStoreWorker.getProductStore(cart.getProductStoreId(), delegator);
+        String paymentMethodTypeId = (String) request.getParameter("paymentMethodTypeId");
+        if (UtilValidate.isNotEmpty(paymentMethodTypeId)) {
+            if ("EXT_PAYPAL".equals(paymentMethodTypeId)) {
+                List<GenericValue> payPalProdStorePaySettings = null;
+                try {
+                    payPalProdStorePaySettings = delegator.findByAnd("ProductStorePaymentSetting", "productStoreId", productStore.getString("productStoreId"), "paymentMethodTypeId", "EXT_PAYPAL");
+                    GenericValue payPalProdStorePaySetting = EntityUtil.getFirst(payPalProdStorePaySettings);
+                    if (payPalProdStorePaySetting != null) {
+                        GenericValue gatewayConfig = payPalProdStorePaySetting.getRelatedOne("PaymentGatewayConfig");
+                        if (gatewayConfig != null && "PAYFLOWPRO".equals(gatewayConfig.getString("paymentGatewayConfigTypeId"))) {
+                            return "paypal";
+                        }
+                    }
+                } catch (GenericEntityException e) {
+                    Debug.logError(e, module);
+                }
+            }
+        }
+        return "success";
+    }
+
     public static String checkExternalPayment(HttpServletRequest request, HttpServletResponse response) {
         // warning there can only be ONE payment preference for this to work
         // you cannot accept multiple payment type when using an external gateway

Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java (original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/CheckOutHelper.java Tue Jul 14 11:43:21 2009
@@ -46,6 +46,7 @@
 import org.ofbiz.entity.GenericValue;
 import org.ofbiz.entity.condition.EntityCondition;
 import org.ofbiz.entity.condition.EntityConditionList;
+import org.ofbiz.entity.condition.EntityExpr;
 import org.ofbiz.entity.condition.EntityFieldValue;
 import org.ofbiz.entity.condition.EntityFunction;
 import org.ofbiz.entity.condition.EntityOperator;
@@ -55,6 +56,7 @@
 import org.ofbiz.order.order.OrderReadHelper;
 import org.ofbiz.order.shoppingcart.product.ProductPromoWorker;
 import org.ofbiz.order.shoppingcart.shipping.ShippingEvents;
+import org.ofbiz.order.thirdparty.paypal.ExpressCheckoutEvents;
 import org.ofbiz.party.contact.ContactHelper;
 import org.ofbiz.product.store.ProductStoreWorker;
 import org.ofbiz.service.GenericServiceException;
@@ -286,7 +288,7 @@
                 BigDecimal accountCredit = this.availableAccountBalance(cart.getBillingAccountId());
                 BigDecimal amountToUse = cart.getBillingAccountAmount();
 
-                // if an amount was entered, check that it doesn't exceed availalble amount
+                // if an amount was entered, check that it doesn't exceed available amount
                 if (amountToUse.compareTo(BigDecimal.ZERO) > 0 && amountToUse.compareTo(accountCredit) > 0) {
                     errMsg = UtilProperties.getMessage(resource_error,"checkhelper.insufficient_credit_available_on_account",
                             (cart != null ? cart.getLocale() : Locale.getDefault()));
@@ -893,7 +895,7 @@
             RETRY_ON_ERROR = "Y";
         }
 
-        List allPaymentPreferences = null;
+        List<GenericValue> allPaymentPreferences = null;
         try {
             allPaymentPreferences = delegator.findByAnd("OrderPaymentPreference", UtilMisc.toMap("orderId", orderId));
         } catch (GenericEntityException e) {
@@ -951,6 +953,17 @@
             }
         }
 
+        // check for a paypal express checkout needing completion
+        List<EntityExpr> payPalExprs = UtilMisc.toList(
+                EntityCondition.makeCondition("paymentMethodId", EntityOperator.NOT_EQUAL, null),
+                EntityCondition.makeCondition("paymentMethodTypeId", "EXT_PAYPAL")
+            );
+        List<GenericValue> payPalPaymentPrefs = EntityUtil.filterByAnd(allPaymentPreferences, payPalExprs);
+        if (UtilValidate.isNotEmpty(payPalPaymentPrefs)) {
+            GenericValue payPalPaymentPref = EntityUtil.getFirst(payPalPaymentPrefs);
+            ExpressCheckoutEvents.doExpressCheckout(productStore.getString("productStoreId"), orderId, payPalPaymentPref, userLogin, delegator, dispatcher);
+        }
+
         // check for online payment methods needing authorization
         Map paymentFields = UtilMisc.toMap("statusId", "PAYMENT_NOT_AUTH");
         List onlinePaymentPrefs = EntityUtil.filterByAnd(allPaymentPreferences, paymentFields);

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=793866&r1=793865&r2=793866&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 Tue Jul 14 11:43:21 2009
@@ -112,7 +112,7 @@
     private List<CartShipInfo> shipInfo = FastList.<CartShipInfo> newInstance();
     private Map contactMechIdsMap = new HashMap();
     private Map orderAttributes = new HashMap();
-    private Map attributes = new HashMap(); // user defined attributes
+    private Map<String, Object> attributes = new HashMap<String, Object>(); // user defined attributes
     // Lists of internal/public notes: when the order is stored they are transformed into OrderHeaderNotes
     private List internalOrderNotes = FastList.newInstance(); // internal notes
     private List orderNotes = FastList.newInstance(); // public notes (printed on documents etc.)
@@ -368,6 +368,10 @@
         this.attributes.put(name, value);
     }
 
+    public void removeAttribute(String name) {
+        this.attributes.remove(name);
+    }
+
     public Object getAttribute(String name) {
         return this.attributes.get(name);
     }
@@ -874,8 +878,8 @@
     }
 
     /** Returns a Collection of items in the cart object. */
-    public List items() {
-        List result = FastList.newInstance();
+    public List<ShoppingCartItem> items() {
+        List<ShoppingCartItem> result = FastList.newInstance();
         result.addAll(cartLines);
         return result;
     }
@@ -4622,6 +4626,8 @@
                         pmObj = delegator.findByPrimaryKey("EftAccount", lookupFields);
                     } else if ("EXT_BILLACT".equals(paymentMethodTypeId)) {
                         pmObj = delegator.findByPrimaryKey("BillingAccount", lookupFields);
+                    } else if ("EXT_PAYPAL".equals(paymentMethodTypeId)) {
+                        pmObj = delegator.findByPrimaryKey("PayPalPaymentMethod", lookupFields);
                     }
                     if (pmObj != null) {
                         postalAddress = pmObj.getRelatedOne("PostalAddress");

Added: ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java?rev=793866&view=auto
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java (added)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java Tue Jul 14 11:43:21 2009
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * 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.
+ *******************************************************************************/
+package org.ofbiz.order.thirdparty.paypal;
+
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilHttp;
+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.order.shoppingcart.ShoppingCart;
+import org.ofbiz.order.shoppingcart.ShoppingCartEvents;
+import org.ofbiz.product.store.ProductStoreWorker;
+import org.ofbiz.service.GenericServiceException;
+import org.ofbiz.service.LocalDispatcher;
+import org.ofbiz.service.ServiceUtil;
+
+
+public class ExpressCheckoutEvents {
+
+    public static final String resourceErr = "AccountingErrorUiLabels";
+    public static final String module = ExpressCheckoutEvents.class.getName();
+    public static enum CheckoutType {PAYFLOW, NONE};
+    
+    public static String setExpressCheckout(HttpServletRequest request, HttpServletResponse response) {
+        Locale locale = UtilHttp.getLocale(request);
+        LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
+        
+        ShoppingCart cart = ShoppingCartEvents.getCartObject(request);
+        CheckoutType checkoutType = determineCheckoutType(request);
+        if (checkoutType.equals(CheckoutType.PAYFLOW)) {
+            Map<String, ? extends Object> inMap = UtilMisc.toMap("userLogin", cart.getUserLogin(), "cart", cart);
+            Map<String, Object> result = null;
+            try {
+                result = dispatcher.runSync("payflowSetExpressCheckout", inMap);
+            } catch (GenericServiceException e) {
+                request.setAttribute("_EVENT_MESSAGE_", UtilProperties.getMessage(resourceErr, "AccountingPayPalCommunicationError", locale));
+                return "error";
+            }
+            if (ServiceUtil.isError(result)) {
+                Debug.logError(ServiceUtil.getErrorMessage(result), module);
+                request.setAttribute("_EVENT_MESSAGE_", ServiceUtil.getErrorMessage(result));
+                return "error";
+            }
+        }
+            
+        return "success";
+    }
+
+    public static String expressCheckoutRedirect(HttpServletRequest request, HttpServletResponse response) {
+        ShoppingCart cart = ShoppingCartEvents.getCartObject(request);
+        String token = (String) cart.getAttribute("payPalCheckoutToken");
+        if (UtilValidate.isEmpty(token)) {
+            Debug.logError("No ExpressCheckout token found in cart, you must do a successful setExpressCheckout before redirecting.", module);
+            return "error";
+        }
+        StringBuilder redirectUrl = new StringBuilder("https://www.sandbox.paypal.com/cgi-bin/webscr");
+        redirectUrl.append("?cmd=_express-checkout&token=");
+        redirectUrl.append(token);
+        try {
+            response.sendRedirect(redirectUrl.toString());
+        } catch (IOException e) {
+            Debug.logError(e, module);
+            return "error";
+        }
+        return "success";
+    }
+    
+    public static String getExpressCheckoutDetails(HttpServletRequest request, HttpServletResponse response) {
+        Locale locale = UtilHttp.getLocale(request);
+        LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
+        
+        ShoppingCart cart = ShoppingCartEvents.getCartObject(request);
+        CheckoutType checkoutType = determineCheckoutType(request);
+        if (checkoutType.equals(CheckoutType.PAYFLOW)) {
+            Map<String, ? extends Object> inMap = UtilMisc.toMap("userLogin", cart.getUserLogin(), "cart", cart);
+            Map<String, Object> result = null;
+            try {
+                result = dispatcher.runSync("payflowGetExpressCheckout", inMap);
+            } catch (GenericServiceException e) {
+                request.setAttribute("_EVENT_MESSAGE_", UtilProperties.getMessage(resourceErr, "AccountingPayPalCommunicationError", locale));
+                return "error";
+            }
+            if (ServiceUtil.isError(result)) {
+                Debug.logError(ServiceUtil.getErrorMessage(result), module);
+                request.setAttribute("_EVENT_MESSAGE_", ServiceUtil.getErrorMessage(result));
+                return "error";
+            }
+        }
+            
+        return "success";
+    }
+    
+    public static Map<String, Object> doExpressCheckout(String productStoreId, String orderId, GenericValue paymentPref, GenericValue userLogin, GenericDelegator delegator, LocalDispatcher dispatcher) {
+        CheckoutType checkoutType = determineCheckoutType(delegator, productStoreId);
+        if (checkoutType.equals(CheckoutType.PAYFLOW)) {
+            Map<String, Object> inMap = FastMap.newInstance();
+            inMap.put("userLogin", userLogin);
+            inMap.put("orderPaymentPreference", paymentPref);
+            Map<String, Object> result = null;
+            try {
+                result = dispatcher.runSync("payflowDoExpressCheckout", inMap);
+            } catch (GenericServiceException e) {
+                return ServiceUtil.returnError(e.getMessage());
+            }
+            return result;
+        }
+            
+        return ServiceUtil.returnSuccess();
+    }
+
+    public static String expressCheckoutCancel(HttpServletRequest request, HttpServletResponse response) {
+        ShoppingCart cart = ShoppingCartEvents.getCartObject(request);
+        cart.removeAttribute("payPalCheckoutToken");
+        return "success";
+    }
+    
+    public static CheckoutType determineCheckoutType(HttpServletRequest request) {
+        GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
+        ShoppingCart cart = ShoppingCartEvents.getCartObject(request);
+        return determineCheckoutType(delegator, cart.getProductStoreId());
+    }
+
+    public static CheckoutType determineCheckoutType(GenericDelegator delegator, String productStoreId) {
+        GenericValue payPalPaymentSetting = ProductStoreWorker.getProductStorePaymentSetting(delegator, productStoreId, "EXT_PAYPAL", null, true);
+        if (payPalPaymentSetting != null && payPalPaymentSetting.getString("paymentGatewayConfigId") != null) {
+            try {
+                GenericValue paymentGatewayConfig = payPalPaymentSetting.getRelatedOne("PaymentGatewayConfig");
+                if (paymentGatewayConfig != null && "PAYFLOWPRO".equals(paymentGatewayConfig.getString("paymentGatewayConfigTypeId"))) {
+                    return CheckoutType.PAYFLOW;
+                }
+            } catch (GenericEntityException e) {
+                Debug.logError(e, module);
+            }
+        }
+        return CheckoutType.NONE;
+    }
+    
+}
\ No newline at end of file

Propchange: ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java
------------------------------------------------------------------------------
    svn:keywords = "Date Rev Author URL Id"

Propchange: ofbiz/trunk/applications/order/src/org/ofbiz/order/thirdparty/paypal/ExpressCheckoutEvents.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/framework/base/src/org/ofbiz/base/util/HttpClient.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/HttpClient.java?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/framework/base/src/org/ofbiz/base/util/HttpClient.java (original)
+++ ofbiz/trunk/framework/base/src/org/ofbiz/base/util/HttpClient.java Tue Jul 14 11:43:21 2009
@@ -388,7 +388,7 @@
 
     private InputStream sendHttpRequestStream(String method, boolean overrideTrust) throws HttpClientException {
         // setup some SSL variables
-        SSLUtil.loadJsseProperties();
+        SSLUtil.loadJsseProperties(this.debug);
 
         String arguments = null;
         InputStream in = null;

Modified: ofbiz/trunk/specialpurpose/ecommerce/data/DemoProduct.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/ecommerce/data/DemoProduct.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/ecommerce/data/DemoProduct.xml (original)
+++ ofbiz/trunk/specialpurpose/ecommerce/data/DemoProduct.xml Tue Jul 14 11:43:21 2009
@@ -70,6 +70,12 @@
     <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="GIFT_CARD" paymentServiceTypeEnumId="PRDS_PAY_RELEASE" paymentService="testGCRelease" paymentCustomMethodId="GIFT_RELEASE_TEST"/>
 
     <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_PAYPAL" paymentServiceTypeEnumId="PRDS_PAY_EXTERNAL" paymentService="" paymentCustomMethodId="" paymentGatewayConfigId="PAYPAL_CONFIG"/>
+    <!-- Example PayPal Payflow Pro Express Checkout Setup
+    <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_PAYPAL" paymentServiceTypeEnumId="PRDS_PAY_AUTH" paymentService="" paymentCustomMethodId="PAYPAL_AUTH_PFP" paymentGatewayConfigId="PAYFLOWPRO_CONFIG"/>
+    <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_PAYPAL" paymentServiceTypeEnumId="PRDS_PAY_CAPTURE" paymentService="" paymentCustomMethodId="PAYPAL_CAPTURE_PFP" paymentGatewayConfigId="PAYFLOWPRO_CONFIG"/>
+    <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_PAYPAL" paymentServiceTypeEnumId="PRDS_PAY_REFUND" paymentService="" paymentCustomMethodId="PAYPAL_REFUND_PFP" paymentGatewayConfigId="PAYFLOWPRO_CONFIG"/>
+    <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_PAYPAL" paymentServiceTypeEnumId="PRDS_PAY_RELEASE" paymentService="" paymentCustomMethodId="PAYPAL_CAPTURE_PFP" paymentGatewayConfigId="PAYFLOWPRO_CONFIG"/>
+    -->
     <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_WORLDPAY" paymentServiceTypeEnumId="PRDS_PAY_EXTERNAL" paymentService="" paymentCustomMethodId="" paymentGatewayConfigId="WORLDPAY_CONFIG"/>
     <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_OFFLINE" paymentServiceTypeEnumId="PRDS_PAY_EXTERNAL" paymentService="" paymentCustomMethodId=""/>
     <ProductStorePaymentSetting productStoreId="9000" paymentMethodTypeId="EXT_COD" paymentServiceTypeEnumId="PRDS_PAY_EXTERNAL" paymentService="" paymentCustomMethodId=""/>

Modified: ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/controller.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/controller.xml?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/controller.xml (original)
+++ ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/controller.xml Tue Jul 14 11:43:21 2009
@@ -339,7 +339,7 @@
     </request-map>
     <request-map uri="processShipSettings">
         <security https="true" auth="false"/>
-        <event type="service" invoke="createUpdateShippingAddress"/>
+        <event type="simple" path="component://ecommerce/script/org/ofbiz/ecommerce/customer/CustomerEvents.xml" invoke="processShipSettings"/>
         <response name="success" type="request" value="setShipOptions"/>
         <response name="error" type="view" value="shipsetting"/>
     </request-map>
@@ -377,7 +377,9 @@
 
     <request-map uri="setPaymentInformation">
         <security https="true" auth="false"/>
+        <event type="java" path="org.ofbiz.order.shoppingcart.CheckOutEvents" invoke="checkExternalCheckout"/>
         <response name="success" type="view" value="paymentinformation"/>
+        <response name="paypal" type="request" value="setPayPalCheckout"/>
     </request-map>
 
     <request-map uri="enterCreditCardAndBillingAddress">
@@ -782,6 +784,31 @@
         <response name="error" type="view" value="main"/>
     </request-map>
 
+    <!-- PayPal Express Checkout Requests -->
+    <request-map uri="setPayPalCheckout">
+        <security auth="false" https="true"/>
+        <event type="java" path="org.ofbiz.order.thirdparty.paypal.ExpressCheckoutEvents" invoke="setExpressCheckout"/>
+        <response name="success" type="request" value="payPalCheckoutRedirect"/>
+        <response name="error" type="view-last"/>
+    </request-map>
+    <request-map uri="payPalCheckoutRedirect">
+        <security auth="false" https="true"/>
+        <event type="java" path="org.ofbiz.order.thirdparty.paypal.ExpressCheckoutEvents" invoke="expressCheckoutRedirect"/>
+        <response name="success" type="none"/>
+        <response name="error" type="view-last"/>
+    </request-map>
+    <request-map uri="payPalCheckoutReturn">
+        <security auth="false" https="true"/>
+        <event type="java" path="org.ofbiz.order.thirdparty.paypal.ExpressCheckoutEvents" invoke="getExpressCheckoutDetails"/>
+        <response name="success" type="request" value="reviewOrder"/>
+        <response name="error" type="view-last"/>
+    </request-map>
+    <request-map uri="payPalCheckoutCancel">
+        <security auth="false" https="true"/>
+        <event type="java" path="org.ofbiz.order.thirdparty.paypal.ExpressCheckoutEvents" invoke="expressCheckoutCancel"/>
+        <response name="success" type="view-last"/>
+    </request-map>
+
     <!-- TO BE REMOVED
     <request-map uri="catalog">
         <security https="false" auth="false"/>

Modified: ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/paymentoptions.ftl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/paymentoptions.ftl?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/paymentoptions.ftl (original)
+++ ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/paymentoptions.ftl Tue Jul 14 11:43:21 2009
@@ -46,6 +46,12 @@
            <label for="paymentMethodTypeId_EFT_ACCOUNT" class="tabletext">${uiLabelMap.AccountingAHCElectronicCheck}</label>
          </div>
        </#if>
+       <#if productStorePaymentMethodTypeIdMap.EXT_PAYPAL?exists>
+         <div>
+           <input type="radio" id="paymentMethodTypeId_EXT_PAYPAL" name="paymentMethodTypeId" value="EXT_PAYPAL" <#if paymentMethodTypeId?exists && paymentMethodTypeId == "EXT_PAYPAL">checked</#if>/>
+           <label for="paymentMethodTypeId_EXT_PAYPAL" class="tabletext">${uiLabelMap.AccountingPayWithPayPal}</label>
+         </div>
+       </#if>
        <div class="buttons">
          <input type="submit" value="${uiLabelMap.CommonContinue}"/>
        </div>

Modified: ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/shipsettings.ftl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/shipsettings.ftl?rev=793866&r1=793865&r2=793866&view=diff
==============================================================================
--- ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/shipsettings.ftl (original)
+++ ofbiz/trunk/specialpurpose/ecommerce/webapp/ecommerce/order/shipsettings.ftl Tue Jul 14 11:43:21 2009
@@ -24,45 +24,45 @@
       <input type="hidden" name="shippingContactMechId" value="${parameters.shippingContactMechId?if_exists}"/>
       <input type="hidden" name="partyId" value="${cart.getPartyId()?default("_NA_")}"/>
       <div>
-        <label for="shipToAddress1">${uiLabelMap.PartyAddressLine1}*</label>
-        <input id="shipToAddress1" name="shipToAddress1" class="required" type="text" value="${shipToAddress1?if_exists}"/>
-        <span id="advice-required-shipToAddress1" class="custom-advice errorMessage" style="display:none"> (required)</span>
+        <label for="address1">${uiLabelMap.PartyAddressLine1}*</label>
+        <input id="address1" name="address1" class="required" type="text" value="${address1?if_exists}"/>
+        <span id="advice-required-address1" class="custom-advice errorMessage" style="display:none"> (required)</span>
       </div>
       <div>
-        <label for="shipToAddress2">${uiLabelMap.PartyAddressLine2}</label>
-        <input id="shipToAddress2" name="shipToAddress2" type="text" value="${shipToAddress2?if_exists}"/>
+        <label for="address2">${uiLabelMap.PartyAddressLine2}</label>
+        <input id="address2" name="address2" type="text" value="${address2?if_exists}"/>
       </div>
       <div>
-        <label for="shipToCity">${uiLabelMap.CommonCity}*</label>
-        <input id="shipToCity" name="shipToCity" class="required" type="text" value="${shipToCity?if_exists}"/>
-        <span id="advice-required-shipToCity" class="custom-advice errorMessage" style="display:none"> (required)</span>
+        <label for="city">${uiLabelMap.CommonCity}*</label>
+        <input id="city" name="city" class="required" type="text" value="${city?if_exists}"/>
+        <span id="advice-required-city" class="custom-advice errorMessage" style="display:none"> (required)</span>
       </div>
       <div>
-        <label for="shipToPostalCode">${uiLabelMap.PartyZipCode}*</label>
-        <input id="shipToPostalCode" name="shipToPostalCode" class="required" type="text" value="${shipToPostalCode?if_exists}" size="12" maxlength="10"/>
-        <span id="advice-required-shipToPostalCode" class="custom-advice errorMessage" style="display:none"> (required)</span>
+        <label for="postalCode">${uiLabelMap.PartyZipCode}*</label>
+        <input id="postalCode" name="postalCode" class="required" type="text" value="${postalCode?if_exists}" size="12" maxlength="10"/>
+        <span id="advice-required-postalCode" class="custom-advice errorMessage" style="display:none"> (required)</span>
       </div>
       <div>
-        <label for="shipToCountryGeoId">${uiLabelMap.PartyCountry}*</label>
-        <select name="shipToCountryGeoId" id="shipToCountryGeoId">
-          <#if shipToCountryGeoId??>
-            <option value="${shipToCountryGeoId!}">${shipToCountryProvinceGeo!(shipToCountryGeoId!)}</option>
+        <label for="countryGeoId">${uiLabelMap.PartyCountry}*</label>
+        <select name="countryGeoId" id="countryGeoId">
+          <#if countryGeoId??>
+            <option value="${countryGeoId!}">${countryProvinceGeo!(countryGeoId!)}</option>
           </#if>
           ${screens.render("component://common/widget/CommonScreens.xml#countries")}
         </select>
-        <span id="advice-required-shipToCountryGeo" style="display:none" class="errorMessage"> (required)</span>
+        <span id="advice-required-countryGeoId" style="display:none" class="errorMessage"> (required)</span>
       </div>
       <div>
         <label for="state">${uiLabelMap.CommonState}*</label>
-        <select id="shipToStateProvinceGeoId" name="shipToStateProvinceGeoId">
-          <#if shipToStateProvinceGeoId?has_content>
-            <option value='${shipToStateProvinceGeoId!}'>${shipToStateProvinceGeo!(shipToStateProvinceGeoId!)}</option>
+        <select id="stateProvinceGeoId" name="stateProvinceGeoId">
+          <#if stateProvinceGeoId?has_content>
+            <option value='${stateProvinceGeoId!}'>${stateProvinceGeo!(stateProvinceGeoId!)}</option>
           <#else>
             <option value="_NA_">${uiLabelMap.PartyNoState}</option>
           </#if>
           ${screens.render("component://common/widget/CommonScreens.xml#states")}
         </select>
-        <span id="advice-required-shipToStateProvinceGeoId" style="display:none" class="errorMessage">(required)</span>
+        <span id="advice-required-stateProvinceGeoId" style="display:none" class="errorMessage">(required)</span>
       </div>
       <div class="buttons">
         <input type="submit" class="smallsubmit" value="${uiLabelMap.CommonContinue}"/>