Broadleaf Microservices
  • v1.0.0-latest-prod

OMS Payment Interactions

The Order Operation Service can execute several types of transactions against payments on an Order via an external payment transaction execution service. By default, this would be our out-of-box Payment Transaction Services:

  • Capture

  • Reverse Authorize

  • Refund

Important Guidelines

There are several important guidelines that are followed whenever executing these transactions:

  1. Whenever executing transactions against payments for an Order, a lock should always be obtained to ensure no other conflicting operations occur simultaneously

    1. This lock should be obtained at the very start of any operation involving payments for the Order

    2. After the lock is obtained, the PaymentSummaries should be re-read from the PaymentTransactionServices to ensure no payments are out of date

    3. ResourceLockProvider provides this ability to create a lock on the Order, stored in the OrderService

  2. By default, Broadleaf only supports performing transactions that encompass one Order Fulfillment at once, not the whole Order

    1. For example, it’s only possible to capture one Order Fulfillment at once

      1. In a partial capture scenario, the Order Fulfillment is split prior the capture, then the capture is performed on the split fulfillment. See Fulfillment Splitting Docs for more details

    2. When Return Confirmations result in refunds, one refund is issued per relevant Return Confirmation

  3. Transaction’s Source Entity Type and Id should always be set in tandem with a new transaction execution

    1. These properties associate a transaction with the entity that triggered it

      1. When a Fulfillment is captured, it connects the capture transaction to that Fulfillment

      2. When a Fulfillment is cancelled, it connects the reverse-authorize or refund transactions to that Fulfillment

      3. When a Return is confirmed, it connects the refund transaction to the Return Confirmation that triggered it

Configurations

All the payment interactions within the OMS are executed through the Payment Transaction Services via the Payment Provider. For payment-related configurations, please refer to:

Payment Interactions

For all the payment transaction executions within the OMS, regardless of the transaction type, are executed with the following flow:

Note
For more details on payment locking concepts, please refer to the Payment Locking Docs

Identifying Payments

When identifying the payments for an Order, its payments are gathered by owner type and id, which are BLC_CART and the cart id stored on the Order by default.

Sorting Payments

Once the payments are gathered, they are then sorted based on configured payment priority based on payment gateway type.

The out-of-box configuration for OMS supports multiple payments for a single Order. In some cases, the sorting order of these payments may matter, such as when you’re capturing or refunding payments (i.e. you may have a preference on which gateway should be used to execute transactions first).

To allow customizations of the payment sorting order, a hook point has been added for the transaction execution in OrderOperationServices:

  1. Capture

    1. DefaultPaymentCaptureService#sortPaymentsByPriority

  2. Reverse Authorize

    1. DefaultPaymentAuthReversalService#sortPaymentsByPriority

  3. Refund

    1. DefaultPaymentRefundService#sortPaymentsByPriority

  4. Refund Or Reverse Payments for the Canceled Fulfillment

    1. PaymentReversalFulfillmentCancelledListener#sortPaymentsByPriority

By default, each of those hook points (except for reverse authorize) delegates to PaymentPriorityStrategy to sort the payments based on the payment gateway type, which can be configured in the Configuration section.

By default, payments are not for reverse authorize transactions, because these transactions are executed against an entire order to reverse all of the remaining authorized amounts for all the order’s payments. Therefore the ordering for reverse authorize transactions doesn’t make much impact.

Configuration

Each configuration property controls the payment priorities for different transaction types.

Important
It is crucial to understand that the list of payment gateways for each property is ordered. Payment gateway that is placed at the first of the list will be the highest priority.
Capture Priorities

Controls the priorities of payments when performing a CAPTURE transaction.

  • Property: broadleaf.orderoperation.service.payment.capture-payment-gateway-priorities

  • Contains the ordered list of payment gateways

Example
broadleaf:
  orderoperation:
    service:
      payment:
        capture-payment-gateway-priorities:
          - PAYPAL
          - CYBERSOURCE
          - AMAZON_PAYMENT_SERVICES
          - STRIPE

With this configuration, capture transactions for PayPal payments will be executed first, then CyberSource, so on and so forth.

Important
It is recommended to prioritize payment gateways that use AuthAndCapture transaction type first, so that checkout-executed capture amounts will be claimed first, before executing new capture transactions.
Refund Priorities

Controls the priorities of payments when performing a REFUND transaction.

  • Property: broadleaf.orderoperation.service.payment.refund-payment-gateway-priorities

  • Contains the ordered list of payment gateways

Example
broadleaf:
  orderoperation:
    service:
      payment:
        refund-payment-gateway-priorities:
          - STRIPE
          - PAYPAL
          - AMAZON_PAYMENT_SERVICES

In this example, refund transactions for Stripe payments will be executed first, then PayPal, so on and so forth.

Refund Or Reverse Payments for the Canceled Fulfillment

Controls the priorities of payments when performing a REFUND or REVERSE_AUTH when the fulfillment is canceled.

  • Property: broadleaf.orderoperation.service.payment.cancel-payment-gateway-priorities

  • Contains the ordered list of payment gateways

Example
broadleaf:
  orderoperation:
    service:
      payment:
        cancel-payment-gateway-priorities:
          - STRIPE
          - PAYPAL
          - AMAZON_PAYMENT_SERVICES

In this example, refund transactions for Stripe payments will be executed first, then PayPal, so on and so forth.

Capture

Performing a payment capture via the OMS is usually done to a single Order Fulfillment which can represent an entire Order or a partial Order. To signify that the Order Fulfillment is being captured, its status is updated to CAPTURING_PAYMENT.

Note
The fulfillment status can be changed to CAPTURE_AWAITING_RESULT if payment transaction results will be provided asynchronously. See Asynchronous Payment Transaction Support.

Therefore, when performing a partial capture on an Order Fulfillment, it is first split into two Order Fulfillments, then the capture transaction is executed against the newly split Order Fulfillment.

For more details on the fulfillment status change and splitting, please refer to Changing Status Docs and Fulfillment Splitting Docs.

Capturing a Payment for a Fulfillment when AUTHORIZE_AND_CAPTURE Transactions Were Used in Checkout

If AUTHORIZE_AND_CAPTURE transactions were used during checkout, then additional CAPTURE transactions may not be necessary when "capturing payment" for a fulfillment. Instead, a portion, or all, of the already-captured amount must be "claimed" for the fulfillment.

For example, if an Order contains two items (item1 is $20 and item2 is $15), and has 2 payments: gift card of $10 (AUTHORIZE_AND_CAPTURE) and credit card of $25 (AUTHORIZE). Additionally, we configured the system to capture gift cards before credit cards.

If we fulfill item1 ($20), then the system will claim $10 that was already captured from the gift card, and then execute an additional $10 capture against the credit card.

From there, if we fulfill item2 ($15), then the system will capture the remaining $15 from the credit card.

A fulfillmentCancelled message is sent when an Order Fulfillment is cancelled, and it will be picked up by the PaymentReversalFulfillmentCancelledListener for processing. The listener executes reverse authorize transaction against any authorized amount on the order, and issues a refund for any captured amount for the fulfillment (more details in the Refund From Cancelled Fulfillment Section).

Important
It is crucial to understand that the reverse authorize transactions will not be executed until the entire order has been fully captured and/or cancelled

Auto Capturing Authorized Payment

Since 1.8.11-GA it is possible to turn on the automatic capturing of the authorized payments after the Order is created. This can be useful for payment gateways whose Capture, ReverseAuth, or Refund interactions have some unique quirks that make for more challenging fulfillment, fulfillment cancellation, or return interactions. For example, Stripe doesn’t support multiple partial captures (i.e. if a partial capture is executed, then they automatically reverse-auth the remaining amount). In this case, you can capture up front, & from there just use refunds for fulfillment cancellations or returns. Similarly, Tabby only allows refunds to be executed if the payment is fully captured, or partially captured & the remainder is reverse-authed. In this case, it’s also beneficial to capture everything prior to executing any fulfillments, fulfillment cancellations, or returns. Once fully captured, these fulfillment cancellations & returns can just execute partial refunds as needed.

To automatically capture the payment add the following configuration:

broadleaf:
  orderoperation:
    service:
      payment:
        enable-auto-capture: true (1)
        auto-capture-payment-gateways:
          - STRIPE
          - TABBY
  1. Enables the com.broadleafcommerce.orderoperation.service.messaging.ordercreated.AutoCapturePaymentsOrderCreatedListener that is responsible for executing auto-capturing after the order is created.

Reverse Authorize

When the Order Fulfillment is cancelled the authorized payment is reversed by the PaymentReversalFulfillmentCancelledListener listener. The payment can be reversed fully or partially, depending on the type of ReverseAuthorize supported by the payment gateway.

If the partial reverse authorization is not supported, it will be fully reversed when the order fulfillment is finalized (i.e. no further actions can be taken against the fulfillment).

Refund

Out of the box, refunds can be triggered from two scenarios, cancelled fulfillment and confirmed returns.

Refund From Cancelled Fulfillment

Similar to Reverse Authorize Transaction, refunds can be issued when the Order Fulfillment is cancelled as well.

The refunds can potentially be issued by the same listener, PaymentReversalFulfillmentCancelledListener. However, refunds will only be issued if the Order Fulfillment has been fully captured. If there’s any amount that is able to be captured, no refunds will be issued. Otherwise, an refund will be issued for the entire fulfillment total.

For refund-related configurations, please refer to Auto Reverse or Refund For Cancelled Fulfillment Property.

Refund From Confirmed Returns

The other scenario of how a refund can be issued is from confirmed returns. Once a return is confirmed, a refund is issued with the calculated refund amount.

For more details on the return flow and refunding, please refer to the Return Flow Docs.

For details on the merchandise total to refund calculation, please refer to the Merchandise Refund Calculation Docs.

Important
It is crucial to understand that the refund transactions will not be executed until all the returns have been confirmed within the same Return Authorization

For return confirmation-related refund configurations, please refer to Auto Refund After Confirmed Return Property.

Asynchronous Payment Transaction Support

Many payment gateways leverage webhooks to asynchronously communicate transaction results. In most cases, they are used as a secondary means of communicating results. On the other hand, some gateways use webhooks as the primary means of communicating transaction results for Capture, Refund, & ReverseAuthorize (Void) transactions. In these cases, the Capture, Refund, & ReverseAuthorize transaction response will simply inform you that the request is received/queued, instead of providing transaction results. Once the transaction has been executed, the transaction result is communicated via webhooks.

To support the gathering of async results for capture & refund transactions in the context of fulfilling or returning items, we introduced the FulfillmentCaptureWebhookListener and ReturnConfirmationRefundWebhookListener. These listeners are used to advance the fulfillment & return confirmation processes, once transaction results are received.

Since most projects likely won’t require these components, they’re disabled by default. With that being said, they can be enabled via the broadleaf.orderoperation.async-payment-transaction-support.enabled property.

Payment Distribution Support

Since 1.7.7-GA, a new feature is introduced to support distributing a transaction amount across multiple payments, meaning that capture or refund transactions will be executed against all the payments based on their distribution ratios.

For example, consider this order setup:

  • Order total: $100

  • Items:

    • Item1: $40

    • Item2: $60

    • For the sake of simplicity, consider fulfillment and shipping totals included

  • Payments:

    • Gift Card: $10 (10% distribution ratio)

    • Reward Points: $20 (20% distribution ratio)

    • Credit Card" $70 (70% distribution ratio)

In this case, capturing item1 will execute a total of three capture transactions:

  • Gift Card: $40 * 10% = $4

  • Reward Points: $40 * 20% = $8

  • Credit Card: $40 * 70% = $28

Since this feature will make OrderOperationService to always execute multiple transactions (if an order has multiple payments), this feature is disabled by default. However, it can be enabled via the broadleaf.orderoperation.service.distribute-payment-transaction-amount-across-payments property.