mirror of
https://github.com/pretix/pretix.git
synced 2026-05-04 15:04:03 +00:00
New implementation of sales channels (#4111)
Co-authored-by: Martin Gross <gross@rami.io>
This commit is contained in:
@@ -438,3 +438,20 @@ class ButtonGroupRadioSelect(forms.RadioSelect):
|
||||
attrs['icon'] = self.option_icons[value]
|
||||
opt = super().create_option(name, value, label, selected, index, subindex, attrs)
|
||||
return opt
|
||||
|
||||
|
||||
class SalesChannelCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
||||
option_template_name = 'pretixbase/forms/widgets/checkbox_sales_channel_option.html'
|
||||
|
||||
def __init__(self, event, attrs=None, choices=()):
|
||||
self.event = event
|
||||
super().__init__(attrs, choices)
|
||||
|
||||
def create_option(
|
||||
self, name, value, label, selected, index, subindex=None, attrs=None
|
||||
):
|
||||
plugin = value.instance.type_instance.required_event_plugin
|
||||
return {
|
||||
**super().create_option(name, value, label, selected, index, subindex, attrs),
|
||||
"plugin_missing": plugin and plugin not in self.event.get_plugins(),
|
||||
}
|
||||
|
||||
@@ -30,11 +30,12 @@ from django_scopes.forms import (
|
||||
SafeModelChoiceField, SafeModelMultipleChoiceField,
|
||||
)
|
||||
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.forms.widgets import SplitDateTimePickerWidget
|
||||
from pretix.base.models import Gate
|
||||
from pretix.base.models.checkin import Checkin, CheckinList
|
||||
from pretix.control.forms import ItemMultipleChoiceField
|
||||
from pretix.control.forms import (
|
||||
ItemMultipleChoiceField, SalesChannelCheckboxSelectMultiple,
|
||||
)
|
||||
from pretix.control.forms.widgets import Select2
|
||||
|
||||
|
||||
@@ -66,14 +67,9 @@ class CheckinListForm(forms.ModelForm):
|
||||
kwargs.pop('locales', None)
|
||||
super().__init__(**kwargs)
|
||||
self.fields['limit_products'].queryset = self.event.items.all()
|
||||
self.fields['auto_checkin_sales_channels'] = forms.MultipleChoiceField(
|
||||
label=self.fields['auto_checkin_sales_channels'].label,
|
||||
help_text=self.fields['auto_checkin_sales_channels'].help_text,
|
||||
required=self.fields['auto_checkin_sales_channels'].required,
|
||||
choices=(
|
||||
(c.identifier, c.verbose_name) for c in get_all_sales_channels().values()
|
||||
),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
self.fields['auto_checkin_sales_channels'].queryset = self.event.organizer.sales_channels.all()
|
||||
self.fields['auto_checkin_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(
|
||||
self.event, choices=self.fields['auto_checkin_sales_channels'].widget.choices
|
||||
)
|
||||
|
||||
if not self.event.organizer.gates.exists():
|
||||
@@ -123,13 +119,13 @@ class CheckinListForm(forms.ModelForm):
|
||||
'gates': forms.CheckboxSelectMultiple(attrs={
|
||||
'class': 'scrolling-multiple-choice'
|
||||
}),
|
||||
'auto_checkin_sales_channels': forms.CheckboxSelectMultiple(),
|
||||
'exit_all_at': NextTimeInput(attrs={'class': 'timepickerfield'}),
|
||||
}
|
||||
field_classes = {
|
||||
'limit_products': ItemMultipleChoiceField,
|
||||
'gates': SafeModelMultipleChoiceField,
|
||||
'subevent': SafeModelChoiceField,
|
||||
'auto_checkin_sales_channels': SafeModelMultipleChoiceField,
|
||||
'exit_all_at': NextTimeField,
|
||||
}
|
||||
|
||||
|
||||
@@ -22,13 +22,16 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes.forms import SafeModelMultipleChoiceField
|
||||
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.channels import get_all_sales_channel_types
|
||||
from pretix.base.forms import I18nModelForm
|
||||
from pretix.base.forms.widgets import SplitDateTimePickerWidget
|
||||
from pretix.base.models import Discount
|
||||
from pretix.control.forms import ItemMultipleChoiceField, SplitDateTimeField
|
||||
from pretix.control.forms import (
|
||||
ItemMultipleChoiceField, SalesChannelCheckboxSelectMultiple,
|
||||
SplitDateTimeField,
|
||||
)
|
||||
|
||||
|
||||
class DiscountForm(I18nModelForm):
|
||||
@@ -38,7 +41,8 @@ class DiscountForm(I18nModelForm):
|
||||
fields = [
|
||||
'active',
|
||||
'internal_name',
|
||||
'sales_channels',
|
||||
'all_sales_channels',
|
||||
'limit_sales_channels',
|
||||
'available_from',
|
||||
'available_until',
|
||||
'subevent_mode',
|
||||
@@ -60,6 +64,7 @@ class DiscountForm(I18nModelForm):
|
||||
'available_until': SplitDateTimeField,
|
||||
'condition_limit_products': ItemMultipleChoiceField,
|
||||
'benefit_limit_products': ItemMultipleChoiceField,
|
||||
'limit_sales_channels': SafeModelMultipleChoiceField,
|
||||
}
|
||||
widgets = {
|
||||
'subevent_mode': forms.RadioSelect,
|
||||
@@ -83,15 +88,12 @@ class DiscountForm(I18nModelForm):
|
||||
self.event = kwargs['event']
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields['sales_channels'] = forms.MultipleChoiceField(
|
||||
label=_('Sales channels'),
|
||||
required=True,
|
||||
choices=(
|
||||
(c.identifier, c.verbose_name) for c in get_all_sales_channels().values()
|
||||
if c.discounts_supported
|
||||
),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.filter(
|
||||
type__in=[k for k, v in get_all_sales_channel_types().items() if v.discounts_supported]
|
||||
)
|
||||
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
|
||||
'data-inverse-dependency': '<[name$=all_sales_channels]',
|
||||
}, choices=self.fields['limit_sales_channels'].widget.choices)
|
||||
self.fields['condition_limit_products'].queryset = self.event.items.all()
|
||||
self.fields['benefit_limit_products'].queryset = self.event.items.all()
|
||||
self.fields['condition_min_count'].required = False
|
||||
|
||||
@@ -44,9 +44,7 @@ from django.conf import settings
|
||||
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
|
||||
from django.core.validators import MaxValueValidator
|
||||
from django.db.models import Prefetch, Q, prefetch_related_objects
|
||||
from django.forms import (
|
||||
CheckboxSelectMultiple, formset_factory, inlineformset_factory,
|
||||
)
|
||||
from django.forms import formset_factory, inlineformset_factory
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import escape, format_html
|
||||
@@ -54,12 +52,12 @@ from django.utils.safestring import mark_safe
|
||||
from django.utils.timezone import get_current_timezone_name
|
||||
from django.utils.translation import gettext, gettext_lazy as _, pgettext_lazy
|
||||
from django_countries.fields import LazyTypedChoiceField
|
||||
from django_scopes.forms import SafeModelMultipleChoiceField
|
||||
from i18nfield.forms import (
|
||||
I18nForm, I18nFormField, I18nFormSetMixin, I18nTextInput,
|
||||
)
|
||||
from pytz import common_timezones
|
||||
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.forms import (
|
||||
I18nMarkdownTextarea, I18nModelForm, PlaceholderValidator, SettingsForm,
|
||||
)
|
||||
@@ -73,8 +71,8 @@ from pretix.base.settings import (
|
||||
)
|
||||
from pretix.base.validators import multimail_validate
|
||||
from pretix.control.forms import (
|
||||
MultipleLanguagesWidget, SlugWidget, SplitDateTimeField,
|
||||
SplitDateTimePickerWidget,
|
||||
MultipleLanguagesWidget, SalesChannelCheckboxSelectMultiple, SlugWidget,
|
||||
SplitDateTimeField, SplitDateTimePickerWidget,
|
||||
)
|
||||
from pretix.control.forms.widgets import Select2
|
||||
from pretix.helpers.countries import CachedCountries
|
||||
@@ -378,16 +376,10 @@ class EventUpdateForm(I18nModelForm):
|
||||
required=False,
|
||||
help_text=_('You need to configure the custom domain in the webserver beforehand.')
|
||||
)
|
||||
self.fields['sales_channels'] = forms.MultipleChoiceField(
|
||||
label=self.fields['sales_channels'].label,
|
||||
help_text=self.fields['sales_channels'].help_text,
|
||||
required=self.fields['sales_channels'].required,
|
||||
initial=self.fields['sales_channels'].initial,
|
||||
choices=(
|
||||
(c.identifier, c.verbose_name) for c in get_all_sales_channels().values()
|
||||
),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all()
|
||||
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
|
||||
'data-inverse-dependency': '<[name$=all_sales_channels]',
|
||||
}, choices=self.fields['limit_sales_channels'].widget.choices)
|
||||
|
||||
def clean_domain(self):
|
||||
d = self.cleaned_data['domain']
|
||||
@@ -444,7 +436,8 @@ class EventUpdateForm(I18nModelForm):
|
||||
'location',
|
||||
'geo_lat',
|
||||
'geo_lon',
|
||||
'sales_channels'
|
||||
'all_sales_channels',
|
||||
'limit_sales_channels',
|
||||
]
|
||||
field_classes = {
|
||||
'date_from': SplitDateTimeField,
|
||||
@@ -452,6 +445,7 @@ class EventUpdateForm(I18nModelForm):
|
||||
'date_admission': SplitDateTimeField,
|
||||
'presale_start': SplitDateTimeField,
|
||||
'presale_end': SplitDateTimeField,
|
||||
'limit_sales_channels': SafeModelMultipleChoiceField,
|
||||
}
|
||||
widgets = {
|
||||
'date_from': SplitDateTimePickerWidget(),
|
||||
@@ -459,7 +453,6 @@ class EventUpdateForm(I18nModelForm):
|
||||
'date_admission': SplitDateTimePickerWidget(attrs={'data-date-default': '#id_date_from_0'}),
|
||||
'presale_start': SplitDateTimePickerWidget(),
|
||||
'presale_end': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_presale_start_0'}),
|
||||
'sales_channels': CheckboxSelectMultiple(),
|
||||
}
|
||||
|
||||
|
||||
@@ -915,7 +908,7 @@ class InvoiceSettingsForm(EventSettingsValidationMixin, SettingsForm):
|
||||
locale_names = dict(settings.LANGUAGES)
|
||||
self.fields['invoice_language'].choices = [('__user__', _('The user\'s language'))] + [(a, locale_names[a]) for a in event.settings.locales]
|
||||
self.fields['invoice_generate_sales_channels'].choices = (
|
||||
(c.identifier, c.verbose_name) for c in get_all_sales_channels().values()
|
||||
(c.identifier, c.label) for c in event.organizer.sales_channels.all()
|
||||
)
|
||||
self.fields['invoice_numbers_counter_length'].validators.append(MaxValueValidator(15))
|
||||
|
||||
@@ -961,7 +954,7 @@ class MailSettingsForm(FormPlaceholderMixin, SettingsForm):
|
||||
]
|
||||
|
||||
mail_sales_channel_placed_paid = forms.MultipleChoiceField(
|
||||
choices=lambda: [(ident, sc.verbose_name) for ident, sc in get_all_sales_channels().items()],
|
||||
choices=[],
|
||||
label=_('Sales channels for checkout emails'),
|
||||
help_text=_('The order placed and paid emails will only be send to orders from these sales channels. '
|
||||
'The online shop must be enabled.'),
|
||||
@@ -972,7 +965,7 @@ class MailSettingsForm(FormPlaceholderMixin, SettingsForm):
|
||||
)
|
||||
|
||||
mail_sales_channel_download_reminder = forms.MultipleChoiceField(
|
||||
choices=lambda: [(ident, sc.verbose_name) for ident, sc in get_all_sales_channels().items()],
|
||||
choices=[],
|
||||
label=_('Sales channels'),
|
||||
help_text=_('This email will only be send to orders from these sales channels. The online shop must be enabled.'),
|
||||
widget=forms.CheckboxSelectMultiple(
|
||||
@@ -1367,6 +1360,12 @@ class MailSettingsForm(FormPlaceholderMixin, SettingsForm):
|
||||
self.fields['mail_html_renderer'].choices = [
|
||||
(r.identifier, r.verbose_name) for r in event.get_html_mail_renderers().values()
|
||||
]
|
||||
self.fields['mail_sales_channel_placed_paid'].choices = (
|
||||
(c.identifier, c.label) for c in event.organizer.sales_channels.all()
|
||||
)
|
||||
self.fields['mail_sales_channel_download_reminder'].choices = (
|
||||
(c.identifier, c.label) for c in event.organizer.sales_channels.all()
|
||||
)
|
||||
|
||||
prefetch_related_objects([self.event.organizer], Prefetch('meta_properties'))
|
||||
self.event.meta_values_cached = self.event.meta_values.select_related('property').all()
|
||||
|
||||
@@ -50,15 +50,14 @@ from django.utils.timezone import get_current_timezone, make_aware, now
|
||||
from django.utils.translation import gettext, gettext_lazy as _, pgettext_lazy
|
||||
from django_scopes.forms import SafeModelChoiceField
|
||||
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.forms.widgets import (
|
||||
DatePickerWidget, SplitDateTimePickerWidget, TimePickerWidget,
|
||||
)
|
||||
from pretix.base.models import (
|
||||
Checkin, CheckinList, Device, Event, EventMetaProperty, EventMetaValue,
|
||||
Gate, Invoice, InvoiceAddress, Item, Order, OrderPayment, OrderPosition,
|
||||
OrderRefund, Organizer, Question, QuestionAnswer, Quota, SubEvent,
|
||||
SubEventMetaValue, Team, TeamAPIToken, TeamInvite, Voucher,
|
||||
OrderRefund, Organizer, Question, QuestionAnswer, Quota, SalesChannel,
|
||||
SubEvent, SubEventMetaValue, Team, TeamAPIToken, TeamInvite, Voucher,
|
||||
)
|
||||
from pretix.base.signals import register_payment_providers
|
||||
from pretix.control.forms.widgets import Select2, Select2ItemVarQuota
|
||||
@@ -579,9 +578,11 @@ class EventOrderExpertFilterForm(EventOrderFilterForm):
|
||||
required=False,
|
||||
label=_('Maximal sum of payments and refunds'),
|
||||
)
|
||||
sales_channel = forms.ChoiceField(
|
||||
sales_channel = SafeModelChoiceField(
|
||||
label=_('Sales channel'),
|
||||
required=False,
|
||||
queryset=SalesChannel.objects.none(),
|
||||
to_field_name="identifier",
|
||||
)
|
||||
has_checkin = forms.NullBooleanField(
|
||||
required=False,
|
||||
@@ -604,9 +605,7 @@ class EventOrderExpertFilterForm(EventOrderFilterForm):
|
||||
del self.fields['subevents_from']
|
||||
del self.fields['subevents_to']
|
||||
|
||||
self.fields['sales_channel'].choices = [('', '')] + [
|
||||
(k, v.verbose_name) for k, v in get_all_sales_channels().items()
|
||||
]
|
||||
self.fields['sales_channel'].queryset = self.event.organizer.sales_channels.all()
|
||||
|
||||
locale_names = dict(settings.LANGUAGES)
|
||||
self.fields['locale'].choices = [('', '')] + [(a, locale_names[a]) for a in self.event.settings.locales]
|
||||
@@ -719,7 +718,7 @@ class EventOrderExpertFilterForm(EventOrderFilterForm):
|
||||
if fdata.get('comment'):
|
||||
qs = qs.filter(comment__icontains=fdata.get('comment'))
|
||||
if fdata.get('sales_channel'):
|
||||
qs = qs.filter(sales_channel=fdata.get('sales_channel'))
|
||||
qs = qs.filter(sales_channel__identifier=fdata.get('sales_channel').identifier)
|
||||
if fdata.get('total'):
|
||||
qs = qs.filter(total=fdata.get('total'))
|
||||
if fdata.get('email_known_to_work') is not None:
|
||||
|
||||
@@ -55,7 +55,6 @@ from django_scopes.forms import (
|
||||
)
|
||||
from i18nfield.forms import I18nFormField, I18nTextarea
|
||||
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.forms import I18nFormSet, I18nMarkdownTextarea, I18nModelForm
|
||||
from pretix.base.forms.widgets import DatePickerWidget
|
||||
from pretix.base.models import (
|
||||
@@ -64,7 +63,8 @@ from pretix.base.models import (
|
||||
from pretix.base.models.items import ItemAddOn, ItemBundle, ItemMetaValue
|
||||
from pretix.base.signals import item_copy_data
|
||||
from pretix.control.forms import (
|
||||
ButtonGroupRadioSelect, ItemMultipleChoiceField, SizeValidationMixin,
|
||||
ButtonGroupRadioSelect, ItemMultipleChoiceField,
|
||||
SalesChannelCheckboxSelectMultiple, SizeValidationMixin,
|
||||
SplitDateTimeField, SplitDateTimePickerWidget,
|
||||
)
|
||||
from pretix.control.forms.widgets import Select2, Select2ItemVarMulti
|
||||
@@ -413,7 +413,7 @@ class ItemCreateForm(I18nModelForm):
|
||||
'checkin_text',
|
||||
'free_price',
|
||||
'original_price',
|
||||
'sales_channels',
|
||||
'all_sales_channels',
|
||||
'issue_giftcard',
|
||||
'require_approval',
|
||||
'allow_waitinglist',
|
||||
@@ -443,9 +443,6 @@ class ItemCreateForm(I18nModelForm):
|
||||
|
||||
if src.picture:
|
||||
self.instance.picture.save(os.path.basename(src.picture.name), src.picture)
|
||||
else:
|
||||
# Add to all sales channels by default
|
||||
self.instance.sales_channels = list(get_all_sales_channels().keys())
|
||||
|
||||
self.instance.position = (self.event.items.aggregate(p=Max('position'))['p'] or 0) + 1
|
||||
if not self.instance.admission:
|
||||
@@ -474,6 +471,8 @@ class ItemCreateForm(I18nModelForm):
|
||||
})
|
||||
|
||||
if self.cleaned_data.get('copy_from'):
|
||||
if not self.instance.all_sales_channels:
|
||||
self.instance.limit_sales_channels.set(self.cleaned_data['copy_from'].limit_sales_channels.all())
|
||||
self.instance.require_membership_types.set(
|
||||
self.cleaned_data['copy_from'].require_membership_types.all()
|
||||
)
|
||||
@@ -574,14 +573,10 @@ class ItemUpdateForm(I18nModelForm):
|
||||
if self.event.tax_rules.exists():
|
||||
self.fields['tax_rule'].required = True
|
||||
self.fields['description'].widget.attrs['rows'] = '4'
|
||||
self.fields['sales_channels'] = forms.MultipleChoiceField(
|
||||
label=_('Sales channels'),
|
||||
required=False,
|
||||
choices=(
|
||||
(c.identifier, c.verbose_name) for c in get_all_sales_channels().values()
|
||||
),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all()
|
||||
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
|
||||
'data-inverse-dependency': '<[name$=all_sales_channels]',
|
||||
}, choices=self.fields['limit_sales_channels'].widget.choices)
|
||||
change_decimal_field(self.fields['default_price'], self.event.currency)
|
||||
|
||||
self.fields['available_from_mode'].widget = ButtonGroupRadioSelect(
|
||||
@@ -772,7 +767,8 @@ class ItemUpdateForm(I18nModelForm):
|
||||
'name',
|
||||
'internal_name',
|
||||
'active',
|
||||
'sales_channels',
|
||||
'all_sales_channels',
|
||||
'limit_sales_channels',
|
||||
'admission',
|
||||
'personalized',
|
||||
'description',
|
||||
@@ -829,6 +825,7 @@ class ItemUpdateForm(I18nModelForm):
|
||||
'hidden_if_item_available': SafeModelChoiceField,
|
||||
'grant_membership_type': SafeModelChoiceField,
|
||||
'require_membership_types': SafeModelMultipleChoiceField,
|
||||
'limit_sales_channels': SafeModelMultipleChoiceField,
|
||||
}
|
||||
widgets = {
|
||||
'available_from': SplitDateTimePickerWidget(),
|
||||
@@ -900,18 +897,10 @@ class ItemVariationForm(I18nModelForm):
|
||||
qs = kwargs.pop('membership_types')
|
||||
super().__init__(*args, **kwargs)
|
||||
change_decimal_field(self.fields['default_price'], self.event.currency)
|
||||
self.fields['sales_channels'] = forms.MultipleChoiceField(
|
||||
label=_('Sales channels'),
|
||||
required=False,
|
||||
choices=(
|
||||
(c.identifier, c.verbose_name) for c in get_all_sales_channels().values()
|
||||
),
|
||||
help_text=_('The sales channel selection for the product as a whole takes precedence, so if a sales channel is '
|
||||
'selected here but not on product level, the variation will not be available.'),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
)
|
||||
if not self.instance.pk:
|
||||
self.initial.setdefault('sales_channels', list(get_all_sales_channels().keys()))
|
||||
self.fields['limit_sales_channels'].queryset = self.event.organizer.sales_channels.all()
|
||||
self.fields['limit_sales_channels'].widget = SalesChannelCheckboxSelectMultiple(self.event, attrs={
|
||||
'data-inverse-dependency': '<[name$=all_sales_channels]',
|
||||
}, choices=self.fields['limit_sales_channels'].widget.choices)
|
||||
|
||||
self.fields['description'].widget.attrs['rows'] = 3
|
||||
if qs:
|
||||
@@ -983,12 +972,14 @@ class ItemVariationForm(I18nModelForm):
|
||||
'available_from_mode',
|
||||
'available_until',
|
||||
'available_until_mode',
|
||||
'sales_channels',
|
||||
'all_sales_channels',
|
||||
'limit_sales_channels',
|
||||
'hide_without_voucher',
|
||||
]
|
||||
field_classes = {
|
||||
'available_from': SplitDateTimeField,
|
||||
'available_until': SplitDateTimeField,
|
||||
'limit_sales_channels': SafeModelMultipleChoiceField,
|
||||
}
|
||||
widgets = {
|
||||
'available_from': SplitDateTimePickerWidget(),
|
||||
|
||||
@@ -50,6 +50,7 @@ from django_scopes.forms import SafeModelChoiceField
|
||||
from i18nfield.forms import (
|
||||
I18nForm, I18nFormField, I18nFormSetMixin, I18nTextInput,
|
||||
)
|
||||
from i18nfield.strings import LazyI18nString
|
||||
from phonenumber_field.formfields import PhoneNumberField
|
||||
from pytz import common_timezones
|
||||
|
||||
@@ -68,7 +69,8 @@ from pretix.base.forms.widgets import (
|
||||
)
|
||||
from pretix.base.models import (
|
||||
Customer, Device, EventMetaProperty, Gate, GiftCard, GiftCardAcceptance,
|
||||
Membership, MembershipType, OrderPosition, Organizer, ReusableMedium, Team,
|
||||
Membership, MembershipType, OrderPosition, Organizer, ReusableMedium,
|
||||
SalesChannel, Team,
|
||||
)
|
||||
from pretix.base.models.customers import CustomerSSOClient, CustomerSSOProvider
|
||||
from pretix.base.models.organizer import OrganizerFooterLink
|
||||
@@ -1090,3 +1092,40 @@ class GiftCardAcceptanceInviteForm(forms.Form):
|
||||
if self.organizer.gift_card_acceptor_acceptance.filter(acceptor=acceptor).exists():
|
||||
raise ValidationError(_('The selected organizer has already been invited.'))
|
||||
return acceptor
|
||||
|
||||
|
||||
class SalesChannelForm(I18nModelForm):
|
||||
class Meta:
|
||||
model = SalesChannel
|
||||
fields = ['label', 'identifier']
|
||||
widgets = {
|
||||
'default': forms.TextInput(),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.type = kwargs.pop("type")
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if not self.type.multiple_allowed or (self.instance and self.instance.pk):
|
||||
self.fields["identifier"].initial = self.type.identifier
|
||||
self.fields["identifier"].disabled = True
|
||||
self.fields["label"].initial = LazyI18nString.from_gettext(self.type.verbose_name)
|
||||
|
||||
def clean(self):
|
||||
d = super().clean()
|
||||
|
||||
if self.instance.pk:
|
||||
d["identifier"] = self.instance.identifier
|
||||
elif self.type.multiple_allowed:
|
||||
d["identifier"] = self.type.identifier + "." + d["identifier"]
|
||||
else:
|
||||
d["identifier"] = self.type.identifier
|
||||
|
||||
if not self.instance.pk:
|
||||
# self.event is actually the organizer, sorry I18nModelForm!
|
||||
if self.event.sales_channels.filter(identifier=d["identifier"]).exists():
|
||||
raise ValidationError(
|
||||
_("A sales channel with the same identifier already exists.")
|
||||
)
|
||||
|
||||
return d
|
||||
|
||||
Reference in New Issue
Block a user