Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cybersource refund request returned ApiException: (400) when refunding a PayPal purchase #1047

Open
sentry-io bot opened this issue Sep 23, 2022 · 8 comments

Comments

@sentry-io
Copy link

sentry-io bot commented Sep 23, 2022

Sentry Issue: MITXONLINE-2DA

ApiException: (400)
Reason: Bad Request
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '-1', 'Strict-Transport-Security': 'max-age=31536000', 'Content-Type': 'application/json', 'Content-Length': '251', 'x-response-time': '127ms', 'X-OPNET-Transaction-Trace': '729deeac-a3f2-4eff-98d5-29e194319572', 'Connection': 'keep-alive', 'v-c-correlation-id': '3ac554f6-0061-4bfc-aa4f-937f2010cb26'})
HTTP response body: {"id":"6639507207906418804983",...
(13 additional frame(s) were not displayed)
...
  File "CyberSource/api_client.py", line 499, in call_api
    return self.__call_api(resource_path, method,
  File "CyberSource/api_client.py", line 293, in __call_api
    response_data = self.request(method, url,
  File "CyberSource/api_client.py", line 542, in request
    return self.rest_client.POST(url,
  File "CyberSource/rest.py", line 281, in POST
    return self.request("POST", url,
  File "CyberSource/rest.py", line 243, in request
    raise ApiException(http_resp=r)

Error processing row from google sheets
@arslanashraf7 arslanashraf7 self-assigned this Sep 27, 2022
@arslanashraf7
Copy link
Contributor

arslanashraf7 commented Sep 28, 2022

Update:

I wasn't able to get through the order completion using Paypal test account locally or on RC, I get Your order was declined. Please choose another payment method. I need to check how I can do a successful transaction using Paypal.

The Cybersource is complaining about invalid field data as seen
image

On the other hand, While I was comparing the data, the only difference I see between a regular refund locally and the refund payload in this issue is that the amount is being sent as a string in this issue whereas while testing locally I could see the amount is a float. This could be a reason for this error since CyberSource is complaining about field data being invalid.

The other thing is, I was testing this through the Refund button in Django Admin, while this issue was raised through the refund sheet.

Some of the things we might need to compare are how the amount is mentioned in the sheet, And what Successful payment response data we had in Fulfilled Orders in Django Admin.

@arslanashraf7
Copy link
Contributor

Please disregard the part in my above comment where I mentioned the issue might be the amount.

The issue is related to the Transaction Id, Where Cybersource is complaining about the transaction id being invalid and this one of the reasons this could happen is that the transaction id we are sending for the refund request doesn't exist on Cybersource and this I was able to reproduce locally too by sending a non-existent transaction id in refunds.

The things I'd suggest verifying are:

  1. Check if there is a transaction with transaction id 6637068427226920904262?
  2. Since this was produced by sheets where we use reference_number and then we get the transaction id from the transaction data we gather in the payment success, in the logs the transaction data is she doesn't have the transaction_id

transaction

Based on point#2, We might also want to see the associated transaction objects with this order in Django Admin. There should ideally be one transaction object having transaction_id in the data.

@pdpinch Could you try to refund this order through Django Admin, Just to check if there is any issue with the refunds through the sheets flow.

@pdpinch
Copy link
Member

pdpinch commented Sep 29, 2022

I tried through the django admin and got another 500 error:

https://sentry.io/organizations/mit-office-of-digital-learning/issues/3632055622/?project=5864687&query=is%3Aunresolved

I also tried making a PayPal order in RC. I was surprised to find that it points to sandbox.paypal.com and not the live service. Unfortunately, I go the same error as you did.

@arslanashraf7
Copy link
Contributor

arslanashraf7 commented Sep 29, 2022

Hmm, This looks like the same issue, The transaction_id being sent for refund is invalid as per CyberSource. Could we check on Cybersource dashboard production and verify that there is a transaction entry there with id 6637068427226920904262?

@pdpinch
Copy link
Member

pdpinch commented Sep 29, 2022

I think so:

image

Let me know if there's more information that would be helpful. Or we can Zoom Friday morning.

@arslanashraf7
Copy link
Contributor

I think a Zoom call might be helpful to check if we can see any specific logs that might be coming from Paypal or if there is something specific wrong to this transaction only, At this point, seeing the logs, CyberSource seems to be complaining about the transaction_id which I assumed might not be present in Cybersource transactions but it is there. So there might be something else blocking the refund for a Paypal transaction. If possible, We might also want to fix Paypal transaction in RC to reproduce this error locally.

@pdpinch
Copy link
Member

pdpinch commented Nov 1, 2022

I put through a PayPal refund through the EBC manually, and I noticed that I had to enter the refund amount. Are we passing the refund amount through the API?

@arslanashraf7
Copy link
Contributor

I put through a PayPal refund through the EBC manually, and I noticed that I had to enter the refund amount. Are we passing the refund amount through the API?

Yes, The refund implementation does that and it's flexible in two ways. (Reference)

  1. We can provide a custom amount (e.g. In case of refund through Django Admin we can add a custom amount) or leave it to default
  2. If no custom amount is provided, The default amount is passed. (The default amount in this case is the value of req_amount field from the payment transaction response)

There might be another thing to look for while refunding through EBC, We need to reflect that in our database too just like the implementation does that, e.g. Ideally we should:

  1. Mark the Order as refunded
  2. (Maybe?) Add a refund transaction object for that order
  3. See, If we want to unenroll the user or not

@pdpinch pdpinch changed the title Cybersource refund request returned ApiException: (400) Cybersource refund request returned ApiException: (400) when refunding a PayPal purchase Nov 2, 2022
@arslanashraf7 arslanashraf7 removed their assignment Apr 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants