Add more Stripe Payment Methods, simplify forms (#1571)

* Add more Stripe Payment Methods, simplify forms

* Revert accidential commit of boxoffice control renderer...

* Use existing QR-Code encoding in presale
This commit is contained in:
Martin Gross
2020-02-05 09:50:29 +01:00
committed by GitHub
parent 6e88054af7
commit b3e3d427cb
8 changed files with 295 additions and 36 deletions

View File

@@ -28,7 +28,7 @@ from pretix.base.payment import BasePaymentProvider, PaymentException
from pretix.base.services.mail import SendMailException
from pretix.base.settings import SettingsSandbox
from pretix.helpers.urls import build_absolute_uri as build_global_uri
from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse
from pretix.plugins.stripe.forms import StripeKeyValidator
from pretix.plugins.stripe.models import (
ReferencedStripeObject, RegisteredApplePayDomain,
@@ -200,6 +200,34 @@ class StripeSettingsHolder(BasePaymentProvider):
),
required=False,
)),
('method_eps',
forms.BooleanField(
label=_('EPS'),
disabled=self.event.currency != 'EUR',
help_text=_('Needs to be enabled in your Stripe account first.'),
required=False,
)),
('method_multibanco',
forms.BooleanField(
label=_('Multibanco'),
disabled=self.event.currency != 'EUR',
help_text=_('Needs to be enabled in your Stripe account first.'),
required=False,
)),
('method_przelewy24',
forms.BooleanField(
label=_('Przelewy24'),
disabled=self.event.currency not in ['EUR', 'PLN'],
help_text=_('Needs to be enabled in your Stripe account first.'),
required=False,
)),
('method_wechatpay',
forms.BooleanField(
label=_('WeChat Pay'),
disabled=self.event.currency not in ['AUD', 'CAD', 'EUR', 'GBP', 'HKD', 'JPY', 'SGD', 'USD'],
help_text=_('Needs to be enabled in your Stripe account first.'),
required=False,
)),
] + list(super().settings_form_fields.items())
)
d.move_to_end('_enabled', last=False)
@@ -603,7 +631,7 @@ class StripeCC(StripeMethod):
if not RegisteredApplePayDomain.objects.filter(account=account, domain=request.host).exists():
stripe_verify_domain.apply_async(args=(self.event.pk, request.host))
template = get_template('pretixplugins/stripe/checkout_payment_form.html')
template = get_template('pretixplugins/stripe/checkout_payment_form_cc.html')
ctx = {
'request': request,
'event': self.event,
@@ -843,7 +871,7 @@ class StripeGiropay(StripeMethod):
method = 'giropay'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_giropay.html')
template = get_template('pretixplugins/stripe/checkout_payment_form_simple.html')
ctx = {
'request': request,
'event': self.event,
@@ -872,9 +900,7 @@ class StripeGiropay(StripeMethod):
owner={
'name': request.session.get('payment_stripe_giropay_account') or ugettext('unknown name')
},
giropay={
'statement_descriptor': self.statement_descriptor(payment, 35),
},
statement_descriptor=self.statement_descriptor(payment, 35),
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
@@ -909,7 +935,7 @@ class StripeIdeal(StripeMethod):
method = 'ideal'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_simple.html')
template = get_template('pretixplugins/stripe/checkout_payment_form_simple_noform.html')
ctx = {
'request': request,
'event': self.event,
@@ -927,9 +953,7 @@ class StripeIdeal(StripeMethod):
'event': self.event.id,
'code': payment.order.code
},
ideal={
'statement_descriptor': self.statement_descriptor(payment)
},
statement_descriptor=self.statement_descriptor(payment),
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
@@ -955,7 +979,7 @@ class StripeAlipay(StripeMethod):
method = 'alipay'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_simple.html')
template = get_template('pretixplugins/stripe/checkout_payment_form_simple_noform.html')
ctx = {
'request': request,
'event': self.event,
@@ -998,7 +1022,7 @@ class StripeBancontact(StripeMethod):
method = 'bancontact'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_bancontact.html')
template = get_template('pretixplugins/stripe/checkout_payment_form_simple.html')
ctx = {
'request': request,
'event': self.event,
@@ -1027,9 +1051,7 @@ class StripeBancontact(StripeMethod):
owner={
'name': request.session.get('payment_stripe_bancontact_account') or ugettext('unknown name')
},
bancontact={
'statement_descriptor': self.statement_descriptor(payment, 35)
},
statement_descriptor=self.statement_descriptor(payment, 35),
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
@@ -1064,7 +1086,7 @@ class StripeSofort(StripeMethod):
method = 'sofort'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_sofort.html')
template = get_template('pretixplugins/stripe/checkout_payment_form_simple.html')
ctx = {
'request': request,
'event': self.event,
@@ -1095,9 +1117,9 @@ class StripeSofort(StripeMethod):
'event': self.event.id,
'code': payment.order.code
},
statement_descriptor=self.statement_descriptor(payment, 35),
sofort={
'country': request.session.get('payment_stripe_sofort_bank_country'),
'statement_descriptor': self.statement_descriptor(payment, 35)
},
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
@@ -1124,3 +1146,244 @@ class StripeSofort(StripeMethod):
def payment_can_retry(self, payment):
return payment.state != OrderPayment.PAYMENT_STATE_PENDING and self._is_still_available(order=payment.order)
class StripeEPS(StripeMethod):
identifier = 'stripe_eps'
verbose_name = _('EPS via Stripe')
public_name = _('EPS')
method = 'eps'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_simple.html')
ctx = {
'request': request,
'event': self.event,
'settings': self.settings,
'form': self.payment_form(request)
}
return template.render(ctx)
@property
def payment_form_fields(self):
return OrderedDict([
('account', forms.CharField(label=_('Account holder'))),
])
def _create_source(self, request, payment):
try:
source = stripe.Source.create(
type='eps',
amount=self._get_amount(payment),
currency=self.event.currency.lower(),
metadata={
'order': str(payment.order.id),
'event': self.event.id,
'code': payment.order.code
},
owner={
'name': request.session.get('payment_stripe_eps_account') or ugettext('unknown name')
},
statement_descriptor=self.statement_descriptor(payment),
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
'payment': payment.pk,
'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
})
},
**self.api_kwargs
)
return source
finally:
if 'payment_stripe_eps_account' in request.session:
del request.session['payment_stripe_eps_account']
def payment_is_valid_session(self, request):
return (
request.session.get('payment_stripe_eps_account', '') != ''
)
def checkout_prepare(self, request, cart):
form = self.payment_form(request)
if form.is_valid():
request.session['payment_stripe_eps_account'] = form.cleaned_data['account']
return True
return False
class StripeMultibanco(StripeMethod):
identifier = 'stripe_multibanco'
verbose_name = _('Multibanco via Stripe')
public_name = _('Multibanco')
method = 'multibanco'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_simple_noform.html')
ctx = {
'request': request,
'event': self.event,
'settings': self.settings,
'form': self.payment_form(request)
}
return template.render(ctx)
def _create_source(self, request, payment):
source = stripe.Source.create(
type='multibanco',
amount=self._get_amount(payment),
currency=self.event.currency.lower(),
metadata={
'order': str(payment.order.id),
'event': self.event.id,
'code': payment.order.code
},
owner={
'email': payment.order.email
},
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
'payment': payment.pk,
'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
})
},
**self.api_kwargs
)
return source
def payment_is_valid_session(self, request):
return True
def checkout_prepare(self, request, cart):
return True
class StripePrzelewy24(StripeMethod):
identifier = 'stripe_przelewy24'
verbose_name = _('Przelewy24 via Stripe')
public_name = _('Przelewy24')
method = 'przelewy24'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_simple_noform.html')
ctx = {
'request': request,
'event': self.event,
'settings': self.settings,
'form': self.payment_form(request)
}
return template.render(ctx)
def _create_source(self, request, payment):
source = stripe.Source.create(
type='p24',
amount=self._get_amount(payment),
currency=self.event.currency.lower(),
metadata={
'order': str(payment.order.id),
'event': self.event.id,
'code': payment.order.code
},
owner={
'email': payment.order.email
},
statement_descriptor=self.statement_descriptor(payment, 35),
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
'payment': payment.pk,
'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
})
},
**self.api_kwargs
)
return source
def payment_is_valid_session(self, request):
return True
def checkout_prepare(self, request, cart):
return True
class StripeWeChatPay(StripeMethod):
identifier = 'stripe_wechatpay'
verbose_name = _('WeChat Pay via Stripe')
public_name = _('WeChat Pay')
method = 'wechatpay'
def payment_form_render(self, request) -> str:
template = get_template('pretixplugins/stripe/checkout_payment_form_simple_noform.html')
ctx = {
'request': request,
'event': self.event,
'settings': self.settings,
'form': self.payment_form(request)
}
return template.render(ctx)
def _create_source(self, request, payment):
source = stripe.Source.create(
type='wechat',
amount=self._get_amount(payment),
currency=self.event.currency.lower(),
metadata={
'order': str(payment.order.id),
'event': self.event.id,
'code': payment.order.code
},
statement_descriptor=self.statement_descriptor(payment, 32),
redirect={
'return_url': build_absolute_uri(self.event, 'plugins:stripe:return', kwargs={
'order': payment.order.code,
'payment': payment.pk,
'hash': hashlib.sha1(payment.order.secret.lower().encode()).hexdigest(),
})
},
**self.api_kwargs
)
return source
def payment_is_valid_session(self, request):
return True
def checkout_prepare(self, request, cart):
return True
def execute_payment(self, request: HttpRequest, payment: OrderPayment):
self._init_api()
try:
source = self._create_source(request, payment)
except stripe.error.StripeError as e:
if e.json_body and 'err' in e.json_body:
err = e.json_body['error']
logger.exception('Stripe error: %s' % str(err))
else:
err = {'message': str(e)}
logger.exception('Stripe error: %s' % str(e))
payment.info_data = {
'error': True,
'message': err['message'],
}
payment.state = OrderPayment.PAYMENT_STATE_FAILED
payment.save()
payment.order.log_action('pretix.event.order.payment.failed', {
'local_id': payment.local_id,
'provider': payment.provider,
'message': err['message']
})
raise PaymentException(_('We had trouble communicating with Stripe. Please try again and get in touch '
'with us if this problem persists.'))
ReferencedStripeObject.objects.get_or_create(
reference=source.id,
defaults={'order': payment.order, 'payment': payment}
)
payment.info = str(source)
payment.save()
return eventreverse(request.event, 'presale:event.order', kwargs={
'order': payment.order.code,
'secret': payment.order.secret
})

