diff options
| author | Damien Bouvy <dbo@odoo.com> | 2019-12-31 09:18:54 +0000 |
|---|---|---|
| committer | Damien Bouvy <dbo@odoo.com> | 2019-12-31 09:19:34 +0000 |
| commit | 525d363b560ca5b3671850163ecd0ec9e6c8a290 (patch) | |
| tree | a2ee911a06efe9d0298a61264333eb6e39be364d /addons/payment_stripe | |
| parent | aca2b7191936f0b72a3a24aea1568b7d32c27a16 (diff) | |
[FIX] payment_stripe: better error handling
In some cases, Stripe will return the result of a transaction with
a faulty HTTP Status (e.g. 4XX statuses) - not because the request
was malformed, but because the payment failed. It is a bit unfortunate
that Stripe would not differentiate between payment status and request
validity, but that's the state of things.
This commit ensures that such a response will be logged correctly, by
making the call to `raise_for_status` conditionnal on the response object's
status code and internal structure, forwarding the response's json to the
validation flow if the status is in the 4XX range and a `code` key is
found in the response, as described in https://stripe.com/docs/error-codes
While testing this fix, it became apparent that some error message
processing in the frontend was not correctly handled as well - instead
of purely rejecting the promise, a failed payment should still send its
payload to the backend, to allow the server to put the transaction in
the correct state according to the response.
Diffstat (limited to 'addons/payment_stripe')
| -rw-r--r-- | addons/payment_stripe/models/payment.py | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index 39a8a67493e..f7aeeb770a1 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -61,17 +61,19 @@ class PaymentAcquirerStripe(models.Model): 'Stripe-Version': '2019-05-16', # SetupIntent need a specific version } resp = requests.request(method, url, data=data, headers=headers) - try: - resp.raise_for_status() - except HTTPError: - _logger.error("Here are some more information for the " - "following HTTP error on %s:\n" - "Request data:\n%s\n" - "Response body:\n%s", - url, pprint.pformat(data), resp.text) - stripe_error = resp.json().get('error', {}).get('message', '') - error_msg = " " + (_("Stripe gave us the following info about the problem: '%s'") % stripe_error) - raise ValidationError(error_msg) + # Stripe can send 4XX errors for payment failure (not badly-formed requests) + # check if error `code` is present in 4XX response and raise only if not + # cfr https://stripe.com/docs/error-codes + # these can be made customer-facing, as they usually indicate a problem with the payment + # (e.g. insufficient funds, expired card, etc.) + if not resp.ok and not (400 <= resp.status_code < 500 and resp.json().get('error', {}).get('code')): + try: + resp.raise_for_status() + except HTTPError: + _logger.error(resp.text) + stripe_error = resp.json().get('error', {}).get('message', '') + error_msg = " " + (_("Stripe gave us the following info about the problem: '%s'") % stripe_error) + raise ValidationError(error_msg) return resp.json() def _create_stripe_session(self, kwargs): @@ -276,11 +278,8 @@ class PaymentTransactionStripe(models.Model): self._set_transaction_pending() return True else: - error = tree.get('failure_message') - _logger.warning(error) - vals.update({'state_message': error}) - self.write(vals) - self._set_transaction_cancel() + error = tree.get("failure_message") or tree.get('error', {}).get('message') + self._set_transaction_error(error) return False def _stripe_form_get_invalid_parameters(self, data): |
