Files
tryton/modules/account_payment_stripe/routes.py
Cédric Krier 54d422f224 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
2026-03-26 16:23:55 +01:00

114 lines
3.8 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import json
import logging
from trytond.protocols.wrappers import (
HTTPStatus, Response, abort, with_pool, with_transaction)
from trytond.wsgi import app
logger = logging.getLogger(__name__)
@app.route(
'/<database_name>/account_payment_stripe/checkout/<model>/<id>',
methods=['GET'])
@with_pool
@with_transaction(context={'_skip_warnings': True})
def checkout(request, pool, model, id):
Payment = pool.get('account.payment')
Customer = pool.get('account.payment.stripe.customer')
if model == Payment.__name__:
Model = Payment
elif model == Customer.__name__:
Model = Customer
else:
abort(HTTPStatus.FORBIDDEN)
try:
record, = Model.search([
('stripe_checkout_id', '=', id),
])
except ValueError:
abort(HTTPStatus.NOT_FOUND)
customer_session_client_secret = ''
if model == Payment.__name__ and record.stripe_customer:
if customer_session := record.stripe_customer.get_session():
customer_session_client_secret = customer_session.client_secret
Report = pool.get('account.payment.stripe.checkout', type='report')
# TODO language
data = {
'model': Model.__name__,
'customer_session_client_secret': customer_session_client_secret,
'return_url': request.base_url + '/end'
}
ext, content, _, _ = Report.execute([record.id], data)
assert ext == 'html'
return Response(content, HTTPStatus.OK, content_type='text/html')
@app.route(
'/<database_name>/account_payment_stripe/checkout/<model>/<id>/end',
methods=['GET'])
@with_pool
@with_transaction(readonly=False, context={'_skip_warnings': True})
def checkout_end(request, pool, model, id):
Payment = pool.get('account.payment')
Customer = pool.get('account.payment.stripe.customer')
if model == Payment.__name__:
Model = Payment
elif model == Customer.__name__:
Model = Customer
else:
abort(HTTPStatus.FORBIDDEN)
try:
record, = Model.search([
('stripe_checkout_id', '=', id),
])
except ValueError:
abort(HTTPStatus.NOT_FOUND)
if model == Payment.__name__:
Payment.process([record])
record.stripe_intent_update()
return Response(
'<body onload="window.close()">', HTTPStatus.OK,
content_type='text/html')
@app.route(
'/<database_name>/account_payment_stripe/webhook/<account>',
methods={'POST'})
@with_pool
@with_transaction(context={'_skip_warnings': True})
def webhooks_endpoint(request, pool, account):
import stripe
Account = pool.get('account.payment.stripe.account')
account, = Account.search([
('webhook_identifier', '=', account),
])
request_body = request.get_data(as_text=True)
if account.webhook_signing_secret:
sig_header = request.headers['STRIPE_SIGNATURE']
try:
event = stripe.Webhook.construct_event(
request_body, sig_header, account.webhook_signing_secret)
except ValueError: # Invalid payload
abort(HTTPStatus.BAD_REQUEST)
except stripe.SignatureVerificationError:
abort(HTTPStatus.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)
result = account.webhook(event)
if result is None:
logger.info("No callback for event type '%s'", event['type'])
elif not result:
return Response(status=HTTPStatus.NOT_FOUND)
return Response(status=HTTPStatus.NO_CONTENT)