/****************************************************************************** * 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.Serializable; import java.math.RoundingMode; import java.util.StringTokenizer; import java.util.logging.Level; 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 { if (log.isLoggable(Level.FINE)) log.fine(p_mbap.getHostAddress() + " " + p_mbap.getHostPort() + ", Timeout=" + getTimeout() + "; Proxy=" + p_mbap.getProxyAddress() + " " + p_mbap.getProxyPort() + " " + p_mbap.getProxyLogon() + " " + p_mbap.getProxyPassword()); if ( p_mbap.getC_Currency_ID() != 0 && p_mbap.getC_Currency_ID() != p_mp.getC_Currency_ID() ) throw new IllegalArgumentException("Payment currency not supported by processor."); if ( p_mbap.getMinimumAmt().compareTo(p_mp.getPayAmt()) > 0) throw new IllegalArgumentException("Payment amount is less than minimum accepted."); if ( p_mbap.isRequireVV() && Util.isEmpty(p_mp.getCreditCardVV(), true) ) throw new IllegalArgumentException("Credit card verification code required."); // StringBuilder param = new StringBuilder(); // 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.getPO().get_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) { StringBuilder param = new StringBuilder(parameter); // Usr/Pwd param .append("&PARTNER=").append(p_mbap.getPartnerID()) .append("&VENDOR=").append(p_mbap.getVendorID()) .append("&USER=").append(p_mbap.getUserID()) .append("&PWD=").append(p_mbap.getPassword()); // PCI DSS don't log private data // log.fine("-> " + param.toString()); SDKProperties.setHostAddress(p_mbap.getHostAddress()); SDKProperties.setHostPort(p_mbap.getHostPort()); SDKProperties.setTimeOut(getTimeout()); SDKProperties.setProxyAddress(p_mbap.getProxyAddress()); SDKProperties.setProxyPort(p_mbap.getProxyPort()); SDKProperties.setProxyLogin(p_mbap.getProxyLogon()); SDKProperties.setProxyPassword(p_mbap.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 occurred 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