Problem/Motivation

When refunding on a completed order, the refund is rejected in the Drupal UI for expected state Pending, but found Completed error, however the payment refund IS indeed processed through PayPal leaving the user with the impression that they have not refunded, when actually they have.

Set to major as this could prove very painful for business owners on larger purchases.

Steps to reproduce

Refund a payment on a completed order.

Proposed resolution

Fix it.

CommentFileSizeAuthor
#3 response-completed.png17.58 KBjsacksick
#3 payment-refunded.png45.55 KBjsacksick
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

tonytheferg created an issue. See original summary.

jsacksick’s picture

Do you have any error to share from the logs?

    catch (BadResponseException $exception) {
      $this->logger->error($exception->getResponse()->getBody()->getContents());
      throw new PaymentGatewayException('An error occurred while refunding the payment.');
    }

    if (strtolower($response['status']) !== 'completed') {
      throw new PaymentGatewayException(sprintf('Invalid state returned by PayPal. Expected: ("%s"), Actual: ("%s").', 'COMPLETED', $response['status']));
    }

The error should be logged...What was displayed in the UI as well? Could be that the response has changed and the status isn't "COMPLETED" as expected? Is this a partial refund?

jsacksick’s picture

Priority: Major » Normal
Status: Active » Postponed (maintainer needs more info)
StatusFileSize
new45.55 KB
new17.58 KB

I just tried reproducing this locally and couldn't... I'd appreciate if we could get a screenshot / dump of the response. I just tried performing a partial and a full refund and both worked, see the attached screenshots:

jsacksick’s picture

hm... Quick q: do you have Webhooks configured? I'm wondering if there is a race condition or something... Since I'm testing locally this isn't happening to me.

tonytheferg’s picture

Partial refund.

Sorry for the lack of clarity in the OP but I was busy contacting the customer to straighten out the mess, so I just plopped this in so I didn't forget.

jsacksick’s picture

Status: Postponed (maintainer needs more info) » Active

Can you confirm if you have Webhooks configured? If so, I think we might have an issue where the webhook is actually causing a double refund... Not really sure how we can prevent that unfortunately...
We'd either need to know that a particular event was processed or whether the refund was initiated from Drupal... Basically the intent was to make sure refunds initiated from PayPal directly would be reflected into Drupal.

In the meantime, perhaps you can stop listening to the PAYMENT.CAPTURE.REFUNDED event?

jsacksick’s picture

Chatted with Ryan on this on Slack. We should check if it is possible to embed context in the API request so we can easily identify events that were initiated from on site activity (e.g: a refund triggered from the Drupal admin).

UPDATE: PayPal doesn't support arbitrary metadata fields like Stripe does, so we can't attach a key-value pair like "source": "drupal" and expect to see it in webhooks. We're not passing a "custom_id" whenever the refund is initiated but we are expecting it in the Webhook, which makes me think it is inherited from when the PayPal order is created.
We could use "invoice_id" as well but that might be reflected somewhere in the PayPal UI and that field has an associated meaning.

jsacksick’s picture

Priority: Normal » Major
Status: Active » Needs review

@tonytheferg: Anyway you could test the patch?

tonytheferg’s picture

I don't have webhooks configured.

I would need to set up the test account to test the patch as this happened on a live site with a live transaction.

  • jsacksick committed 29ed61b3 on 8.x-1.x
    Issue #3519157 by jsacksick: Refunds are processed in PayPal despite...
jsacksick’s picture

Priority: Major » Normal
Status: Needs review » Postponed (maintainer needs more info)

Ok so my analysis isn't correct even though I believe this is also a problem.
Could you check if the status returned was "pending" perhaps? We can't consider "pending" refunds as "completed", so perhaps we should add special handling for this and add a message informing the merchant.
Anything else that could help us further diagnose the issue?

If webhooks are configured properly, then I believe the payment would be later marked as refunded.

Will merge the MR (that is unrelated), but update this issue status back to Postponed until more information is provided.

tonytheferg’s picture

Yes, When I get some free time I can try to reproduce in a sandbox, or if I have another PayPal refund on the live site, I can try as well, and provide better info.

Thanks!

jsacksick’s picture

But do you have logs for the problematic refund?

tonytheferg’s picture

Unfortunately no, as the log only goes back to the 18th.

Maybe I do in one of the dev environments. I'll follow up

tonytheferg’s picture

I have the DB log for that time, but no error logs in the DB for the transaction. My guess is it's just a form validation error that is not logged.

grevil’s picture

Status: Postponed (maintainer needs more info) » Needs work

@jsacksick you forgot to initiate the UUID service! Which currently leads to the following error when refunding:

Error: Call to a member function generate() on null in Drupal\commerce_paypal\Plugin\Commerce\PaymentGateway\Checkout->refundPayment() (line 669 of modules/contrib/commerce_paypal/src/Plugin/Commerce/PaymentGateway/Checkout.php).

  • jsacksick committed da46d9da on 8.x-1.x
    Issue #3519157 by jsacksick: Fix a regression introduced with refunds...
jsacksick’s picture

Status: Needs work » Fixed

Fixed this and tagged a new release.

grevil’s picture

Thank you!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.