Compare commits

...

1 Commits

Author SHA1 Message Date
Raphael Michel
951e498089 Use Stripe's new connect onboardning 2020-10-14 18:42:34 +02:00
6 changed files with 69 additions and 96 deletions

View File

@@ -18,8 +18,9 @@ from i18nfield.strings import LazyI18nString
from pretix.base.channels import get_all_sales_channels from pretix.base.channels import get_all_sales_channels
from pretix.base.forms.questions import guess_country from pretix.base.forms.questions import guess_country
from pretix.base.models import ( from pretix.base.models import (
ItemVariation, OrderPosition, QuestionAnswer, QuestionOption, Seat, ItemVariation, OrderPosition, Question, QuestionAnswer, QuestionOption,
Question) Seat,
)
from pretix.base.services.pricing import get_price from pretix.base.services.pricing import get_price
from pretix.base.settings import ( from pretix.base.settings import (
COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SCHEMES, COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SCHEMES,

View File

@@ -15,7 +15,6 @@ from django.db import transaction
from django.http import HttpRequest from django.http import HttpRequest
from django.template.loader import get_template from django.template.loader import get_template
from django.urls import reverse from django.urls import reverse
from django.utils.crypto import get_random_string
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.timezone import now from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _, pgettext from django.utils.translation import gettext, gettext_lazy as _, pgettext
@@ -52,17 +51,10 @@ class StripeSettingsHolder(BasePaymentProvider):
self.settings = SettingsSandbox('payment', 'stripe', event) self.settings = SettingsSandbox('payment', 'stripe', event)
def get_connect_url(self, request): def get_connect_url(self, request):
request.session['payment_stripe_oauth_event'] = request.event.pk return reverse('plugins:stripe:oauth.connect', kwargs={
if 'payment_stripe_oauth_token' not in request.session: 'organizer': self.event.organizer.slug,
request.session['payment_stripe_oauth_token'] = get_random_string(32) 'event': self.event.slug,
return ( })
"https://connect.stripe.com/oauth/authorize?response_type=code&client_id={}&state={}"
"&scope=read_write&redirect_uri={}"
).format(
self.settings.connect_client_id,
request.session['payment_stripe_oauth_token'],
urllib.parse.quote(build_global_uri('plugins:stripe:oauth.return')),
)
def settings_content_render(self, request): def settings_content_render(self, request):
if self.settings.connect_client_id and not self.settings.secret_key: if self.settings.connect_client_id and not self.settings.secret_key:

View File

@@ -38,15 +38,19 @@ def html_head_presale(sender, request=None, **kwargs):
provider = StripeSettingsHolder(sender) provider = StripeSettingsHolder(sender)
url = resolve(request.path_info) url = resolve(request.path_info)
if provider.settings.connect_client_id:
pubkey = provider.settings.connect_publishable_key
if (provider.settings.get('endpoint', 'live') == 'test' or sender.testmode):
pubkey = provider.settings.connect_test_publishable_key
else:
pubkey = provider.settings.publishable_key
if provider.settings.get('_enabled', as_type=bool) and ("checkout" in url.url_name or "order.pay" in url.url_name): if provider.settings.get('_enabled', as_type=bool) and ("checkout" in url.url_name or "order.pay" in url.url_name):
template = get_template('pretixplugins/stripe/presale_head.html') template = get_template('pretixplugins/stripe/presale_head.html')
ctx = { ctx = {
'event': sender, 'event': sender,
'settings': provider.settings, 'pubkey': pubkey,
'testmode': (
(provider.settings.get('endpoint', 'live') == 'test' or sender.testmode)
and provider.settings.publishable_test_key
)
} }
return template.render(ctx) return template.render(ctx)
else: else:

View File

@@ -8,12 +8,8 @@
{% compress css %} {% compress css %}
<link type="text/css" rel="stylesheet" href="{% static "pretixplugins/stripe/pretix-stripe.css" %}"> <link type="text/css" rel="stylesheet" href="{% static "pretixplugins/stripe/pretix-stripe.css" %}">
{% endcompress %} {% endcompress %}
{% if testmode %} <script type="text/plain" id="stripe_pubkey">{{ pubkey }}</script>
<script type="text/plain" id="stripe_pubkey">{{ settings.publishable_test_key }}</script>
{% else %}
<script type="text/plain" id="stripe_pubkey">{{ settings.publishable_key }}</script>
{% endif %}
{% if settings.connect_user_id %} {% if settings.connect_user_id %}
<script type="text/plain" id="stripe_connectedAccountId">{{ settings.connect_user_id }}</script> <script type="text/plain" id="stripe_connectedAccountId">{{ settings.connect_user_id }}</script>
{% endif %} {% endif %}
<script type="text/plain" id="stripe_merchantcountry">{{ settings.merchant_country|default:"" }}</script> <script type="text/plain" id="stripe_merchantcountry">{{ settings.merchant_country|default:"" }}</script>

View File

@@ -4,8 +4,8 @@ from pretix.multidomain import event_url
from .views import ( from .views import (
OrganizerSettingsFormView, ReturnView, ScaReturnView, ScaView, OrganizerSettingsFormView, ReturnView, ScaReturnView, ScaView,
applepay_association, oauth_disconnect, oauth_return, redirect_view, applepay_association, oauth_connect, oauth_disconnect, oauth_return,
webhook, redirect_view, webhook,
) )
event_patterns = [ event_patterns = [
@@ -29,6 +29,8 @@ organizer_patterns = [
urlpatterns = [ urlpatterns = [
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/stripe/disconnect/', url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/stripe/disconnect/',
oauth_disconnect, name='oauth.disconnect'), oauth_disconnect, name='oauth.disconnect'),
url(r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/stripe/connect/',
oauth_connect, name='oauth.connect'),
url(r'^control/organizer/(?P<organizer>[^/]+)/stripeconnect/', url(r'^control/organizer/(?P<organizer>[^/]+)/stripeconnect/',
OrganizerSettingsFormView.as_view(), name='settings.connect'), OrganizerSettingsFormView.as_view(), name='settings.connect'),
url(r'^_stripe/webhook/$', webhook, name='webhook'), url(r'^_stripe/webhook/$', webhook, name='webhook'),

View File

@@ -2,7 +2,6 @@ import hashlib
import json import json
import logging import logging
import requests
import stripe import stripe
from django.contrib import messages from django.contrib import messages
from django.core import signing from django.core import signing
@@ -29,6 +28,7 @@ from pretix.control.permissions import (
) )
from pretix.control.views.event import DecoupleMixin from pretix.control.views.event import DecoupleMixin
from pretix.control.views.organizer import OrganizerDetailViewMixin from pretix.control.views.organizer import OrganizerDetailViewMixin
from pretix.helpers.urls import build_absolute_uri as build_global_uri
from pretix.multidomain.urlreverse import eventreverse from pretix.multidomain.urlreverse import eventreverse
from pretix.plugins.stripe.forms import OrganizerStripeSettingsForm from pretix.plugins.stripe.forms import OrganizerStripeSettingsForm
from pretix.plugins.stripe.models import ReferencedStripeObject from pretix.plugins.stripe.models import ReferencedStripeObject
@@ -57,87 +57,30 @@ def redirect_view(request, *args, **kwargs):
@scopes_disabled() @scopes_disabled()
def oauth_return(request, *args, **kwargs): def oauth_return(request, *args, **kwargs):
if 'payment_stripe_oauth_event' not in request.session: if 'payment_stripe_oauth_event' not in request.session or 'payment_stripe_oauth_account' not in request.session:
messages.error(request, _('An error occurred during connecting with Stripe, please try again.')) messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:index')) return redirect(reverse('control:index'))
event = get_object_or_404(Event, pk=request.session['payment_stripe_oauth_event']) event = get_object_or_404(Event, pk=request.session['payment_stripe_oauth_event'])
if request.GET.get('state') != request.session['payment_stripe_oauth_token']:
messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:event.settings.payment.provider', kwargs={
'organizer': event.organizer.slug,
'event': event.slug,
'provider': 'stripe_settings'
}))
gs = GlobalSettingsObject() gs = GlobalSettingsObject()
testdata = {} stripe.api_key = gs.settings.payment_stripe_connect_secret_key or gs.settings.payment_stripe_connect_test_secret_key
try: try:
resp = requests.post('https://connect.stripe.com/oauth/token', data={ account = stripe.Account.retrieve(request.session['payment_stripe_oauth_account'])
'grant_type': 'authorization_code',
'client_secret': (
gs.settings.payment_stripe_connect_secret_key or gs.settings.payment_stripe_connect_test_secret_key
),
'code': request.GET.get('code')
})
data = resp.json()
if 'error' not in data:
account = stripe.Account.retrieve(
data['stripe_user_id'],
api_key=gs.settings.payment_stripe_connect_secret_key or gs.settings.payment_stripe_connect_test_secret_key
)
except: except:
logger.exception('Failed to obtain OAuth token') logger.exception('Failed to obtain OAuth token')
messages.error(request, _('An error occurred during connecting with Stripe, please try again.')) messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
else: else:
if 'error' not in data and data['livemode']: event.settings.payment_stripe_connect_user_id = account.id
try: event.settings.payment_stripe_connect_user_name = (
testresp = requests.post('https://connect.stripe.com/oauth/token', data={ account.get('business_profile', {}).get('name') or account.get('email')
'grant_type': 'refresh_token', )
'client_secret': gs.settings.payment_stripe_connect_test_secret_key, if request.session.get('payment_stripe_oauth_enable', False):
'refresh_token': data['refresh_token'] event.settings.payment_stripe__enabled = True
}) del request.session['payment_stripe_oauth_enable']
testdata = testresp.json()
except:
logger.exception('Failed to obtain OAuth token')
messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:event.settings.payment.provider', kwargs={
'organizer': event.organizer.slug,
'event': event.slug,
'provider': 'stripe_settings'
}))
if 'error' in data: stripe_verify_domain.apply_async(args=(event.pk, get_domain_for_event(event)))
messages.error(request, _('Stripe returned an error: {}').format(data['error_description']))
elif data['livemode'] and 'error' in testdata:
messages.error(request, _('Stripe returned an error: {}').format(testdata['error_description']))
else:
messages.success(request,
_('Your Stripe account is now connected to pretix. You can change the settings in '
'detail below.'))
event.settings.payment_stripe_publishable_key = data['stripe_publishable_key']
# event.settings.payment_stripe_connect_access_token = data['access_token'] we don't need it, right?
event.settings.payment_stripe_connect_refresh_token = data['refresh_token']
event.settings.payment_stripe_connect_user_id = data['stripe_user_id']
event.settings.payment_stripe_merchant_country = account.get('country')
if account.get('business_name') or account.get('display_name') or account.get('email'):
event.settings.payment_stripe_connect_user_name = (
account.get('business_name') or account.get('display_name') or account.get('email')
)
if data['livemode']:
event.settings.payment_stripe_publishable_test_key = testdata['stripe_publishable_key']
else:
event.settings.payment_stripe_publishable_test_key = event.settings.payment_stripe_publishable_key
if request.session.get('payment_stripe_oauth_enable', False):
event.settings.payment_stripe__enabled = True
del request.session['payment_stripe_oauth_enable']
stripe_verify_domain.apply_async(args=(event.pk, get_domain_for_event(event)))
return redirect(reverse('control:event.settings.payment.provider', kwargs={ return redirect(reverse('control:event.settings.payment.provider', kwargs={
'organizer': event.organizer.slug, 'organizer': event.organizer.slug,
@@ -409,6 +352,41 @@ def oauth_disconnect(request, **kwargs):
})) }))
@event_permission_required('can_change_event_settings')
def oauth_connect(request, **kwargs):
gs = GlobalSettingsObject()
stripe.api_key = gs.settings.payment_stripe_connect_secret_key or gs.settings.payment_stripe_connect_test_secret_key
request.session['payment_stripe_oauth_event'] = request.event.pk
try:
account = stripe.Account.create(
type='standard',
metadata={
'organizer': request.organizer.slug,
}
)
request.session['payment_stripe_oauth_account'] = account.stripe_id
account_link = stripe.AccountLink.create(
account=account.stripe_id,
return_url=build_global_uri('plugins:stripe:oauth.return'),
refresh_url=build_global_uri('plugins:stripe:oauth.connect', kwargs={
'organizer': request.organizer.slug,
'event': request.event.slug,
}),
type='account_onboarding',
)
except:
logger.exception('Failed to obtain account link')
messages.error(request, _('An error occurred during connecting with Stripe, please try again.'))
return redirect(reverse('control:event.settings.payment.provider', kwargs={
'organizer': request.event.organizer.slug,
'event': request.event.slug,
'provider': 'stripe_settings'
}))
return redirect(account_link.url)
@xframe_options_exempt @xframe_options_exempt
def applepay_association(request, *args, **kwargs): def applepay_association(request, *args, **kwargs):
r = render(request, 'pretixplugins/stripe/apple-developer-merchantid-domain-association') r = render(request, 'pretixplugins/stripe/apple-developer-merchantid-domain-association')