Adyen / adyen-magento2

Adyen Payment plugin for Magento2
MIT License
155 stars 211 forks source link

[ECP-9444] Klarna payment gets cancelled on paymentDetails endpoint, but then authorised successfully via webhook #2702

Closed pknap closed 2 months ago

pknap commented 3 months ago

Describe the bug

We are facing an issue with Klarna through Adyen integration, where paymentsDetails response result code is refused, which makes Magento cancel the order, but then few minutes later Adyen sends webhook with Authorised event. However since order is already cancelled Magento cannot move it to processing state. This ends up with critical issue where funds are taken from customer's account but his/hers order is cancelled.

Example case:

image

Aug 6, 2024, 21:14:46 Magento calls payments-details endpoint of Adyen integration. Adyen then forwards this request to Klarna. Klarna answers that payment is refused.

image

So Adyen tells Magento to cancel the order here:

https://github.com/Adyen/adyen-magento2/blob/9.3.0/Helper/PaymentResponseHandler.php#L274

Magento cancels the order.

Aug 6, 2024, 21:14:53, 7 seconds later, Adyen receives Authorisation event from Klarna. Payment gets captured.

image

Aug 6, 2024, 21:16:17 Adyen sends webhook request to Magento to tell it that payment is successful and it should update order state to processing

Aug 6, 2024, 21:18:05 Magento cron runs and processes the webhook. At this point order is already cancelled, so Magento won't move it to processing state, because this kind of transition is not allowed.

We have opened a ticket via Adyen customer area too providing more data (case number 04124616) but I'm also opening ticket here, because the answer of the support was:

I checked in the logs for the shared payment and we get both of the two responses, however since the later one is the most reliable response, the first resultCode is overwritten and payment is authorised. The second status is the one that is shared in the Authorisation Webhook as that is the most reliable source of payment status in this case. The best course of action for the future is to relay on the Authorisation Webhook rather than the details call for your order creation system as stated in our docs [here](https://docs.adyen.com/development-resources/webhooks/webhook-types/#event-codes).

so I'm wondering why the module operates differently.

I'd gladly help to resolve the issue but I'd need to first understand what is expected behaviour in such scenario. Unfortunately we don't know anything about the reasons of Klarna refusing the payment, thus I'm not able to replicate it on my own.

I'm just guessing but should we not cancel the order at all in case Klarna sends refused resultCode, because the session is still open and it is possible that the same payment will end up successful? Or perhaps should Klarna payment orders automatically go to payment_review state instead of pending_payment here:

https://github.com/Adyen/adyen-magento2/blob/main/Observer/SetOrderStateAfterPaymentObserver.php#L119

and then canCancel method on order during paymentsDetails would return false and order would not get cancelled?

I know that there have been some changes in cancellation logic here:

https://github.com/Adyen/adyen-magento2/pull/2592/files

which were introduced in 9.5.1 (we are using 9.3.0) but my understanding is that it would not resolve our issue anyway as order in pending_payment would still return true on canCancel() call.

To Reproduce

Unfortunately at this point I don't have a clue how to replicate the issue with getting Payment refused response from Klarna with the same PSP reference and get it authorised 7 seconds later. We don't have enough data logged in Adyen dashboard / Magento logs to understand reason for Klarna refusal in the first place.

Expected behavior Order is not cancelled on Klarna payment refusal if there is still a chance that the same payment session will get authorised later and processed successfully by webhook.

Magento version 2.4.6-p6

Plugin version 9.3.0

Desktop (please complete the following information): I don't think this is browser / device related issue as it seems to be an inconsistency between paymentDetails response and following webhook response.

Smartphone (please complete the following information): I don't think this is browser / device related issue as it seems to be an inconsistency between paymentDetails response and following webhook response.

candemiralp commented 2 months ago

Hello @pknap,

Thank you for your contribution and all the detailed explanation of the issue.

Unfortunately, this is a known issue of Klarna. Ideally, payment session on Klarna side should be closed/cancelled after a failing attempt or shopper cancellation. However, that is not the case. This open session on Klarna allows shoppers to complete the payment even after the first failure.

As expected, the plugin cancels the order after getting the initial refusal (after making /payments/details API call). However there is no way to handle the follow-up authorisation since the order has already been cancelled.

I appreciate your effort to solve this issue by creating a PR but we have decided to continue our investigation to solve this issue on a higher level. Therefore, I'll keep the PR open at least until completing the investigation.

You will be informed once we complete the investigation.

Best Regards, Can

candemiralp commented 2 months ago

Hello @pknap,

Thank you for your patience while we're investigating this issue. As promised, we have solved this issue on Adyen implementation level and this PR can be closed now for the reasons I've explained above. With this new implementation, Klarna payments can not be authorised again if the shopper already cancels it. Therefore, there won't be Authorisation webhooks after the order cancellation.

As the next step, I kindly request you to reach out to Adyen support via sending an email to support@adyen.com to enable this new implementation on your Merchant Account.

Please indicate that you are a Adobe Commerce / Magento 2 merchant and ask them to enable account data property (ADP) klarnaPaymentsDoTechnicalReversal: true on your merchant account on your email. Also, adding ticket number ECP-9444 and URL of this PR to your email will be useful.

I've already informed our support team and they are waiting for your email. This process needs be done on a secure channel and we can't proceed to the rest on Github comments.

Best Regards, Can