Follow common Java practices to create a Java file inside the
src/ directory. You can give it any name and place
it in any package you want. The merchant gateway class must extend
GenericMerchantGateway:
public class MyMerchantGateway extends GenericMerchantGateway {
....
}
See documentation to the GenericMerchantGateway class and the MerchantGateway interface.
To support standard H-Sphere gateway functionality, you must import the following classes:
import psoft.epayment.GenericMerchantGateway;
import psoft.epayment.MerchantGateway;
import psoft.epayment.CreditCard;
Aside from these classes, you can import other classes offered by Psoft, gateway developers, or your own utility classes.
Your class must implement the following methods:
getValues() - return used values in a Map;init() - initialize class variables with settings
entered in the merchant gateway configuration;authorize() - initialize the transaction and put it
"on hold" to reserve, but not bill the payment amount.charge() - charge the amount immediately.capture() - finalize the initialized transaction.voidAuthorize() - cancel the initialized (authorized) transaction.
The transaction methods (authorize, charge, capture, and voidAuthorize)
return HashMaps that must be populated with data to be used in other
methods. For instance, if you initialized a transaction with the
authorize() method, and you need to pass the transaction ID
to the void() or capture() methods, you need to
put it into this HashMap. The two variables you have to put into this HashMap are:
amount - transaction amount;id - order ID (transaction ID).Other variables can be put into the HashMap optionally.
GenericMerchantGateway class doesn't include CVV by default because it's not used by most of merchant gateways.
If your merchant gateway uses CVV verification, redefine the default method GenericMerchantGateway.checkCC with the following code:
public HashMap checkCC(long acctid, CreditCard cc) throws Exception {
return checkCCCVV(acctid, cc);
}
Method GenericMerchantGateway.checkCCCVV(acctid, cc) performs AUTHORIZATION and then VOID transactions. If your merchant gateway uses CVV, make sure to add the following code right after the AUTHORIZATION and VOID transaction calls:
String cvv = cc.getCVV();
... // AUTHORIZATION call
... // VOID call
if (cvv != null && !"".equals(cvv)) {
cc.setCVVChecked(success);
}
To write messages to H-Sphere log (/var/log/hsphere/hsphere.log), create
and use an object of the org.apache.log4j.Category class.
To create an instance of the class:
For more information, see
log4j manual.
private static org.apache.log4j.Category log =
org.apache.log4j.Category.getInstance(MyMerchantGateway.class);
To write messages to ChargeLog (stored in the H-Sphere database), use the following methods:
writeLog(id, amount, trType) - call this at the beginning of the
transaction methods;writeLog(logId, id, amount, trType, request.toString(),
result.toString(), error, success) - call this after the attempt to
run a transaction.
package psoft.epayment;
import psoft.util.HttpResponse;
import psoft.util.HttpUtils;
import psoft.hsphere.Session;
import psoft.hsphere.resource.epayment.GenericCreditCard;
import java.util.Map;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.io.IOException;
public class Protx extends GenericMerchantGateway {
private String server;
private int port;
private String authpath;
private String settlepath;
private String login;
private String currency;
private String adminEmail;
private static java.text.DateFormat date
= new java.text.SimpleDateFormat("MMyy");
private static HashMap ccTypes;
static {
defaultValues.put("SERVER", "ukvpstest.protx.com");
defaultValues.put("PORT", "443");
defaultValues.put("AUTHPATH", "/VPSDirectAuth/PaymentGateway.asp");
defaultValues.put("REPEATPATH", "/vps200/dotransaction.dll");
ccTypes = new HashMap();
//supported cc types: VISA, MC, DELTA, SOLO, SWITCH or AMEX
ccTypes.put("AX", "AMEX");
}
public Map getValues() {
HashMap map = new HashMap();
map.put("SERVER", server);
map.put("PORT", Integer.toString(port));
map.put("AUTHPATH", authpath);
map.put("REPEATPATH", settlepath);
map.put("LOGIN", login);
map.put("CURRENCY", currency);
map.put("NOTIFICATIONEMAIL", adminEmail);
return null;
}
public void init(int id, HashMap values) throws Exception {
this.id = id;
server = getValue(values, "SERVER");
port = Integer.parseInt(getValue(values, "PORT"));
authpath = getValue(values, "AUTHPATH");
settlepath = getValue(values, "REPEATPATH");
login = getValue(values, "LOGIN");
currency = getValue(values, "CURRENCY");
adminEmail = getValue(values, "NOTIFICATIONEMAIL");
}
private HashMap processTransaction(int trType,
long id,
String description,
double amount,
HashMap data,
CreditCard cc) throws Exception {
long logId = writeLog(id, amount, trType);
boolean success = false;
HashMap result = new HashMap();
HashMap request = new HashMap();
HashMap response = new HashMap();
String error = "";
String path = "";
String cvv = "";
try {
request.put("VPSProtocol", "2.22");
request.put("VendorTxCode", Long.toString(logId));
request.put("Amount", formatAmount(amount));
request.put("Vendor", login);
String sCode = ISOCodes.getShortNameByISO(currency);
request.put("Currency", sCode);
request.put("Description", description);
if (trType == CHARGE || trType == AUTH) {
if (trType == CHARGE) {
request.put("TxType", "PAYMENT");
} else {
request.put("TxType", "PREAUTH");
}
request.put("CardHolder", cc.getName());
request.put("CardNumber", cc.getNumber());
request.put("ExpiryDate", cc.getExp(date));
String issuenum = cc.getIssueNo();
if (!"".equals(issuenum)) {
request.put("IssueNumber", issuenum);
}
cvv = cc.getCVV();
if (!"".equals(cvv) && cvv != null) {
//Force AVS/CV2 checks even if not enabled for the account. If rules apply, use rules.
request.put("ApplyAVSCV2", "1");
request.put("CV2", cvv);
} else if (cc.isCVVChecked() == GenericCreditCard.CVVOK) {
//Force NO AVS/CV2 checks even if enabled on account. override the default security checks.
request.put("ApplyAVSCV2", "2");
}
//request.put("CardType", cc.getType());
request.put("CardType", getCCType(cc));
request.put("Address", cc.getAddress());
request.put("PostCode", cc.getZip());
path = authpath;
} else if (trType == CAPTURE) {
request.put("service", "VendorRepeatTx");
request.put("TxType", "REPEAT");
request.put("RelatedVPSTxID", data.get("id"));
request.put("RelatedVendorTxCode", data.get("LogID"));
request.put("RelatedSecurityKey", data.get("SecurityKey"));
request.put("RelatedTxAuthNo", data.get("TxAuthNo"));
path = settlepath;
}
HttpResponse httpresponse
= HttpUtils.postForm("https", server, port, path, request);
String message = httpresponse.getBody();
result.put("response", message);
StringTokenizer st = new StringTokenizer(message, "\n");
while (st.hasMoreTokens()) {
String str = st.nextToken();
int tmppos = str.indexOf("=");
if (tmppos > 0) {
String key = str.substring(0, tmppos);
String value = "";
if (str.length() > tmppos +1) {
value = str.substring(tmppos + 1);
response.put(key, value);
}
}
}
if (response.containsKey("Status")) {
String status = (String)response.get("Status");
if ("OK".equals(status)) {
result.put("LogID", Long.toString(logId));
result.put("id", response.get("VPSTxID"));
result.put("SecurityKey", response.get("SecurityKey"));
result.put("TxAuthNo", response.get("TxAuthNo"));
result.put("amount", new Double(amount));
success = true;
}
if (!success) {
error = "Status: " + status;
if (response.containsKey("StatusDetail")) {
error += " " + response.get("StatusDetail");
}
}
}
} catch (IOException ex) {
error = "Could not connect to "
+ server + ":" + port + "/" + path;
Session.getLog().error(error, ex);
} catch (Exception ex) {
error = "Could not perform transaction";
Session.getLog().error("Could not perform transaction", ex);
}
if (request.containsKey("CV2")) {
request.remove("CV2");
request.put("CV2", "****");
}
writeLog(logId, id, amount, trType,
request.toString(), response.toString(), error, success);
if (!success)
throw new Exception(error);
if (trType == CHARGE || trType == AUTH) {
if (cvv != null && !"".equals(cvv)) cc.setCVVChecked(success);
}
return result;
}
public HashMap charge(long id,
String description,
double amount,
CreditCard cc) throws Exception
{
HashMap result
= processTransaction(CHARGE, id,
description, amount, new HashMap(), cc);
writeCharge(amount);
return result;
}
public HashMap authorize(long id,
String description,
double amount,
CreditCard cc) throws Exception
{
HashMap result
= processTransaction(AUTH, id,
description, amount, new HashMap(), cc);
writeAuthorize(amount);
return result;
}
public HashMap capture(long id,
String description,
HashMap data,
CreditCard cc) throws Exception
{
double amount = ((Double) data.get("amount")).doubleValue();
HashMap result
= processTransaction(CAPTURE, id, description, amount, data, cc);
writeCapture(amount);
return result;
}
public HashMap voidAuthorize(long id,
String description,
HashMap data,
CreditCard cc) throws Exception
{
double amount = ((Double) data.get("amount")).doubleValue();
String transid = (String)data.get("id");
try {
sendEmail(adminEmail, VOID, description, id, "");
} catch (Exception ex) {
Session.getLog().error("Error sending notification email: ", ex);
}
HashMap retval = new HashMap();
retval.put("amount", new Double(amount));
retval.put("id", transid);
writeLog(0, id, amount, VOID, "Transaction: \"" + transid
+ "\" should be voided manually", "", "", true);
writeVoid(amount);
return retval;
}
public HashMap checkCC(long acctid, CreditCard cc) throws Exception {
return checkCCCVV(acctid, cc);
}
public String getDescription() {
return "protx.com VSP Direct v2.22";
}
private String getCCType(CreditCard cc) {
String internalType = cc.getType();
if (ccTypes.containsKey(internalType)) {
return (String) ccTypes.get(internalType);
}
return internalType;
}
}
For another example, see Moneris implementation.