org.ofbiz.accounting.thirdparty.verisign.PayflowPro.java Source code

Java tutorial

Introduction

Here is the source code for org.ofbiz.accounting.thirdparty.verisign.PayflowPro.java

Source

/*******************************************************************************
 * 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.accounting.thirdparty.verisign;

import java.math.BigDecimal;
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;
import org.ofbiz.base.util.string.FlexibleStringExpander;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.util.EntityUtilProperties;
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;
import paypal.payflow.SDKProperties;

/**
 * PayflowPro - Verisign PayFlow Pro <=> OFBiz Service Module
 */
public class PayflowPro {

    public static final String module = PayflowPro.class.getName();
    public final static String resource = "AccountingUiLabels";

    /**
     * Authorize credit card payment service. Service wrapper around PayFlow Pro API.
     * @param dctx Service Engine DispatchContext.
     * @param context Map context of parameters.
     * @return Response map, including RESPMSG, and RESULT keys.
     */
    public static Map<String, Object> ccProcessor(DispatchContext dctx, Map<String, ? extends Object> context) {
        Delegator delegator = dctx.getDelegator();
        GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference");
        GenericValue authTrans = (GenericValue) context.get("authTrans");
        String orderId = (String) context.get("orderId");
        String cvv2 = (String) context.get("cardSecurityCode");
        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";
        }

        boolean isPayPal = false;
        // Are we doing a cc or a paypal payment?
        if ("EXT_PAYPAL".equals(paymentPref.getString("paymentMethodTypeId"))) {
            isPayPal = true;
        }

        Map<String, String> data = FastMap.newInstance();

        boolean isReAuth = false;
        if (isPayPal) {
            data.put("TRXTYPE", "A");
            data.put("TENDER", "P");
            data.put("ORIGID", payPalPaymentMethod.getString("transactionId"));
        } else {
            if (authTrans == null) {
                authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
            }

            // 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");
            }

            // credit card tender
            data.put("TENDER", "C");

            // card security code
            if (UtilValidate.isNotEmpty(cvv2)) {
                data.put("CVV2", cvv2);
            }

            // 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);
            }

            // gather the address info
            if (ps != null) {
                String street = ps.getString("address1")
                        + ((UtilValidate.isNotEmpty(ps.getString("address2"))) ? " " + ps.getString("address2")
                                : "");
                data.put("STREET" + "[" + street.length() + "]", 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
        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, configString);

        // 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&AUTHCODE=T&PNREF=" + (new Date()).getTime() + "&RESPMSG=Testing";
        }

        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, isPayPal);
        result.put("processAmount", processAmount);
        return result;
    }

    public static Map<String, Object> ccCapture(DispatchContext dctx, Map<String, ? extends Object> context) {
        Delegator delegator = dctx.getDelegator();
        GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference");
        GenericValue authTrans = (GenericValue) context.get("authTrans");
        BigDecimal amount = (BigDecimal) context.get("captureAmount");
        String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
        String configString = (String) context.get("paymentConfig");
        Locale locale = (Locale) context.get("locale");
        if (configString == null) {
            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);
        }

        if (authTrans == null) {
            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                    "AccountingPaymentTransactionAuthorizationNotFoundCannotCapture", locale));
        }

        // auth ref number
        String refNum = authTrans.getString("referenceNum");
        Map<String, String> data = UtilMisc.toMap("ORIGID", refNum);

        // tx type (Delayed Capture)
        data.put("TRXTYPE", "D");

        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);
        }

        // amount to capture
        data.put("AMT", amount.toString());

        PayflowAPI pfp = init(delegator, paymentGatewayConfigId, configString, context);

        // get the base params
        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, configString);

        // 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&AUTHCODE=T&PNREF=" + (new Date()).getTime() + "&RESPMSG=Testing";
        }

        if (Debug.verboseOn())
            Debug.logVerbose("Response from Verisign: " + resp, module);

        // check the response
        Map<String, Object> result = ServiceUtil.returnSuccess();
        parseCaptureResponse(resp, result);
        result.put("captureAmount", amount);
        return result;
    }

    public static Map<String, Object> ccVoid(DispatchContext dctx, Map<String, ? extends Object> context) {
        Delegator delegator = dctx.getDelegator();
        GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference");
        GenericValue authTrans = (GenericValue) context.get("authTrans");
        BigDecimal amount = (BigDecimal) context.get("releaseAmount");
        String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
        String configString = (String) context.get("paymentConfig");
        Locale locale = (Locale) context.get("locale");
        if (configString == null) {
            configString = "payment.properties";
        }

        if (authTrans == null) {
            authTrans = PaymentGatewayServices.getAuthTransaction(paymentPref);
        }

        if (authTrans == null) {
            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                    "AccountingPaymentTransactionAuthorizationNotFoundCannotRelease", locale));
        }

        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);

        // tx type (Void)
        data.put("TRXTYPE", "V");

        // get the orderID
        String orderId = paymentPref.getString("orderId");

        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);

        // get the base params
        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, configString);

        // 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&AUTHCODE=T&PNREF=" + (new Date()).getTime() + "&RESPMSG=Testing";
        }

        if (Debug.verboseOn())
            Debug.logVerbose("Response from Verisign: " + resp, module);

        // check the response
        Map<String, Object> result = ServiceUtil.returnSuccess();
        parseVoidResponse(resp, result);
        result.put("releaseAmount", amount);
        return result;
    }

    public static Map<String, Object> ccRefund(DispatchContext dctx, Map<String, ? extends Object> context) {
        Delegator delegator = dctx.getDelegator();
        GenericValue paymentPref = (GenericValue) context.get("orderPaymentPreference");
        BigDecimal amount = (BigDecimal) context.get("refundAmount");
        String paymentGatewayConfigId = (String) context.get("paymentGatewayConfigId");
        String configString = (String) context.get("paymentConfig");
        Locale locale = (Locale) context.get("locale");
        if (configString == null) {
            configString = "payment.properties";
        }

        GenericValue captureTrans = PaymentGatewayServices.getCaptureTransaction(paymentPref);

        if (captureTrans == null) {
            return ServiceUtil.returnError(UtilProperties.getMessage(resource,
                    "AccountingPaymentTransactionAuthorizationNotFoundCannotRefund", locale));
        }

        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);

        // tx type (Credit)
        data.put("TRXTYPE", "C");

        // get the orderID
        String orderId = paymentPref.getString("orderId");

        if (isPayPal) {
            data.put("TENDER", "P");

            data.put("MEMO", orderId);
            // PayPal won't allow us to refund more than the capture amount
            BigDecimal captureAmount = captureTrans.getBigDecimal("amount");
            amount = amount.min(captureAmount);
        } else {
            // credit card tender
            data.put("TENDER", "C");

            data.put("COMMENT1", orderId);
        }

        // amount to capture
        data.put("AMT", amount.toString());

        PayflowAPI pfp = init(delegator, paymentGatewayConfigId, configString, context);

        // get the base params
        StringBuilder params = makeBaseParams(delegator, paymentGatewayConfigId, configString);

        // 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&AUTHCODE=T&PNREF=" + (new Date()).getTime() + "&RESPMSG=Testing";
        }

        if (Debug.verboseOn())
            Debug.logVerbose("Response from Verisign: " + resp, module);

        // check the response
        Map<String, Object> result = ServiceUtil.returnSuccess();
        parseRefundResponse(resp, result);
        result.put("refundAmount", amount);
        return result;
    }

    public static Map<String, Object> setExpressCheckout(DispatchContext dctx,
            Map<String, ? extends Object> context) {
        Delegator 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);
            return ServiceUtil.returnError(
                    UtilProperties.getMessage(resource, "AccountingPayflowErrorRetreivingCartDetails", locale));
        }

        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", false);
                parameterMap.put("SHIPTOSTATE", StringUtils.left(stateProvinceGeo.getString("geoCode"), 40));
            }
            parameterMap.put("SHIPTOZIP", StringUtils.left(shippingAddress.getString("postalCode"), 16));
            GenericValue countryGeo = shippingAddress.getRelatedOne("CountryGeo", false);
            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();
        Delegator 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));

        // 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();
        Delegator 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", false);
            payPalPaymentMethod = payPalPaymentMethod.getRelatedOne("PayPalPaymentMethod", false);
        } 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<String, String> parameters = FastMap.newInstance();
        List<String> params = StringUtil.split(resp, "&");
        for (String str : params) {
            if (str.length() > 0) {
                List<String> kv = StringUtil.split(str, "=");
                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(Delegator 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");

        // avs checking - ignore on re-auth
        boolean avsCheckOkay = true;
        String avsCode = null;
        if (!isReAuth) {
            boolean checkAvs = comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "checkAvs",
                    resource, "payment.verisign.checkAvs", "Y");
            if (checkAvs && !isSale) {
                String addAvs = (String) parameters.get("AVSADDR");
                String zipAvs = (String) parameters.get("AVSZIP");
                avsCode = addAvs + zipAvs;
                if (addAvs == null || "N".equals(addAvs) || zipAvs == null || "N".equals(zipAvs)) {
                    avsCheckOkay = false;
                }
            }
        }

        // cvv2 checking - ignore on re-auth or paypal
        boolean cvv2CheckOkay = true;
        String cvvCode = null;
        if (!isReAuth && !isPayPal) {
            boolean checkCvv2 = comparePaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "checkCvv2",
                    resource, "payment.verisign.checkCvv2", "Y");
            if (checkCvv2 && !isSale) {
                cvvCode = (String) parameters.get("CVV2MATCH");
                if (cvvCode == null || "N".equals(cvvCode)) {
                    cvv2CheckOkay = false;
                }
            }
        }

        String respCode = (String) parameters.get("RESULT");
        int codeInt = -999; // custom response code -- not from payflow docs
        try {
            codeInt = Integer.parseInt(respCode);
        } catch (NumberFormatException e) {
            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"));
        } else if (codeInt < 0) {
            // communications error
            Debug.logWarning("In PayflowPro failing authorization; respCode/RESULT=" + respCode + ", avsCheckOkay="
                    + avsCheckOkay + ", cvv2CheckOkay=" + cvv2CheckOkay + "; AUTHCODE="
                    + parameters.get("AUTHCODE"), module);
            result.put("authResult", Boolean.FALSE);
            result.put("authRefNum", respCode);
        } else if (codeInt == 0) {
            Debug.logWarning("In PayflowPro approved, but invalid flags; respCode/RESULT=" + respCode
                    + ", avsCheckOkay=" + avsCheckOkay + ", cvv2CheckOkay=" + cvv2CheckOkay + "; AUTHCODE="
                    + parameters.get("AUTHCODE"), module);
            result.put("authResult", Boolean.TRUE);
            result.put("authCode", parameters.get("AUTHCODE"));
        } else {
            // other error
            Debug.logWarning("In PayflowPro failing authorization; respCode/RESULT=" + respCode + ", avsCheckOkay="
                    + avsCheckOkay + ", cvv2CheckOkay=" + cvv2CheckOkay + "; AUTHCODE="
                    + parameters.get("AUTHCODE"), module);
            result.put("authResult", Boolean.FALSE);

            // now check certain special conditions and report back through the generic params
            if ("12".equals(respCode)) {
                result.put("resultDeclined", Boolean.TRUE);
            } else if ("50".equals(respCode)) {
                result.put("resultNsf", Boolean.TRUE);
            } else if ("23".equals(respCode)) {
                result.put("resultBadCardNumber", Boolean.TRUE);
            } else if ("24".equals(respCode)) {
                result.put("resultBadExpire", Boolean.TRUE);
            }
        }
        result.put("cvCode", cvvCode);
        result.put("avsCode", avsCode);
        result.put("authFlag", parameters.get("RESULT"));
        result.put("authMessage", parameters.get("RESPMSG"));
    }

    private static void parseCaptureResponse(String resp, Map<String, Object> result) {
        Map<String, String> parameters = parseResponse(resp);

        String respCode = (String) parameters.get("RESULT");
        int codeInt = -999; // custom response code -- not from payflow docs
        try {
            codeInt = Integer.parseInt(respCode);
        } catch (NumberFormatException e) {
            Debug.logError(e, "Unable to parse response code; not a number!", module);
        }

        if (codeInt == 0) {
            result.put("captureResult", Boolean.TRUE);
            result.put("captureCode", parameters.get("AUTHCODE"));
        } else if (codeInt < 0) {
            // communications error
            Debug.logWarning("In PayflowPro failing capture; respCode/RESULT=" + respCode + "; PNREF="
                    + parameters.get("PNREF") + "; AUTHCODE=" + parameters.get("AUTHCODE"), module);
            result.put("captureResult", Boolean.FALSE);
            result.put("captureRefNum", respCode);
        } else {
            Debug.logWarning("In PayflowPro failing capture; respCode/RESULT=" + respCode + "; PNREF="
                    + parameters.get("PNREF") + "; AUTHCODE=" + parameters.get("AUTHCODE"), module);
            result.put("captureResult", Boolean.FALSE);
        }
        result.put("captureRefNum", parameters.get("PNREF"));
        result.put("captureFlag", parameters.get("RESULT"));
        result.put("captureMessage", parameters.get("RESPMSG"));
    }

    private static void parseVoidResponse(String resp, Map<String, Object> result) {
        Map<String, String> parameters = parseResponse(resp);

        String respCode = (String) parameters.get("RESULT");
        int codeInt = -999; // custom response code -- not from payflow docs
        try {
            codeInt = Integer.parseInt(respCode);
        } catch (NumberFormatException e) {
            Debug.logError(e, "Unable to parse response code; not a number!", module);
        }

        if (codeInt == 0) {
            result.put("releaseResult", Boolean.TRUE);
            result.put("releaseCode", parameters.get("AUTHCODE"));
        } else if (codeInt < 0) {
            // communications error
            Debug.logWarning("In PayflowPro failing void; respCode/RESULT=" + respCode + "; PNREF="
                    + parameters.get("PNREF") + "; AUTHCODE=" + parameters.get("AUTHCODE"), module);
            result.put("releaseResult", Boolean.FALSE);
            result.put("releaseRefNum", respCode);
        } else {
            Debug.logWarning("In PayflowPro failing void; respCode/RESULT=" + respCode + "; PNREF="
                    + parameters.get("PNREF") + "; AUTHCODE=" + parameters.get("AUTHCODE"), module);
            result.put("releaseResult", Boolean.FALSE);
        }
        result.put("releaseRefNum", parameters.get("PNREF"));
        result.put("releaseFlag", parameters.get("RESULT"));
        result.put("releaseMessage", parameters.get("RESPMSG"));
    }

    private static void parseRefundResponse(String resp, Map<String, Object> result) {
        Map<String, String> parameters = parseResponse(resp);

        String respCode = (String) parameters.get("RESULT");
        int codeInt = -999; // custom response code -- not from payflow docs
        try {
            codeInt = Integer.parseInt(respCode);
        } catch (NumberFormatException e) {
            Debug.logError(e, "Unable to parse response code; not a number!", module);
        }

        if (codeInt == 0) {
            result.put("refundResult", Boolean.TRUE);
            result.put("refundCode", parameters.get("AUTHCODE"));
        } else if (codeInt < 0) {
            // communications error
            Debug.logWarning("In PayflowPro failing refund; respCode/RESULT=" + respCode + "; PNREF="
                    + parameters.get("PNREF") + "; AUTHCODE=" + parameters.get("AUTHCODE"), module);
            result.put("refundResult", Boolean.FALSE);
            result.put("refundRefNum", respCode);
        } else {
            Debug.logWarning("In PayflowPro failing refund; respCode/RESULT=" + respCode + "; PNREF="
                    + parameters.get("PNREF") + "; AUTHCODE=" + parameters.get("AUTHCODE"), module);
            result.put("refundResult", Boolean.FALSE);
        }
        result.put("refundRefNum", parameters.get("PNREF"));
        result.put("refundFlag", parameters.get("RESULT"));
        result.put("refundMessage", parameters.get("RESPMSG"));
    }

    private static String parseContext(Map<String, ? extends Object> context) {
        StringBuilder buf = new StringBuilder();
        Set<String> keySet = context.keySet();
        Iterator<String> i = keySet.iterator();

        while (i.hasNext()) {
            String name = (String) i.next();
            Object valueObj = context.get(name);

            if (valueObj == null || (valueObj instanceof String) && ((String) valueObj).length() == 0) {
                // not valid; do nothing
            } else {
                String value = valueObj.toString();

                // Payflow expects an unencoded name/value pair string
                buf.append(name).append("=");
                buf.append(value);
                if (i.hasNext())
                    buf.append("&");
            }
        }
        return buf.toString();
    }

    private static StringBuilder makeBaseParams(Delegator delegator, String paymentGatewayConfigId,
            String resource) {
        StringBuilder buf = new StringBuilder();

        try {
            buf.append("PARTNER=");
            buf.append(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "partner", resource,
                    "payment.verisign.partner", "VeriSign"));
            buf.append("&");
            buf.append("VENDOR=");
            buf.append(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "vendor", resource,
                    "payment.verisign.vendor", "nobody"));
            buf.append("&");
            buf.append("USER=");
            buf.append(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "userId", resource,
                    "payment.verisign.user", "nobody"));
            buf.append("&");
            buf.append("PWD=");
            buf.append(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "pwd", resource,
                    "payment.verisign.pwd", "password"));
        } catch (Exception e) {
            Debug.logError(e, module);
            return null;
        }
        return buf;
    }

    private static PayflowAPI init(Delegator delegator, String paymentGatewayConfigId, String resource,
            Map<String, ? extends Object> context) {
        // No more used
        // String certsPath = FlexibleStringExpander.expandString(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "certsPath", resource, "payment.verisign.certsPath", "pfcerts"), context);
        String hostAddress = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "hostAddress",
                resource, "payment.verisign.hostAddress", "pilot-payflowpro.paypal.com");
        Integer hostPort = Integer.decode(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                "hostPort", resource, "payment.verisign.hostPort", "443"));
        Integer timeout = Integer.decode(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "timeout",
                resource, "payment.verisign.timeout", "80"));
        String proxyAddress = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "proxyAddress",
                resource, "payment.verisign.proxyAddress", "");
        Integer proxyPort = Integer.decode(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                "proxyPort", resource, "payment.verisign.proxyPort", "80"));
        String proxyLogon = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "proxyLogon", resource,
                "payment.verisign.proxyLogon", "");
        String proxyPassword = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId, "proxyPassword",
                resource, "payment.verisign.proxyPassword", "");
        String logFileName = FlexibleStringExpander.expandString(getPaymentGatewayConfigValue(delegator,
                paymentGatewayConfigId, "logFileName", resource, "payment.verisign.logFileName", ""), context);
        Integer loggingLevel = Integer.decode(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                "loggingLevel", resource, "payment.verisign.loggingLevel", "6"));
        Integer maxLogFileSize = Integer.decode(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                "maxLogFileSize", resource, "payment.verisign.maxLogFileSize", "1000000"));
        boolean stackTraceOn = "Y".equalsIgnoreCase(getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                "stackTraceOn", resource, "payment.verisign.stackTraceOn", "N"));

        PayflowAPI pfp = new PayflowAPI(hostAddress, hostPort.intValue(), timeout.intValue(), proxyAddress,
                proxyPort.intValue(), proxyLogon, proxyPassword);
        SDKProperties.setLogFileName(logFileName);
        SDKProperties.setLoggingLevel(loggingLevel);
        SDKProperties.setMaxLogFileSize(maxLogFileSize);
        SDKProperties.setStackTraceOn(stackTraceOn);
        return pfp;
    }

    private static String getPaymentGatewayConfigValue(Delegator delegator, String paymentGatewayConfigId,
            String paymentGatewayConfigParameterName, String resource, String parameterName) {
        String returnValue = "";
        if (UtilValidate.isNotEmpty(paymentGatewayConfigId)) {
            try {
                GenericValue payflowPro = EntityQuery.use(delegator).from("PaymentGatewayPayflowPro")
                        .where("paymentGatewayConfigId", paymentGatewayConfigId).queryOne();
                if (UtilValidate.isNotEmpty(payflowPro)) {
                    Object payflowProField = payflowPro.get(paymentGatewayConfigParameterName);
                    if (payflowProField != null) {
                        returnValue = payflowProField.toString().trim();
                    }
                }
            } catch (GenericEntityException e) {
                Debug.logError(e, module);
            }
        } else {
            String value = EntityUtilProperties.getPropertyValue(resource, parameterName, delegator);
            if (value != null) {
                returnValue = value.trim();
            }
        }
        return returnValue;
    }

    private static String getPaymentGatewayConfigValue(Delegator delegator, String paymentGatewayConfigId,
            String paymentGatewayConfigParameterName, String resource, String parameterName, String defaultValue) {
        String returnValue = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                paymentGatewayConfigParameterName, resource, parameterName);
        if (UtilValidate.isEmpty(returnValue)) {
            returnValue = defaultValue;
        }
        return returnValue;
    }

    private static boolean comparePaymentGatewayConfigValue(Delegator delegator, String paymentGatewayConfigId,
            String paymentGatewayConfigParameterName, String resource, String parameterName, String compareValue) {
        boolean returnValue = false;

        String value = getPaymentGatewayConfigValue(delegator, paymentGatewayConfigId,
                paymentGatewayConfigParameterName, resource, parameterName, compareValue);
        if (UtilValidate.isNotEmpty(value)) {
            returnValue = value.trim().equalsIgnoreCase(compareValue);
        }
        return returnValue;
    }

    /*
     * RESULT values (and RESPMSG text)
     *
    0 Approved
    1 User authentication failed. Error is caused by one or more of the following:
    Login information is incorrect. Verify that USER, VENDOR, PARTNER, and
    PASSWORD have been entered correctly. See Table 3.2 on page 26 for additional
    information and field descriptions.
    Invalid Processor information entered. Contact merchant bank to verify.
    "Allowed IP Address" security feature implemented. The transaction is coming
    from an unknown IP address. See VeriSign Manager online help for details on how
    to use Manager to update the allowed IP addresses.
    You are using a test (not active) account to submit a transaction to the live VeriSign
    servers. Change the URL from pilot-payflowpro.paypal.com to payflowpro.paypal.com.
    2 Invalid tender type. Your merchant bank account does not support the following
    credit card type that was submitted.
    3 Invalid transaction type. Transaction type is not appropriate for this transaction. For
    example, you cannot credit an authorization-only transaction.
    4 Invalid amount format. Use the format: #####.##  Do not include currency
    symbols or commas.
    5 Invalid merchant information. Processor does not recognize your merchant account
    information. Contact your bank account acquirer to resolve this problem.
    6 Invalid or unsupported currency code
    7 Field format error. Invalid information entered. See RESPMSG.
    8 Not a transaction server
    9 Too many parameters or invalid stream
    10 Too many line items
    11 Client time-out waiting for response
    12 Declined. Check the credit card number, expiration date, and transaction information to
    make sure they were entered correctly. If this does not resolve the problem, have the
    customer call their card issuing bank to resolve.
    13 Referral. Transaction cannot be approved electronically but can be approved with a
    verbal authorization. Contact your merchant bank to obtain an authorization and submit
    a manual Voice Authorization transaction.
    14 Invalid Client Certification ID. Check the HTTP header. If the tag, X-VPS-VIT-
    CLIENT-CERTIFICATION-ID, is missing, RESULT code 14 is returned.
    19 Original transaction ID not found. The transaction ID you entered for this
    transaction is not valid. See RESPMSG.
    20 Cannot find the customer reference number
    22 Invalid ABA number
        
    23 Invalid account number. Check credit card number and re-submit.
    24 Invalid expiration date. Check and re-submit.
    25 Invalid Host Mapping. You are trying to process a tender type such as Discover Card,
    but you are not set up with your merchant bank to accept this card type.
    26 Invalid vendor account
    27 Insufficient partner permissions
    28 Insufficient user permissions
    29 Invalid XML document. This could be caused by an unrecognized XML tag or a bad
    XML format that cannot be parsed by the system.
    30 Duplicate transaction
    31 Error in adding the recurring profile
    32 Error in modifying the recurring profile
    33 Error in canceling the recurring profile
    34 Error in forcing the recurring profile
    35 Error in reactivating the recurring profile
    36 OLTP Transaction failed
    37 Invalid recurring profile ID
    50 Insufficient funds available in account
    99 General error. See RESPMSG.
    100 Transaction type not supported by host
    101 Time-out value too small
    102 Processor not available
    103 Error reading response from host
    104 Timeout waiting for processor response. Try your transaction again.
    105 Credit error. Make sure you have not already credited this transaction, or that this
    transaction ID is for a creditable transaction. (For example, you cannot credit an
    authorization.)
    106 Host not available
    107 Duplicate suppression time-out
        
    108 Void error. See RESPMSG. Make sure the transaction ID entered has not already been
    voided. If not, then look at the Transaction Detail screen for this transaction to see if it
    has settled. (The Batch field is set to a number greater than zero if the transaction has
    been settled). If the transaction has already settled, your only recourse is a reversal
    (credit a payment or submit a payment for a credit).
    109 Time-out waiting for host response
    111 Capture error. Either an attempt to capture a transaction that is not an authorization
    transaction type, or an attempt to capture an authorization transaction that has already
    been captured.
    112 Failed AVS check. Address and ZIP code do not match. An authorization may still
    exist on the cardholder account.
    113 Merchant sale total will exceed the sales cap with current transaction. ACH
    transactions only.
    114 Card Security Code (CSC) Mismatch. An authorization may still exist on the
    cardholder account.
    115 System busy, try again later
    116 VPS Internal error. Failed to lock terminal number
    117 Failed merchant rule check. One or more of the following three failures occurred:
    An attempt was made to submit a transaction that failed to meet the security settings
    specified on the Payflow Pro Java SDK Security Settings page. If the transaction
    exceeded the Maximum Amount security setting, then no values are returned for AVS
    or CSC.
    AVS validation failed. The AVS return value should appear in the RESPMSG.
    CSC validation failed. The CSC return value should appear in the RESPMSG.
    118 Invalid keywords found in string fields
    122 Merchant sale total will exceed the credit cap with current transaction. ACH
    transactions only.
    125 Fraud Protection Services Filter _ Declined by filters
        
    126 Fraud Protection Services Filter _ Flagged for review by filters
    Important Note: Result code 126 indicates that a transaction triggered a fraud filter.
    This is not an error, but a notice that the transaction is in a review status. The
    transaction has been authorized but requires you to review and to manually accept the
    transaction before it will be allowed to settle.
    Result code 126 is intended to give you an idea of the kind of transaction that is
    considered suspicious to enable you to evaluate whether you can benefit from using the
    Fraud Protection Services.
    To eliminate result 126, turn the filters off.
    For more information, see the User Guide for Payflow Pro With Fraud Protection
    Services or User Guide for Payflow Link Guide With Fraud Protection Services.
    127 Fraud Protection Services Filter _ Not processed by filters
    128 Fraud Protection Services Filter _ Declined by merchant after being flagged for
    review by filters
    131 Version 1 Payflow Pro SDK client no longer supported. Upgrade to the most recent
    version of the Payflow Pro client.
    150 Issuing bank timed out
    151 Issuing bank unavailable
    1000 Generic host error. This is a generic message returned by your credit card processor.
    The RESPMSG will contain more information describing the error.
    1001 Buyer Authentication Service unavailable
    1002 Buyer Authentication Service _ Transaction timeout
    1003 Buyer Authentication Service _ Invalid client version
    1004 Buyer Authentication Service _ Invalid timeout value
    1011 Buyer Authentication Service unavailable
    1012 Buyer Authentication Service unavailable
    1013 Buyer Authentication Service unavailable
    1014 Buyer Authentication Service _ Merchant is not enrolled for Buyer
    Authentication Service (3-D Secure).
    1016 Buyer Authentication Service _ 3-D Secure error response received. Instead of
    receiving a PARes response to a Validate Authentication transaction, an error response
    was received.
    1017 Buyer Authentication Service _ 3-D Secure error response is invalid. An error
    response is received and the response is not well formed for a Validate Authentication
    transaction.
        
    1021 Buyer Authentication Service _ Invalid card type
    1022 Buyer Authentication Service _ Invalid or missing currency code
    1023 Buyer Authentication Service _ merchant status for 3D secure is invalid
    1041 Buyer Authentication Service _ Validate Authentication failed: missing or
    invalid PARES
    1042 Buyer Authentication Service _ Validate Authentication failed: PARES format is
    invalid
    1043 Buyer Authentication Service _ Validate Authentication failed: Cannot find
    successful Verify Enrollment
    1044 Buyer Authentication Service _ Validate Authentication failed: Signature
    validation failed for PARES
    1045 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid amount in PARES
    1046 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid acquirer in PARES
    1047 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid Merchant ID in PARES
    1048 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid card number in PARES
    1049 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid currency code in PARES
    1050 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid XID in PARES
    1051 Buyer Authentication Service _ Validate Authentication failed: Mismatched or
    invalid order date in PARES
    1052 Buyer Authentication Service _ Validate Authentication failed: This PARES was
    already validated for a previous Validate Authentication transaction
        
     */

    /* RESULT for communication errors (less than 0)
     *
    -1 Failed to connect to host
    -2 Failed to resolve hostname
    -5 Failed to initialize SSL context
    -6 Parameter list format error: & in name
    -7 Parameter list format error: invalid [ ] name length clause
    -8 SSL failed to connect to host
    -9 SSL read failed
    -10 SSL write failed
    -11 Proxy authorization failed
    -12 Timeout waiting for response
    -13 Select failure
    -14 Too many connections
    -15 Failed to set socket options
    -20 Proxy read failed
    -21 Proxy write failed
    -22 Failed to initialize SSL certificate
    -23 Host address not specified
    -24 Invalid transaction type
    -25 Failed to create a socket
    -26 Failed to initialize socket layer
    -27 Parameter list format error: invalid [ ] name length clause
    -28 Parameter list format error: name
    -29 Failed to initialize SSL connection
    -30 Invalid timeout value
        
    -31 The certificate chain did not validate, no local certificate found
    -32 The certificate chain did not validate, common name did not match URL
    - 40 Unexpected Request ID found in request.
    - 41 Required Request ID not found in request
    - 42 Required Response ID not found in request
    - 43 Unexpected Response ID found in request
    - 44 Response ID not found in the response received from the server
    -99 Out of memory
    -100 Parameter list cannot be empty
    -103 Context initialization failed
    -104 Unexpected transaction state
    -105 Invalid name value pair request
    -106 Invalid response format
    -107 This XMLPay version is not supported
    -108 The server certificate chain did not validate
    -109 Unable to do logging
    -111 The following error occurred while initializing from message file: <Details of
    the error message>
    -113 Unable to round and truncate the currency value simultaneously
     */
}