diff --git a/doc/api/resources/item_variations.rst b/doc/api/resources/item_variations.rst index e92ad33c7..0a31ab72b 100644 --- a/doc/api/resources/item_variations.rst +++ b/doc/api/resources/item_variations.rst @@ -24,6 +24,8 @@ active boolean If ``false``, t description multi-lingual string A public description of the variation. May contain Markdown syntax or can be ``null``. position integer An integer, used for sorting +require_membership boolean If ``true``, booking this variation requires an active membership. +require_membership_types list of integers Internal IDs of membership types valid if ``require_membership`` is ``true`` ===================================== ========================== ======================================================= Endpoints @@ -60,6 +62,8 @@ Endpoints "en": "S" }, "active": true, + "require_membership": false, + "require_membership_types": [], "description": { "en": "Test2" }, @@ -74,6 +78,8 @@ Endpoints "en": "L" }, "active": true, + "require_membership": false, + "require_membership_types": [], "description": {}, "position": 1, "default_price": null, @@ -121,6 +127,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 } @@ -150,6 +158,8 @@ Endpoints "value": {"en": "Student"}, "default_price": "10.00", "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 } @@ -169,6 +179,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 } @@ -219,6 +231,8 @@ Endpoints "price": "10.00", "original_price": null, "active": false, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 1 } diff --git a/doc/api/resources/items.rst b/doc/api/resources/items.rst index 59e3eb074..be6dc20ff 100644 --- a/doc/api/resources/items.rst +++ b/doc/api/resources/items.rst @@ -104,6 +104,8 @@ variations list of objects A list with one for price calculations (or ``null``). ├ active boolean If ``false``, this variation will not be sold or shown. ├ description multi-lingual string A public description of the variation. May contain +├ require_membership boolean If ``true``, booking this variation requires an active membership. +├ require_membership_types list of integers Internal IDs of membership types valid if ``require_membership`` is ``true`` Markdown syntax or can be ``null``. └ position integer An integer, used for sorting addons list of objects Definition of add-ons that can be chosen for this item. @@ -136,6 +138,11 @@ meta_data object Values set for The attribute ``multi_allowed`` has been added to ``addons``. +.. versionchanged:: 4.0 + + The attributes ``require_membership``, ``require_membership_types``, ``grant_membership_type``, ``grant_membership_duration_like_event``, + ``grant_membership_duration_days`` and ``grant_membership_duration_months`` have been added. + Notes ----- @@ -221,6 +228,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 }, @@ -230,6 +239,8 @@ Endpoints "price": "23.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 1 } @@ -323,6 +334,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 }, @@ -332,6 +345,8 @@ Endpoints "price": "23.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 1 } @@ -405,6 +420,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 }, @@ -414,6 +431,8 @@ Endpoints "price": "23.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 1 } @@ -476,6 +495,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 }, @@ -485,6 +506,8 @@ Endpoints "price": "23.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 1 } @@ -578,6 +601,8 @@ Endpoints "price": "10.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 0 }, @@ -587,6 +612,8 @@ Endpoints "price": "23.00", "original_price": null, "active": true, + "require_membership": false, + "require_membership_types": [], "description": null, "position": 1 } diff --git a/src/pretix/api/serializers/item.py b/src/pretix/api/serializers/item.py index 1b3047b57..70f68d253 100644 --- a/src/pretix/api/serializers/item.py +++ b/src/pretix/api/serializers/item.py @@ -36,7 +36,8 @@ from decimal import Decimal from django.core.exceptions import ValidationError from django.db import transaction -from django.utils.functional import cached_property +from django.db.models import QuerySet +from django.utils.functional import cached_property, lazy from django.utils.translation import gettext_lazy as _ from rest_framework import serializers @@ -56,7 +57,12 @@ class InlineItemVariationSerializer(I18nAwareModelSerializer): class Meta: model = ItemVariation fields = ('id', 'value', 'active', 'description', - 'position', 'default_price', 'price', 'original_price') + 'position', 'default_price', 'price', 'original_price', + 'require_membership', 'require_membership_types',) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['require_membership_types'].queryset = lazy(lambda: self.context['event'].organizer.membership_types.all(), QuerySet) class ItemVariationSerializer(I18nAwareModelSerializer): @@ -66,7 +72,12 @@ class ItemVariationSerializer(I18nAwareModelSerializer): class Meta: model = ItemVariation fields = ('id', 'value', 'active', 'description', - 'position', 'default_price', 'price', 'original_price') + 'position', 'default_price', 'price', 'original_price', + 'require_membership', 'require_membership_types',) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['require_membership_types'].queryset = self.context['event'].organizer.membership_types.all() class InlineItemBundleSerializer(serializers.ModelSerializer): @@ -237,7 +248,10 @@ class ItemSerializer(I18nAwareModelSerializer): item = Item.objects.create(**validated_data) for variation_data in variations_data: - ItemVariation.objects.create(item=item, **variation_data) + require_membership_types = variation_data.pop('require_membership_types') + v = ItemVariation.objects.create(item=item, **variation_data) + if require_membership_types: + v.require_membership_types.add(*require_membership_types) for addon_data in addons_data: ItemAddOn.objects.create(base_item=item, **addon_data) for bundle_data in bundles_data: diff --git a/src/pretix/api/views/item.py b/src/pretix/api/views/item.py index 438c4c4d0..2036d7076 100644 --- a/src/pretix/api/views/item.py +++ b/src/pretix/api/views/item.py @@ -152,6 +152,7 @@ class ItemVariationViewSet(viewsets.ModelViewSet): def get_serializer_context(self): ctx = super().get_serializer_context() ctx['item'] = self.item + ctx['event'] = self.request.event return ctx def perform_create(self, serializer): diff --git a/src/tests/api/test_items.py b/src/tests/api/test_items.py index 746593501..96153ef52 100644 --- a/src/tests/api/test_items.py +++ b/src/tests/api/test_items.py @@ -372,6 +372,8 @@ def test_item_detail_variations(token_client, organizer, event, team, item): "active": True, "description": None, "position": 0, + "require_membership": False, + "require_membership_types": [], "original_price": None }] res["has_variations"] = True @@ -497,6 +499,8 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego "en": "Comment" }, "active": True, + "require_membership": False, + "require_membership_types": [], "description": None, "position": 0, "default_price": None, @@ -1123,6 +1127,8 @@ TEST_VARIATIONS_RES = { "position": 0, "default_price": None, "price": "23.00", + "require_membership": False, + "require_membership_types": [], "original_price": None } @@ -1134,6 +1140,8 @@ TEST_VARIATIONS_UPDATE = { "description": None, "position": 1, "default_price": "20.0", + "require_membership": False, + "require_membership_types": [], "original_price": None }