forked from CGM_Public/pretix_original
- [x] Write operations for subevents - [x] Tests - [x] Documentation
This commit is contained in:
committed by
Raphael Michel
parent
516fab52da
commit
ca7d55082b
@@ -191,8 +191,8 @@ class SubEventItemVariationSerializer(I18nAwareModelSerializer):
|
||||
|
||||
|
||||
class SubEventSerializer(I18nAwareModelSerializer):
|
||||
item_price_overrides = SubEventItemSerializer(source='subeventitem_set', many=True)
|
||||
variation_price_overrides = SubEventItemVariationSerializer(source='subeventitemvariation_set', many=True)
|
||||
item_price_overrides = SubEventItemSerializer(source='subeventitem_set', many=True, required=False)
|
||||
variation_price_overrides = SubEventItemVariationSerializer(source='subeventitemvariation_set', many=True, required=False)
|
||||
event = SlugRelatedField(slug_field='slug', read_only=True)
|
||||
meta_data = MetaDataField(source='*')
|
||||
|
||||
@@ -202,6 +202,103 @@ class SubEventSerializer(I18nAwareModelSerializer):
|
||||
'presale_start', 'presale_end', 'location', 'event',
|
||||
'item_price_overrides', 'variation_price_overrides', 'meta_data')
|
||||
|
||||
def validate(self, data):
|
||||
data = super().validate(data)
|
||||
event = self.context['request'].event
|
||||
|
||||
full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {}
|
||||
full_data.update(data)
|
||||
|
||||
Event.clean_dates(data.get('date_from'), data.get('date_to'))
|
||||
Event.clean_presale(data.get('presale_start'), data.get('presale_end'))
|
||||
|
||||
SubEvent.clean_items(event, [item['item'] for item in full_data.get('subeventitem_set')])
|
||||
SubEvent.clean_variations(event, [item['variation'] for item in full_data.get('subeventitemvariation_set')])
|
||||
return data
|
||||
|
||||
def validate_item_price_overrides(self, data):
|
||||
return list(filter(lambda i: 'item' in i, data))
|
||||
|
||||
def validate_variation_price_overrides(self, data):
|
||||
return list(filter(lambda i: 'variation' in i, data))
|
||||
|
||||
@cached_property
|
||||
def meta_properties(self):
|
||||
return {
|
||||
p.name: p for p in self.context['request'].organizer.meta_properties.all()
|
||||
}
|
||||
|
||||
def validate_meta_data(self, value):
|
||||
for key in value['meta_data'].keys():
|
||||
if key not in self.meta_properties:
|
||||
raise ValidationError(_('Meta data property \'{name}\' does not exist.').format(name=key))
|
||||
return value
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
item_price_overrides_data = validated_data.pop('subeventitem_set') if 'subeventitem_set' in validated_data else {}
|
||||
variation_price_overrides_data = validated_data.pop('subeventitemvariation_set') if 'subeventitemvariation_set' in validated_data else {}
|
||||
meta_data = validated_data.pop('meta_data', None)
|
||||
subevent = super().create(validated_data)
|
||||
|
||||
for item_price_override_data in item_price_overrides_data:
|
||||
SubEventItem.objects.create(subevent=subevent, **item_price_override_data)
|
||||
for variation_price_override_data in variation_price_overrides_data:
|
||||
SubEventItemVariation.objects.create(subevent=subevent, **variation_price_override_data)
|
||||
|
||||
# Meta data
|
||||
if meta_data is not None:
|
||||
for key, value in meta_data.items():
|
||||
subevent.meta_values.create(
|
||||
property=self.meta_properties.get(key),
|
||||
value=value
|
||||
)
|
||||
|
||||
return subevent
|
||||
|
||||
@transaction.atomic
|
||||
def update(self, instance, validated_data):
|
||||
item_price_overrides_data = validated_data.pop('subeventitem_set') if 'subeventitem_set' in validated_data else {}
|
||||
variation_price_overrides_data = validated_data.pop('subeventitemvariation_set') if 'subeventitemvariation_set' in validated_data else {}
|
||||
meta_data = validated_data.pop('meta_data', None)
|
||||
subevent = super().update(instance, validated_data)
|
||||
|
||||
existing_item_overrides = {item.item: item.id for item in SubEventItem.objects.filter(subevent=subevent)}
|
||||
|
||||
for item_price_override_data in item_price_overrides_data:
|
||||
id = existing_item_overrides.pop(item_price_override_data['item'], None)
|
||||
SubEventItem(id=id, subevent=subevent, **item_price_override_data).save()
|
||||
|
||||
SubEventItem.objects.filter(id__in=existing_item_overrides.values()).delete()
|
||||
|
||||
existing_variation_overrides = {item.variation: item.id for item in SubEventItemVariation.objects.filter(subevent=subevent)}
|
||||
|
||||
for variation_price_override_data in variation_price_overrides_data:
|
||||
id = existing_variation_overrides.pop(variation_price_override_data['variation'], None)
|
||||
SubEventItemVariation(id=id, subevent=subevent, **variation_price_override_data).save()
|
||||
|
||||
SubEventItemVariation.objects.filter(id__in=existing_variation_overrides.values()).delete()
|
||||
|
||||
# Meta data
|
||||
if meta_data is not None:
|
||||
current = {mv.property: mv for mv in subevent.meta_values.select_related('property')}
|
||||
for key, value in meta_data.items():
|
||||
prop = self.meta_properties.get(key)
|
||||
if prop in current:
|
||||
current[prop].value = value
|
||||
current[prop].save()
|
||||
else:
|
||||
subevent.meta_values.create(
|
||||
property=self.meta_properties.get(key),
|
||||
value=value
|
||||
)
|
||||
|
||||
for prop, current_object in current.items():
|
||||
if prop.name not in meta_data:
|
||||
current_object.delete()
|
||||
|
||||
return subevent
|
||||
|
||||
|
||||
class TaxRuleSerializer(CountryFieldMixin, I18nAwareModelSerializer):
|
||||
class Meta:
|
||||
|
||||
@@ -217,9 +217,10 @@ class SubEventFilter(FilterSet):
|
||||
return queryset.exclude(expr)
|
||||
|
||||
|
||||
class SubEventViewSet(ConditionalListView, viewsets.ReadOnlyModelViewSet):
|
||||
class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = SubEventSerializer
|
||||
queryset = ItemCategory.objects.none()
|
||||
write_permission = 'can_change_event_settings'
|
||||
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
|
||||
filterset_class = SubEventFilter
|
||||
|
||||
@@ -240,6 +241,42 @@ class SubEventViewSet(ConditionalListView, viewsets.ReadOnlyModelViewSet):
|
||||
'subeventitem_set', 'subeventitemvariation_set'
|
||||
)
|
||||
|
||||
def perform_update(self, serializer):
|
||||
super().perform_update(serializer)
|
||||
|
||||
serializer.instance.log_action(
|
||||
'pretix.subevent.changed',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
'pretix.subevent.added',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('The sub-event can not be deleted as it has already been used in orders. Please set'
|
||||
' \'active\' to false instead to hide it from users.')
|
||||
try:
|
||||
with transaction.atomic():
|
||||
instance.log_action(
|
||||
'pretix.subevent.deleted',
|
||||
user=self.request.user,
|
||||
auth=self.request.auth,
|
||||
data=self.request.data
|
||||
)
|
||||
super().perform_destroy(instance)
|
||||
except ProtectedError:
|
||||
raise PermissionDenied('The sub-event could not be deleted as some constraints (e.g. data created by '
|
||||
'plug-ins) do not allow it.')
|
||||
|
||||
|
||||
class TaxRuleViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = TaxRuleSerializer
|
||||
|
||||
@@ -936,6 +936,18 @@ class SubEvent(EventMixin, LoggedModel):
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
@staticmethod
|
||||
def clean_items(event, items):
|
||||
for item in items:
|
||||
if event != item.event:
|
||||
raise ValidationError(_('One or more items do not belong to this event.'))
|
||||
|
||||
@staticmethod
|
||||
def clean_variations(event, variations):
|
||||
for variation in variations:
|
||||
if event != variation.item.event:
|
||||
raise ValidationError(_('One or more variations do not belong to this event.'))
|
||||
|
||||
|
||||
def generate_invite_token():
|
||||
return get_random_string(length=32, allowed_chars=string.ascii_lowercase + string.digits)
|
||||
|
||||
Reference in New Issue
Block a user