fix: skip stale authorization voided webhooks#659
fix: skip stale authorization voided webhooks#659Vladimir Kalchenko (vkalchenko) wants to merge 2 commits into
Conversation
Max Stegmeyer (mstegmeyer)
left a comment
There was a problem hiding this comment.
Looking good, thanks for the improvement 💙
| - Fixes an issue, where the express checkout could choose a customer country that was not assigned to the correct sales channel (shopware/SwagPayPal#479) | ||
| - Fixes an issue, where cookies are added even though associated payment methods are not active (shopware/SwagPayPal#457) | ||
| - Fixes an issue, where the state of a country was not correctly transmitted to PayPal (shopware/SwagPayPal#469) | ||
| - Fixes an issue, where stale `PAYMENT.AUTHORIZATION.VOIDED` webhooks could cancel unrelated order transactions |
There was a problem hiding this comment.
This version has long been released. Actually, there are currently no unreleased changes.
Please add a new version "tag" here # REPLACE_GLOBALLY_WITH_NEXT_VERSION and put your changelog entry in there.
There was a problem hiding this comment.
Done
Chuc Le (untilu29)
left a comment
There was a problem hiding this comment.
Looks good to me 👍. Just a tiny nitpick (feel free to ignore).
Thanks for the contribution!
| $orderTransactionRepo = $container->get('order_transaction.repository'); | ||
| $orderTransactionRepo->update([[ |
There was a problem hiding this comment.
| $orderTransactionRepo = $container->get('order_transaction.repository'); | |
| $orderTransactionRepo->update([[ | |
| $this->orderTransactionRepository->update([[ |
There was a problem hiding this comment.
Updated, thanks for suggestion
| if ($resource instanceof Authorization) { | ||
| $storedResourceId = ($orderTransaction->getCustomFields() ?? [])[SwagPayPal::ORDER_TRANSACTION_CUSTOM_FIELDS_PAYPAL_RESOURCE_ID] ?? null; | ||
| if ($storedResourceId !== null && $storedResourceId !== $resource->getId()) { | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
| if ($resource instanceof Authorization) { | |
| $storedResourceId = ($orderTransaction->getCustomFields() ?? [])[SwagPayPal::ORDER_TRANSACTION_CUSTOM_FIELDS_PAYPAL_RESOURCE_ID] ?? null; | |
| if ($storedResourceId !== null && $storedResourceId !== $resource->getId()) { | |
| return; | |
| } | |
| } | |
| if ($resource instanceof Authorization) { | |
| $customFields = $orderTransaction->getCustomFields() ?? []; | |
| $storedResourceId = $customFields[SwagPayPal::ORDER_TRANSACTION_CUSTOM_FIELDS_PAYPAL_RESOURCE_ID] ?? null; | |
| $isStaleAuthorization = $storedResourceId !== null && $storedResourceId !== $resource->getId(); | |
| if ($isStaleAuthorization) { | |
| return; | |
| } | |
| } |
tt's just easier to understand
There was a problem hiding this comment.
Agreed and updated the code
|
|
||
| $webhook = $this->createWebhookV2(Event::RESOURCE_TYPE_AUTHORIZATION); | ||
| $resource = $webhook->getResource(); | ||
| static::assertInstanceOf(Payment::class, $resource); |
There was a problem hiding this comment.
| static::assertInstanceOf(Payment::class, $resource); | |
| static::assertInstanceOf(Authorization:::class, $resource); |
There was a problem hiding this comment.
Updated
When a customer re-authorizes a PayPal payment, PayPal voids the old authorization and sends a PAYMENT.AUTHORIZATION.VOIDED webhook. Because both old and new authorizations share the same orderTransactionId in custom_id, the handler was cancelling the transaction even though the current authorization is still valid. Before cancelling, compare the webhook resource ID against the swag_paypal_resource_id stored on the order transaction. If they do not match, silently skip the stale webhook.
7459958 to
d15497f
Compare
| - Added Apple Pay support for third-party browsers (shopware/SwagPayPal#485) | ||
| - Added setting to mark the shop as local environment to preventing connection issues when testing in a non-publicly accessible environment (shopware/SwagPayPal#463) | ||
| - Updated and optimized payment method icons | ||
| - Fixes an issue, where stale `PAYMENT.AUTHORIZATION.VOIDED` webhooks could cancel unrelated order transactions |
There was a problem hiding this comment.
Now you moved all entries to that new version. Please only add your entry there.
Also, please provide a translated version in CHANGELOG_de-DE.md (via AI / DeepL or similar if you don't speak German 😉 )
Ignore PAYMENT.AUTHORIZATION.VOIDED webhooks when the authorization resource ID does not match the one stored on the order transaction. This prevents stale webhooks from cancelling unrelated transactions.
1. Why is this change necessary?
When a customer re-authorizes a PayPal payment (e.g. after a failed initial capture), PayPal eventually voids the old authorization and sends a
PAYMENT.AUTHORIZATION.VOIDEDwebhook. The currentAuthorizationVoidedhandler resolves the Shopware order transaction viacustom_id(which contains theorderTransactionId) but does not verify whether the voided authorization ID matches the one currently stored on the transaction. Because both the old and new authorizations reference the sameorderTransactionId, the handler cancels the transaction - even though the new authorization is still valid on PayPal's side.This causes Shopware and PayPal to go out of sync: the transaction shows as "Cancelled" in Shopware while the PayPal authorization remains active and capturable.
2. What does this change do, exactly?
In
AuthorizationVoided::invoke(), before cancelling the transaction, the patch compares the PayPal authorization ID from the webhook resource ($resource->getId()) against theswag_paypal_resource_idstored in the order transaction's custom fields. If they do not match, the webhook is for a stale/previous authorization and is silently skipped.3. Describe each step to reproduce the issue or behaviour.
/account/order/edit/{orderId}). A new PayPal authorization is created, andswag_paypal_resource_idis updated on the Shopware transaction.PAYMENT.AUTHORIZATION.VOIDEDwebhook.orderTransactionIdincustom_id), sees it is in "authorized" state, and cancels it — even though the webhook refers to the old authorization, not the current one.4. Please link to the relevant issues (if any).
5. Checklist