diff --git a/src/pretix/api/serializers/order.py b/src/pretix/api/serializers/order.py
index 1065feb325..82e12a9301 100644
--- a/src/pretix/api/serializers/order.py
+++ b/src/pretix/api/serializers/order.py
@@ -911,6 +911,19 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
if pos_data['voucher'].allow_ignore_quota or pos_data['voucher'].block_quota:
continue
+ if pos_data.get('subevent'):
+ if pos_data.get('item').pk in pos_data['subevent'].item_overrides and pos_data['subevent'].item_overrides[pos_data['item'].pk].disabled:
+ errs[i]['item'] = [gettext_lazy('The product "{}" is not available on this date.').format(
+ str(pos_data.get('item'))
+ )]
+ if (
+ pos_data.get('variation') and pos_data['variation'].pk in pos_data['subevent'].var_overrides and
+ pos_data['subevent'].var_overrides[pos_data['variation'].pk].disabled
+ ):
+ errs[i]['item'] = [gettext_lazy('The product "{}" is not available on this date.').format(
+ str(pos_data.get('item'))
+ )]
+
new_quotas = (pos_data.get('variation').quotas.filter(subevent=pos_data.get('subevent'))
if pos_data.get('variation')
else pos_data.get('item').quotas.filter(subevent=pos_data.get('subevent')))
diff --git a/src/pretix/base/migrations/0154_auto_20200620_1633.py b/src/pretix/base/migrations/0154_auto_20200620_1633.py
new file mode 100644
index 0000000000..89e461bf7e
--- /dev/null
+++ b/src/pretix/base/migrations/0154_auto_20200620_1633.py
@@ -0,0 +1,31 @@
+# Generated by Django 3.0.6 on 2020-06-20 16:33
+
+import django_countries.fields
+from django.db import migrations, models
+
+import pretix.helpers.countries
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('pretixbase', '0153_auto_20200528_1953'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='subeventitem',
+ name='disabled',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AddField(
+ model_name='subeventitemvariation',
+ name='disabled',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AlterField(
+ model_name='invoiceaddress',
+ name='country',
+ field=django_countries.fields.CountryField(countries=pretix.helpers.countries.CachedCountries, max_length=2),
+ ),
+ ]
diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py
index c20a40bbf0..52453652b9 100644
--- a/src/pretix/base/models/event.py
+++ b/src/pretix/base/models/event.py
@@ -1061,21 +1061,35 @@ class SubEvent(EventMixin, LoggedModel):
return self.event.settings
@cached_property
- def item_price_overrides(self):
+ def item_overrides(self):
from .items import SubEventItem
return {
- si.item_id: si.price
- for si in SubEventItem.objects.filter(subevent=self, price__isnull=False)
+ si.item_id: si
+ for si in SubEventItem.objects.filter(subevent=self)
}
@cached_property
- def var_price_overrides(self):
+ def var_overrides(self):
from .items import SubEventItemVariation
+ return {
+ si.variation_id: si
+ for si in SubEventItemVariation.objects.filter(subevent=self)
+ }
+
+ @property
+ def item_price_overrides(self):
+ return {
+ si.item_id: si.price
+ for si in self.item_overrides.values() if si.price is not None
+ }
+
+ @property
+ def var_price_overrides(self):
return {
si.variation_id: si.price
- for si in SubEventItemVariation.objects.filter(subevent=self, price__isnull=False)
+ for si in self.var_overrides.values() if si.price is not None
}
@property
diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py
index 648d8b7adc..d0629ba47d 100644
--- a/src/pretix/base/models/items.py
+++ b/src/pretix/base/models/items.py
@@ -118,6 +118,7 @@ class SubEventItem(models.Model):
subevent = models.ForeignKey('SubEvent', on_delete=models.CASCADE)
item = models.ForeignKey('Item', on_delete=models.CASCADE)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
+ disabled = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
@@ -145,6 +146,7 @@ class SubEventItemVariation(models.Model):
subevent = models.ForeignKey('SubEvent', on_delete=models.CASCADE)
variation = models.ForeignKey('ItemVariation', on_delete=models.CASCADE)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
+ disabled = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py
index 380a91d298..b627decd47 100644
--- a/src/pretix/base/services/cart.py
+++ b/src/pretix/base/services/cart.py
@@ -253,6 +253,12 @@ class CartManager:
if self._sales_channel not in op.item.sales_channels:
raise CartError(error_messages['unavailable'])
+ if op.subevent and op.item.pk in op.subevent.item_overrides and op.subevent.item_overrides[op.item.pk].disabled:
+ raise CartError(error_messages['not_for_sale'])
+
+ if op.subevent and op.variation and op.variation.pk in op.subevent.var_overrides and op.subevent.var_overrides[op.variation.pk].disabled:
+ raise CartError(error_messages['not_for_sale'])
+
if op.item.has_variations and not op.variation:
raise CartError(error_messages['not_for_sale'])
diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py
index d15fdd2446..784c6c1c1b 100644
--- a/src/pretix/base/services/orders.py
+++ b/src/pretix/base/services/orders.py
@@ -641,6 +641,16 @@ def _check_positions(event: Event, now_dt: datetime, positions: List[CartPositio
delete(cp)
continue
+ if cp.subevent and cp.item.pk in cp.subevent.item_overrides and cp.subevent.item_overrides[cp.item.pk].disabled:
+ err = err or error_messages['unavailable']
+ delete(cp)
+ continue
+
+ if cp.subevent and cp.variation and cp.variation.pk in cp.subevent.var_overrides and cp.subevent.var_overrides[cp.variation.pk].disabled:
+ err = err or error_messages['unavailable']
+ delete(cp)
+ continue
+
if cp.voucher:
if cp.voucher.valid_until and cp.voucher.valid_until < now_dt:
err = err or error_messages['voucher_expired']
diff --git a/src/pretix/control/forms/subevents.py b/src/pretix/control/forms/subevents.py
index 81850ff9e6..389894ec0e 100644
--- a/src/pretix/control/forms/subevents.py
+++ b/src/pretix/control/forms/subevents.py
@@ -99,7 +99,7 @@ class SubEventItemForm(SubEventItemOrVariationFormMixin, forms.ModelForm):
class Meta:
model = SubEventItem
- fields = ['price']
+ fields = ['price', 'disabled']
widgets = {
'price': forms.TextInput
}
@@ -113,7 +113,7 @@ class SubEventItemVariationForm(SubEventItemOrVariationFormMixin, forms.ModelFor
class Meta:
model = SubEventItem
- fields = ['price']
+ fields = ['price', 'disabled']
widgets = {
'price': forms.TextInput
}
diff --git a/src/pretix/control/templates/pretixcontrol/subevents/bulk.html b/src/pretix/control/templates/pretixcontrol/subevents/bulk.html
index 59356d9e64..67b87d6aad 100644
--- a/src/pretix/control/templates/pretixcontrol/subevents/bulk.html
+++ b/src/pretix/control/templates/pretixcontrol/subevents/bulk.html
@@ -461,7 +461,19 @@