/****************************************************************************** * 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.util.Properties; import java.util.logging.Level; import org.adempiere.util.PaymentUtil; import org.compiere.util.CLogMgt; /** * Optimal Payment Processor Services Interface. * * @author Jorg Janke * @version $Id: PP_Optimal.java,v 1.3 2006/07/30 00:51:03 jjanke Exp $ */ public class PP_Optimal extends PaymentProcessor implements Serializable { /** * */ private static final long serialVersionUID = -3588486265248400291L; /** * PP_Optimal */ public PP_Optimal () { super (); } // PP_Optimal /** Status */ private boolean m_ok = false; /** Optimal Client Version */ private static final String _CLIENT_VERSION = "1.1"; // Mandatory parameters protected static final String MERCHANT_ID = "merchantId"; protected static final String MERCHANT_PWD = "merchantPwd"; protected static final String ACCOUNT_ID = "account"; protected static final String CIPHER = "Cipher"; protected static final String PAYMENT_SERVER = "PaymentServerURL"; protected static final String PAYMENT_SERVER_PORT = "PaymentServerPort"; protected static final String PROXY_SERVER = "ProxyServer"; protected static final String PROXY_PORT = "ProxyPort"; protected static final String PROXY_USERID = "ProxyUserId"; protected static final String PROXY_PWD = "ProxyPwd"; protected static final String ACTIVE_RECOVERY = "ActiveRecovery"; protected static final String HTTPVERSION = "HTTPVersion"; // Optional parameters protected static final String RETRIES = "Retries"; protected static final String TIMEOUT = "Timeout"; protected static final String LOGLEVEL = "LogLevel"; protected static final String LOG_BASE_PATH = "LogBasePath"; protected static final String LOG_FILENAME = "LogFilename"; protected static final String LOG_MAX_SIZE = "LogMaxSize"; protected static final String LOG_MAX_BACKUP = "LogMaxBackupFiles"; // some request parameters protected static final String MERCHANT_TXN = "merchantTxn"; protected static final String MERCHANT_DATA = "merchantData"; protected static final String CLIENT_VERSION = "clientVersion"; protected static final String TXN_NUMBER = "txnNumber"; protected static final String CARD_NUMBER = "cardNumber"; protected static final String CARD_EXPIRATION = "cardExp"; protected static final String CARD_TYPE = "cardType"; protected static final String STREET = "streetAddr"; protected static final String STREET2 = "streetAddr2"; protected static final String EMAIL = "email"; protected static final String PHONE = "phone"; protected static final String PROVINCE = "province"; protected static final String COUNTRY = "country"; protected static final String CITY = "city"; protected static final String ZIP = "zip"; protected static final String CVD_INDICATOR = "cvdIndicator"; protected static final String CVD_INDICATOR_None = "0"; protected static final String CVD_INDICATOR_Provided = "1"; protected static final String CVD_VALUE = "cvdValue"; protected static final String CVD_INFO = "cvdInfo"; protected static final String CUST_NAME1 = "custName1"; protected static final String CUST_NAME2 = "custName2"; // some response parameters protected static final String STATUS = "status"; protected static final String TXN_TYPE = "txnType"; protected static final String AMOUNT = "amount"; protected static final String CURRENT_AMOUNT = "curAmount"; protected static final String ERROR_CODE = "errCode"; protected static final String ERROR_STRING = "errString"; protected static final String SUB_ERROR = "subError"; protected static final String SUB_ERROR_STRING = "subErrorString"; protected static final String AUTH_CODE = "authCode"; protected static final String AUTH_TIME = "authTime"; protected static final String AVS_INFO = "avsInfo"; // some useful constants protected static final String QUERY_OPERATION = "Q"; protected static final String FAILURE_LOOKUP_OPERATION = "FT"; /** Operation p1-8 */ protected static final String OPERATION = "operation"; protected static final String OPERATION_Purchase = "P"; protected static final String OPERATION_Authorization = "A"; protected static final String OPERATION_Settlement = "S"; // Stratus returned by Failure Lookup Request protected static final String STATUS_SEARCH_COMPLETED = "status=C" ; // Status returned by a Query Request protected static final String REQUEST_PENDING = "status=P"; protected static final String REQUEST_COMPLETE = "status=C"; protected static final String REQUEST_FAILED = "status=F"; protected static final String AUTHORIZATION_COMPLETE = "status=A"; protected static final String AUTHORIZATION_FAILED = "status=AF"; protected static final String SETTLEMENT_COMPLETE = "status=S"; protected static final String SETTLEMENT_FAILED = "status=SF"; protected static final String MANUAL_INTERVENTION = "status=M"; protected static final String REQUEST_ABORTED = "status=AB"; protected static final String REQUEST_NOT_FOUND = "status=NF"; protected static final String UNKNOWN_TYPE = "status=U"; protected static final String REQUEST_ERROR = "status=E"; /** AVS Codes */ protected static Properties AVSCodes = new Properties(); /** Card Types */ protected static Properties CARDTypes = new Properties(); /** CVD Info */ protected static Properties CVDInfo = new Properties(); static { // Page 1-9 AVSCodes.put("X", "Exact. Nine digit zip and address match"); AVSCodes.put("Y", "Yes. Five digit zip and address match"); AVSCodes.put("A", "Address matches, Zip not"); AVSCodes.put("W", "Nine digit zip matches, address not"); AVSCodes.put("Z", "Five digit zip matches, address not"); AVSCodes.put("N", "No Part matches"); AVSCodes.put("U", "Address info unavailable"); AVSCodes.put("R", "Retry"); AVSCodes.put("S", "AVS not supported"); AVSCodes.put("E", "AVS not supported for this industry"); AVSCodes.put("B", "AVS not performed"); AVSCodes.put("Q", "Unknown response from issuer"); // Page 1-14 CARDTypes.put("AMEX", "AM"); CARDTypes.put("DINERS", "DI"); CARDTypes.put("VISA", "VI"); // CVD Info 1-20 CVDInfo.put("M", "Match"); CVDInfo.put("N", "No Match"); CVDInfo.put("P", "Not Processed"); CVDInfo.put("S", "Not Present"); CVDInfo.put("U", "Issuer not certified"); } /** * Get Version * @return version */ public String getVersion() { return "Optimal " + _CLIENT_VERSION; } // getVersion /** * Process CC * @return true if OK * @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()); setEncoded(true); String urlString = p_mbap.getHostAddress(); // "https://realtime.firepay.com/servlet/DPServlet"; // "https://realtime.test.firepay.com/servlet/DPServlet"; if (p_mbap.getHostPort() != 0) urlString += ":" + p_mbap.getHostPort(); /** General Parameters */ StringBuilder param = new StringBuilder(200); // Merchant username and password. param.append(createPair(MERCHANT_ID, p_mbap.getUserID(), 80)) .append(AMP).append(createPair(MERCHANT_PWD, p_mbap.getPassword(), 20)) .append(AMP).append(createPair(ACCOUNT_ID, p_mbap.getPartnerID(), 10)); // param.append(AMP).append(createPair(MERCHANT_DATA, "comment", 255)); /** Cipher supported : SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5 param.append("&Cipher=SSL_RSA_WITH_RC4_128_MD5"); // HTTP Version param.append("&HTTPVersion=1.0"); // Path to the keystore (cacerts) file. **/ param.append(AMP).append(createPair(CARD_TYPE, "VI", 6)); param.append(AMP).append(createPair(CARD_NUMBER, p_mp.getCreditCardNumber(), 19)); param.append(AMP).append(createPair(CARD_EXPIRATION, PaymentUtil.getCreditCardExp(p_mp.getCreditCardExpMM(), p_mp.getCreditCardExpYY(), "/"), 5)); param.append(AMP).append(createPair(AMOUNT, PaymentUtil.getPayAmtInCents(p_mp.getPayAmt()), 10)); param.append(AMP).append(createPair(OPERATION, OPERATION_Purchase, 1)); param.append(AMP).append(createPair(MERCHANT_TXN, p_mp.getPO().get_ID(), 255)); param.append(AMP).append(createPair(CLIENT_VERSION, _CLIENT_VERSION, 4)); param.append(AMP).append(createPair(CUST_NAME1, p_mp.getA_Name(), 255)); param.append(AMP).append(createPair(STREET, p_mp.getA_Street(), 255)); param.append(AMP).append(createPair(CITY, p_mp.getA_City(), 255)); param.append(AMP).append(createPair(PROVINCE, p_mp.getA_State(), 2)); param.append(AMP).append(createPair(ZIP, p_mp.getA_Zip(), 10)); param.append(AMP).append(createPair(COUNTRY, p_mp.getA_Country(), 2)); // param.append(AMP).append(createPair("&phone", p_mp.getA_Phone(), 40)); param.append(AMP).append(createPair("&email", p_mp.getA_EMail(), 40)); param.append(AMP).append(createPair(CVD_INDICATOR, CVD_INDICATOR_Provided, 1)); param.append(AMP).append(createPair(CVD_VALUE, "123", 4)); try { if (log.isLoggable(Level.FINE)) log.fine("-> " + param.toString()); Properties prop = getConnectPostProperties(urlString, param.toString()); m_ok = prop != null; // authCode=, authTime=1132330817, subErrorString=Card has expired: 04/04, errCode=91, clientVersion=1.1, status=E, subError=0, actionCode=CP, errString=Invalid Payment Information. Please verify request parameters. // authCode=197705, authTime=1132336527, curAmount=0, avsInfo=B, clientVersion=1.1, status=SP, amount=200, cvdInfo=M, txnNumber=1000000 if (m_ok) { String status = prop.getProperty(STATUS); m_ok = status != null && status.equals("SP"); // Successful Purchase String authCode = prop.getProperty(AUTH_CODE); @SuppressWarnings("unused") String authTime = prop.getProperty(AUTH_TIME); // @SuppressWarnings("unused") String errCode = prop.getProperty(ERROR_CODE); String errString = prop.getProperty(ERROR_STRING); @SuppressWarnings("unused") String subError = prop.getProperty(SUB_ERROR); @SuppressWarnings("unused") String subErrorString = prop.getProperty(SUB_ERROR_STRING); @SuppressWarnings("unused") String actionCode = prop.getProperty("actionCode"); // @SuppressWarnings("unused") String authorisedAmount = prop.getProperty(CURRENT_AMOUNT); @SuppressWarnings("unused") String amount = prop.getProperty(AMOUNT); @SuppressWarnings("unused") String avsInfo = prop.getProperty(AVS_INFO); @SuppressWarnings("unused") String cvdInfo = prop.getProperty(CVD_INFO); if (log.isLoggable(Level.FINE)) log.fine("<- Status=" + status + ", AuthCode=" + authCode + ", Error=" + errString); } if (!m_ok) log.warning("<- " + prop); } catch (Exception e) { log.log(Level.SEVERE, param.toString(), e); m_ok = false; } return m_ok; } // processCC /** * Is Processed OK * @return true of ok */ public boolean isProcessedOK () { return m_ok; } // isProcessedOK /** * Test * @param args ifnored */ public static void main (String[] args) { /** > Test Administration Server and Login > ----------------------------------- > The information you require to access the TEST administration server > is (case sensitivity matters): > > Web Site: https://admin.test.firepay.com > > Test Account #2 > Username: sparctwo001 > User password: abcd1234 > > Test Payment Server URL > ----------------------- > To connect your web site to our TEST payment service, your technical > people will use the following URL: > > https://realtime.test.firepay.com/servlet/DPServlet > > Test Cards > ---------- > Below are the cards you can use in the test environment. Transactions > done with these cards will either be successful or fail depending on > the amount provided with the transaction (see below). > > Visa: > 4387751111011 > 4387751111029 > 4387751111111038 > 4387751111111053 > > MasterCard: > 5442981111111015 > 5442981111111023 > 5442981111111031 > 5442981111111056 > > The following amounts will cause either approval or various declines > with the cards mentioned above: > Amount less than 20.00 = Approval > 20.00 to 29.99 = (221, 1002) Reenter > 30.00 to 39.99 = (221, 1003) Referral > 40.00 to 49.99 = (221, 1004) PickUp > 50.00 to 59.99 = (34, 1005) Decline > 60.00 to 69.99 = (2) Timeout > Amount greater than 69.99 = Approval **/ CLogMgt.initialize(true); CLogMgt.setLevel(Level.ALL); PP_Optimal pp = new PP_Optimal(); pp.processCC(); pp.isProcessedOK(); } // main } // PP_Optimal