Creating a Payment Gateway Module
Before you begin, it is recommended that you fully understand how gateways works before attempting to implement
any of the BLC interfaces. Please make sure to read Understanding Payment Gateways first to aid in this process.
Conventions
We'll go over some of the conventions to create consistency across all Payment Modules.
1. Here is the package structure that many of these Broadleaf Payment Modules follow:
All implementations of the BLC Common
interfaces will be in the following packages
org.broadleafcommerce.payment.service.gateway
com.broadleafcommerce.payment.service.gateway
All gateway specific services and constants will go under the following package structure
org.broadleafcommerce.vendor.replace_with_gateway_name.service
com.broadleafcommerce.vendor.replace_with_gateway_name.service
All gateway specific web components such as Spring MVC Controllers and Thymeleaf Processors will go under
org.broadleafcommerce.vendor.replace_with_gateway_name.web
com.broadleafcommerce.vendor.replace_with_gateway_name.web
2. Utilize any SDK that the gateway may provide.
Note that some gateways don't publish their Java SDK on Maven Central, so you may need to install it locally and in your documentation note that their is a dependency on their JAR for compilation. If this is the case, please make note of that and where to find that dependency in your documentation.
3. Utilize AbstractExternalPaymentGatewayCall
In a lot of cases, you may notice that a lot of the transaction methods share common code to create a Request which then calls an external API or SDK and parses the Response. If this is the case, you may wish to create a parent class that all these extend to unify this boiler plate code. It's also important to extend AbstractExternalPaymentGatewayCall
if your service makes an SDK or External API call. This allows anyone using the framework to configure the ServiceMonitor AOP hooks and detect any outages to provide (email/logging) feedback when necessary. You can look at the Java Docs on that class for further examples and documentation.
4. Create a Spring MVC controller to process the Payment Response within the Module
Each of the Payment Modules will now provide out-of-the-box endpoints to handle processing web responses back from the Gateway. These Spring MVC controllers will reside under the .../vendor/replace_with_gateway_name/web/
package. These controllers will provide default @RequestMappings and extend PaymentGatewayAbstractController
You will need to implement the handleProcessingException()
and handleUnsuccessfulTransaction()
methods. In most cases, you will just need to log the exception and add a processing error to the Redirect Attributes. In some implementations you can re-throw the exception as the Gateway will listen back for an error response and VOID the transaction. In other cases, you never communicate back to the Gateway and need to show an error message to the customer.
if (LOG.isTraceEnabled()) {
LOG.trace("A Processing Exception Occurred for " + GATEWAY_CONTEXT_KEY +
". Adding Error to Redirect Attributes.");
}
redirectAttributes.addAttribute(PAYMENT_PROCESSING_ERROR, getProcessingErrorMessage());
5. Make sure to capture the Raw Response on your PaymentResponseDTO.
It's often very helpful and in some cases required to capture the entire response back from a gateway. Make sure to serialize all the information coming back from the gateway in the Raw Response field. You may wish to use the PaymentGatewayWebResponsePrintServiceImpl
to translate an HttpServletRequest
into a Raw Response String.
6. Utilize a MessageConstants
class
Create a MessageConstants
class that define the gateway specific constants that you pass between the additional fields map of the Request and Response DTO's to the Gateway Services.
One important convention to take note of as you push fields into the additional fields map of the ResponseDTO: make sure to be aware of the fields that you place into the map, as that map is saved into the PaymentTransaction.additionalFields
map in the framework. One gotcha, is that MySQL is by default case-insensitive, so be sure to not place duplicate fields into this map (of different case) as you may face a unique-constraint violation when that object is persisted.
Implementation Guidelines
Here are some steps to follow to help get you started developing your own module.
Extend and Implement the
PaymentGatewayConfiguration
. Every module should provide a configuration bean that provides information about what it can and cannot handle as well as any specific configuration parameters it needs.Implement the
PaymentGatewayConfigurationService
. Every module should provide an implementation of this service that will define all the Payment Gateway Interfaces that this module supports.Implement the
PaymentGatewayTransactionService
to handle any post Authorize or Authroize and Capture operations.Implement the
PaymentGatewayWebResponseService
. In most cases, the Gateway will send back the transaction information back to your system using anHTTPServletRequest
. Use this interface method to encapsulate translating this into aPaymentResponseDTO
.Implement a Spring MVC controller that receives the results of the transactions that extends
PaymentGatewayAbstractController
. This abstract controller expects certain methods to be implmented by the Gateway specific implementation.Implement the
PaymentGatewayRollbackService
to handle error scenarios. This API will be called in the event an error gets thrown in the Checkout Workflow after a payment has been confirmed. That means the payment has already been captured or authorized however something else in the workflow has caused an exception to occur which therefore needs to rollback any payments that have already been processed.
Hosted or Transparent Redirect?
If it is a Hosted Solution:
- Implement the
PaymentGatewayHostedService
- Create a Thymeleaf Processor to render the button/form needed to redirect to the hosted page.
If it is a Transparent Redirect/Silent Post Solution:
- Implement the
PaymentGatewayTransparentRedirectService
- Create a Thymeleaf Processor Extension Handler that extends
AbstractTRCreditCardExtensionHandler
. This will dynamically change a Credit Card Form (seeTransparentRedirectCreditCardFormProcessor
) on the checkout page and changes its ACTION URL and append any gateway specific hidden fields to that form. - Create a Thymeleaf Expression Extension Handler that extends
AbstractPaymentGatewayFieldExtensionHandler
. This will dynamically change any HTML fieldname
attributes to be those that are expected from the gateway. - If the Payment Gateway requires the Credit Card Type (e.g. Visa, Mastercard, etc...) be sent along with the Credit Card Number and the Expiry Date. Implement the
CreditCardTypesExtensionHandler
to add the code/card type map to your Thymeleaf evaluation model.
Example Gateway
The Heat Clinic Demo Site includes a test "Null Payment Gateway" implementation that shows the implementations involved to integrate an actual payment gateway. This is not an actual payment gateway and in no way should be used in production. This was created for demo purposes only and is helpful in showing how all the payment "plumbing" is configured.
View the classes in the package DemoSite/core/src/main/java/com/mycompany/sample
Testing
You can mock the Payment Request DTO without worrying about creating an actual Broadleaf Order since modules are only dependent on BLC Common
. This allows you to create isolated integration tests for each service.
If you've followed the package structure outlined above, it is helpful to enable trace debugging for the following:
<logger name="org.broadleafcommerce.payment.service.gateway"><level value="TRACE"/></logger>
<logger name="com.broadleafcommerce.payment.service.gateway"><level value="TRACE"/></logger>
<logger name="org.broadleafcommerce.vendor"><level value="TRACE"/></logger>
<logger name="com.broadleafcommerce.vendor"><level value="TRACE"/></logger>
<logger name="org.broadleafcommerce.common.web.payment"><level value="TRACE"/></logger>