Braintree Module Documentation

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. In your core applicationContext.xml, replace the block of text
    <!-- Scan DemoSite Sample Payment Gateway Implementation -->
    ...
    <!-- /End DemoSite NullPaymentGateway Config -->

with

    <context:component-scan base-package="com.broadleafcommerce.payment.service.gateway"/>
    <context:component-scan base-package="com.broadleafcommerce.vendor.braintree"/>
    <bean class="com.broadleafcommerce.vendor.braintree.service.payment.BraintreePaymentGatewayType"/>

    <bean id="blMergedPersistenceXmlLocations" class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list>
                <value>classpath*:/META-INF/persistence-core.xml</value>
            </list>
        </property>
    </bean>

    <!-- Set up custom entity overrides. These are defined in core/src/main/resources -->
    <bean id="blMergedEntityContexts" class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list>
                <value>classpath:applicationContext-entity.xml</value>
            </list>
        </property>
    </bean>

    <bean id="mySampleConfigurationServices" class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list>
                <ref bean="blBraintreeConfigurationService"/>
            </list>
        </property>
    </bean>
    <bean class="org.broadleafcommerce.common.extensibility.context.merge.LateStageMergeBeanPostProcessor">
        <property name="collectionRef" value="mySampleConfigurationServices"/>
        <property name="targetRef" value="blPaymentGatewayConfigurationServices"/>
    </bean>

    <bean id="blVariableExpressions" class="org.springframework.beans.factory.config.ListFactoryBean">
        <property name="sourceList">
            <list>
                <ref bean="blBraintreeVariableExpression" />
            </list>
        </property>
    </bean>

Note - If using Braintree's V.Zero API, you'll need to use <ref bean="blBraintreeVZeroConfigurationService"/> instead of <ref bean="blBraintreeConfigurationService"/>. You may also need to exclude BraintreeConfigurationServiceImpl from your component scan, as well as the contents of the com.broadleafcommerce.vendor.braintree.web.processor package, to avoid any bean loading problems.

  1. Make sure the Braintree JS library is loaded on your checkout page:
<script src="https://js.braintreegateway.com/v2/braintree.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="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/javascript+java/sdk/client/drop-in for more options)
    braintree.setup([[${#braintree.generateClientToken()}]], "dropin", {
        container: "payment-form-dropin"
    });
  1. Create a Spring MVC Controller to handle the form you created above in order to process the payment nonce and confirm the transaction
@Controller
public class MyBraintreeCheckoutController extends BroadleafCheckoutController {

    @RequestMapping(value = "/checkout/braintree/complete")
    public String completeBraintreeCheckout(Model model, HttpServletRequest request, RedirectAttributes redirectAttributes, @PathVariable Map<String, String> pathVars) throws PaymentException {
        //Get Cart
        //Get Payment Nonce From Request

        //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

        // 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, paymentNonceFromRequeest);

        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.

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.