You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by le...@apache.org on 2009/08/13 04:48:19 UTC
svn commit: r803760 -
/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/paypal/PayPalServices.java
Author: lektran
Date: Thu Aug 13 02:48:19 2009
New Revision: 803760
URL: http://svn.apache.org/viewvc?rev=803760&view=rev
Log:
A few fixes for Express Checkout, the shipping estimate callback from PayPal is now processing correctly
Modified:
ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/paypal/PayPalServices.java
Modified: ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/paypal/PayPalServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/paypal/PayPalServices.java?rev=803760&r1=803759&r2=803760&view=diff
==============================================================================
--- ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/paypal/PayPalServices.java (original)
+++ ofbiz/trunk/applications/accounting/src/org/ofbiz/accounting/thirdparty/paypal/PayPalServices.java Thu Aug 13 02:48:19 2009
@@ -18,7 +18,6 @@
*******************************************************************************/
package org.ofbiz.accounting.thirdparty.paypal;
-import java.io.BufferedReader;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
@@ -32,14 +31,17 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.transaction.Transaction;
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.GeneralException;
import org.ofbiz.base.util.StringUtil;
import org.ofbiz.base.util.UtilDateTime;
+import org.ofbiz.base.util.UtilHttp;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.base.util.UtilValidate;
@@ -49,6 +51,8 @@
import org.ofbiz.entity.condition.EntityComparisonOperator;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.condition.EntityFunction;
+import org.ofbiz.entity.transaction.GenericTransactionException;
+import org.ofbiz.entity.transaction.TransactionUtil;
import org.ofbiz.entity.util.EntityUtil;
import org.ofbiz.order.order.OrderReadHelper;
import org.ofbiz.order.shoppingcart.CartItemModifyException;
@@ -84,7 +88,7 @@
// is a weak reference to the ShoppingCart itself. Entries will be removed as carts are removed from the
// session (i.e. on cart clear or successful checkout) or when the session is destroyed
private static Map<TokenWrapper, WeakReference<ShoppingCart>> tokenCartMap = new WeakHashMap<TokenWrapper, WeakReference<ShoppingCart>>();
-
+
public static Map<String, Object> setExpressCheckout(DispatchContext dctx, Map<String, ? extends Object> context) {
ShoppingCart cart = (ShoppingCart) context.get("cart");
Locale locale = cart.getLocale();
@@ -97,9 +101,9 @@
return ServiceUtil.returnError("Couldn't retrieve a PaymentGatewayConfigPayPal record for Express Checkout, cannot continue.");
}
-
+
NVPEncoder encoder = new NVPEncoder();
-
+
// Set Express Checkout Request Parameters
encoder.add("METHOD", "SetExpressCheckout");
String token = (String) cart.getAttribute("payPalCheckoutToken");
@@ -118,16 +122,14 @@
encoder.add("REQCONFIRMSHIPPING", reqConfirmShipping);
// Default shipment method
encoder.add("L_SHIPPINGOPTIONISDEFAULT0", "true");
- encoder.add("L_SHIPPINGOPTIONNAME0", "NO_SHIPPING@_NA_");
- //TODO: This isn't working
- encoder.add("L_SHIPINGPOPTIONLABEL0", "Calculated Offline");
+ encoder.add("L_SHIPPINGOPTIONNAME0", "Calculated Offline");
encoder.add("L_SHIPPINGOPTIONAMOUNT0", "0.00");
}
encoder.add("ALLOWNOTE", "1");
encoder.add("INSURANCEOPTIONOFFERED", "false");
if (UtilValidate.isNotEmpty(payPalConfig.getString("imageUrl")));
encoder.add("PAYMENTACTION", "Order");
-
+
// Cart information
try {
addCartDetails(encoder, cart);
@@ -143,7 +145,7 @@
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
-
+
Map<String, String> errorMessages = getErrorMessageMap(decoder);
if (UtilValidate.isNotEmpty(errorMessages)) {
if (errorMessages.containsKey("10411")) {
@@ -156,135 +158,136 @@
token = decoder.get("TOKEN");
cart.setAttribute("payPalCheckoutToken", token);
- cart.setAttribute("payPalCheckoutTokenObj", new TokenWrapper(token));
- //PayPalServices.tokenCartMap.put(token, new ShoppingCartWrapper(cart));
+ TokenWrapper tokenWrapper = new TokenWrapper(token);
+ cart.setAttribute("payPalCheckoutTokenObj", tokenWrapper);
+ PayPalServices.tokenCartMap.put(tokenWrapper, new WeakReference<ShoppingCart>(cart));
return ServiceUtil.returnSuccess();
}
- public static Map<String, Object> payPalCheckoutUpdate(DispatchContext dctx, Map context) {
+ public static Map<String, Object> payPalCheckoutUpdate(DispatchContext dctx, Map<String, Object> context) {
LocalDispatcher dispatcher = dctx.getDispatcher();
GenericDelegator delegator = dctx.getDelegator();
HttpServletRequest request = (HttpServletRequest) context.get("request");
HttpServletResponse response = (HttpServletResponse) context.get("response");
-// String remoteHost = request.getRemoteHost();
-// if (!remoteHost.endsWith(".paypal.com")) {
-// try {
-// response.sendError(HttpServletResponse.SC_FORBIDDEN);
-// Debug.logError("An Express Checkout Update request was received from a host other than *.paypal.com, responded with 403 Forbidden", module);
-// } catch (IOException e) {
-// Debug.logError(e, module);
-// }
-// return ServiceUtil.returnSuccess();
-// }
-
- String requestMessage = null;
- try {
- BufferedReader reader = request.getReader();
- requestMessage = reader.readLine();
- reader.close();
- } catch (IOException e) {
- Debug.logError(e, module);
+
+ Map<String, Object> paramMap = UtilHttp.getParameterMap(request);
+
+ String token = (String)paramMap.get("TOKEN");
+ WeakReference<ShoppingCart> weakCart = tokenCartMap.get(new TokenWrapper(token));
+ ShoppingCart cart = null;
+ if (weakCart != null) {
+ cart = weakCart.get();
}
- if (requestMessage == null) {
+ if (cart == null) {
+ Debug.logError("Could locate the ShoppingCart for token " + token, module);
return ServiceUtil.returnSuccess();
}
-
- NVPDecoder decoder = new NVPDecoder();
+ // Since most if not all of the shipping estimate codes requires a persisted contactMechId we'll create one and
+ // then delete once we're done, now is not the time to worry about updating everything
+ String contactMechId = null;
+ Map<String, Object> inMap = FastMap.newInstance();
+ inMap.put("address1", paramMap.get("SHIPTOSTREET"));
+ inMap.put("address2", paramMap.get("SHIPTOSTREET2"));
+ inMap.put("city", paramMap.get("SHIPTOCITY"));
+ inMap.put("stateProvinceGeoId", paramMap.get("SHIPTOSTATE"));
+ inMap.put("postalCode", paramMap.get("SHIPTOZIP"));
+ String countryGeoCode = (String) paramMap.get("SHIPTOCOUNTRY");
+ String countryGeoId = PayPalServices.getCountryGeoIdFromGeoCode(countryGeoCode, delegator);
+ if (countryGeoId == null) {
+ return ServiceUtil.returnSuccess();
+ }
+ inMap.put("countryGeoId", countryGeoId);
+
try {
- decoder.decode(requestMessage);
- } catch (PayPalException e) {
+ GenericValue userLogin = delegator.findOne("UserLogin", true, UtilMisc.toMap("userLoginId", "system"));
+ inMap.put("userLogin", userLogin);
+ } catch (GenericEntityException e) {
Debug.logError(e, module);
+ }
+ boolean beganTransaction = false;
+ Transaction parentTransaction = null;
+ try {
+ parentTransaction = TransactionUtil.suspend();
+ beganTransaction = TransactionUtil.begin();
+ } catch (GenericTransactionException e1) {
+ Debug.logError(e1, module);
+ }
+ try {
+ Map<String, Object> outMap = dispatcher.runSync("createPostalAddress", inMap);
+ contactMechId = (String) outMap.get("contactMechId");
+ } catch (GenericServiceException e) {
+ Debug.logError(e.getMessage(), module);
return ServiceUtil.returnSuccess();
}
+ try {
+ TransactionUtil.commit(beganTransaction);
+ if (parentTransaction != null) TransactionUtil.resume(parentTransaction);
+ } catch (GenericTransactionException e) {
+ Debug.logError(e, module);
+ }
+ // clone the cart so we can modify it temporarily
+ CheckOutHelper coh = new CheckOutHelper(dispatcher, delegator, cart);
+ String oldShipAddress = cart.getShippingContactMechId();
+ coh.setCheckOutShippingAddress(contactMechId);
+ ShippingEstimateWrapper estWrapper = new ShippingEstimateWrapper(dispatcher, cart, 0);
+ int line = 0;
+ NVPEncoder encoder = new NVPEncoder();
+ encoder.add("METHOD", "CallbackResponse");
- String token = decoder.get("TOKEN");
- WeakReference<ShoppingCart> weakCart = tokenCartMap.get(new TokenWrapper(token));
- ShoppingCart customerCart = weakCart.get();
- if (customerCart != null) {
- // Since most if not all of the shipping estimate codes requires a persisted contactMechId we'll create one and
- // then delete once we're done, now is not the time to worry about updating everything
- GenericValue shipAddress = delegator.makeValue("PostalAddress");
- String contactMechId = delegator.getNextSeqId("ContactMech");
- shipAddress.put("contactMechId", contactMechId);
- shipAddress.put("address1", decoder.get("SHIPTOSTREET"));
- shipAddress.put("address2", decoder.get("SHIPTOSTREET2"));
- shipAddress.put("city", decoder.get("SHIPTOCITY"));
- shipAddress.put("stateProvinceGeoId", decoder.get("SHIPTOSTATE"));
- shipAddress.put("postalCode", decoder.get("SHIPTOZIP"));
- String countryGeoCode = decoder.get("SHIPTOCOUNTRY"); // PayPal says it is required so I'm not going to check
- try {
- String countryGeoId = PayPalServices.getCountryGeoIdFromGeoCode(countryGeoCode, delegator);
- if (countryGeoId == null) {
- return ServiceUtil.returnSuccess();
- }
- shipAddress.put("countryGeoId", countryGeoId);
- shipAddress.create();
- } catch (GenericEntityException e) {
- Debug.logError(e, module);
- }
- // clone the cart so we can modify it temporarily
- ShoppingCart cart = new ShoppingCart(customerCart);
- CheckOutHelper coh = new CheckOutHelper(dispatcher, delegator, cart);
- coh.setCheckOutShippingAddress(contactMechId);
- ShippingEstimateWrapper estWrapper = new ShippingEstimateWrapper(dispatcher, cart, 0);
- int line = 0;
- NVPEncoder encoder = new NVPEncoder();
- encoder.add("METHOD", "CallbackResponse");
-
- for (GenericValue shipMethod : estWrapper.getShippingMethods()) {
- BigDecimal estimate = estWrapper.getShippingEstimate(shipMethod);
- //Check that we have a valid estimate (allowing zero value estimates for now)
- if (estimate == null || estimate.compareTo(BigDecimal.ZERO) < 0) {
- continue;
- }
- cart.setShipmentMethodTypeId(shipMethod.getString("shipmentMethodTypeId"));
- cart.setCarrierPartyId(shipMethod.getString("partyId"));
- try {
- coh.calcAndAddTax();
- } catch (GeneralException e) {
- Debug.logError(e, module);
- continue;
- }
- String estimateName = shipMethod.getString("shipmentMethodTypeId") + "@" + shipMethod.getString("partyId");
- encoder.add("L_SHIPPINGOPTIONLABEL" + line, estimateName);
- String estimateLabel = shipMethod.getString("partyId") + " " + shipMethod.getString("description");
- encoder.add("L_SHIPPINGOPTIONNAME" + line, estimateLabel);
- encoder.add("L_SHIPPINGOPTIONAMOUNT" + line, estimate.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
- // Just make this first one default for now
- encoder.add("L_SHIPPINGOPTIONISDEFAULT" + line, line == 0 ? "true" : "false");
- encoder.add("L_TAXAMT" + line, cart.getTotalSalesTax().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
- line++;
- }
- String responseMsg = null;
+ for (GenericValue shipMethod : estWrapper.getShippingMethods()) {
+ BigDecimal estimate = estWrapper.getShippingEstimate(shipMethod);
+ //Check that we have a valid estimate (allowing zero value estimates for now)
+ if (estimate == null || estimate.compareTo(BigDecimal.ZERO) < 0) {
+ continue;
+ }
+ cart.setShipmentMethodTypeId(shipMethod.getString("shipmentMethodTypeId"));
+ cart.setCarrierPartyId(shipMethod.getString("partyId"));
+ try {
+ coh.calcAndAddTax();
+ } catch (GeneralException e) {
+ Debug.logError(e, module);
+ continue;
+ }
+ String estimateLabel = shipMethod.getString("partyId") + " - " + shipMethod.getString("description");
+ encoder.add("L_SHIPINGPOPTIONLABEL" + line, estimateLabel);
+ encoder.add("L_SHIPPINGOPTIONAMOUNT" + line, estimate.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
+ // Just make this first one default for now
+ encoder.add("L_SHIPPINGOPTIONISDEFAULT" + line, line == 0 ? "true" : "false");
+ encoder.add("L_TAXAMT" + line, cart.getTotalSalesTax().setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
+ line++;
+ }
+ String responseMsg = null;
+ try {
+ responseMsg = encoder.encode();
+ } catch (PayPalException e) {
+ Debug.logError(e, module);
+ }
+ if (responseMsg != null) {
try {
- responseMsg = encoder.encode();
- } catch (PayPalException e) {
+ response.setContentLength(responseMsg.getBytes("UTF-8").length);
+ } catch (UnsupportedEncodingException e) {
Debug.logError(e, module);
}
- if (responseMsg != null) {
- try {
- response.setContentLength(responseMsg.getBytes("UTF-8").length);
- } catch (UnsupportedEncodingException e) {
- Debug.logError(e, module);
- }
-
- try {
- Writer writer = response.getWriter();
- writer.write(responseMsg);
- writer.close();
- } catch (IOException e) {
- Debug.logError(e, module);
- }
- }
- // Remove the temporary ship address
try {
- shipAddress.remove();
- } catch (GenericEntityException e) {
+ Writer writer = response.getWriter();
+ writer.write(responseMsg);
+ writer.close();
+ } catch (IOException e) {
Debug.logError(e, module);
}
}
+ // Remove the temporary ship address
+ try {
+ GenericValue postalAddress = delegator.findOne("PostalAddress", false, UtilMisc.toMap("contactMechId", contactMechId));
+ postalAddress.remove();
+ GenericValue contactMech = delegator.findOne("ContactMech", false, UtilMisc.toMap("contactMechId", contactMechId));
+ contactMech.remove();
+ } catch (GenericEntityException e) {
+ Debug.logError(e, module);
+ }
+ coh.setCheckOutShippingAddress(oldShipAddress);
return ServiceUtil.returnSuccess();
}
@@ -337,7 +340,7 @@
//NOTE: The docs say this is optional but then won't work without it
encoder.add("MAXAMT", cart.getSubTotal().add(otherAdjustments).setScale(2).toPlainString());
}
-
+
public static Map<String, Object> getExpressCheckout(DispatchContext dctx, Map<String, Object> context) {
LocalDispatcher dispatcher = dctx.getDispatcher();
GenericDelegator delegator = dctx.getDelegator();
@@ -356,7 +359,7 @@
} else {
return ServiceUtil.returnError("Express Checkout token not present in cart, cannot get checkout details.");
}
-
+
NVPDecoder decoder;
try {
decoder = sendNVPRequest(payPalConfig, encoder);
@@ -368,7 +371,7 @@
if (UtilValidate.isNotEmpty(decoder.get("NOTE"))) {
cart.addOrderNote(decoder.get("NOTE"));
}
-
+
if (cart.getUserLogin() == null) {
try {
GenericValue userLogin = delegator.findOne("UserLogin", false, "userLoginId", "anonymous");
@@ -576,12 +579,27 @@
Debug.log(e.getMessage());
}
}
-
- // Load the selected shipping method
+
+ // Load the selected shipping method - thanks to PayPal's less than sane API all we've to work with is the shipping option label
+ // that was shown to the customer
String shipMethod = decoder.get("SHIPPINGOPTIONNAME");
- String[] shipMethodSplit = shipMethod.split("@");
- cart.setShipmentMethodTypeId(shipMethodSplit[0]);
- cart.setCarrierPartyId(shipMethodSplit[1]);
+ if ("Calculated Offline".equals(shipMethod)) {
+ cart.setCarrierPartyId("_NA_");
+ cart.setShipmentMethodTypeId("NO_SHIPPING");
+ } else {
+ String[] shipMethodSplit = shipMethod.split(" - ");
+ cart.setCarrierPartyId(shipMethodSplit[0]);
+ String shippingMethodTypeDesc = StringUtils.join(shipMethodSplit, " - ", 1, shipMethodSplit.length);
+ try {
+ EntityCondition cond = EntityCondition.makeCondition(
+ UtilMisc.toMap("productStoreId", cart.getProductStoreId(), "partyId", shipMethodSplit[0], "roleTypeId", "CARRIER", "description", shippingMethodTypeDesc)
+ );
+ GenericValue shipmentMethod = EntityUtil.getFirst(delegator.findList("ProductStoreShipmentMethView", cond, null, null, null, false));
+ cart.setShipmentMethodTypeId(shipmentMethod.getString("shipmentMethodTypeId"));
+ } catch (GenericEntityException e1) {
+ Debug.logError(e1, module);
+ }
+ }
//Get rid of any excess ship groups
List<CartShipInfo> shipGroups = cart.getShipGroups();
for (int i = 1; i < shipGroups.size(); i++) {
@@ -609,7 +627,7 @@
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
-
+
// Create the PayPal payment method
inMap.clear();
inMap.put("userLogin", cart.getUserLogin());
@@ -627,11 +645,11 @@
return ServiceUtil.returnError(e.getMessage());
}
String paymentMethodId = (String) outMap.get("paymentMethodId");
-
+
cart.clearPayments();
BigDecimal maxAmount = cart.getGrandTotal().setScale(2, BigDecimal.ROUND_HALF_UP);
cart.addPaymentAmount(paymentMethodId, maxAmount, true);
-
+
return ServiceUtil.returnSuccess();
}
@@ -672,7 +690,7 @@
encoder.add("ITEMAMT", subTotal.toPlainString());
encoder.add("SHIPPINGAMT", shippingTotal.toPlainString());
encoder.add("TAXAMT", taxTotal.toPlainString());
-
+
NVPDecoder decoder = null;
try {
decoder = sendNVPRequest(payPalPaymentSetting, encoder);
@@ -702,7 +720,7 @@
inMap.put("userLogin", userLogin);
inMap.put("paymentMethodId", payPalPaymentMethod.get("paymentMethodId"));
inMap.put("transactionId", decoder.get("TRANSACTIONID"));
-
+
Map<String, Object> outMap = null;
try {
outMap = dispatcher.runSync("updatePayPalPaymentMethod", inMap);
@@ -724,7 +742,7 @@
GenericValue payPalPaymentMethod = (GenericValue) context.get("payPalPaymentMethod");
OrderReadHelper orh = new OrderReadHelper(delegator, orderId);
GenericValue payPalConfig = getPaymentMethodGatewayPayPal(dctx, context, PaymentGatewayServices.AUTH_SERVICE_TYPE);
-
+
NVPEncoder encoder = new NVPEncoder();
encoder.add("METHOD", "DoAuthorization");
encoder.add("TRANSACTIONID", payPalPaymentMethod.getString("transactionId"));
@@ -743,11 +761,11 @@
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
-
+
if (decoder == null) {
return ServiceUtil.returnError("An unknown error occurred while contacting PayPal");
}
-
+
Map<String, Object> result = ServiceUtil.returnSuccess();
Map<String, String> errors = getErrorMessageMap(decoder);
if (UtilValidate.isNotEmpty(errors)) {
@@ -777,14 +795,14 @@
if (authTrans == null) {
authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
}
-
+
NVPEncoder encoder = new NVPEncoder();
encoder.add("METHOD", "DoCapture");
encoder.add("AUTHORIZATIONID", authTrans.getString("referenceNum"));
encoder.add("AMT", captureAmount.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
encoder.add("CURRENCYCODE", authTrans.getString("currencyUomId"));
encoder.add("COMPLETETYPE", "NotComplete");
-
+
NVPDecoder decoder = null;
try {
decoder = sendNVPRequest(payPalConfig, encoder);
@@ -792,11 +810,11 @@
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
-
+
if (decoder == null) {
return ServiceUtil.returnError("An unknown error occurred while contacting PayPal");
}
-
+
Map<String, Object> result = ServiceUtil.returnSuccess();
Map<String, String> errors = getErrorMessageMap(decoder);
if (UtilValidate.isNotEmpty(errors)) {
@@ -835,7 +853,7 @@
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
-
+
if (decoder == null) {
return ServiceUtil.returnError("An unknown error occurred while contacting PayPal");
}
@@ -883,7 +901,7 @@
Debug.logError(e, module);
return ServiceUtil.returnError(e.getMessage());
}
-
+
if (decoder == null) {
return ServiceUtil.returnError("An unknown error occurred while contacting PayPal");
}
@@ -934,7 +952,7 @@
}
if (paymentGatewayConfigId != null) {
try {
- payPalGatewayConfig = delegator.findOne("PaymentGatewayPayPal", true, "paymentGatewayConfigId", paymentGatewayConfigId);
+ payPalGatewayConfig = delegator.findOne("PaymentGatewayPayPal", true, "paymentGatewayConfigId", paymentGatewayConfigId);
} catch (GenericEntityException e) {
Debug.logError(e, module);
}
@@ -966,7 +984,7 @@
return decoder;
}
-
+
private static String getCountryGeoIdFromGeoCode(String geoCode, GenericDelegator delegator) {
String geoId = null;
try {
@@ -986,10 +1004,13 @@
public TokenWrapper(String theString) {
this.theString = theString;
}
-
+
@Override
public boolean equals(Object o) {
- return theString.equals(o);
+ if (o == null) return false;
+ if (!(o instanceof TokenWrapper)) return false;
+ TokenWrapper other = (TokenWrapper) o;
+ return theString.equals(other.theString);
}
@Override
public int hashCode() {