View File

@@ -21,10 +21,13 @@ from pretix.presale.signals import html_head
def register_payment_provider(sender, **kwargs):
from .payment import (
StripeSettingsHolder, StripeCC, StripeGiropay, StripeIdeal, StripeAlipay, StripeBancontact,
StripeSofort
StripeSofort, StripeEPS, StripeMultibanco, StripePrzelewy24, StripeWeChatPay
)
return [StripeSettingsHolder, StripeCC, StripeGiropay, StripeIdeal, StripeAlipay, StripeBancontact, StripeSofort]
return [
StripeSettingsHolder, StripeCC, StripeGiropay, StripeIdeal, StripeAlipay, StripeBancontact,
StripeSofort, StripeEPS, StripeMultibanco, StripePrzelewy24, StripeWeChatPay
]
@receiver(html_head, dispatch_uid="payment_stripe_html_head")

View File

@@ -1,7 +0,0 @@
{% load i18n %}
{% load bootstrap3 %}
{% bootstrap_form form layout='horizontal' %}
<p>{% blocktrans trimmed %}
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
You will then be redirected back here to get your tickets.
{% endblocktrans %}</p>

View File

@@ -1,4 +1,6 @@
{% load i18n %}
{% load bootstrap3 %}
{% bootstrap_form form layout='horizontal' %}
<p>{% blocktrans trimmed %}
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
You will then be redirected back here to get your tickets.

View File

@@ -1,6 +1,4 @@
{% load i18n %}
{% load bootstrap3 %}
{% bootstrap_form form layout='horizontal' %}
<p>{% blocktrans trimmed %}
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
You will then be redirected back here to get your tickets.

View File

@@ -1,7 +0,0 @@
{% load i18n %}
{% load bootstrap3 %}
{% bootstrap_form form layout='horizontal' %}
<p>{% blocktrans trimmed %}
After you submitted your order, we will redirect you to the payment service provider to complete your payment.
You will then be redirected back here to get your tickets.
{% endblocktrans %}</p>

View File

@@ -17,7 +17,14 @@
</div>
<div class="clearfix"></div>
</p>
{% elif payment.state == "created" and payment.provider == "stripe_wechatpay" %}
<p>{% blocktrans trimmed %}
Please scan the barcode below to complete your WeChat payment.
Once you have completed your payment, you can refresh this page.
{% endblocktrans %}</p>
<div class="text-center">
<script type="text/plain" data-size="150" data-replace-with-qr>{{ payment_info.wechat.qr_code_url }}</script>
</div>
{% else %}
<p>{% blocktrans trimmed %}
The payment transaction could not be completed for the following reason: