Documentation Home

Braintree Quick Start

Broadleaf Commerces offers an out-of-the-box Braintree solution that requires little configuration and is easily set up.
The quick start solution implements the [[v.zero (javascript + java) SDK | https://developers.braintreepayments.com/javascript+java/sdk/overview/how-it-works]] model offered by the Braintree API.
This implementation should be useful for those with a simple checkout flow.

You must have completed the Braintree Environment Setup before continuing

Adding Braintree Checkout Support

These instructions assume integration with the default Heat Clinic Demo Site provided with the framework.

  1. Make sure the Braintree JS library(at the time of writing this was the latest v3 js lib) is loaded on your checkout page:
<script src="https://js.braintreegateway.com/web/dropin/1.22.1/js/dropin.min.js"></script>
  1. Create a Payment Form on your checkout page without any fields (if using the Drop-in UI, it will be created for you by the Braintree JS lib)
<blc:form th:action="@{/checkout/braintree/complete}" method="POST">
    <div id="payment-form-dropin"></div>
    <input type="hidden" id="nonce" name="payment_method_nonce" />
    <input type="submit" value="Complete Order" />
</blc:form>
  1. Insert the following Javascript into your checkout html in order to generate the client token to retrieve the payment nonce: (See https://developers.braintreepayments.com/guides/drop-in/setup-and-integration/javascript/v3 for more options)
    <script type="text/javascript" th:inline="javascript">
    /*<![CDATA[*/
        $( document ).ready(function() {

            braintree.dropin.create({
                authorization: /*[[${#braintree.generateClientToken()}]]*/null,
                container: '#payment-form-dropin'
            }, function (createErr, instance) {
                //check for createErr if it has some errors, show some message, handle error etc
                //if no errors, add some button click or form submit listener and
                var form = document.querySelector('#YOUR_FORM_ID'); 
                form.addEventListener('submit', function (event) {
                    event.preventDefault();
                    instance.requestPaymentMethod(function (err, payload) {
                        if (err) {
                            console.log('Error', err);
                            return;
                        }

                        // Add the nonce to the form and submit
                        document.querySelector('#nonce').value = payload.nonce;
                        form.submit();
                    });
                });
            });
          });  
       /*]]>*/



    </script>
  1. Create a Spring MVC Controller to handle the form you created above in order to process the payment nonce and confirm the transaction. It would look something like this:
@Controller
public class BraintreeCheckoutController extends BroadleafCheckoutController {

    @Resource(name = "blAddressService")
    protected AddressService addressService;

    @RequestMapping(value = "/checkout/braintree/complete")
    public String completeBraintreeCheckout(Model model, HttpServletRequest request, RedirectAttributes redirectAttributes, @PathVariable Map<String, String> pathVars) throws PaymentException, PricingException {
        //Get Cart
        Order cart = CartState.getCart();
        //Get Payment Nonce From Request
        String nonce = request.getParameter("payment_method_nonce");

        //Create a new PAYMENT_NONCE Order Payment
        OrderPayment paymentNonce = orderPaymentService.create();
        paymentNonce.setType(BraintreePaymentType.PAYMENT_NONCE);
        paymentNonce.setPaymentGatewayType(BraintreePaymentGatewayType.BRAINTREE);
        paymentNonce.setAmount(cart.getTotalAfterAppliedPayments());
        paymentNonce.setOrder(cart);

        //Populate Billing Address per UI requirements
        //For this example, we'll copy the address from the temporary Credit Card's Billing address and archive the payment,
        // (since Heat Clinic's checkout template saves and validates the address in a previous section).
        OrderPayment tempPayment = null;
        for (OrderPayment payment : cart.getPayments()) {
            if (PaymentGatewayType.TEMPORARY.equals(payment.getGatewayType()) &&
                    PaymentType.CREDIT_CARD.equals(payment.getType())) {
                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("Braintree Payment Nonce");
        transaction.setSuccess(true);
        transaction.setType(PaymentTransactionType.UNCONFIRMED);
        transaction.getAdditionalFields().put(MessageConstants.PAYMENT_NONCE, nonce);

        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 nonce.

Enable Braintree OMS Support

  1. The OMS allows for creation of Customer Payment Tokens so that a CSR can change orders and add new payment methods when necessary. To integrate Braintree with Customer Payment capability, you will need to create a Spring MVC Controller to handle the drop-in credit card form to process the payment nonce and save the token as a Customer Payment. It might look something like this:
@Controller
public class BraintreeCustomerPaymentController {

    protected static final String CUSTOMER_PAYMENT_ERROR = "CUSTOMER_PAYMENT_OMS_ERROR";
    protected static String customerPaymentErrorMessage = "customerPaymentOMSErrorMessage";

    @Resource(name = "blBraintreeCustomerService")
    protected PaymentGatewayCustomerService braintreeCustomerService;

    @Resource(name = "blCustomerPaymentGatewayService")
    protected CustomerPaymentGatewayService customerPaymentGatewayService;

    @Resource(name = "blBraintreeConfiguration")
    protected BraintreeConfiguration configuration;

    @Resource
    protected SystemPropertiesService propertiesSvc;

    @RequestMapping(value = "/payment-method-oms/braintree/add")
    public String addBraintreePaymentMethod(Model model, HttpServletRequest request, RedirectAttributes redirectAttributes, @PathVariable Map<String, String> pathVars) throws PaymentException, PricingException {
        //Get Cart
        Customer customer = CustomerState.getCustomer();
        //Get Payment Nonce From Request
        String nonce = request.getParameter("payment_method_nonce");

        PaymentRequestDTO requestDTO = new PaymentRequestDTO()
                .customer()
                    .customerId(customer.getId().toString())
                    .firstName(customer.getFirstName())
                    .lastName(customer.getLastName())
                    .email(customer.getEmailAddress())
                    .done()
                .additionalField(MessageConstants.PAYMENT_NONCE, nonce);

        PaymentResponseDTO responseDTO = braintreeCustomerService.createGatewayCustomer(requestDTO);
        if (responseDTO.isSuccessful()) {

            // Populate BillTo Address per business requirements...
            // For demonstration purposes, we'll just add an address manually.
            // In most cases you can POST it along with the form and get it off the request.
            responseDTO.billTo()
                    .addressFullName("Bill Braintree")
                    .addressLine1("123 Broadleaf Rd")
                    .addressCityLocality("Austin")
                    .addressStateRegion("TX")
                    .addressCountryCode("US")
                    .addressPostalCode("78759");

            customerPaymentGatewayService.createCustomerPaymentFromResponseDTO(responseDTO, configuration);
            return OMSCsrToolsController.REDIRECT_OMS_CHECKOUT;
        }

        redirectAttributes.addAttribute(CUSTOMER_PAYMENT_ERROR, customerPaymentErrorMessage);
        return getOMSCustomerPaymentRedirectUrl();
    }

    public String getOMSCustomerPaymentRedirectUrl() {
        String redirect = propertiesSvc.resolveSystemProperty("oms.changeOrder.payment.gateway.customerPayment.redirectUrl");
        return BLCRequestUtils.getRequestedServerPrefix() + redirect;
    }
}

Done!

At this point, all the configuration should be complete and you are now ready to test your integration with Braintree. Add something to your cart and proceed with checkout.