details:   https://code.tryton.org/tryton/commit/60f0a98a3721
branch:    7.0
user:      Cédric Krier <[email protected]>
date:      Thu Mar 26 16:23:55 2026 +0100
description:
        Always convert JSON payload to stripe Event and replace dict methods by 
StripeObject methods

        Since Stripe 15.0.0 the StripeObject no longer inherits from dict. This 
means
        that we can no more manage payload as simple JSON but we must convert 
it to stripe.Event.
        And we must replace dict method by their StripeObject equivalent.

        Closes #14714
        (grafted from 5993be1ee56f1d5b51917b19f4b9379c0caee8db)
diffstat:

 modules/account_payment_stripe/payment.py                                      
  |  14 +++++-----
 modules/account_payment_stripe/routes.py                                       
  |  12 +++++--
 
modules/account_payment_stripe/tests/scenario_account_payment_stripe_dispute.rst
 |  12 ++++----
 3 files changed, 21 insertions(+), 17 deletions(-)

diffs (131 lines):

diff -r fec6344ae3f6 -r 60f0a98a3721 modules/account_payment_stripe/payment.py
--- a/modules/account_payment_stripe/payment.py Wed Mar 18 13:15:43 2026 +0100
+++ b/modules/account_payment_stripe/payment.py Thu Mar 26 16:23:55 2026 +0100
@@ -1018,16 +1018,16 @@
                     account.save()
                     Transaction().commit()
 
-    def webhook(self, payload):
+    def webhook(self, event):
         """This method handles stripe webhook callbacks
 
         The return values are:
-            - None if the method could not handle payload['type']
-            - True if the payload has been handled
+            - None if the method could not handle event.type
+            - True if the event has been handled
             - False if the webhook should be retried by Stripe
         """
-        data = payload['data']
-        type_ = payload['type']
+        data = event.data
+        type_ = event.type
         if type_ == 'charge.succeeded':
             return self.webhook_charge_succeeded(data)
         if type_ == 'charge.captured':
@@ -1071,7 +1071,7 @@
                 ('stripe_charge_id', '=', charge['id']),
                 ])
         if not payments:
-            payment_intent_id = charge.get('payment_intent')
+            payment_intent_id = getattr(charge, 'payment_intent', None)
             if payment_intent_id:
                 found = Payment.search([
                         ('stripe_payment_intent_id', '=', payment_intent_id),
@@ -1144,7 +1144,7 @@
                 ('stripe_charge_id', '=', charge['id']),
                 ])
         if not payments:
-            payment_intent_id = charge.get('payment_intent')
+            payment_intent_id = getattr(charge, 'payment_intent', None)
             if payment_intent_id:
                 found = Payment.search([
                         ('stripe_payment_intent_id', '=', payment_intent_id),
diff -r fec6344ae3f6 -r 60f0a98a3721 modules/account_payment_stripe/routes.py
--- a/modules/account_payment_stripe/routes.py  Wed Mar 18 13:15:43 2026 +0100
+++ b/modules/account_payment_stripe/routes.py  Thu Mar 26 16:23:55 2026 +0100
@@ -65,7 +65,7 @@
     if account.webhook_signing_secret:
         sig_header = request.headers['STRIPE_SIGNATURE']
         try:
-            stripe.Webhook.construct_event(
+            event = stripe.Webhook.construct_event(
                 request_body, sig_header, account.webhook_signing_secret)
         except ValueError:  # Invalid payload
             abort(http.client.BAD_REQUEST)
@@ -73,11 +73,15 @@
             abort(http.client.BAD_REQUEST)
     else:
         logger.warn("Stripe signature ignored")
+        try:
+            event = stripe.Event.construct_from(
+                json.loads(request_body), account.secret_key)
+        except ValueError:
+            abort(HTTPStatus.BAD_REQUEST)
 
-    payload = json.loads(request_body)
-    result = account.webhook(payload)
+    result = account.webhook(event)
     if result is None:
-        logger.info("No callback for payload type '%s'", payload['type'])
+        logger.info("No callback for event type '%s'", event['type'])
     elif not result:
         return Response(status=http.client.NOT_FOUND)
     return Response(status=http.client.NO_CONTENT)
diff -r fec6344ae3f6 -r 60f0a98a3721 
modules/account_payment_stripe/tests/scenario_account_payment_stripe_dispute.rst
--- 
a/modules/account_payment_stripe/tests/scenario_account_payment_stripe_dispute.rst
  Wed Mar 18 13:15:43 2026 +0100
+++ 
b/modules/account_payment_stripe/tests/scenario_account_payment_stripe_dispute.rst
  Thu Mar 26 16:23:55 2026 +0100
@@ -117,7 +117,7 @@
 
 Simulate charge.dispute.created event::
 
-    >>> StripeAccount.webhook([stripe_account], {
+    >>> StripeAccount.webhook([stripe_account], stripe.Event.construct_from({
     ...         'type': 'charge.dispute.created',
     ...         'data': {
     ...             'object': {
@@ -129,7 +129,7 @@
     ...                 'status': 'needs_response',
     ...                 },
     ...             },
-    ...         }, {})
+    ...         }, stripe_account.secret_key), {})
     [True]
     >>> payment.reload()
     >>> payment.state
@@ -141,7 +141,7 @@
 
 Simulate charge.dispute.closed event::
 
-    >>> StripeAccount.webhook([stripe_account], {
+    >>> StripeAccount.webhook([stripe_account], stripe.Event.construct_from({
     ...         'type': 'charge.dispute.closed',
     ...         'data': {
     ...             'object': {
@@ -153,7 +153,7 @@
     ...                 'status': 'lost',
     ...                 },
     ...             },
-    ...         }, {})
+    ...         }, stripe_account.secret_key), {})
     [True]
     >>> payment.reload()
     >>> payment.state
@@ -211,7 +211,7 @@
 
 Simulate charge.dispute.closed event::
 
-    >>> StripeAccount.webhook([stripe_account], {
+    >>> StripeAccount.webhook([stripe_account], stripe.Event.construct_from({
     ...         'type': 'charge.dispute.closed',
     ...         'data': {
     ...             'object': {
@@ -223,7 +223,7 @@
     ...                 'status': 'lost',
     ...                 },
     ...             },
-    ...         }, {})
+    ...         }, stripe_account.secret_key), {})
     [True]
     >>> payment.reload()
     >>> payment.state

Reply via email to