Implementing Merchant Gateway

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.

Imports

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.

Required Methods

Your class must implement the following methods:

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:

Other variables can be put into the HashMap optionally.

CVV Verification

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

Logging

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:

    private static org.apache.log4j.Category log =
            org.apache.log4j.Category.getInstance(MyMerchantGateway.class);
For more information, see log4j manual.

To write messages to ChargeLog (stored in the H-Sphere database), use the following methods:

Example


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.