diff --git a/src/pretix/plugins/stripe/payment.py b/src/pretix/plugins/stripe/payment.py index 24fff0f7a..30344f3ab 100644 --- a/src/pretix/plugins/stripe/payment.py +++ b/src/pretix/plugins/stripe/payment.py @@ -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 + }) diff --git a/src/pretix/plugins/stripe/signals.py b/src/pretix/plugins/stripe/signals.py index 200de8a52..7a55c2d8d 100644 --- a/src/pretix/plugins/stripe/signals.py +++ b/src/pretix/plugins/stripe/signals.py @@ -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") diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_cc.html similarity index 100% rename from src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form.html rename to src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_cc.html diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_giropay.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_giropay.html deleted file mode 100644 index b1a340292..000000000 --- a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_giropay.html +++ /dev/null @@ -1,7 +0,0 @@ -{% load i18n %} -{% load bootstrap3 %} -{% bootstrap_form form layout='horizontal' %} -

{% 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 %}

diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple.html index e54c7699d..b1a340292 100644 --- a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple.html +++ b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple.html @@ -1,4 +1,6 @@ {% load i18n %} +{% load bootstrap3 %} +{% bootstrap_form form layout='horizontal' %}

{% 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. diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_bancontact.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple_noform.html similarity index 78% rename from src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_bancontact.html rename to src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple_noform.html index b1a340292..e54c7699d 100644 --- a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_bancontact.html +++ b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple_noform.html @@ -1,6 +1,4 @@ {% load i18n %} -{% load bootstrap3 %} -{% bootstrap_form form layout='horizontal' %}

{% 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. diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sofort.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sofort.html deleted file mode 100644 index b1a340292..000000000 --- a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sofort.html +++ /dev/null @@ -1,7 +0,0 @@ -{% load i18n %} -{% load bootstrap3 %} -{% bootstrap_form form layout='horizontal' %} -

{% 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 %}

diff --git a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html index 53324e69f..67d7a941e 100644 --- a/src/pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html +++ b/src/pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html @@ -17,7 +17,14 @@

- +{% elif payment.state == "created" and payment.provider == "stripe_wechatpay" %} +

{% blocktrans trimmed %} + Please scan the barcode below to complete your WeChat payment. + Once you have completed your payment, you can refresh this page. + {% endblocktrans %}

+
+ +
{% else %}

{% blocktrans trimmed %} The payment transaction could not be completed for the following reason: