From daaa969db5e4763032283f9d5c17ed6656252640 Mon Sep 17 00:00:00 2001 From: phib Date: Mon, 15 Feb 2010 23:35:13 +0000 Subject: [PATCH] Payflow payment processor SDK 4 Link to SF Tracker: http://sourceforge.net/support/tracker.php?aid=2792045 --- .classpath | 1 + .../org/compiere/model/PP_PayFlowPro4.java | 272 ++++++++++++++++++ tools/build.xml | 6 + 3 files changed, 279 insertions(+) create mode 100644 base/src/org/compiere/model/PP_PayFlowPro4.java diff --git a/.classpath b/.classpath index 15bed53638..a81a7e3bad 100644 --- a/.classpath +++ b/.classpath @@ -137,5 +137,6 @@ + diff --git a/base/src/org/compiere/model/PP_PayFlowPro4.java b/base/src/org/compiere/model/PP_PayFlowPro4.java new file mode 100644 index 0000000000..7b2e1772c3 --- /dev/null +++ b/base/src/org/compiere/model/PP_PayFlowPro4.java @@ -0,0 +1,272 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * + * This program is free software; you can redistribute it and/or modify it * + * under the terms version 2 of the GNU General Public License as published * + * by the Free Software Foundation. This program is distributed in the hope * + * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * + * For the text or an alternative of this public license, you may reach us * + * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * + * or via info@compiere.org or http://www.compiere.org/license.html * + *****************************************************************************/ +package org.compiere.model; + +import java.io.*; +import java.math.RoundingMode; +import java.util.*; +import java.util.logging.*; + +import org.compiere.util.Util; + +import paypal.payflow.ClientInfo; +import paypal.payflow.PayflowAPI; +import paypal.payflow.SDKProperties; + + +/** + * Payment Processor for PayPal PayFlow Pro SDK 4. + * + * @author Jorg Janke + * @author Paul Bowden updated to SDK version 4 + */ +public final class PP_PayFlowPro4 extends PaymentProcessor + implements Serializable +{ + /** + * + */ + private static final long serialVersionUID = -3904174878402449633L; + + /** + * PayFowPro Constructor + */ + public PP_PayFlowPro4() + { + super(); + + } // PP_PayFowPro + + // Payment System */ + private PayflowAPI m_pp = null; + private boolean m_ok = false; + + protected final static String RESULT_OK = "0"; + protected final static String RESULT_DECLINED = "12"; + protected final static String RESULT_INVALID_NO = "23"; + protected final static String RESULT_INVALID_EXP = "24"; + protected final static String RESULT_INSUFFICIENT_FUNDS = "50"; + protected final static String RESULT_TIMEOUT_PROCESSOR = "104"; + protected final static String RESULT_TIMEOUT_HOST = "109"; + + /** + * Get Version + * @return version + */ + public String getVersion() + { + return "PayFlowPro " + m_pp.getVersion(); + } // getVersion + + /** + * Process CreditCard (no date check) + * @return true if processed successfully + * @throws IllegalArgumentException + */ + public boolean processCC () throws IllegalArgumentException + { + log.fine(p_mpp.getHostAddress() + " " + p_mpp.getHostPort() + ", Timeout=" + getTimeout() + + "; Proxy=" + p_mpp.getProxyAddress() + " " + p_mpp.getProxyPort() + " " + p_mpp.getProxyLogon() + " " + p_mpp.getProxyPassword()); + + if ( p_mpp.getC_Currency_ID() != 0 && p_mpp.getC_Currency_ID() != p_mp.getC_Currency_ID() ) + throw new IllegalArgumentException("Payment currency not supported by processor."); + if ( p_mpp.getMinimumAmt().compareTo(p_mp.getPayAmt()) > 0) + throw new IllegalArgumentException("Payment amount is less than minimum accepted."); + if ( p_mpp.isRequireVV() && Util.isEmpty(p_mp.getCreditCardVV(), true) ) + throw new IllegalArgumentException("Credit card verification code required."); + + + // + StringBuffer param = new StringBuffer(); + // Transaction Type + if (p_mp.getTrxType().equals(MPayment.TRXTYPE_Sales)) + param.append("TRXTYPE=").append(p_mp.getTrxType()); + else + throw new IllegalArgumentException("PP_PayFlowPro TrxType not supported - " + p_mp.getTrxType()); + + // Mandatory Fields + param.append("&TENDER=C") // CreditCard + .append("&ACCT=").append(MPaymentValidate.checkNumeric(p_mp.getCreditCardNumber())); // CreditCard No + param.append("&EXPDATE="); // ExpNo + String month = String.valueOf(p_mp.getCreditCardExpMM()); + if (month.length() == 1) + param.append("0"); + param.append(month); + int expYY = p_mp.getCreditCardExpYY(); + if (expYY > 2000) + expYY -= 2000; + String year = String.valueOf(expYY); + if (year.length() == 1) + param.append("0"); + param.append(year); + + // CURRENCY + int precision = 2; // cents + I_C_Currency currency = null; + currency = p_mp.getC_Currency(); + if ( currency != null ) + { + precision = currency.getStdPrecision(); + param.append(createPair("&CURRENCY", currency.getISO_Code(), 3)); + } + // rounded to cent + param.append("&AMT=").append(p_mp.getPayAmt().setScale(precision, RoundingMode.HALF_UP)); // Amount + + // Optional Control Fields - AuthCode & Orig ID + param.append(createPair("&AUTHCODE", p_mp.getVoiceAuthCode(), 6)); + param.append(createPair("&ORIGID", p_mp.getOrig_TrxID(), 12)); // PNREF - returned + // CVV + param.append(createPair("&CVV2", p_mp.getCreditCardVV(), 4)); + // param.append(createPair("&SWIPE", p_mp.getXXX(), 80)); // Track 1+2 + + // Address + param.append(createPair("&NAME", p_mp.getA_Name(), 30)); + param.append(createPair("&STREET", p_mp.getA_Street(), 30)); // Street + param.append(createPair("&ZIP", p_mp.getA_Zip(), 9)); // Zip 5-9 + // CITY 20, STATE 2, + param.append(createPair("&EMAIL", p_mp.getA_EMail(), 64)); // EMail + + // Amex Fields + // DESC, SHIPTOZIP, TAXAMT + // param.append(createPair("&DESC", p_mp.getXXX(), 23)); // Description + param.append(createPair("&SHIPTOZIP", p_mp.getA_Zip(), 6)); // Zip 6 + param.append(createPair("&TAXAMT", p_mp.getTaxAmt(), 10)); // Tax + + // Invoice No + param.append(createPair("&INVNUM", p_mp.getC_Invoice_ID(), 9)); + + // COMMENT1/2 + param.append(createPair("&COMMENT1", p_mp.getC_Payment_ID(), 128)); // Comment + param.append(createPair("&COMMENT2", p_mp.getC_BPartner_ID(), 128)); // Comment2 + + return process(param.toString()); + + } + // processCC + + /** + * Process Transaction + * @param parameter Command String + * @return true if processed successfully + */ + public boolean process (String parameter) + { + long start = System.currentTimeMillis(); + StringBuffer param = new StringBuffer(parameter); + // Usr/Pwd + param + .append("&PARTNER=").append(p_mpp.getPartnerID()) + .append("&VENDOR=").append(p_mpp.getVendorID()) + .append("&USER=").append(p_mpp.getUserID()) + .append("&PWD=").append(p_mpp.getPassword()); + // PCI DSS don't log private data + // log.fine("-> " + param.toString()); + + + SDKProperties.setHostAddress(p_mpp.getHostAddress()); + SDKProperties.setHostPort(p_mpp.getHostPort()); + SDKProperties.setTimeOut(getTimeout()); + + SDKProperties.setProxyAddress(p_mpp.getProxyAddress()); + SDKProperties.setProxyPort(p_mpp.getProxyPort()); + SDKProperties.setProxyLogin(p_mpp.getProxyLogon()); + SDKProperties.setProxyPassword(p_mpp.getProxyPassword()); + + //Logging is by default off. To turn logging on uncomment the following lines: + //SDKProperties.setLogFileName("payflow_java.log"); + //SDKProperties.setLoggingLevel(PayflowConstants.SEVERITY_DEBUG); + //SDKProperties.setMaxLogFileSize(1000000); + //SDKProperties.setStackTraceOn(true); + // Create an instance of PayflowAPI. + + m_pp = new PayflowAPI(); + + + // RequestId is a unique string that is required for each & every transaction. + // The merchant can use her/his own algorithm to generate this unique request id or + // use the SDK provided API to generate this as shown below (PayflowAPI.generateRequestId). + String requestId = m_pp.generateRequestId(); + String response = m_pp.submitTransaction(param.toString(), requestId); + + // Create a new Client Information data object. + ClientInfo clInfo = new ClientInfo(); + + // Set the ClientInfo object of the PayflowAPI. + m_pp.setClientInfo(clInfo); + + + // Following lines of code are optional. + // Begin optional code for displaying SDK errors ... + // It is used to read any errors that might have occured in the SDK. + // Get the transaction errors. + + String transErrors = m_pp.getTransactionContext().toString(); + if (transErrors != null && transErrors.length() > 0) { + log.log(Level.SEVERE, "Transaction Errors from SDK = \n" + transErrors); + } + + + p_mp.setR_Result(""); + p_mp.setR_Info(response); // complete info + + // RESULT=1&PNREF=PN0001480030&RESPMSG=Invalid User Authentication + // RESULT=0&PNREF=P60501480167&RESPMSG=Approved&AUTHCODE=010101&AVSADDR=X&AVSZIP=X + // RESULT=-31&RESPMSG=The certificate chain did not validate, no local certificate found, javax.net.ssl.SSLException: Cert Path = C:\Adempiere\lib, Working Directory = C:\Adempiere\adempiere-all2\client\temp + StringTokenizer st = new StringTokenizer(response, "&", false); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + int pos = token.indexOf('='); + String name = token.substring(0, pos); + String value = token.substring(pos+1); + // + if (name.equals("RESULT")) + { + p_mp.setR_Result (value); + m_ok = RESULT_OK.equals(value); + } + else if (name.equals("PNREF")) + p_mp.setR_PnRef(value); + else if (name.equals("RESPMSG")) + p_mp.setR_RespMsg(value); + else if (name.equals("AUTHCODE")) + p_mp.setR_AuthCode(value); + else if (name.equals("AVSADDR")) + p_mp.setR_AvsAddr(value); + else if (name.equals("AVSZIP")) + p_mp.setR_AvsZip(value); + else if (name.equals("IAVS")) // N=YSA, Y=International + ; + else if (name.equals("CVV2MATCH")) // Y/N X=not supported + ; + else + log.log(Level.SEVERE, "Response unknown = " + token); + } + // Problems with rc (e.g. 0 with Result=24) + return m_ok; + } // process + + /** + * Payment is processed successfully + * @return true if OK + */ + public boolean isProcessedOK() + { + return m_ok; + } // isProcessedOK + +} // PP_PayFowPro diff --git a/tools/build.xml b/tools/build.xml index d6d73556f7..8514060666 100644 --- a/tools/build.xml +++ b/tools/build.xml @@ -229,6 +229,9 @@ + + + @@ -374,6 +377,9 @@ + + +