Vantiv Quick Start
Broadleaf Commerce offers an out-of-the-box Vantiv solution that requires little configuration and is easily set up. The quick start solution implements the Vantiv eProtect (JavaScript and iFrame strategies) + Java SDK APIs offered by Vantiv.
This implementation should be useful for those with a simple checkout flow.
You must have completed the Vantiv Environment Setup before continuing
Adding Vantiv Checkout Support
These instructions assume integration with the default Heat Clinic Demo Site provided with the framework.
- In your core
applicationContext.xml
, remove the following block of text
<!-- Scan DemoSite Sample Payment Gateway Implementation -->
<context:component-scan base-package="com.mycompany.sample" />
<context:component-scan base-package="com.broadleafcommerce.demo"/>
In the site applicationContext.xml
, remove the following block of text
<!-- Scan DemoSite Sample Payment Gateway Implementation -->
<context:component-scan base-package="com.mycompany.sample" />
If you are using the Spring Boot Reference Site, then you'll need to remove the following dependency from your core pom.xml
<dependency>
<groupId>org.broadleafcommerce</groupId>
<artifactId>broadleaf-sample-payment-gateway</artifactId>
</dependency>
Note: depending on which version of ReferenceSite you are running, you may also need to remove any provided controller methods that reference
the sample payment gateway as well.
- Make sure the Vantiv JS Library is loaded on your checkout page.
Note: Per Vantiv documentation - the jQuery JavaScript library must be loaded by your checkout page before loading the eProtect client JavaScript library. Documentation recommends using version 1.4.2 or higher.
For pre-live environment (testing and certification), you'll want to load one of the following JS files depending on your integration strategy.
Note: make sure to configure
gateway.vantiv.javascriptLibUrl
orgateway.vantiv.iFrameLibUrl
depending on your strategy
JavaScript Strategy:
<script th:src="${#props.get('gateway.vantiv.javascriptLibUrl')}" type="text/javascript"></script>
```html
#### iFrame Strategy:
```html
<script th:src="${#props.get('gateway.vantiv.iFrameLibUrl')}" type="text/javascript"></script>
```html
For Production, you'll need to get the production URLs directly from your eProtect implementation consultant.
3. Replace the Payment Form with the Vantiv Specific forms and JavaScript:
#### JavaScript Strategy:
For this strategy, you will want to create a credit card form and add the appropriate JavaScript similar to the one below:
function setEprotectResponseFields(response) {
document.getElementById('response$code').value = response.response;
document.getElementById('response$message').value = response.message;
document.getElementById('response$responseTime').value = response.responseTime;
document.getElementById('response$vantivTxnId').value = response.vantivTxnId;
document.getElementById('response$type').value = response.type;
document.getElementById('response$firstSix').value = response.firstSix;
document.getElementById('response$lastFour').value = response.lastFour;
document.getElementById('response$nameOnCard').value = document.getElementById('nameOnCard').value;
document.getElementById('response$cvv').value = document.getElementById('cvv2Num').value;
document.getElementById('response$cardExpDate').value = document.getElementById('cardExpDate').value;
}
function submitAfterEprotect (response) {
setEprotectResponseFields(response);
document.forms['eProtectForm'].submit();
}
function onErrorAfterEprotect (response) {
setEprotectResponseFields(response);
if(response.response == '871') {
alert("Invalid card number. Check and retry. (Not Mod10)");
}
else if(response.response == '872') {
alert("Invalid card number. Check and retry. (Too short)");
}
else if(response.response == '873') {
alert("Invalid card number. Check and retry. (Too long)");
}
else if(response.response == '874') {
alert("Invalid card number. Check and retry. (Not a number)");
}
else if(response.response == '875') {
alert("We are experiencing technical difficulties. Please try again later or call 555-555-1212");
}
else if(response.response == '876') {
alert("Invalid card number. Check and retry. (Failure from Server)");
}
else if(response.response == '881') {
alert("Invalid card validation code. Check and retry. (Not a number)");
}
else if(response.response == '882') {
alert("Invalid card validation code. Check and retry. (Too short)");
}
else if(response.response == '883') {
alert("Invalid card validation code. Check and retry. (Too long)");
}
else if(response.response == '889') {
alert("We are experiencing technical difficulties. Please try again later or call 555-555-1212");
}
return false;
}
function timeoutOnEprotect () {
alert("We are experiencing technical difficulties. Please try again later or call 555-555-1212 (timeout)");
}
function callEprotect() {
if(typeof eProtect !== 'function') {
alert("We are experiencing technical difficulties. Please try again later or call 555-555-1212 (API unavailable)" );
}
}
$("#submitId").click(
function() {
setEprotectResponseFields({
"response": "",
"message": ""
});
var eProtectRequest = {
"paypageId": document.getElementById("request$paypageId").value,
"reportGroup": document.getElementById("request$reportGroup").value,
"orderId": document.getElementById("request$orderId").value,
"id": document.getElementById("request$merchantTxnId").value,
"url": document.getElementById("request$url").value
};
var formFields = {
"accountNum" :document.getElementById('ccNum'),
"cvv2" :document.getElementById('cvv2Num'),
"paypageRegistrationId":document.getElementById('response$paypageRegistrationId'),
"bin" :document.getElementById('response$bin')
};
new eProtect().sendToEprotect(eProtectRequest, formFields, submitAfterEprotect,
onErrorAfterEprotect, timeoutOnEprotect, 15000);
);
```html
<blc:form th:action="@{/checkout/eProtect/complete}" role="form" method="POST" id="eProtectForm" name="eProtectForm">
<input type="text" value="4111111111111111" id="ccNum" autocomplete="off" size="20" />
<input type="text" name="creditCard.creditCardCvv" id="cvv2Num" autocomplete="off" size="4" value="123" />
<input type="text" name="creditCard.creditCardHolderName" id="nameOnCard" value="Hotsauce Connoisseur" />
<input type="text" name="creditCard.creditCardExpDate" id="cardExpDate" autocomplete="off" placeholder="MM/YY" value="01/99" />
<input type="hidden" id="request$paypageId" name="request$paypageId" th:value="${#props.get('gateway.vantiv.paypageId')}" />
<input type="hidden" id="request$merchantTxnId" name="request$merchantTxnId" th:value="${#vantiv.generateRequestId(cart.id)}" />
<input type="hidden" id="request$orderId" name="request$orderId" th:value="${cart.id}" />
<input type="hidden" id="request$reportGroup" name="request$reportGroup" th:value="${#props.get('gateway.vantiv.reportGroup')}" />
<input type="hidden" id="response$paypageRegistrationId" name="response$paypageRegistrationId" readOnly="true" value="" />
<input type="hidden" id="response$bin" name="response$bin" readOnly="true" />
<input type="hidden" id="response$code" name="response$code" readOnly="true" />
<input type="hidden" id="response$message" name="response$message" readOnly="true" />
<input type="hidden" id="response$responseTime" name="response$responseTime" readOnly="true" />
<input type="hidden" id="response$type" name="response$type" readOnly="true" />
<input type="hidden" id="response$vantivTxnId" name="response$vantivTxnId" readOnly="true" />
<input type="hidden" id="response$firstSix" name="response$firstSix" readOnly="true" />
<input type="hidden" id="response$lastFour" name="response$lastFour" readOnly="true" />
<script>
document.write('<button type="button" id="submitId">Checkout</button>');
</script>
<noscript>
<button type="button" id="submitId">Enable JavaScript or call us at 555-555-1212</button>
</noscript>
</blc:form>
iFrame Strategy:
<script th:inline="javascript">
$( document ).ready(function() {
var startTime;
var payframeClientCallback = function(response) {
if (response.timeout) {
var elapsedTime = new Date().getTime() - startTime;
document.getElementById('timeoutMessage').value = 'Timed out after ' + elapsedTime + 'ms';
}
else {
document.getElementById('response$code').value = response.response;
document.getElementById('response$message').value = response.message;
document.getElementById('response$responseTime').value = response.responseTime;
document.getElementById('response$reportGroup').value = response.reportGroup;
document.getElementById('response$merchantTxnId').value = response.id;
document.getElementById('response$orderId').value = response.orderId;
document.getElementById('response$vantivTxnId').value = response.vantivTxnId;
document.getElementById('response$type').value = response.type;
document.getElementById('response$lastFour').value = response.lastFour;
document.getElementById('response$firstSix').value = response.firstSix;
document.getElementById('paypageRegistrationId').value = response.paypageRegistrationId;
document.getElementById('bin').value = response.bin;
document.getElementById('response$expMonth').value = response.expMonth;
document.getElementById('response$expYear').value = response.expYear;
}
};
function inputsEmptyCallback(res) {
console.log("inputsEmptyCallback: message received");
console.log(res);
var isEmpty = res.allInputsEmpty;
if(isEmpty) {
console.log("Card input fields empty");
$( "<p>Inputs are Empty</p>" ).insertAfter( ".checkout" );
return true;
} else {
console.log("Card inputs not empty");
$( "<p>Inputs are not Empty</p>" ).insertAfter( ".checkout" );
return false;
}
}
var configure = {
"paypageId":document.getElementById("request$paypageId").value,
"style":"EnhancedDemo",
"height":"275",
"reportGroup":document.getElementById("request$reportGroup").value,
"timeout":document.getElementById("request$timeout").value,
"div": "eProtectiframe",
"callback": payframeClientCallback,
"showCvv": true,
"months": {
"1":"January",
"2":"February",
"3":"March",
"4":"April",
"5":"May",
"6":"June",
"7":"July",
"8":"August",
"9":"September",
"10":"October",
"11":"November",
"12":"December"
},
"numYears": 8,
"tooltipText": "A CVV is the 3 digit code on the back of your Visa, MasterCard and Discover or a 4 digit code on the front of your American Express",
"tabIndex": {
"accountNumber":1,
"cvv":2,
"expMonth":3,
"expYear":4
},
"placeholderText": {
"cvv":"CVV",
"accountNumber":"Account Number"
},
"htmlTimeout":document.getElementById("request$timeout").value,
"inputsEmptyCallback": inputsEmptyCallback,
"clearCvvMaskOnReturn": true,
"enhancedUxFeatures" : {
"inlineFieldValidations": true,
"numericInputsOnly": true
}
};
var payframeClient = new EprotectIframeClient(configure);
document.getElementById("eProtectForm").onsubmit = function(){
if (payframeClient.allInputsEmpty()) {
return false;
}
var message = {
"id":document.getElementById("request$merchantTxnId").value,
"orderId":document.getElementById("request$orderId").value
};
startTime = new Date().getTime();
payframeClient.getPaypageRegistrationId(message);
return false;
};
});
</script>
<blc:form th:action="@{/checkout/eProtect/complete}" role="form" method="POST" id="eProtectForm" name="eProtectForm">
<div id="eProtectiframe"></div>
<input type="hidden" id="request$paypageId" name="request$paypageId" th:value="${#props.get('gateway.vantiv.paypageId')}" />
<input type="hidden" id="request$merchantTxnId" name="request$merchantTxnId" th:value="${#vantiv.generateRequestId(cart.id)}" />
<input type="hidden" id="request$orderId" name="request$orderId" th:value="${cart.id}" />
<input type="hidden" id="request$reportGroup" name="request$reportGroup" th:value="${#props.get('gateway.vantiv.reportGroup')}" />
<input type="hidden" id="request$timeout" name="request$timeout" value="15000" />
<input type="hidden" id="response$code" name="response$code" readOnly="true" />
<input type="hidden" id="response$message" name="response$message" readOnly="true" />
<input type="hidden" id="response$responseTime" name="response$responseTime" readOnly="true" />
<input type="hidden" id="response$reportGroup" name="response$reportGroup" readOnly="true" />
<input type="hidden" id="response$merchantTxnId" name="response$merchantTxnId" readOnly="true" />
<input type="hidden" id="response$orderId" name="response$orderId" readOnly="true" />
<input type="hidden" id="response$vantivTxnId" name="response$vantivTxnId" readOnly="true" />
<input type="hidden" id="response$type" name="response$type" readOnly="true" />
<input type="hidden" id="response$lastFour" name="response$lastFour" readOnly="true" />
<input type="hidden" id="response$firstSix" name="response$firstSix" readOnly="true" />
<input type="hidden" id="paypageRegistrationId" name="paypageRegistrationId" readOnly="true"/>
<input type="hidden" id="bin" name="bin" readOnly="true"/>
<input type="hidden" id="response$expMonth" name="response$expMonth" readOnly="true"/>
<input type="hidden" id="response$expYear" name="response$expYear" readOnly="true"/>
<button type="submit" id="submitId">Checkout</button>
</blc:form>
- Create a Spring MVC Controller to handle the form you created above in order ot process the payment token and confirm the transaction
@Controller
public class VantivCheckoutController extends BroadleafCheckoutController {
@RequestMapping(value = "/checkout/eProtect/complete")
public String completeVantivEProtectCheckout(Model model, HttpServletRequest request, RedirectAttributes redirectAttributes, @PathVariable Map<String, String> pathVars) throws PaymentException, PricingException {
//Get Cart
Order cart = CartState.getCart();
//Create a new PayPage Order Payment
OrderPayment paymentNonce = orderPaymentService.create();
paymentNonce.setType(VantivPaymentType.PAYPAGE);
paymentNonce.setPaymentGatewayType(VantivGatewayType.VANTIV);
paymentNonce.setAmount(cart.getTotalAfterAppliedPayments());
paymentNonce.setOrder(cart);
//Populate Billing Address per UI requirements
//For this Heat Clinic example, we'll want to copy the address from the temporary Credit Card's Billing address and archive the payment,
OrderPayment tempPayment = null;
for (OrderPayment payment : cart.getPayments()) {
if (PaymentGatewayType.TEMPORARY.equals(payment.getGatewayType()) &&
PaymentType.CREDIT_CARD.equals(payment.getType()) &&
payment.isActive()) {
tempPayment = payment;
break;
}
}
if (tempPayment != null){
paymentNonce.setBillingAddress(addressService.copyAddress(tempPayment.getBillingAddress()));
orderService.removePaymentFromOrder(cart, tempPayment);
}
// Create the UNCONFIRMED transaction for the payment
PaymentTransaction transaction = orderPaymentService.createTransaction();
transaction.setAmount(cart.getTotalAfterAppliedPayments());
transaction.setRawResponse("Vantiv eProtect Token");
transaction.setSuccess(true);
transaction.setType(PaymentTransactionType.UNCONFIRMED);
transaction.getAdditionalFields().put(MessageConstants.PAYPAGEREGISTRATIONID, request.getParameter("response$paypageRegistrationId"));
transaction.getAdditionalFields().put(MessageConstants.VANTIVTXNID, request.getParameter("response$vantivTxnId"));
transaction.getAdditionalFields().put(MessageConstants.MESSAGE, request.getParameter("response$message"));
transaction.getAdditionalFields().put(MessageConstants.RESPONSETIME, request.getParameter("response$responseTime"));
transaction.getAdditionalFields().put(MessageConstants.BIN, request.getParameter("response$bin"));
transaction.getAdditionalFields().put(MessageConstants.TYPE, request.getParameter("response$type"));
transaction.getAdditionalFields().put(MessageConstants.CARDFIRSTSIX, request.getParameter("response$firstSix"));
transaction.getAdditionalFields().put(MessageConstants.CARDLASTFOUR, request.getParameter("response$lastFour"));
transaction.getAdditionalFields().put(MessageConstants.NAMEONCARD, request.getParameter("response$nameOnCard"));
transaction.getAdditionalFields().put(MessageConstants.CARDVALIDATIONNUM, request.getParameter("response$cvv"));
transaction.getAdditionalFields().put(MessageConstants.CARDEXPDATE, request.getParameter("response$cardExpDate"));
transaction.getAdditionalFields().put(MessageConstants.BIN, request.getParameter("response$bin"));
transaction.setOrderPayment(paymentNonce);
paymentNonce.addTransaction(transaction);
orderService.addPaymentToOrder(cart, paymentNonce, null);
orderService.save(cart, true);
return processCompleteCheckoutOrderFinalized(redirectAttributes);
}
}
When processCompleteCheckoutOrderFinalized
is called, the checkout workflow is invoked and the ValidateAndConfirmPaymentActivity
is executed to confirm the payment token.
Done!
At this point, all the configuration should be complete and you are now ready to test your integration with Vantiv. Add something to your cart and proceed with checkout.