J2Pay – Implementing A Gateway
Introduction
We are very excited to welcome contributors, if you have worked on any gateway you can implement that gateway in our library and support the open source world.
You can find our github repository here
Before you begin to implement a gateway there are some other classes you should see first.
Below are the classes defined briefly.
HTTPClient
The main thing when working with gateways you post some data to gateway and parse the response.
To work with http post request this class provides two overloaded static httpPost methods.
- public static HTTPResponse httpPost(String url, String postParams, ContentType contentType)
- public static HTTPResponse httpPost(String url, String postParams, ContentType contentType, Charset charset)
So you don’t have to worry about handling http requests.
Helpers
While you are working with multiple gateways the main problem developer usually face is some gateways receive xml while some receive JSON or query string since J2pay always returns JSON Response so you do not have to worry about data conversion from between any of these xml, JSON or query string.
Here is the list of helper classes located in com.tranxactive.paymentprocessor.net package.
- QueryStringHelper
- JSONHelper
- StringHelper
- XMLHelper
Note: All of the methods defined in helper classes are static.
Responses
To provide generic response j2pay provides five response classes located in com.tranxactive.paymentprocessor.gateways.responses package.
- ErrorResponse
- PurchaseResponse
- RebillResponse
- RefundResponse
- VoidResponse
As you can identify by their names if you are working with purchase method you will be using PurchaseResponse class if working with rebill method you will be using RebillRespons class and so on
ErrorResponse class is the only class which will be used in all four methods.
One thing you should also know four classes except ErrorResponse considered as success response. So we will be returning them if and only if transaction was successful.
ParamList
ParamList is an enum located in com.tranxactive.paymentprocessor.gateways.parameters package contains the list of variables that must be keep generic in all transactions like if you would like to assign transaction id to variable transactionId there are some chances of typo, but if you will be using paramList enum you are very safe.
Here is how could you use that while assigning transactionId In JSON.
JSONObject json = new JSONObject(); Json.put(ParamList.TRANSACTION_ID.getName(), "1234567890");
Example
Now you have all the knowledge required to integrate a new gateway. In this example we will be integrating NMI gateway.
While working on this example we assumed you have read the NMI official documentation.
Let’s code.
To integrate NMI gateway we will create a class in com.tranxactive.paymentprocessor.gateways package with the name NMIGateway.
Next we will extends the Gateway class which lead us to implementing all the methods that must be present in a gateway.
Here is how our class will look like.
public class NMIGateway extends Gateway{ @Override public HTTPResponse purchase(JSONObject apiParameters, Customer customer, CustomerCard customerCard, Currency currency, float amount) { } @Override public HTTPResponse refund(JSONObject apiParameters, JSONObject refundParameters, float amount) { } @Override public HTTPResponse rebill(JSONObject apiParameters, JSONObject rebillParameters, float amount) { } @Override public HTTPResponse voidTransaction(JSONObject apiParameters, JSONObject voidParameters) { } @Override public JSONObject getApiSampleParameters() { } @Override public JSONObject getRefundSampleParameters() { } @Override public JSONObject getRebillSampleParameters() { } @Override public JSONObject getVoidSampleParameters() { } }
Next we will add four below methods at the end of our class. These will be helping us to build the final parameters that need to be posted on the gateway.
private JSONObject buildPurchaseParameters(JSONObject apiParameters, Customer customer, CustomerCard customerCard, Currency currency, float amount){} private JSONObject buildVoidParameters(JSONObject apiParameters, JSONObject voidParameters) {} private JSONObject buildRefundParameters(JSONObject apiParameters, JSONObject refundParameters, float amount){} private JSONObject buildRebillParameters(JSONObject apiParameters, JSONObject rebillParameters, float amount){}
Next we will define apiURL variable globally where all request will be posted.
private final String apiURL = "https://secure.networkmerchants.com/api/transact.php";
Next we will work on four SampleParameters methods.
First and most important is getApiSampleParameters method which is required to perform all transactions.
If you have read the NMI documentation you will see API parameters are username and password.
Here is how getApiSampleParameters method will look like.
@Override public JSONObject getApiSampleParameters() { return new JSONObject() .put("username", "the api user name use demo as the user name for testing") .put("password", "the api password use password as the password for testing"); }
Below are the three remaining methods after updating.
@Override public JSONObject getRefundSampleParameters() { return new JSONObject() .put(ParamList.TRANSACTION_ID.getName(), "the transaction id which will be refunded"); } @Override public JSONObject getRebillSampleParameters() { return new JSONObject() .put("customerVaultId", "the customer vault id"); } @Override public JSONObject getVoidSampleParameters() { return new JSONObject() .put(ParamList.TRANSACTION_ID.getName(), "the transaction id which will be void"); }
Next we will be working on four buildparameters methods. Here is how these look like after inserting our code.
private JSONObject buildPurchaseParameters(JSONObject apiParameters, Customer customer, CustomerCard customerCard, Currency currency, float amount) { JSONObject object = new JSONObject(); object .put("type", "sale") .put("username", apiParameters.getString("username")) .put("password", apiParameters.getString("password")) .put("ccnumber", customerCard.getNumber()) .put("ccexp", customerCard.getExpiryMonth() + customerCard.getExpiryYear().substring(2)) .put("cvv", customerCard.getCvv()) .put("amount", amount) .put("currency", currency) .put("first_name", customer.getFirstName()) .put("last_name", customer.getLastName()) .put("address1", customer.getAddress()) .put("city", customer.getCity()) .put("state", customer.getState()) .put("zip", customer.getZip()) .put("country", customer.getCountry().getCodeISO2()) .put("phone", customer.getPhoneNumber()) .put("email", customer.getEmail()) .put("ipaddress", customer.getIp()) .put("customer_vault", "add_customer"); return object; } private JSONObject buildVoidParameters(JSONObject apiParameters, JSONObject voidParameters) { JSONObject object = new JSONObject(); object .put("type", "void") .put("username", apiParameters.getString("username")) .put("password", apiParameters.getString("password")) .put("transactionid", voidParameters.getString(ParamList.TRANSACTION_ID.getName())); return object; } private JSONObject buildRefundParameters(JSONObject apiParameters, JSONObject refundParameters, float amount) { JSONObject object = new JSONObject(); object .put("type", "refund") .put("username", apiParameters.getString("username")) .put("password", apiParameters.getString("password")) .put("transactionid", refundParameters.getString(ParamList.TRANSACTION_ID.getName())) .put("amount", Float.toString(amount)); return object; } private JSONObject buildRebillParameters(JSONObject apiParameters, JSONObject rebillParameters, float amount) { JSONObject object = new JSONObject(); object .put("username", apiParameters.getString("username")) .put("password", apiParameters.getString("password")) .put("customer_vault_id", rebillParameters.getString("customerVaultId")) .put("amount", Float.toString(amount)); return object; }
Next we will be working on purchase method.
First of all we will build our final parameters that need to be posted on gateway with the help of buildPurchaseParameters method.
JSONObject requestObject = this.buildPurchaseParameters(apiParameters, customer, customerCard, currency, amount);
Next we will define some variables to handle the request don’t worry it’s all depends on how you code.
JSONObject responseObject; String requestString; String responseString; int responseCode; requestObject = JSONHelper.encode(requestObject); requestString = QueryStringHelper.toQueryString(requestObject); HTTPResponse httpResponse; PurchaseResponse successResponse = null; ErrorResponse errorResponse = new ErrorResponse();
Since NMI requires queryString data to be posted so we are using two helper class.
JSONHelper and QueryStringHelper
First we will urlencode the json returned by buildPurchaseParameters with the help of this code.
requestObject = JSONHelper.encode(requestObject);
Next we converted the encoded json to query string with the help of this code.
requestString = QueryStringHelper.toQueryString(requestObject);
You must be wondering why we initialized errorResponse but set successResponse as null. That all for some programming login to handle the request easily.
Next we will be posting the data to gateway, here is how we will do that.
httpResponse = HTTPClient.httpPost(this.apiURL, requestString, ContentType.APPLICATION_FORM_URLENCODED);
Here are two scenarios that must keep in mind.
- Communication with gateway servers was successful.
- There was some network issue or gateway server was temporary not available.
Here is how you will handle second scenario.
if (httpResponse.getStatusCode() == -1) { return httpResponse; }
If the communication with gateway server was successful then our code will not return from this point and continue.
Next we will get the gateway response and parse it to JSON so we can easily work on response.
responseString = httpResponse.getContent(); responseObject = JSONHelper.decode(QueryStringHelper.toJson(responseString)); responseCode = responseObject.getInt("response_code");
As you can see we again used the QueryStringHelper and JSONHelper. Wasn’t that easy with the help of helper class.
As we know if gateway response was successful than it must return response code 100. See below code.
if (responseCode == 100) { httpResponse.setSuccessful(true); successResponse = new PurchaseResponse(); successResponse.setMessage(responseObject.getString("responsetext")); successResponse.setTransactionId(responseObject.get("transactionid").toString()); successResponse.setCardValuesFrom(customerCard); successResponse.setAmount(amount); successResponse.setCurrencyCode(currency); successResponse.setRebillParams(new JSONObject() .put("customerVaultId", responseObject.get("customer_vault_id").toString()) ); successResponse.setRefundParams(new JSONObject() .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString()) ); successResponse.setVoidParams(new JSONObject() .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString()) ); } else { errorResponse.setMessage(responseObject.getString("responsetext")); }
Let’s understand the above code line by line.
httpResponse.setSuccessful(true);
httpResponse by default set the success to false, so we are only setting it to true in success case as we did above.
successResponse = new PurchaseResponse();
We initialized successResponse variable defined in the beginning of method.
When you take a look at the code of PurchaseResponse class you will see all the parameters that must be set before returning the response.
//this sets the gateway success message. successResponse.setMessage(responseObject.getString("responsetext"));
//this sets the gateway returned transaction id. successResponse.setTransactionId(responseObject.get("transactionid").toString());
//this is our standard we provide some card detail in purchase response. You will see in final response. successResponse.setCardValuesFrom(customerCard);
successResponse.setAmount(amount); successResponse.setCurrencyCode(currency);
Next we set the amount and currency that was charged.
Since it’s our responsibility to provide the ready to use parameters required for rebill, refund or void.
Here is how we did this.
successResponse.setRebillParams(new JSONObject() .put("customerVaultId", responseObject.get("customer_vault_id").toString()) ); successResponse.setRefundParams(new JSONObject() .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString()) ); successResponse.setVoidParams(new JSONObject() .put(ParamList.TRANSACTION_ID.getName(), responseObject.get("transactionid").toString()) );
But what if response what not success and we got some error like insufficient fund or avs error.
Here is how we did this in else block.
errorResponse.setMessage(responseObject.getString("responsetext"));
Next we will return the final response that will be HTTPResponse.
if (successResponse != null) { successResponse.setGatewayResponse(responseObject); httpResponse.setContent(successResponse.getResponse().toString()); } else { errorResponse.setGatewayResponse(responseObject); httpResponse.setContent(errorResponse.getResponse().toString()); } return httpResponse;
That’s all we have successfully integrated the NMI purchase method, next three methods will be same except you will be using different Response classes for each of them i.e. you will be using
RebillResponse in rebill method.
RefundResponse in refund method.
VoidResponse in voidTransaction method.
Instead of PurchaseResponse.
It is highly recommended to see source of all the these response class and also sample responses (given here)
To see the complete code of NMI gateway you can see on our github repository.
Published on Java Code Geeks with permission by Muhammad Ilyas, partner at our JCG program. See the original article here: Implementing A Gateway Opinions expressed by Java Code Geeks contributors are their own. |