[FIX] payment_stripe: prevent crash if the payment intent can't be created

When the payment method was detached from the customer, trying to pay
with the linked payment token would end up with a crash because Stripe
failed to send us the payment intent, as it could not create it.

With this commit, we test for the existence of the returned payment
intent and prematurely return in `_send_payment_request` to prevent a
cursor rollback. The transaction is set in 'error' and the error
message is logged in the stdout and on the transaction's state message
field.

closes odoo/odoo#120348

X-original-commit: 4ebf0efc16ef78ca568ef93fb2c36ce404cb0c12
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
Antoine Vandevenne (anv)
2023-05-03 11:16:43 +02:00
parent ded123b65f
commit 1ac7b728cb
2 changed files with 11 additions and 1 deletions
@@ -270,7 +270,8 @@ class PaymentProvider(models.Model):
# Stripe can send 4XX errors for payment failures (not only for badly-formed requests).
# Check if an error code is present in the response content and raise only if not.
# See https://stripe.com/docs/error-codes.
# If the request originates from an offline operation, don't raise and return the resp.
# If the request originates from an offline operation, don't raise to avoid a cursor
# rollback and return the response as-is for flow-specific handling.
if not response.ok \
and not offline \
and 400 <= response.status_code < 500 \
@@ -203,6 +203,8 @@ class PaymentTransaction(models.Model):
"payment request response for transaction with reference %s:\n%s",
self.reference, pprint.pformat(payment_intent)
)
if not payment_intent: # The PI might be missing if Stripe failed to create it.
return # There is nothing to process; the transaction is in error at this point.
self.stripe_payment_intent = payment_intent['id']
# Handle the payment request response
@@ -242,7 +244,14 @@ class PaymentTransaction(models.Model):
if 'error' not in response:
payment_intent = response
else: # A processing error was returned in place of the payment intent
# The request failed and no error was raised because we are in an offline payment flow.
# Extract the error from the response, log it, and set the transaction in error to let
# the calling module handle the issue without rolling back the cursor.
error_msg = response['error'].get('message')
_logger.error(
"The creation of the payment intent failed.\n"
"Stripe gave us the following info about the problem:\n'%s'", error_msg
)
self._set_error("Stripe: " + _(
"The communication with the API failed.\n"
"Stripe gave us the following info about the problem:\n'%s'", error_msg