Java tutorial
/* * Copyright 2009 Denys Pavlov, Igor Azarnyi * * Licensed 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.yes.cart.payment.impl; import org.apache.commons.lang.SerializationUtils; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.springframework.util.Assert; import org.yes.cart.payment.PaymentGatewayExternalForm; import org.yes.cart.payment.dto.Payment; import org.yes.cart.payment.dto.PaymentGatewayFeature; import org.yes.cart.payment.dto.PaymentMiscParam; import org.yes.cart.payment.dto.impl.PaymentGatewayFeatureImpl; import org.yes.cart.payment.dto.impl.PaymentImpl; import org.yes.cart.util.HttpParamsUtils; import org.yes.cart.util.ShopCodeContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.UUID; /** * User: Igor Azarny iazarny@yahoo.com * Date: 12/14/11 * Time: 2:33 PM */ public class PayPalExpressCheckoutPaymentGatewayImpl extends AbstractPayPalPaymentGatewayImpl implements PaymentGatewayExternalForm { private static final String EQ = "="; private static final String AND = "&"; private final static PaymentGatewayFeature paymentGatewayFeature = new PaymentGatewayFeatureImpl(false, false, false, true, false, false, false, true, true, false, null, false, false); /** * {@inheritDoc} */ public PaymentGatewayFeature getPaymentGatewayFeatures() { return paymentGatewayFeature; } /** * Get the POST url for form * may be vary for sandbox and real payment gateway * possible values are: */ public String getPostActionUrl() { //must be special mounted page in UI return "paymentpaypalexpress"; } /** * {@inheritDoc} */ public String getSubmitButton() { return getParameterValue(PP_SUBMIT_BTN); } /** * {@inheritDoc} */ public Payment authorizeCapture(final Payment paymentIn) { final Payment payment = (Payment) SerializationUtils.clone(paymentIn); payment.setTransactionOperation(AUTH_CAPTURE); try { final Map<String, String> paymentResult = doDoExpressCheckoutPayment( payment.getTransactionRequestToken(), payment.getTransactionReferenceId(), payment.getPaymentAmount(), payment.getOrderCurrency()); final CallbackResult res = getExternalCallbackResult(paymentResult); payment.setPaymentProcessorResult(res.getStatus()); payment.setPaymentProcessorBatchSettlement(res.isSettled()); } catch (IOException e) { payment.setPaymentProcessorResult(Payment.PAYMENT_STATUS_FAILED); payment.setPaymentProcessorBatchSettlement(false); ShopCodeContext.getLog(this).error(e.getMessage(), e); } return payment; } /** * {@inheritDoc} */ public Payment authorize(final Payment paymentIn) { final Payment payment = (Payment) SerializationUtils.clone(paymentIn); payment.setTransactionOperation(AUTH); payment.setTransactionReferenceId(UUID.randomUUID().toString()); payment.setTransactionAuthorizationCode(UUID.randomUUID().toString()); payment.setPaymentProcessorResult(Payment.PAYMENT_STATUS_MANUAL_PROCESSING_REQUIRED); payment.setPaymentProcessorBatchSettlement(false); return payment; } /** * {@inheritDoc} */ public Payment reverseAuthorization(final Payment paymentIn) { final Payment payment = (Payment) SerializationUtils.clone(paymentIn); payment.setTransactionOperation(REVERSE_AUTH); payment.setTransactionReferenceId(UUID.randomUUID().toString()); payment.setTransactionAuthorizationCode(UUID.randomUUID().toString()); payment.setPaymentProcessorResult(Payment.PAYMENT_STATUS_MANUAL_PROCESSING_REQUIRED); payment.setPaymentProcessorBatchSettlement(false); return payment; } /** * {@inheritDoc} */ public Payment capture(final Payment paymentIn) { final Payment payment = (Payment) SerializationUtils.clone(paymentIn); payment.setTransactionOperation(CAPTURE); payment.setTransactionReferenceId(UUID.randomUUID().toString()); payment.setTransactionAuthorizationCode(UUID.randomUUID().toString()); payment.setPaymentProcessorResult(Payment.PAYMENT_STATUS_MANUAL_PROCESSING_REQUIRED); payment.setPaymentProcessorBatchSettlement(false); return payment; } /** * {@inheritDoc} */ public Payment voidCapture(final Payment paymentIn) { final Payment payment = (Payment) SerializationUtils.clone(paymentIn); payment.setTransactionOperation(VOID_CAPTURE); payment.setTransactionReferenceId(UUID.randomUUID().toString()); payment.setTransactionAuthorizationCode(UUID.randomUUID().toString()); payment.setPaymentProcessorResult(Payment.PAYMENT_STATUS_MANUAL_PROCESSING_REQUIRED); payment.setPaymentProcessorBatchSettlement(false); return payment; } /** * {@inheritDoc} */ public Payment refund(final Payment paymentIn) { final Payment payment = (Payment) SerializationUtils.clone(paymentIn); payment.setTransactionOperation(REFUND); payment.setTransactionReferenceId(UUID.randomUUID().toString()); payment.setTransactionAuthorizationCode(UUID.randomUUID().toString()); payment.setPaymentProcessorResult(Payment.PAYMENT_STATUS_MANUAL_PROCESSING_REQUIRED); payment.setPaymentProcessorBatchSettlement(false); return payment; } /** * {@inheritDoc} */ public String restoreOrderGuid(final Map privateCallBackParameters) { return HttpParamsUtils.getSingleValue(privateCallBackParameters.get(ORDER_GUID)); } /** * Get the express checkout details via GetExpressCheckoutDetails method of * pay pal payment gateway * * @param token the token obtained via SetExpressCheckout method * @param payerId the token obtained via GetExpressCheckoutDetails method * @param amount the amount * @return map of parsed key - values with detail information * @throws java.io.IOException in case of errors */ public Map<String, String> doDoExpressCheckoutPayment(final String token, final String payerId, final BigDecimal amount, final String currencyCode) throws IOException { Assert.notNull(token, "The pay pal tonek must be not null"); Assert.notNull(payerId, "Payer must be provided"); Assert.notNull(amount, "Amount must be provided"); Assert.isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "Amount must be positive"); Assert.notNull(currencyCode, "Currency code must be provided"); final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(PP_EC_TOKEN); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(token)); stringBuilder.append(AND); stringBuilder.append(PP_EC_PAYERID); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(payerId)); stringBuilder.append(AND); stringBuilder.append(PP_EC_PAYMENTREQUEST_0_AMT); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode("" + amount)); stringBuilder.append(AND); stringBuilder.append(PP_EC_PAYMENTREQUEST_0_CURRENCYCODE); stringBuilder.append(EQ); stringBuilder.append(currencyCode); stringBuilder.append(AND); stringBuilder.append(PP_EC_PAYMENTREQUEST_0_PAYMENTACTION); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode("Sale")); return performHttpCall("DoExpressCheckoutPayment", stringBuilder.toString()); } /** * Get the express checkout details via GetExpressCheckoutDetails method of * pay pal payment gateway * * @param token the token obtained via SetExpressCheckout method * @return map of parsed key - values with detail information * @throws java.io.IOException in case of errors */ public Map<String, String> getExpressCheckoutDetails(final String token) throws IOException { Assert.notNull(token, "The pay pal token must be not null"); final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(PP_EC_TOKEN); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(token)); return performHttpCall("GetExpressCheckoutDetails", stringBuilder.toString()); } /** * Support for pp express checkout. In case if gateway not support this operation , return will be empty hashmap. * * All info about SetExpressCheckout see here: * https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_nvp_r_SetExpressCheckout * * @param amount amount * @param currencyCode currecny * @return map with auth token * @throws java.io.IOException in case of errors */ public Map<String, String> setExpressCheckoutMethod(final BigDecimal amount, final String currencyCode) throws IOException { Assert.notNull(amount, "Amount must be provided"); Assert.isTrue(amount.compareTo(BigDecimal.ZERO) > 0, "Amount must be positive"); Assert.notNull(currencyCode, "Currency code must be provided"); final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(PP_EC_PAYMENTREQUEST_0_AMT); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode("" + amount)); stringBuilder.append(AND); stringBuilder.append(PP_EC_PAYMENTREQUEST_0_PAYMENTACTION); stringBuilder.append(EQ); stringBuilder.append("Sale"); stringBuilder.append(AND); stringBuilder.append(PP_EC_RETURNURL); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(getParameterValue(PP_EC_RETURNURL))); stringBuilder.append(AND); stringBuilder.append(PP_EC_CANCELURL); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(getParameterValue(PP_EC_CANCELURL))); stringBuilder.append(AND); stringBuilder.append(PP_EC_NOSHIPPING); stringBuilder.append(EQ); stringBuilder.append("1"); stringBuilder.append(AND); stringBuilder.append(PP_EC_PAYMENTREQUEST_0_CURRENCYCODE); stringBuilder.append(EQ); stringBuilder.append(currencyCode); return performHttpCall("SetExpressCheckout", stringBuilder.toString()); } private Map<String, String> performHttpCall(final String method, final String nvpStr) throws IOException { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(PP_EC_METHOD); stringBuilder.append(EQ); stringBuilder.append(method); stringBuilder.append(AND); stringBuilder.append(PP_EC_VERSION); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode("2.3")); stringBuilder.append(AND); stringBuilder.append("PWD"); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(getParameterValue(PP_API_USER_PASSWORD))); stringBuilder.append(AND); stringBuilder.append("USER"); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(getParameterValue(PP_API_USER_NAME))); stringBuilder.append(AND); stringBuilder.append(PP_SIGNATURE); stringBuilder.append(EQ); stringBuilder.append(URLEncoder.encode(getParameterValue(PP_SIGNATURE))); stringBuilder.append(AND); stringBuilder.append(nvpStr); return deformatNVP(performPayPalApiCall(stringBuilder.toString())); } private String performPayPalApiCall(final String callParams) throws IOException { ShopCodeContext.getLog(this).info( "PayPalExpressCheckoutPaymentGatewayImpl#performPayPalApiCall call parameters : {}", callParams); final StringBuilder respBuilder = new StringBuilder(); final HttpPost httpPost = new HttpPost(getParameterValue(PP_EC_API_URL)); httpPost.setEntity(new StringEntity(callParams)); final DefaultHttpClient client = new DefaultHttpClient(); final HttpResponse response = client.execute(httpPost); final BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); String _line; while (((_line = rd.readLine()) != null)) { respBuilder.append(_line); } ShopCodeContext.getLog(this) .info("PayPalExpressCheckoutPaymentGatewayImpl#performPayPalApiCall response : {}", respBuilder); return respBuilder.toString(); } /** * Check the result for success attributes. * * * @param callbackResult call result * @return true in case of success */ public CallbackResult getExternalCallbackResult(final Map<String, String> callbackResult) { if ((callbackResult.get("ACK") != null && callbackResult.get("ACK").equalsIgnoreCase("Success"))) { return CallbackResult.OK; } return CallbackResult.FAILED; } /** {@inheritDoc} */ public void handleNotification(final HttpServletRequest request, final HttpServletResponse response) { //nothing to do } /** * ****************************************************************************** * deformatNVP: Function to break the NVP string into a HashMap * pPayLoad is the NVP string. * returns a HashMap object containing all the name value pairs of the string. * ******************************************************************************* * * @param pPayload given string * @return map */ public Map<String, String> deformatNVP(final String pPayload) { Map<String, String> nvp = new HashMap<String, String>(); StringTokenizer stTok = new StringTokenizer(pPayload, AND); while (stTok.hasMoreTokens()) { StringTokenizer stInternalTokenizer = new StringTokenizer(stTok.nextToken(), EQ); if (stInternalTokenizer.countTokens() == 2) { try { String key = URLDecoder.decode(stInternalTokenizer.nextToken(), "UTF-8"); String value = URLDecoder.decode(stInternalTokenizer.nextToken(), "UTF-8"); nvp.put(key.toUpperCase(), value); } catch (UnsupportedEncodingException e) { ShopCodeContext.getLog(this).error("Unable to decode NVP payload " + pPayload, e); } } } return nvp; } /** * {@inheritDoc} * All fields are hidden, hence not need to localize and etc. */ public String getHtmlForm(final String cardHolderName, final String locale, final BigDecimal amount, final String currencyCode, final String orderGuid, final Payment payment) { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(getHiddenField(ORDER_GUID, orderGuid)); // this will be bypassed via payment gateway to restore it latter return stringBuilder.toString(); } /** * {@inheritDoc} */ public Payment createPaymentPrototype(final String operation, final Map parametersMap) { final Payment payment = new PaymentImpl(); final Map<String, String> params = HttpParamsUtils.createSingleValueMap(parametersMap); payment.setTransactionRequestToken(params.get("TOKEN")); payment.setTransactionReferenceId(params.get("PAYERID")); payment.setTransactionAuthorizationCode(params.get("CORRELATIONID")); final CallbackResult res = getExternalCallbackResult(parametersMap); payment.setPaymentProcessorResult(res.getStatus()); payment.setPaymentProcessorBatchSettlement(res.isSettled()); payment.setShopperIpAddress(params.get(PaymentMiscParam.CLIENT_IP)); return payment; } /** * {@inheritDoc} */ public String getLabel() { return "payPalExpressPaymentGateway"; } }