diff --git a/src/pretix/base/channels.py b/src/pretix/base/channels.py index 0a89cc2257..e3295c4b5c 100644 --- a/src/pretix/base/channels.py +++ b/src/pretix/base/channels.py @@ -42,6 +42,17 @@ class SalesChannel: """ return True + @property + def payment_restrictions_supported(self) -> bool: + """ + If this property is ``True``, organizers can restrict the usage of payment providers to this sales channel. + + Example: pretixPOS provides its own sales channel, ignores the configured payment providers completely and + handles payments locally. Therefor, this property should be set to ``False`` for the pretixPOS sales channel as + the event organizer cannot restrict the usage of any payment provider through the backend. + """ + return True + def get_all_sales_channels(): global _ALL_CHANNELS diff --git a/src/pretix/base/payment.py b/src/pretix/base/payment.py index e5911772bc..ea8962596e 100644 --- a/src/pretix/base/payment.py +++ b/src/pretix/base/payment.py @@ -20,6 +20,7 @@ from django_countries import Countries from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput from i18nfield.strings import LazyI18nString +from pretix.base.channels import get_all_sales_channels from pretix.base.forms import PlaceholderValidator from pretix.base.models import ( CartPosition, Event, GiftCard, InvoiceAddress, Order, OrderPayment, @@ -62,12 +63,11 @@ class BasePaymentProvider: def __str__(self): return self.identifier - @property - def is_implicit(self) -> bool: + def is_implicit(self, request: HttpRequest) -> bool: """ Returns whether or whether not this payment provider is an "implicit" payment provider that will *always* and unconditionally be used if is_allowed() returns True and does not require any input. - This is intended to be used by the FreePaymentProvider, which skips the payment choice page. + This is intended to be used by the FreeOrderProvider, which skips the payment choice page. By default, this returns ``False``. Please do not set this if you don't know exactly what you are doing. """ return False @@ -278,8 +278,21 @@ class BasePaymentProvider: required=False, disabled=not self.event.settings.invoice_address_required )), + ('_restrict_to_sales_channels', + forms.MultipleChoiceField( + label=_('Restrict to specific sales channels'), + choices=( + (c.identifier, c.verbose_name) for c in get_all_sales_channels().values() + if c.payment_restrictions_supported + ), + initial=['web'], + widget=forms.CheckboxSelectMultiple, + help_text=_( + 'Only allow the usage of this payment provider in the following sales channels'), + )) ]) d['_restricted_countries']._as_type = list + d['_restrict_to_sales_channels']._as_type = list return d def settings_form_clean(self, cleaned_data): @@ -391,7 +404,7 @@ class BasePaymentProvider: The default implementation checks for the _availability_date setting to be either unset or in the future and for the _total_max and _total_min requirements to be met. It also checks the ``_restrict_countries`` - setting. + and ``_restrict_to_sales_channels`` setting. :param total: The total value without the payment method fee, after taxes. @@ -432,6 +445,10 @@ class BasePaymentProvider: if str(ia.country) not in restricted_countries: return False + if hasattr(request, 'sales_channel') and request.sales_channel.identifier not in \ + self.settings.get('_restrict_to_sales_channels', as_type=list, default=['web']): + return False + return timing and pricing def payment_form_render(self, request: HttpRequest, total: Decimal) -> str: @@ -765,8 +782,7 @@ class ManualPayment(BasePaymentProvider): return _('In test mode, you can just manually mark this order as paid in the backend after it has been ' 'created.') - @property - def is_implicit(self): + def is_implicit(self, request: HttpRequest): return 'pretix.plugins.manualpayment' not in self.event.plugins def is_allowed(self, request: HttpRequest, total: Decimal=None): diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 1d79c260b8..f646a7331c 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -137,6 +137,10 @@ DEFAULTS = { 'default': 'True', 'type': bool }, + 'payment_resellers__restrict_to_sales_channels': { + 'default': ['resellers'], + 'type': list + }, 'payment_term_accept_late': { 'default': 'True', 'type': bool diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index e383fbdd18..4460bc31dc 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -719,7 +719,7 @@ class ProviderForm(SettingsForm): v.set_event(self.obj) if hasattr(v, '_as_type'): - self.initial[k] = self.obj.settings.get(k, as_type=v._as_type) + self.initial[k] = self.obj.settings.get(k, as_type=v._as_type, default=v.initial) def clean(self): cleaned_data = super().clean() diff --git a/src/pretix/control/templates/pretixcontrol/event/payment.html b/src/pretix/control/templates/pretixcontrol/event/payment.html index 170e07b0a7..3e0bc1de0f 100644 --- a/src/pretix/control/templates/pretixcontrol/event/payment.html +++ b/src/pretix/control/templates/pretixcontrol/event/payment.html @@ -28,6 +28,12 @@ {% endif %} +