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
or AUTHORIZE_AND_CAPTURE
in real time,
we leverage CheckoutRollbackEventListener
to mark the successful transactions as reversal candidates
(i.e. managementState = "REVERSAL_CANDIDATE"
). These transactions are identified by the payment’s related cart id
and the checkout attempt’s requestId
.
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.
Note
|
|
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 requestId
and clear its managementState
(previously blank or "REVERSAL_CANDIDATE"
).
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.
Note
|
This is done via PaymentTransactionExecutionActivity (CartOperationServices) calling
PaymentTransactionManagementEndpoint#claimTransactionsForRequest(…) (PaymentTransactionServices).
|
Note
|
When a checkout successfully completed, the cart’s payment transactions have their managementState
set to "AUTOMATIC_REVERSAL_NOT_ALLOWED" to block the reversal of the transactions.
|