mirror of
https://github.com/pretix/pretix.git
synced 2025-12-05 21:32:28 +00:00
Compare commits
5 Commits
v2025.6.0
...
walletdete
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
451ed221d9 | ||
|
|
b9af34f0fd | ||
|
|
fc15811b7f | ||
|
|
fdb2a20514 | ||
|
|
1b1c4358d3 |
@@ -70,6 +70,8 @@ The provider class
|
||||
|
||||
.. autoattribute:: settings_form_fields
|
||||
|
||||
.. autoattribute:: walletqueries
|
||||
|
||||
.. automethod:: settings_form_clean
|
||||
|
||||
.. automethod:: settings_content_render
|
||||
|
||||
@@ -249,7 +249,7 @@ class SecurityMiddleware(MiddlewareMixin):
|
||||
|
||||
h = {
|
||||
'default-src': ["{static}"],
|
||||
'script-src': ['{static}', 'https://checkout.stripe.com', 'https://js.stripe.com'],
|
||||
'script-src': ['{static}', 'https://checkout.stripe.com', 'https://js.stripe.com', 'https://pay.google.com'],
|
||||
'object-src': ["'none'"],
|
||||
'frame-src': ['{static}', 'https://checkout.stripe.com', 'https://js.stripe.com'],
|
||||
'style-src': ["{static}", "{media}"],
|
||||
|
||||
@@ -78,6 +78,16 @@ from pretix.presale.views.cart import cart_session, get_or_create_cart_id
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WalletQueries:
|
||||
APPLEPAY = 'applepay'
|
||||
GOOGLEPAY = 'googlepay'
|
||||
|
||||
WALLETS = (
|
||||
(APPLEPAY, pgettext_lazy('payment', 'Apple Pay')),
|
||||
(GOOGLEPAY, pgettext_lazy('payment', 'Google Pay')),
|
||||
)
|
||||
|
||||
|
||||
class PaymentProviderForm(Form):
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
@@ -436,6 +446,19 @@ class BasePaymentProvider:
|
||||
d['_restrict_to_sales_channels']._as_type = list
|
||||
return d
|
||||
|
||||
@property
|
||||
def walletqueries(self):
|
||||
"""
|
||||
.. warning:: This property is considered **experimental**. It might change or get removed at any time without
|
||||
prior notice.
|
||||
|
||||
A list of wallet payment methods that should be dynamically joined to the public name of the payment method,
|
||||
if they are available to the user.
|
||||
The detection is made on a best effort basis with no guarantees of correctness and actual availability.
|
||||
Wallets that pretix can check for are exposed through ``pretix.base.payment.WalletQueries``.
|
||||
"""
|
||||
return []
|
||||
|
||||
def settings_form_clean(self, cleaned_data):
|
||||
"""
|
||||
Overriding this method allows you to inject custom validation into the settings form.
|
||||
|
||||
@@ -59,7 +59,9 @@ from pretix import __version__
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.forms import SecretKeySettingsField
|
||||
from pretix.base.models import Event, OrderPayment, OrderRefund, Quota
|
||||
from pretix.base.payment import BasePaymentProvider, PaymentException
|
||||
from pretix.base.payment import (
|
||||
BasePaymentProvider, PaymentException, WalletQueries,
|
||||
)
|
||||
from pretix.base.plugins import get_all_plugins
|
||||
from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.settings import SettingsSandbox
|
||||
@@ -219,6 +221,20 @@ class StripeSettingsHolder(BasePaymentProvider):
|
||||
]
|
||||
|
||||
extra_fields = [
|
||||
('walletdetection',
|
||||
forms.BooleanField(
|
||||
label=mark_safe(
|
||||
_('Check for Apple Pay/Google Pay') +
|
||||
' ' +
|
||||
'<span class="label label-info">{}</span>'.format(_('experimental'))
|
||||
),
|
||||
help_text=_("pretix will attempt to check if the customer's webbrowser supports wallet-based payment "
|
||||
"methods like Apple Pay or Google Pay and display them prominently with the credit card"
|
||||
"payment method. This detection does not take into consideration if Google Pay/Apple Pay "
|
||||
"has been disabled in the Stripe Dashboard."),
|
||||
initial=True,
|
||||
required=False,
|
||||
)),
|
||||
('postfix',
|
||||
forms.CharField(
|
||||
label=_('Statement descriptor postfix'),
|
||||
@@ -747,6 +763,15 @@ class StripeCC(StripeMethod):
|
||||
public_name = _('Credit card')
|
||||
method = 'cc'
|
||||
|
||||
@property
|
||||
def walletqueries(self):
|
||||
# ToDo: Check against Stripe API, if ApplePay and GooglePay are even activated/available
|
||||
# This is probably only really feasable once the Payment Methods Configuration API is out of beta
|
||||
# https://stripe.com/docs/connect/payment-method-configurations
|
||||
if self.settings.get("walletdetection", True, as_type=bool):
|
||||
return [WalletQueries.APPLEPAY, WalletQueries.GOOGLEPAY]
|
||||
return []
|
||||
|
||||
def payment_form_render(self, request, total) -> str:
|
||||
account = get_stripe_account_key(self)
|
||||
if not RegisteredApplePayDomain.objects.filter(account=account, domain=request.host).exists():
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
{% load money %}
|
||||
{% load bootstrap3 %}
|
||||
{% load rich_text %}
|
||||
{% block custom_header %}
|
||||
{{ block.super }}
|
||||
{% include "pretixpresale/event/fragment_walletdetection_head.html" %}
|
||||
{% endblock %}
|
||||
{% block inner %}
|
||||
{% if current_payments %}
|
||||
<p>{% trans "You already selected the following payment methods:" %}</p>
|
||||
@@ -71,7 +75,8 @@
|
||||
{% if selected == p.provider.identifier %}checked="checked"{% endif %}
|
||||
id="input_payment_{{ p.provider.identifier }}"
|
||||
aria-describedby="payment_{{ p.provider.identifier }}"
|
||||
data-toggle="radiocollapse" data-target="#payment_{{ p.provider.identifier }}"/>
|
||||
data-toggle="radiocollapse" data-target="#payment_{{ p.provider.identifier }}"
|
||||
data-wallets="{{ p.provider.walletqueries|join:"|" }}" />
|
||||
<label for="input_payment_{{ p.provider.identifier }}"><strong>{{ p.provider.public_name }}</strong></label>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{% load static %}
|
||||
{% load compress %}
|
||||
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static "pretixpresale/js/walletdetection.js" %}"></script>
|
||||
{% endcompress %}
|
||||
@@ -3,6 +3,10 @@
|
||||
{% load eventurl %}
|
||||
{% load money %}
|
||||
{% block title %}{% trans "Change payment method" %}{% endblock %}
|
||||
{% block custom_header %}
|
||||
{{ block.super }}
|
||||
{% include "pretixpresale/event/fragment_walletdetection_head.html" %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>
|
||||
{% blocktrans trimmed with code=order.code %}
|
||||
@@ -29,7 +33,8 @@
|
||||
<input type="radio" name="payment" value="{{ p.provider.identifier }}"
|
||||
data-parent="#payment_accordion"
|
||||
{% if selected == p.provider.identifier %}checked="checked"{% endif %}
|
||||
data-toggle="radiocollapse" data-target="#payment_{{ p.provider.identifier }}" />
|
||||
data-toggle="radiocollapse" data-target="#payment_{{ p.provider.identifier }}"
|
||||
data-wallets="{{ p.provider.walletqueries|join:"|" }}"/>
|
||||
<strong>{{ p.provider.public_name }}</strong>
|
||||
</label>
|
||||
</h4>
|
||||
|
||||
71
src/pretix/static/pretixpresale/js/walletdetection.js
Normal file
71
src/pretix/static/pretixpresale/js/walletdetection.js
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
var walletdetection = {
|
||||
applepay: async function () {
|
||||
// This is a weak check for Apple Pay - in order to do a proper check, we would need to also call
|
||||
// canMakePaymentsWithActiveCard(merchantIdentifier)
|
||||
|
||||
return !!(window.ApplePaySession && window.ApplePaySession.canMakePayments());
|
||||
},
|
||||
googlepay: async function () {
|
||||
// Checking for Google Pay is a little bit more involved, since it requires including the Google Pay JS SDK, and
|
||||
// providing a lot of information.
|
||||
// So for the time being, we only check if Google Pay is available in TEST-mode, which should hopefully give us a
|
||||
// good enough idea if Google Pay could be present on this device; even though there are still a lot of other
|
||||
// factors that could inhibit Google Pay from actually being offered to the customer.
|
||||
|
||||
return $.ajax({
|
||||
url: 'https://pay.google.com/gp/p/js/pay.js',
|
||||
dataType: 'script',
|
||||
}).then(function() {
|
||||
const paymentsClient = new google.payments.api.PaymentsClient({environment: 'TEST'});
|
||||
return paymentsClient.isReadyToPay({
|
||||
apiVersion: 2,
|
||||
apiVersionMinor: 0,
|
||||
allowedPaymentMethods: [{
|
||||
type: 'CARD',
|
||||
parameters: {
|
||||
allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
|
||||
allowedCardNetworks: ["AMEX", "DISCOVER", "INTERAC", "JCB", "MASTERCARD", "VISA"]
|
||||
}
|
||||
}],
|
||||
})
|
||||
}).then(function (response) {
|
||||
return !!response.result;
|
||||
});
|
||||
},
|
||||
name_map: {
|
||||
applepay: gettext('Apple Pay'),
|
||||
googlepay: gettext('Google Pay'),
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
const wallets = $('[data-wallets]')
|
||||
.map(function(index, pm) {
|
||||
return pm.getAttribute("data-wallets").split("|");
|
||||
})
|
||||
.get()
|
||||
.flat()
|
||||
.filter(function(item, pos, self) {
|
||||
// filter out empty or duplicate values
|
||||
return item && self.indexOf(item) == pos;
|
||||
});
|
||||
|
||||
wallets.forEach(function(wallet) {
|
||||
const labels = $('[data-wallets*='+wallet+'] + label strong, [data-wallets*='+wallet+'] + strong')
|
||||
.append('<span class="wallet wallet-loading"> <i aria-hidden="true" class="fa fa-cog fa-spin"></i></span>')
|
||||
walletdetection[wallet]()
|
||||
.then(function(result) {
|
||||
const spans = labels.find(".wallet-loading:nth-of-type(1)");
|
||||
if (result) {
|
||||
spans.removeClass('wallet-loading').hide().text(', ' + walletdetection.name_map[wallet]).fadeIn(300);
|
||||
} else {
|
||||
spans.remove();
|
||||
}
|
||||
})
|
||||
.catch(function(result) {
|
||||
labels.find(".wallet-loading:nth-of-type(1)").remove();
|
||||
})
|
||||
});
|
||||
});
|
||||
@@ -179,3 +179,7 @@
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-loading + .wallet-loading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user