In some checkout scenarios, you can be left with a successful payment transaction and an overall failed checkout. For example, if you have 2 payments, the first payment’s transaction is successful, and the second payment’s transaction fails. In this case, the successful transaction should eventually be reversed, if it’s not used for a subsequent successful checkout.
Instead of attempting to reverse an
AUTHORIZE_AND_CAPTURE in real time,
CheckoutRollbackEventListener to mark the successful transactions as reversal candidates
managementState = "REVERSAL_CANDIDATE"). These transactions are identified by the payment’s related cart id
and the checkout attempt’s
From there, the
PaymentTransactionReversalJobListener is responsible for identifying reversal candidate transactions
and executing reversal transactions. By default, this scheduled job is configured to execute every 5 minutes,
and uses a 15 minutes buffer for identifying transactions. Therefore, reversal candidate transactions have
a 15-minute window where they can still contribute to a successful checkout attempt.
To avoid a race condition where the
CheckoutRollbackEventListener and the customer’s second checkout attempt
don’t negatively effect each other, we take the following steps:
Lock the payment when taking action against its transaction(s)
When reusing a successful transaction for the second checkout attempt, we update the transaction’s
and clear its
managementState (previously blank or
Therefore, if the
CheckoutRollbackEvent is processed after this checkout attempt,
then it won’t find the successful transaction to mark it as a reversal candidate.
This is done via
When a checkout successfully completed, the cart’s payment transactions have their