diff --git a/src/pretix/api/auth/device.py b/src/pretix/api/auth/device.py index 8bc3ee2ec0..9e813dce83 100644 --- a/src/pretix/api/auth/device.py +++ b/src/pretix/api/auth/device.py @@ -1,4 +1,5 @@ from django.contrib.auth.models import AnonymousUser +from django_scopes import scopes_disabled from rest_framework import exceptions from rest_framework.authentication import TokenAuthentication @@ -12,7 +13,8 @@ class DeviceTokenAuthentication(TokenAuthentication): def authenticate_credentials(self, key): model = self.get_model() try: - device = model.objects.select_related('organizer').get(api_token=key) + with scopes_disabled(): + device = model.objects.select_related('organizer').get(api_token=key) except model.DoesNotExist: raise exceptions.AuthenticationFailed('Invalid token.') diff --git a/src/pretix/api/auth/permission.py b/src/pretix/api/auth/permission.py index 6534f68a6e..3fbe851b49 100644 --- a/src/pretix/api/auth/permission.py +++ b/src/pretix/api/auth/permission.py @@ -3,7 +3,7 @@ from rest_framework.permissions import SAFE_METHODS, BasePermission from pretix.api.models import OAuthAccessToken from pretix.base.models import Device, Event, User from pretix.base.models.auth import SuperuserPermissionSet -from pretix.base.models.organizer import Organizer, TeamAPIToken +from pretix.base.models.organizer import TeamAPIToken from pretix.helpers.security import ( SessionInvalid, SessionReauthRequired, assert_session_valid, ) @@ -50,9 +50,6 @@ class EventPermission(BasePermission): return False elif 'organizer' in request.resolver_match.kwargs: - request.organizer = Organizer.objects.filter( - slug=request.resolver_match.kwargs['organizer'], - ).first() if not request.organizer or not perm_holder.has_organizer_permission(request.organizer, request=request): return False if isinstance(perm_holder, User) and perm_holder.has_active_staff_session(request.session.session_key): diff --git a/src/pretix/api/middleware.py b/src/pretix/api/middleware.py index c75623ae00..fa77fba10b 100644 --- a/src/pretix/api/middleware.py +++ b/src/pretix/api/middleware.py @@ -4,10 +4,13 @@ from hashlib import sha1 from django.conf import settings from django.db import transaction from django.http import HttpRequest, HttpResponse, JsonResponse +from django.urls import resolve from django.utils.timezone import now +from django_scopes import scope from rest_framework import status from pretix.api.models import ApiCall +from pretix.base.models import Organizer class IdempotencyMiddleware: @@ -89,3 +92,21 @@ class IdempotencyMiddleware: for k, v in json.loads(call.response_headers).values(): r[k] = v return r + + +class ApiScopeMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request: HttpRequest): + if not request.path.startswith('/api/'): + return self.get_response(request) + + url = resolve(request.path_info) + if 'organizer' in url.kwargs: + request.organizer = Organizer.objects.filter( + slug=url.kwargs['organizer'], + ).first() + + with scope(organizer=getattr(request, 'organizer', None)): + return self.get_response(request) diff --git a/src/pretix/api/signals.py b/src/pretix/api/signals.py index 0fd2824e13..689cde048f 100644 --- a/src/pretix/api/signals.py +++ b/src/pretix/api/signals.py @@ -2,6 +2,7 @@ from datetime import timedelta from django.dispatch import Signal, receiver from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.api.models import ApiCall, WebHookCall from pretix.base.signals import periodic_task @@ -17,10 +18,12 @@ instances. @receiver(periodic_task) +@scopes_disabled() def cleanup_webhook_logs(sender, **kwargs): WebHookCall.objects.filter(datetime__lte=now() - timedelta(days=30)).delete() @receiver(periodic_task) +@scopes_disabled() def cleanup_api_logs(sender, **kwargs): ApiCall.objects.filter(created__lte=now() - timedelta(hours=24)).delete() diff --git a/src/pretix/api/views/checkin.py b/src/pretix/api/views/checkin.py index f02bcb93bd..4558eaca6c 100644 --- a/src/pretix/api/views/checkin.py +++ b/src/pretix/api/views/checkin.py @@ -6,6 +6,7 @@ from django.shortcuts import get_object_or_404 from django.utils.functional import cached_property from django.utils.timezone import now from django_filters.rest_framework import DjangoFilterBackend, FilterSet +from django_scopes import scopes_disabled from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.fields import DateTimeField @@ -24,11 +25,11 @@ from pretix.base.services.checkin import ( ) from pretix.helpers.database import FixedOrderBy - -class CheckinListFilter(FilterSet): - class Meta: - model = CheckinList - fields = ['subevent'] +with scopes_disabled(): + class CheckinListFilter(FilterSet): + class Meta: + model = CheckinList + fields = ['subevent'] class CheckinListViewSet(viewsets.ModelViewSet): @@ -146,15 +147,16 @@ class CheckinListViewSet(viewsets.ModelViewSet): return Response(response) -class CheckinOrderPositionFilter(OrderPositionFilter): +with scopes_disabled(): + class CheckinOrderPositionFilter(OrderPositionFilter): - def has_checkin_qs(self, queryset, name, value): - return queryset.filter(last_checked_in__isnull=not value) + def has_checkin_qs(self, queryset, name, value): + return queryset.filter(last_checked_in__isnull=not value) class CheckinListPositionViewSet(viewsets.ReadOnlyModelViewSet): serializer_class = CheckinListOrderPositionSerializer - queryset = OrderPosition.objects.none() + queryset = OrderPosition.all.none() filter_backends = (DjangoFilterBackend, RichOrderingFilter) ordering = ('attendee_name_cached', 'positionid') ordering_fields = ( diff --git a/src/pretix/api/views/event.py b/src/pretix/api/views/event.py index 9dd95b0fd5..67fb1ae7ad 100644 --- a/src/pretix/api/views/event.py +++ b/src/pretix/api/views/event.py @@ -3,6 +3,7 @@ from django.db import transaction from django.db.models import ProtectedError, Q from django.utils.timezone import now from django_filters.rest_framework import DjangoFilterBackend, FilterSet +from django_scopes import scopes_disabled from rest_framework import filters, viewsets from rest_framework.exceptions import PermissionDenied @@ -18,51 +19,51 @@ from pretix.base.models import ( from pretix.base.models.event import SubEvent from pretix.helpers.dicts import merge_dicts +with scopes_disabled(): + class EventFilter(FilterSet): + is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') + is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') + ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs') -class EventFilter(FilterSet): - is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') - is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') - ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs') + class Meta: + model = Event + fields = ['is_public', 'live', 'has_subevents'] - class Meta: - model = Event - fields = ['is_public', 'live', 'has_subevents'] - - def ends_after_qs(self, queryset, name, value): - expr = ( - Q(has_subevents=False) & - Q( - Q(Q(date_to__isnull=True) & Q(date_from__gte=value)) - | Q(Q(date_to__isnull=False) & Q(date_to__gte=value)) + def ends_after_qs(self, queryset, name, value): + expr = ( + Q(has_subevents=False) & + Q( + Q(Q(date_to__isnull=True) & Q(date_from__gte=value)) + | Q(Q(date_to__isnull=False) & Q(date_to__gte=value)) + ) ) - ) - return queryset.filter(expr) - - def is_past_qs(self, queryset, name, value): - expr = ( - Q(has_subevents=False) & - Q( - Q(Q(date_to__isnull=True) & Q(date_from__lt=now())) - | Q(Q(date_to__isnull=False) & Q(date_to__lt=now())) - ) - ) - if value: return queryset.filter(expr) - else: - return queryset.exclude(expr) - def is_future_qs(self, queryset, name, value): - expr = ( - Q(has_subevents=False) & - Q( - Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) - | Q(Q(date_to__isnull=False) & Q(date_to__gte=now())) + def is_past_qs(self, queryset, name, value): + expr = ( + Q(has_subevents=False) & + Q( + Q(Q(date_to__isnull=True) & Q(date_from__lt=now())) + | Q(Q(date_to__isnull=False) & Q(date_to__lt=now())) + ) ) - ) - if value: - return queryset.filter(expr) - else: - return queryset.exclude(expr) + if value: + return queryset.filter(expr) + else: + return queryset.exclude(expr) + + def is_future_qs(self, queryset, name, value): + expr = ( + Q(has_subevents=False) & + Q( + Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) + | Q(Q(date_to__isnull=False) & Q(date_to__gte=now())) + ) + ) + if value: + return queryset.filter(expr) + else: + return queryset.exclude(expr) class EventViewSet(viewsets.ModelViewSet): @@ -182,41 +183,42 @@ class CloneEventViewSet(viewsets.ModelViewSet): ) -class SubEventFilter(FilterSet): - is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') - is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') - ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs') +with scopes_disabled(): + class SubEventFilter(FilterSet): + is_past = django_filters.rest_framework.BooleanFilter(method='is_past_qs') + is_future = django_filters.rest_framework.BooleanFilter(method='is_future_qs') + ends_after = django_filters.rest_framework.IsoDateTimeFilter(method='ends_after_qs') - class Meta: - model = SubEvent - fields = ['active', 'event__live'] + class Meta: + model = SubEvent + fields = ['active', 'event__live'] - def ends_after_qs(self, queryset, name, value): - expr = Q( - Q(Q(date_to__isnull=True) & Q(date_from__gte=value)) - | Q(Q(date_to__isnull=False) & Q(date_to__gte=value)) - ) - return queryset.filter(expr) - - def is_past_qs(self, queryset, name, value): - expr = Q( - Q(Q(date_to__isnull=True) & Q(date_from__lt=now())) - | Q(Q(date_to__isnull=False) & Q(date_to__lt=now())) - ) - if value: + def ends_after_qs(self, queryset, name, value): + expr = Q( + Q(Q(date_to__isnull=True) & Q(date_from__gte=value)) + | Q(Q(date_to__isnull=False) & Q(date_to__gte=value)) + ) return queryset.filter(expr) - else: - return queryset.exclude(expr) - def is_future_qs(self, queryset, name, value): - expr = Q( - Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) - | Q(Q(date_to__isnull=False) & Q(date_to__gte=now())) - ) - if value: - return queryset.filter(expr) - else: - return queryset.exclude(expr) + def is_past_qs(self, queryset, name, value): + expr = Q( + Q(Q(date_to__isnull=True) & Q(date_from__lt=now())) + | Q(Q(date_to__isnull=False) & Q(date_to__lt=now())) + ) + if value: + return queryset.filter(expr) + else: + return queryset.exclude(expr) + + def is_future_qs(self, queryset, name, value): + expr = Q( + Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) + | Q(Q(date_to__isnull=False) & Q(date_to__gte=now())) + ) + if value: + return queryset.filter(expr) + else: + return queryset.exclude(expr) class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet): diff --git a/src/pretix/api/views/item.py b/src/pretix/api/views/item.py index 872db4969e..a06088e568 100644 --- a/src/pretix/api/views/item.py +++ b/src/pretix/api/views/item.py @@ -3,6 +3,7 @@ from django.db.models import Q from django.shortcuts import get_object_or_404 from django.utils.functional import cached_property from django_filters.rest_framework import DjangoFilterBackend, FilterSet +from django_scopes import scopes_disabled from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied @@ -21,19 +22,19 @@ from pretix.base.models import ( ) from pretix.helpers.dicts import merge_dicts +with scopes_disabled(): + class ItemFilter(FilterSet): + tax_rate = django_filters.CharFilter(method='tax_rate_qs') -class ItemFilter(FilterSet): - tax_rate = django_filters.CharFilter(method='tax_rate_qs') + def tax_rate_qs(self, queryset, name, value): + if value in ("0", "None", "0.00"): + return queryset.filter(Q(tax_rule__isnull=True) | Q(tax_rule__rate=0)) + else: + return queryset.filter(tax_rule__rate=value) - def tax_rate_qs(self, queryset, name, value): - if value in ("0", "None", "0.00"): - return queryset.filter(Q(tax_rule__isnull=True) | Q(tax_rule__rate=0)) - else: - return queryset.filter(tax_rule__rate=value) - - class Meta: - model = Item - fields = ['active', 'category', 'admission', 'tax_rate', 'free_price'] + class Meta: + model = Item + fields = ['active', 'category', 'admission', 'tax_rate', 'free_price'] class ItemViewSet(ConditionalListView, viewsets.ModelViewSet): @@ -319,10 +320,11 @@ class ItemCategoryViewSet(ConditionalListView, viewsets.ModelViewSet): super().perform_destroy(instance) -class QuestionFilter(FilterSet): - class Meta: - model = Question - fields = ['ask_during_checkin', 'required', 'identifier'] +with scopes_disabled(): + class QuestionFilter(FilterSet): + class Meta: + model = Question + fields = ['ask_during_checkin', 'required', 'identifier'] class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet): @@ -418,10 +420,11 @@ class QuestionOptionViewSet(viewsets.ModelViewSet): super().perform_destroy(instance) -class QuotaFilter(FilterSet): - class Meta: - model = Quota - fields = ['subevent'] +with scopes_disabled(): + class QuotaFilter(FilterSet): + class Meta: + model = Quota + fields = ['subevent'] class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet): diff --git a/src/pretix/api/views/order.py b/src/pretix/api/views/order.py index fdb076d849..689835a256 100644 --- a/src/pretix/api/views/order.py +++ b/src/pretix/api/views/order.py @@ -11,6 +11,7 @@ from django.shortcuts import get_object_or_404 from django.utils.timezone import make_aware, now from django.utils.translation import ugettext as _ from django_filters.rest_framework import DjangoFilterBackend, FilterSet +from django_scopes import scopes_disabled from rest_framework import mixins, serializers, status, viewsets from rest_framework.decorators import action from rest_framework.exceptions import ( @@ -50,17 +51,17 @@ from pretix.base.signals import ( ) from pretix.base.templatetags.money import money_filter +with scopes_disabled(): + class OrderFilter(FilterSet): + email = django_filters.CharFilter(field_name='email', lookup_expr='iexact') + code = django_filters.CharFilter(field_name='code', lookup_expr='iexact') + status = django_filters.CharFilter(field_name='status', lookup_expr='iexact') + modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte') + created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte') -class OrderFilter(FilterSet): - email = django_filters.CharFilter(field_name='email', lookup_expr='iexact') - code = django_filters.CharFilter(field_name='code', lookup_expr='iexact') - status = django_filters.CharFilter(field_name='status', lookup_expr='iexact') - modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte') - created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte') - - class Meta: - model = Order - fields = ['code', 'status', 'email', 'locale', 'testmode', 'require_approval'] + class Meta: + model = Order + fields = ['code', 'status', 'email', 'locale', 'testmode', 'require_approval'] class OrderViewSet(viewsets.ModelViewSet): @@ -531,48 +532,49 @@ class OrderViewSet(viewsets.ModelViewSet): self.get_object().gracefully_delete(user=self.request.user if self.request.user.is_authenticated else None, auth=self.request.auth) -class OrderPositionFilter(FilterSet): - order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact') - has_checkin = django_filters.rest_framework.BooleanFilter(method='has_checkin_qs') - attendee_name = django_filters.CharFilter(method='attendee_name_qs') - search = django_filters.CharFilter(method='search_qs') +with scopes_disabled(): + class OrderPositionFilter(FilterSet): + order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact') + has_checkin = django_filters.rest_framework.BooleanFilter(method='has_checkin_qs') + attendee_name = django_filters.CharFilter(method='attendee_name_qs') + search = django_filters.CharFilter(method='search_qs') - def search_qs(self, queryset, name, value): - return queryset.filter( - Q(secret__istartswith=value) - | Q(attendee_name_cached__icontains=value) - | Q(addon_to__attendee_name_cached__icontains=value) - | Q(attendee_email__icontains=value) - | Q(addon_to__attendee_email__icontains=value) - | Q(order__code__istartswith=value) - | Q(order__invoice_address__name_cached__icontains=value) - | Q(order__email__icontains=value) - ) + def search_qs(self, queryset, name, value): + return queryset.filter( + Q(secret__istartswith=value) + | Q(attendee_name_cached__icontains=value) + | Q(addon_to__attendee_name_cached__icontains=value) + | Q(attendee_email__icontains=value) + | Q(addon_to__attendee_email__icontains=value) + | Q(order__code__istartswith=value) + | Q(order__invoice_address__name_cached__icontains=value) + | Q(order__email__icontains=value) + ) - def has_checkin_qs(self, queryset, name, value): - return queryset.filter(checkins__isnull=not value) + def has_checkin_qs(self, queryset, name, value): + return queryset.filter(checkins__isnull=not value) - def attendee_name_qs(self, queryset, name, value): - return queryset.filter(Q(attendee_name_cached__iexact=value) | Q(addon_to__attendee_name_cached__iexact=value)) + def attendee_name_qs(self, queryset, name, value): + return queryset.filter(Q(attendee_name_cached__iexact=value) | Q(addon_to__attendee_name_cached__iexact=value)) - class Meta: - model = OrderPosition - fields = { - 'item': ['exact', 'in'], - 'variation': ['exact', 'in'], - 'secret': ['exact'], - 'order__status': ['exact', 'in'], - 'addon_to': ['exact', 'in'], - 'subevent': ['exact', 'in'], - 'pseudonymization_id': ['exact'], - 'voucher__code': ['exact'], - 'voucher': ['exact'], - } + class Meta: + model = OrderPosition + fields = { + 'item': ['exact', 'in'], + 'variation': ['exact', 'in'], + 'secret': ['exact'], + 'order__status': ['exact', 'in'], + 'addon_to': ['exact', 'in'], + 'subevent': ['exact', 'in'], + 'pseudonymization_id': ['exact'], + 'voucher__code': ['exact'], + 'voucher': ['exact'], + } class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewSet): serializer_class = OrderPositionSerializer - queryset = OrderPosition.objects.none() + queryset = OrderPosition.all.none() filter_backends = (DjangoFilterBackend, OrderingFilter) ordering = ('order__datetime', 'positionid') ordering_fields = ('order__code', 'order__datetime', 'positionid', 'attendee_name', 'order__status',) @@ -960,22 +962,23 @@ class RefundViewSet(CreateModelMixin, viewsets.ReadOnlyModelViewSet): serializer.save() -class InvoiceFilter(FilterSet): - refers = django_filters.CharFilter(method='refers_qs') - number = django_filters.CharFilter(method='nr_qs') - order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact') +with scopes_disabled(): + class InvoiceFilter(FilterSet): + refers = django_filters.CharFilter(method='refers_qs') + number = django_filters.CharFilter(method='nr_qs') + order = django_filters.CharFilter(field_name='order', lookup_expr='code__iexact') - def refers_qs(self, queryset, name, value): - return queryset.annotate( - refers_nr=Concat('refers__prefix', 'refers__invoice_no') - ).filter(refers_nr__iexact=value) + def refers_qs(self, queryset, name, value): + return queryset.annotate( + refers_nr=Concat('refers__prefix', 'refers__invoice_no') + ).filter(refers_nr__iexact=value) - def nr_qs(self, queryset, name, value): - return queryset.filter(nr__iexact=value) + def nr_qs(self, queryset, name, value): + return queryset.filter(nr__iexact=value) - class Meta: - model = Invoice - fields = ['order', 'number', 'is_cancellation', 'refers', 'locale'] + class Meta: + model = Invoice + fields = ['order', 'number', 'is_cancellation', 'refers', 'locale'] class RetryException(APIException): diff --git a/src/pretix/api/views/voucher.py b/src/pretix/api/views/voucher.py index 187a048370..d897cc2268 100644 --- a/src/pretix/api/views/voucher.py +++ b/src/pretix/api/views/voucher.py @@ -6,6 +6,7 @@ from django.utils.timezone import now from django_filters.rest_framework import ( BooleanFilter, DjangoFilterBackend, FilterSet, ) +from django_scopes import scopes_disabled from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied @@ -15,22 +16,22 @@ from rest_framework.response import Response from pretix.api.serializers.voucher import VoucherSerializer from pretix.base.models import Voucher +with scopes_disabled(): + class VoucherFilter(FilterSet): + active = BooleanFilter(method='filter_active') -class VoucherFilter(FilterSet): - active = BooleanFilter(method='filter_active') + class Meta: + model = Voucher + fields = ['code', 'max_usages', 'redeemed', 'block_quota', 'allow_ignore_quota', + 'price_mode', 'value', 'item', 'variation', 'quota', 'tag', 'subevent'] - class Meta: - model = Voucher - fields = ['code', 'max_usages', 'redeemed', 'block_quota', 'allow_ignore_quota', - 'price_mode', 'value', 'item', 'variation', 'quota', 'tag', 'subevent'] - - def filter_active(self, queryset, name, value): - if value: - return queryset.filter(Q(redeemed__lt=F('max_usages')) & - (Q(valid_until__isnull=True) | Q(valid_until__gt=now()))) - else: - return queryset.filter(Q(redeemed__gte=F('max_usages')) | - (Q(valid_until__isnull=False) & Q(valid_until__lte=now()))) + def filter_active(self, queryset, name, value): + if value: + return queryset.filter(Q(redeemed__lt=F('max_usages')) & + (Q(valid_until__isnull=True) | Q(valid_until__gt=now()))) + else: + return queryset.filter(Q(redeemed__gte=F('max_usages')) | + (Q(valid_until__isnull=False) & Q(valid_until__lte=now()))) class VoucherViewSet(viewsets.ModelViewSet): diff --git a/src/pretix/api/views/waitinglist.py b/src/pretix/api/views/waitinglist.py index d8bb516293..d189b950b0 100644 --- a/src/pretix/api/views/waitinglist.py +++ b/src/pretix/api/views/waitinglist.py @@ -1,5 +1,6 @@ import django_filters from django_filters.rest_framework import DjangoFilterBackend, FilterSet +from django_scopes import scopes_disabled from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.exceptions import PermissionDenied, ValidationError @@ -10,16 +11,16 @@ from pretix.api.serializers.waitinglist import WaitingListSerializer from pretix.base.models import WaitingListEntry from pretix.base.models.waitinglist import WaitingListException +with scopes_disabled(): + class WaitingListFilter(FilterSet): + has_voucher = django_filters.rest_framework.BooleanFilter(method='has_voucher_qs') -class WaitingListFilter(FilterSet): - has_voucher = django_filters.rest_framework.BooleanFilter(method='has_voucher_qs') + def has_voucher_qs(self, queryset, name, value): + return queryset.filter(voucher__isnull=not value) - def has_voucher_qs(self, queryset, name, value): - return queryset.filter(voucher__isnull=not value) - - class Meta: - model = WaitingListEntry - fields = ['item', 'variation', 'email', 'locale', 'has_voucher', 'subevent'] + class Meta: + model = WaitingListEntry + fields = ['item', 'variation', 'email', 'locale', 'has_voucher', 'subevent'] class WaitingListViewSet(viewsets.ModelViewSet): diff --git a/src/pretix/api/webhooks.py b/src/pretix/api/webhooks.py index cf5d3bb186..b9ae9ca4e0 100644 --- a/src/pretix/api/webhooks.py +++ b/src/pretix/api/webhooks.py @@ -8,6 +8,7 @@ from celery.exceptions import MaxRetriesExceededError from django.db.models import Exists, OuterRef, Q from django.dispatch import receiver from django.utils.translation import ugettext_lazy as _ +from django_scopes import scope, scopes_disabled from requests import RequestException from pretix.api.models import WebHook, WebHookCall, WebHookEventListener @@ -203,51 +204,52 @@ def notify_webhooks(logentry_id: int): @app.task(base=ProfiledTask, bind=True, max_retries=9) def send_webhook(self, logentry_id: int, action_type: str, webhook_id: int): # 9 retries with 2**(2*x) timing is roughly 72 hours - logentry = LogEntry.all.get(id=logentry_id) - webhook = WebHook.objects.get(id=webhook_id) + with scopes_disabled(): + webhook = WebHook.objects.get(id=webhook_id) + with scope(organizer=webhook.organizer): + logentry = LogEntry.all.get(id=logentry_id) + types = get_all_webhook_events() + event_type = types.get(action_type) + if not event_type or not webhook.enabled: + return # Ignore, e.g. plugin not installed - types = get_all_webhook_events() - event_type = types.get(action_type) - if not event_type or not webhook.enabled: - return # Ignore, e.g. plugin not installed + payload = event_type.build_payload(logentry) + t = time.time() - payload = event_type.build_payload(logentry) - t = time.time() - - try: try: - resp = requests.post( - webhook.target_url, - json=payload, - allow_redirects=False - ) - WebHookCall.objects.create( - webhook=webhook, - action_type=logentry.action_type, - target_url=webhook.target_url, - is_retry=self.request.retries > 0, - execution_time=time.time() - t, - return_code=resp.status_code, - payload=json.dumps(payload), - response_body=resp.text[:1024 * 1024], - success=200 <= resp.status_code <= 299 - ) - if resp.status_code == 410: - webhook.enabled = False - webhook.save() - elif resp.status_code > 299: + try: + resp = requests.post( + webhook.target_url, + json=payload, + allow_redirects=False + ) + WebHookCall.objects.create( + webhook=webhook, + action_type=logentry.action_type, + target_url=webhook.target_url, + is_retry=self.request.retries > 0, + execution_time=time.time() - t, + return_code=resp.status_code, + payload=json.dumps(payload), + response_body=resp.text[:1024 * 1024], + success=200 <= resp.status_code <= 299 + ) + if resp.status_code == 410: + webhook.enabled = False + webhook.save() + elif resp.status_code > 299: + raise self.retry(countdown=2 ** (self.request.retries * 2)) + except RequestException as e: + WebHookCall.objects.create( + webhook=webhook, + action_type=logentry.action_type, + target_url=webhook.target_url, + is_retry=self.request.retries > 0, + execution_time=time.time() - t, + return_code=0, + payload=json.dumps(payload), + response_body=str(e)[:1024 * 1024] + ) raise self.retry(countdown=2 ** (self.request.retries * 2)) - except RequestException as e: - WebHookCall.objects.create( - webhook=webhook, - action_type=logentry.action_type, - target_url=webhook.target_url, - is_retry=self.request.retries > 0, - execution_time=time.time() - t, - return_code=0, - payload=json.dumps(payload), - response_body=str(e)[:1024 * 1024] - ) - raise self.retry(countdown=2 ** (self.request.retries * 2)) - except MaxRetriesExceededError: - pass + except MaxRetriesExceededError: + pass diff --git a/src/pretix/base/models/auth.py b/src/pretix/base/models/auth.py index 414f895d6b..2cd4d0f087 100644 --- a/src/pretix/base/models/auth.py +++ b/src/pretix/base/models/auth.py @@ -12,6 +12,7 @@ from django.utils.crypto import get_random_string from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from django_otp.models import Device +from django_scopes import scopes_disabled from pretix.base.i18n import language from pretix.helpers.urls import build_absolute_uri @@ -283,6 +284,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin): return True return False + @scopes_disabled() def get_events_with_any_permission(self, request=None): """ Returns a queryset of events the user has any permissions to. @@ -300,6 +302,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin): | Q(id__in=self.teams.values_list('limit_events__id', flat=True)) ) + @scopes_disabled() def get_events_with_permission(self, permission, request=None): """ Returns a queryset of events the user has a specific permissions to. diff --git a/src/pretix/base/models/checkin.py b/src/pretix/base/models/checkin.py index 308576aeb9..2d46f5e1f1 100644 --- a/src/pretix/base/models/checkin.py +++ b/src/pretix/base/models/checkin.py @@ -3,6 +3,7 @@ from django.db.models import Case, Count, F, OuterRef, Q, Subquery, When from django.db.models.functions import Coalesce from django.utils.timezone import now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django_scopes import ScopedManager from pretix.base.models import LoggedModel @@ -20,6 +21,8 @@ class CheckinList(LoggedModel): 'order have not been paid. This only works with pretixdesk ' '0.3.0 or newer or pretixdroid 1.9 or newer.')) + objects = ScopedManager(organizer='event__organizer') + class Meta: ordering = ('subevent__date_from', 'name') @@ -167,6 +170,8 @@ class Checkin(models.Model): 'pretixbase.CheckinList', related_name='checkins', on_delete=models.PROTECT, ) + objects = ScopedManager(organizer='position__order__event__organizer') + class Meta: unique_together = (('list', 'position'),) diff --git a/src/pretix/base/models/devices.py b/src/pretix/base/models/devices.py index 69f9ae3438..bba27a0458 100644 --- a/src/pretix/base/models/devices.py +++ b/src/pretix/base/models/devices.py @@ -4,6 +4,7 @@ from django.db import models from django.db.models import Max from django.utils.crypto import get_random_string from django.utils.translation import ugettext_lazy as _ +from django_scopes import ScopedManager from pretix.base.models import LoggedModel @@ -71,6 +72,8 @@ class Device(LoggedModel): null=True, blank=True ) + objects = ScopedManager(organizer='organizer') + class Meta: unique_together = (('organizer', 'device_id'),) diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py index 3803f1ead0..7697d7ca37 100644 --- a/src/pretix/base/models/event.py +++ b/src/pretix/base/models/event.py @@ -17,6 +17,7 @@ from django.utils.crypto import get_random_string from django.utils.functional import cached_property from django.utils.timezone import make_aware, now from django.utils.translation import ugettext_lazy as _ +from django_scopes import ScopedManager from i18nfield.fields import I18nCharField, I18nTextField from pretix.base.models.base import LoggedModel @@ -336,6 +337,8 @@ class Event(EventMixin, LoggedModel): default=False ) + objects = ScopedManager(organizer='organizer') + class Meta: verbose_name = _("Event") verbose_name_plural = _("Events") @@ -875,6 +878,8 @@ class SubEvent(EventMixin, LoggedModel): items = models.ManyToManyField('Item', through='SubEventItem') variations = models.ManyToManyField('ItemVariation', through='SubEventItemVariation') + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Date in event series") verbose_name_plural = _("Dates in event series") diff --git a/src/pretix/base/models/invoices.py b/src/pretix/base/models/invoices.py index 81e93fb8d8..7312542b08 100644 --- a/src/pretix/base/models/invoices.py +++ b/src/pretix/base/models/invoices.py @@ -9,6 +9,7 @@ from django.utils.crypto import get_random_string from django.utils.functional import cached_property from django.utils.translation import pgettext from django_countries.fields import CountryField +from django_scopes import ScopedManager def invoice_filename(instance, filename: str) -> str: @@ -107,6 +108,8 @@ class Invoice(models.Model): file = models.FileField(null=True, blank=True, upload_to=invoice_filename, max_length=255) internal_reference = models.TextField(blank=True) + objects = ScopedManager(organizer='event__organizer') + @staticmethod def _to_numeric_invoice_number(number): return '{:05d}'.format(int(number)) diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py index cea6e05760..7c51005eb3 100644 --- a/src/pretix/base/models/items.py +++ b/src/pretix/base/models/items.py @@ -17,6 +17,7 @@ from django.utils.functional import cached_property from django.utils.timezone import is_naive, make_aware, now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django_countries.fields import Country +from django_scopes import ScopedManager from i18nfield.fields import I18nCharField, I18nTextField from pretix.base.models import fields @@ -155,28 +156,41 @@ class SubEventItemVariation(models.Model): self.subevent.event.cache.clear() +def filter_available(qs, channel='web', voucher=None, allow_addons=False): + q = ( + # IMPORTANT: If this is updated, also update the ItemVariation query + # in models/event.py: EventMixin.annotated() + Q(active=True) + & Q(Q(available_from__isnull=True) | Q(available_from__lte=now())) + & Q(Q(available_until__isnull=True) | Q(available_until__gte=now())) + & Q(sales_channels__contains=channel) & Q(require_bundling=False) + ) + if not allow_addons: + q &= Q(Q(category__isnull=True) | Q(category__is_addon=False)) + qs = qs.filter(q) + + vouchq = Q(hide_without_voucher=False) + if voucher: + if voucher.item_id: + vouchq |= Q(pk=voucher.item_id) + qs = qs.filter(pk=voucher.item_id) + elif voucher.quota_id: + qs = qs.filter(quotas__in=[voucher.quota_id]) + return qs.filter(vouchq) + + class ItemQuerySet(models.QuerySet): def filter_available(self, channel='web', voucher=None, allow_addons=False): - q = ( - # IMPORTANT: If this is updated, also update the ItemVariation query - # in models/event.py: EventMixin.annotated() - Q(active=True) - & Q(Q(available_from__isnull=True) | Q(available_from__lte=now())) - & Q(Q(available_until__isnull=True) | Q(available_until__gte=now())) - & Q(sales_channels__contains=channel) & Q(require_bundling=False) - ) - if not allow_addons: - q &= Q(Q(category__isnull=True) | Q(category__is_addon=False)) - qs = self.filter(q) + return filter_available(self, channel, voucher, allow_addons) - vouchq = Q(hide_without_voucher=False) - if voucher: - if voucher.item_id: - vouchq |= Q(pk=voucher.item_id) - qs = qs.filter(pk=voucher.item_id) - elif voucher.quota_id: - qs = qs.filter(quotas__in=[voucher.quota_id]) - return qs.filter(vouchq) + +class ItemQuerySetManager(ScopedManager(organizer='event__organizer').__class__): + def __init__(self): + super().__init__() + self._queryset_class = ItemQuerySet + + def filter_available(self, channel='web', voucher=None, allow_addons=False): + return filter_available(self.get_queryset(), channel, voucher, allow_addons) class Item(LoggedModel): @@ -226,7 +240,7 @@ class Item(LoggedModel): :type sales_channels: bool """ - objects = ItemQuerySet.as_manager() + objects = ItemQuerySetManager() event = models.ForeignKey( Event, @@ -591,6 +605,8 @@ class ItemVariation(models.Model): 'discounted one. This is just a cosmetic setting and will not actually impact pricing.') ) + objects = ScopedManager(organizer='item__event__organizer') + class Meta: verbose_name = _("Product variation") verbose_name_plural = _("Product variations") @@ -985,6 +1001,8 @@ class Question(LoggedModel): ) dependency_value = models.TextField(null=True, blank=True) + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Question") verbose_name_plural = _("Questions") @@ -1234,6 +1252,8 @@ class Quota(LoggedModel): cached_availability_paid_orders = models.PositiveIntegerField(null=True, blank=True) cached_availability_time = models.DateTimeField(null=True, blank=True) + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Quota") verbose_name_plural = _("Quotas") diff --git a/src/pretix/base/models/orders.py b/src/pretix/base/models/orders.py index 280d06bfb0..e8d507b886 100644 --- a/src/pretix/base/models/orders.py +++ b/src/pretix/base/models/orders.py @@ -26,6 +26,7 @@ from django.utils.functional import cached_property from django.utils.timezone import make_aware, now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ from django_countries.fields import Country, CountryField +from django_scopes import ScopedManager, scopes_disabled from i18nfield.strings import LazyI18nString from jsonfallback.fields import FallbackJSONField @@ -186,6 +187,8 @@ class Order(LockModel, LoggedModel): verbose_name=_('E-mail address verified') ) + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Order") verbose_name_plural = _("Orders") @@ -231,6 +234,7 @@ class Order(LockModel, LoggedModel): return self.all_fees(manager='objects') @cached_property + @scopes_disabled() def count_positions(self): if hasattr(self, 'pcnt'): return self.pcnt or 0 @@ -254,6 +258,7 @@ class Order(LockModel, LoggedModel): return None @property + @scopes_disabled() def payment_refund_sum(self): payment_sum = self.payments.filter( state__in=(OrderPayment.PAYMENT_STATE_CONFIRMED, OrderPayment.PAYMENT_STATE_REFUNDED) @@ -265,6 +270,7 @@ class Order(LockModel, LoggedModel): return payment_sum - refund_sum @property + @scopes_disabled() def pending_sum(self): total = self.total if self.status == Order.STATUS_CANCELED: @@ -439,6 +445,7 @@ class Order(LockModel, LoggedModel): return round_decimal(fee, self.event.currency) @property + @scopes_disabled() def user_cancel_allowed(self) -> bool: """ Returns whether or not this order can be canceled by the user. @@ -822,6 +829,8 @@ class QuestionAnswer(models.Model): max_length=255 ) + objects = ScopedManager(organizer='question__event__organizer') + @property def backend_file_url(self): if self.file: @@ -1145,6 +1154,8 @@ class OrderPayment(models.Model): ) migrated = models.BooleanField(default=False) + objects = ScopedManager(organizer='order__event__organizer') + class Meta: ordering = ('local_id',) @@ -1501,6 +1512,8 @@ class OrderRefund(models.Model): null=True, blank=True ) + objects = ScopedManager(organizer='order__event__organizer') + class Meta: ordering = ('local_id',) @@ -1562,7 +1575,7 @@ class OrderRefund(models.Model): super().save(*args, **kwargs) -class ActivePositionManager(models.Manager): +class ActivePositionManager(ScopedManager(organizer='order__event__organizer').__class__): def get_queryset(self): return super().get_queryset().filter(canceled=False) @@ -1639,7 +1652,7 @@ class OrderFee(models.Model): ) canceled = models.BooleanField(default=False) - all = models.Manager() + all = ScopedManager(organizer='order__event__organizer') objects = ActivePositionManager() @property @@ -1744,7 +1757,7 @@ class OrderPosition(AbstractPosition): ) canceled = models.BooleanField(default=False) - all = models.Manager() + all = ScopedManager(organizer='order__event__organizer') objects = ActivePositionManager() class Meta: @@ -1951,6 +1964,8 @@ class CartPosition(AbstractPosition): ) is_bundled = models.BooleanField(default=False) + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Cart position") verbose_name_plural = _("Cart positions") @@ -2000,6 +2015,8 @@ class InvoiceAddress(models.Model): blank=True ) + objects = ScopedManager(organizer='order__event__organizer') + def save(self, **kwargs): if self.order: self.order.touch() diff --git a/src/pretix/base/models/vouchers.py b/src/pretix/base/models/vouchers.py index 053937d1e5..3f79ad0fc4 100644 --- a/src/pretix/base/models/vouchers.py +++ b/src/pretix/base/models/vouchers.py @@ -8,6 +8,7 @@ from django.db.models import Q from django.utils.crypto import get_random_string from django.utils.timezone import now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django_scopes import ScopedManager from ..decimal import round_decimal from .base import LoggedModel @@ -173,6 +174,8 @@ class Voucher(LoggedModel): "convenience.") ) + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Voucher") verbose_name_plural = _("Vouchers") diff --git a/src/pretix/base/models/waitinglist.py b/src/pretix/base/models/waitinglist.py index bf283e55b2..a68ada92e2 100644 --- a/src/pretix/base/models/waitinglist.py +++ b/src/pretix/base/models/waitinglist.py @@ -4,6 +4,7 @@ from django.core.exceptions import ValidationError from django.db import models, transaction from django.utils.timezone import now from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django_scopes import ScopedManager from pretix.base.i18n import language from pretix.base.models import Voucher @@ -67,6 +68,8 @@ class WaitingListEntry(LoggedModel): ) priority = models.IntegerField(default=0) + objects = ScopedManager(organizer='event__organizer') + class Meta: verbose_name = _("Waiting list entry") verbose_name_plural = _("Waiting list entries") diff --git a/src/pretix/base/services/cart.py b/src/pretix/base/services/cart.py index ae003fdd9b..378beacace 100644 --- a/src/pretix/base/services/cart.py +++ b/src/pretix/base/services/cart.py @@ -10,6 +10,7 @@ from django.db.models import Q from django.dispatch import receiver from django.utils.timezone import make_aware, now from django.utils.translation import pgettext_lazy, ugettext as _ +from django_scopes import scopes_disabled from pretix.base.i18n import language from pretix.base.models import ( @@ -23,7 +24,7 @@ from pretix.base.reldate import RelativeDateWrapper from pretix.base.services.checkin import _save_answers from pretix.base.services.locking import LockTimeoutException, NoLockManager from pretix.base.services.pricing import get_price -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import ProfiledEventTask from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.templatetags.rich_text import rich_text from pretix.celery_app import app @@ -902,7 +903,7 @@ def get_fees(event, request, total, invoice_address, provider): return fees -@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) +@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, locale='en', invoice_address: int=None, widget_data=None, sales_channel='web') -> None: """ @@ -913,12 +914,11 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, lo :raises CartError: On any error that occured """ with language(locale): - event = Event.objects.get(id=event) - ia = False if invoice_address: try: - ia = InvoiceAddress.objects.get(pk=invoice_address) + with scopes_disabled(): + ia = InvoiceAddress.objects.get(pk=invoice_address) except InvoiceAddress.DoesNotExist: pass @@ -934,8 +934,8 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, lo raise CartError(error_messages['busy']) -@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) -def remove_cart_position(self, event: int, position: int, cart_id: str=None, locale='en') -> None: +@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) +def remove_cart_position(self, event: Event, position: int, cart_id: str=None, locale='en') -> None: """ Removes a list of items from a user's cart. :param event: The event ID in question @@ -943,7 +943,6 @@ def remove_cart_position(self, event: int, position: int, cart_id: str=None, loc :param session: Session ID of a guest """ with language(locale): - event = Event.objects.get(id=event) try: try: cm = CartManager(event=event, cart_id=cart_id) @@ -955,15 +954,14 @@ def remove_cart_position(self, event: int, position: int, cart_id: str=None, loc raise CartError(error_messages['busy']) -@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) -def clear_cart(self, event: int, cart_id: str=None, locale='en') -> None: +@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) +def clear_cart(self, event: Event, cart_id: str=None, locale='en') -> None: """ Removes a list of items from a user's cart. :param event: The event ID in question :param session: Session ID of a guest """ with language(locale): - event = Event.objects.get(id=event) try: try: cm = CartManager(event=event, cart_id=cart_id) @@ -975,8 +973,8 @@ def clear_cart(self, event: int, cart_id: str=None, locale='en') -> None: raise CartError(error_messages['busy']) -@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) -def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, locale='en', +@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,)) +def set_cart_addons(self, event: Event, addons: List[dict], cart_id: str=None, locale='en', invoice_address: int=None, sales_channel='web') -> None: """ Removes a list of items from a user's cart. @@ -985,12 +983,11 @@ def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, loc :param session: Session ID of a guest """ with language(locale): - event = Event.objects.get(id=event) - ia = False if invoice_address: try: - ia = InvoiceAddress.objects.get(pk=invoice_address) + with scopes_disabled(): + ia = InvoiceAddress.objects.get(pk=invoice_address) except InvoiceAddress.DoesNotExist: pass try: diff --git a/src/pretix/base/services/cleanup.py b/src/pretix/base/services/cleanup.py index 3a3ba4b0d9..330689ad29 100644 --- a/src/pretix/base/services/cleanup.py +++ b/src/pretix/base/services/cleanup.py @@ -2,6 +2,7 @@ from datetime import timedelta from django.dispatch import receiver from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.models import CachedCombinedTicket, CachedTicket @@ -10,6 +11,7 @@ from ..signals import periodic_task @receiver(signal=periodic_task) +@scopes_disabled() def clean_cart_positions(sender, **kwargs): for cp in CartPosition.objects.filter(expires__lt=now() - timedelta(days=14), addon_to__isnull=False): cp.delete() @@ -20,12 +22,14 @@ def clean_cart_positions(sender, **kwargs): @receiver(signal=periodic_task) +@scopes_disabled() def clean_cached_files(sender, **kwargs): for cf in CachedFile.objects.filter(expires__isnull=False, expires__lt=now()): cf.delete() @receiver(signal=periodic_task) +@scopes_disabled() def clean_cached_tickets(sender, **kwargs): for cf in CachedTicket.objects.filter(created__lte=now() - timedelta(days=30)): cf.delete() diff --git a/src/pretix/base/services/export.py b/src/pretix/base/services/export.py index 60ee1015eb..b547d62f30 100644 --- a/src/pretix/base/services/export.py +++ b/src/pretix/base/services/export.py @@ -6,7 +6,7 @@ from django.utils.translation import ugettext from pretix.base.i18n import LazyLocaleException, language from pretix.base.models import CachedFile, Event, cachedfile_name -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import ProfiledEventTask from pretix.base.signals import register_data_exporters from pretix.celery_app import app @@ -15,9 +15,8 @@ class ExportError(LazyLocaleException): pass -@app.task(base=ProfiledTask, throws=(ExportError,)) -def export(event: str, fileid: str, provider: str, form_data: Dict[str, Any]) -> None: - event = Event.objects.get(id=event) +@app.task(base=ProfiledEventTask, throws=(ExportError,)) +def export(event: Event, fileid: str, provider: str, form_data: Dict[str, Any]) -> None: file = CachedFile.objects.get(id=fileid) with language(event.settings.locale), override(event.settings.timezone): responses = register_data_exporters.send(event) diff --git a/src/pretix/base/services/invoices.py b/src/pretix/base/services/invoices.py index 803bba2120..979148de52 100644 --- a/src/pretix/base/services/invoices.py +++ b/src/pretix/base/services/invoices.py @@ -15,6 +15,7 @@ from django.utils import timezone from django.utils.timezone import now from django.utils.translation import pgettext, ugettext as _ from django_countries.fields import Country +from django_scopes import scope, scopes_disabled from i18nfield.strings import LazyI18nString from pretix.base.i18n import language @@ -244,16 +245,18 @@ def generate_invoice(order: Order, trigger_pdf=True): @app.task(base=TransactionAwareTask) def invoice_pdf_task(invoice: int): - i = Invoice.objects.get(pk=invoice) - if i.shredded: - return None - if i.file: - i.file.delete() - with language(i.locale): - fname, ftype, fcontent = i.event.invoice_renderer.generate(i) - i.file.save(fname, ContentFile(fcontent)) - i.save() - return i.file.name + with scopes_disabled(): + i = Invoice.objects.get(pk=invoice) + with scope(organizer=i.order.event.organizer): + if i.shredded: + return None + if i.file: + i.file.delete() + with language(i.locale): + fname, ftype, fcontent = i.event.invoice_renderer.generate(i) + i.file.save(fname, ContentFile(fcontent)) + i.save() + return i.file.name def invoice_qualified(order: Order): diff --git a/src/pretix/base/services/mail.py b/src/pretix/base/services/mail.py index 7e979842fb..d21758e8cb 100644 --- a/src/pretix/base/services/mail.py +++ b/src/pretix/base/services/mail.py @@ -10,6 +10,7 @@ from django.conf import settings from django.core.mail import EmailMultiAlternatives, get_connection from django.template.loader import get_template from django.utils.translation import ugettext as _ +from django_scopes import scope, scopes_disabled from i18nfield.strings import LazyI18nString from pretix.base.email import ClassicMailRenderer @@ -234,83 +235,87 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st pass if event: - event = Event.objects.get(id=event) + with scopes_disabled(): + event = Event.objects.get(id=event) backend = event.get_mail_backend() + cm = lambda: scope(organizer=event.organizer) # noqa else: backend = get_connection(fail_silently=False) + cm = lambda: scopes_disabled() # noqa - if event: - if order: - try: - order = event.orders.get(pk=order) - except Order.DoesNotExist: - order = None - else: - if position: - try: - position = order.positions.get(pk=position) - except OrderPosition.DoesNotExist: - attach_tickets = False - if attach_tickets: - args = [] - attach_size = 0 - for name, ct in get_tickets_for_order(order, base_position=position): - content = ct.file.read() - args.append((name, content, ct.type)) - attach_size += len(content) + with cm(): + if event: + if order: + try: + order = event.orders.get(pk=order) + except Order.DoesNotExist: + order = None + else: + if position: + try: + position = order.positions.get(pk=position) + except OrderPosition.DoesNotExist: + attach_tickets = False + if attach_tickets: + args = [] + attach_size = 0 + for name, ct in get_tickets_for_order(order, base_position=position): + content = ct.file.read() + args.append((name, content, ct.type)) + attach_size += len(content) - if attach_size < 4 * 1024 * 1024: - # Do not attach more than 4MB, it will bounce way to often. - for a in args: - try: - email.attach(*a) - except: - pass - else: - order.log_action( - 'pretix.event.order.email.attachments.skipped', - data={ - 'subject': 'Attachments skipped', - 'message': 'Attachment have not been send because {} bytes are likely too large to arrive.'.format(attach_size), - 'recipient': '', - 'invoices': [], - } - ) + if attach_size < 4 * 1024 * 1024: + # Do not attach more than 4MB, it will bounce way to often. + for a in args: + try: + email.attach(*a) + except: + pass + else: + order.log_action( + 'pretix.event.order.email.attachments.skipped', + data={ + 'subject': 'Attachments skipped', + 'message': 'Attachment have not been send because {} bytes are likely too large to arrive.'.format(attach_size), + 'recipient': '', + 'invoices': [], + } + ) - email = email_filter.send_chained(event, 'message', message=email, order=order) + email = email_filter.send_chained(event, 'message', message=email, order=order) - try: - backend.send_messages([email]) - except smtplib.SMTPResponseException as e: - if e.smtp_code in (101, 111, 421, 422, 431, 442, 447, 452): - self.retry(max_retries=5, countdown=2 ** (self.request.retries * 2)) - logger.exception('Error sending email') + try: + backend.send_messages([email]) + except smtplib.SMTPResponseException as e: + if e.smtp_code in (101, 111, 421, 422, 431, 442, 447, 452): + self.retry(max_retries=5, countdown=2 ** (self.request.retries * 2)) + logger.exception('Error sending email') - if order: - order.log_action( - 'pretix.event.order.email.error', - data={ - 'subject': 'SMTP code {}'.format(e.smtp_code), - 'message': e.smtp_error.decode() if isinstance(e.smtp_error, bytes) else str(e.smtp_error), - 'recipient': '', - 'invoices': [], - } - ) + if order: + order.log_action( + 'pretix.event.order.email.error', + data={ + 'subject': 'SMTP code {}'.format(e.smtp_code), + 'message': e.smtp_error.decode() if isinstance(e.smtp_error, bytes) else str(e.smtp_error), + 'recipient': '', + 'invoices': [], + } + ) - raise SendMailException('Failed to send an email to {}.'.format(to)) - except Exception as e: - if order: - order.log_action( - 'pretix.event.order.email.error', - data={ - 'subject': 'Internal error', - 'message': str(e), - 'recipient': '', - 'invoices': [], - } - ) - logger.exception('Error sending email') - raise SendMailException('Failed to send an email to {}.'.format(to)) + raise SendMailException('Failed to send an email to {}.'.format(to)) + except Exception as e: + if order: + order.log_action( + 'pretix.event.order.email.error', + data={ + 'subject': 'Internal error', + 'message': str(e), + 'recipient': '', + 'invoices': [], + } + ) + logger.exception('Error sending email') + raise SendMailException('Failed to send an email to {}.'.format(to)) def mail_send(*args, **kwargs): diff --git a/src/pretix/base/services/notifications.py b/src/pretix/base/services/notifications.py index 9c5460b755..35327ead06 100644 --- a/src/pretix/base/services/notifications.py +++ b/src/pretix/base/services/notifications.py @@ -1,5 +1,6 @@ from django.conf import settings from django.template.loader import get_template +from django_scopes import scope, scopes_disabled from inlinestyler.utils import inline_css from pretix.base.i18n import language @@ -12,6 +13,7 @@ from pretix.helpers.urls import build_absolute_uri @app.task(base=TransactionAwareTask) +@scopes_disabled() def notify(logentry_id: int): logentry = LogEntry.all.get(id=logentry_id) if not logentry.event: @@ -66,17 +68,22 @@ def notify(logentry_id: int): @app.task(base=ProfiledTask) def send_notification(logentry_id: int, action_type: str, user_id: int, method: str): logentry = LogEntry.all.get(id=logentry_id) - user = User.objects.get(id=user_id) - types = get_all_notification_types(logentry.event) - notification_type = types.get(action_type) - if not notification_type: - return # Ignore, e.g. plugin not active for this event + if logentry.event: + sm = lambda: scope(organizer=logentry.event.organizer) # noqa + else: + sm = lambda: scopes_disabled() # noqa + with sm(): + user = User.objects.get(id=user_id) + types = get_all_notification_types(logentry.event) + notification_type = types.get(action_type) + if not notification_type: + return # Ignore, e.g. plugin not active for this event - with language(user.locale): - notification = notification_type.build_notification(logentry) + with language(user.locale): + notification = notification_type.build_notification(logentry) - if method == "mail": - send_notification_mail(notification, user) + if method == "mail": + send_notification_mail(notification, user) def send_notification_mail(notification: Notification, user: User): diff --git a/src/pretix/base/services/orders.py b/src/pretix/base/services/orders.py index 811d2773a2..b2997d5f88 100644 --- a/src/pretix/base/services/orders.py +++ b/src/pretix/base/services/orders.py @@ -16,6 +16,7 @@ from django.utils.formats import date_format from django.utils.functional import cached_property from django.utils.timezone import make_aware, now from django.utils.translation import ugettext as _ +from django_scopes import scopes_disabled from pretix.api.models import OAuthApplication from pretix.base.i18n import ( @@ -42,7 +43,7 @@ from pretix.base.services.invoices import ( from pretix.base.services.locking import LockTimeoutException, NoLockManager from pretix.base.services.mail import SendMailException from pretix.base.services.pricing import get_price -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import ProfiledEventTask, ProfiledTask from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.signals import ( allow_ticket_download, order_approved, order_canceled, order_changed, @@ -715,10 +716,8 @@ def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosi logger.exception('Order received email could not be sent to attendee') -def _perform_order(event: str, payment_provider: str, position_ids: List[str], +def _perform_order(event: Event, payment_provider: str, position_ids: List[str], email: str, locale: str, address: int, meta_info: dict=None, sales_channel: str='web'): - - event = Event.objects.get(id=event) if payment_provider: pprov = event.get_payment_providers().get(payment_provider) if not pprov: @@ -732,7 +731,8 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str], addr = None if address is not None: try: - addr = InvoiceAddress.objects.get(pk=address) + with scopes_disabled(): + addr = InvoiceAddress.objects.get(pk=address) except InvoiceAddress.DoesNotExist: pass @@ -804,6 +804,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str], @receiver(signal=periodic_task) +@scopes_disabled() def expire_orders(sender, **kwargs): eventcache = {} @@ -818,6 +819,7 @@ def expire_orders(sender, **kwargs): @receiver(signal=periodic_task) +@scopes_disabled() def send_expiry_warnings(sender, **kwargs): eventcache = {} today = now().replace(hour=0, minute=0, second=0) @@ -875,6 +877,7 @@ def send_expiry_warnings(sender, **kwargs): @receiver(signal=periodic_task) +@scopes_disabled() def send_download_reminders(sender, **kwargs): today = now().replace(hour=0, minute=0, second=0, microsecond=0) @@ -1497,8 +1500,8 @@ class OrderChangeManager: return pprov -@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,)) -def perform_order(self, event: str, payment_provider: str, positions: List[str], +@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,)) +def perform_order(self, event: Event, payment_provider: str, positions: List[str], email: str=None, locale: str=None, address: int=None, meta_info: dict=None, sales_channel: str='web'): with language(locale): @@ -1513,6 +1516,7 @@ def perform_order(self, event: str, payment_provider: str, positions: List[str], @app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,)) +@scopes_disabled() def cancel_order(self, order: int, user: int=None, send_mail: bool=True, api_token=None, oauth_application=None, device=None, cancellation_fee=None, try_auto_refund=False): try: diff --git a/src/pretix/base/services/quotas.py b/src/pretix/base/services/quotas.py index 76dab041af..0a182f877b 100644 --- a/src/pretix/base/services/quotas.py +++ b/src/pretix/base/services/quotas.py @@ -4,6 +4,7 @@ from django.conf import settings from django.db.models import Max, Q from django.dispatch import receiver from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.models import Event, LogEntry from pretix.celery_app import app @@ -17,6 +18,7 @@ def build_all_quota_caches(sender, **kwargs): @app.task +@scopes_disabled() def refresh_quota_caches(): # Active events active = LogEntry.objects.using(settings.DATABASE_REPLICA).filter( diff --git a/src/pretix/base/services/shredder.py b/src/pretix/base/services/shredder.py index e857d19ba8..9956c5d221 100644 --- a/src/pretix/base/services/shredder.py +++ b/src/pretix/base/services/shredder.py @@ -11,14 +11,13 @@ from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from pretix.base.models import CachedFile, Event, cachedfile_name -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import ProfiledEventTask from pretix.base.shredder import ShredError from pretix.celery_app import app -@app.task(base=ProfiledTask) -def export(event: str, shredders: List[str]) -> None: - event = Event.objects.get(id=event) +@app.task(base=ProfiledEventTask) +def export(event: Event, shredders: List[str]) -> None: known_shredders = event.get_data_shredders() with NamedTemporaryFile() as rawfile: @@ -63,9 +62,8 @@ def export(event: str, shredders: List[str]) -> None: return cf.pk -@app.task(base=ProfiledTask, throws=(ShredError,)) -def shred(event: str, fileid: str, confirm_code: str) -> None: - event = Event.objects.get(id=event) +@app.task(base=ProfiledEventTask, throws=(ShredError,)) +def shred(event: Event, fileid: str, confirm_code: str) -> None: known_shredders = event.get_data_shredders() try: cf = CachedFile.objects.get(pk=fileid) diff --git a/src/pretix/base/services/tasks.py b/src/pretix/base/services/tasks.py index 145a88ae08..71a461eefc 100644 --- a/src/pretix/base/services/tasks.py +++ b/src/pretix/base/services/tasks.py @@ -14,10 +14,12 @@ import time from django.conf import settings from django.db import transaction +from django_scopes import scope, scopes_disabled from pretix.base.metrics import ( pretix_task_duration_seconds, pretix_task_runs_total, ) +from pretix.base.models import Event from pretix.celery_app import app @@ -61,6 +63,35 @@ class ProfiledTask(app.Task): return super().on_success(retval, task_id, args, kwargs) +class EventTask(app.Task): + def __call__(self, *args, **kwargs): + if 'event_id' in kwargs: + event_id = kwargs.get('event_id') + with scopes_disabled(): + event = Event.objects.select_related('organizer').get(pk=event_id) + del kwargs['event_id'] + kwargs['event'] = event + elif 'event' in kwargs: + event_id = kwargs.get('event') + with scopes_disabled(): + event = Event.objects.select_related('organizer').get(pk=event_id) + kwargs['event'] = event + else: + args = list(args) + event_id = args[0] + with scopes_disabled(): + event = Event.objects.select_related('organizer').get(pk=event_id) + args[0] = event + + with scope(organizer=event.organizer): + ret = super().__call__(*args, **kwargs) + return ret + + +class ProfiledEventTask(ProfiledTask, EventTask): + pass + + class TransactionAwareTask(ProfiledTask): """ Task class which is aware of django db transactions and only executes tasks diff --git a/src/pretix/base/services/tickets.py b/src/pretix/base/services/tickets.py index 2b006e89c3..bb327888dc 100644 --- a/src/pretix/base/services/tickets.py +++ b/src/pretix/base/services/tickets.py @@ -4,13 +4,14 @@ import os from django.core.files.base import ContentFile from django.utils.timezone import now from django.utils.translation import ugettext as _ +from django_scopes import scopes_disabled from pretix.base.i18n import language from pretix.base.models import ( CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order, OrderPosition, ) -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import EventTask, ProfiledTask from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.signals import allow_ticket_download, register_ticket_outputs from pretix.celery_app import app @@ -57,10 +58,11 @@ def generate_order(order: int, provider: str): @app.task(base=ProfiledTask) def generate(model: str, pk: int, provider: str): - if model == 'order': - return generate_order(pk, provider) - elif model == 'orderposition': - return generate_orderposition(pk, provider) + with scopes_disabled(): + if model == 'order': + return generate_order(pk, provider) + elif model == 'orderposition': + return generate_orderposition(pk, provider) class DummyRollbackException(Exception): @@ -165,9 +167,8 @@ def get_tickets_for_order(order, base_position=None): return tickets -@app.task(base=ProfiledTask) -def invalidate_cache(event: int, item: int=None, provider: str=None, order: int=None, **kwargs): - event = Event.objects.get(id=event) +@app.task(base=EventTask) +def invalidate_cache(event: Event, item: int=None, provider: str=None, order: int=None, **kwargs): qs = CachedTicket.objects.filter(order_position__order__event=event) qsc = CachedCombinedTicket.objects.filter(order__event=event) diff --git a/src/pretix/base/services/update_check.py b/src/pretix/base/services/update_check.py index a29df018e1..eba9726340 100644 --- a/src/pretix/base/services/update_check.py +++ b/src/pretix/base/services/update_check.py @@ -6,6 +6,7 @@ import requests from django.dispatch import receiver from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _, ugettext_noop +from django_scopes import scopes_disabled from i18nfield.strings import LazyI18nString from pretix import __version__ @@ -29,6 +30,7 @@ def run_update_check(sender, **kwargs): @app.task +@scopes_disabled() def update_check(): gs = GlobalSettingsObject() diff --git a/src/pretix/base/services/waitinglist.py b/src/pretix/base/services/waitinglist.py index 0241e34765..ec711e7d8e 100644 --- a/src/pretix/base/services/waitinglist.py +++ b/src/pretix/base/services/waitinglist.py @@ -1,17 +1,17 @@ import sys from django.dispatch import receiver +from django_scopes import scopes_disabled from pretix.base.models import Event, User, WaitingListEntry from pretix.base.models.waitinglist import WaitingListException -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import EventTask from pretix.base.signals import periodic_task from pretix.celery_app import app -@app.task(base=ProfiledTask) -def assign_automatically(event_id: int, user_id: int=None, subevent_id: int=None): - event = Event.objects.get(id=event_id) +@app.task(base=EventTask) +def assign_automatically(event: Event, user_id: int=None, subevent_id: int=None): if user_id: user = User.objects.get(id=user_id) else: @@ -69,6 +69,7 @@ def assign_automatically(event_id: int, user_id: int=None, subevent_id: int=None @receiver(signal=periodic_task) +@scopes_disabled() def process_waitinglist(sender, **kwargs): qs = Event.objects.filter( live=True diff --git a/src/pretix/base/views/metrics.py b/src/pretix/base/views/metrics.py index f94479b46f..fd238c46b0 100644 --- a/src/pretix/base/views/metrics.py +++ b/src/pretix/base/views/metrics.py @@ -3,6 +3,7 @@ import hmac from django.conf import settings from django.http import HttpResponse +from django_scopes import scopes_disabled from .. import metrics @@ -15,6 +16,7 @@ def unauthed_response(): return response +@scopes_disabled() def serve_metrics(request): if not settings.METRICS_ENABLED: return unauthed_response() diff --git a/src/pretix/control/context.py b/src/pretix/control/context.py index dfa0999a18..8be6703bec 100644 --- a/src/pretix/control/context.py +++ b/src/pretix/control/context.py @@ -5,6 +5,7 @@ from django.conf import settings from django.db.models import Q from django.urls import Resolver404, get_script_prefix, resolve from django.utils.translation import get_language +from django_scopes import scope from pretix.base.models.auth import StaffSession from pretix.base.settings import GlobalSettingsObject @@ -53,10 +54,11 @@ def contextprocessor(request): ctx['has_domain'] = request.event.organizer.domains.exists() if not request.event.testmode: - complain_testmode_orders = request.event.cache.get('complain_testmode_orders') - if complain_testmode_orders is None: - complain_testmode_orders = request.event.orders.filter(testmode=True).exists() - request.event.cache.set('complain_testmode_orders', complain_testmode_orders, 30) + with scope(organizer=request.organizer): + complain_testmode_orders = request.event.cache.get('complain_testmode_orders') + if complain_testmode_orders is None: + complain_testmode_orders = request.event.orders.filter(testmode=True).exists() + request.event.cache.set('complain_testmode_orders', complain_testmode_orders, 30) ctx['complain_testmode_orders'] = complain_testmode_orders else: ctx['complain_testmode_orders'] = False diff --git a/src/pretix/control/forms/checkin.py b/src/pretix/control/forms/checkin.py index e3e1106f0a..5740308639 100644 --- a/src/pretix/control/forms/checkin.py +++ b/src/pretix/control/forms/checkin.py @@ -1,6 +1,9 @@ from django import forms from django.urls import reverse from django.utils.translation import pgettext_lazy +from django_scopes.forms import ( + SafeModelChoiceField, SafeModelMultipleChoiceField, +) from pretix.base.models.checkin import CheckinList from pretix.control.forms.widgets import Select2 @@ -44,3 +47,7 @@ class CheckinListForm(forms.ModelForm): 'data-inverse-dependency': '<[name$=all_products]' }), } + field_classes = { + 'limit_products': SafeModelMultipleChoiceField, + 'subevent': SafeModelChoiceField, + } diff --git a/src/pretix/control/forms/item.py b/src/pretix/control/forms/item.py index 9cd705ab95..f01119a7b6 100644 --- a/src/pretix/control/forms/item.py +++ b/src/pretix/control/forms/item.py @@ -6,6 +6,9 @@ from django.urls import reverse from django.utils.translation import ( pgettext_lazy, ugettext as __, ugettext_lazy as _, ) +from django_scopes.forms import ( + SafeModelChoiceField, SafeModelMultipleChoiceField, +) from i18nfield.forms import I18nFormField, I18nTextarea from pretix.base.channels import get_all_sales_channels @@ -94,6 +97,10 @@ class QuestionForm(I18nModelForm): ), 'dependency_value': forms.Select, } + field_classes = { + 'items': SafeModelMultipleChoiceField, + 'dependency_question': SafeModelChoiceField, + } class QuestionOptionForm(I18nModelForm): @@ -159,6 +166,9 @@ class QuotaForm(I18nModelForm): 'size', 'subevent' ] + field_classes = { + 'subevent': SafeModelChoiceField, + } def save(self, *args, **kwargs): creating = not self.instance.pk diff --git a/src/pretix/control/forms/orders.py b/src/pretix/control/forms/orders.py index 190bf4ba22..f1af1e20ed 100644 --- a/src/pretix/control/forms/orders.py +++ b/src/pretix/control/forms/orders.py @@ -192,7 +192,7 @@ class OrderPositionAddForm(forms.Form): label=_('Product') ) addon_to = forms.ModelChoiceField( - OrderPosition.objects.none(), + OrderPosition.all.none(), required=False, label=_('Add-on to'), ) diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py index 37395978f0..118af4eefb 100644 --- a/src/pretix/control/forms/organizer.py +++ b/src/pretix/control/forms/organizer.py @@ -6,6 +6,7 @@ from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from django.utils.safestring import mark_safe from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django_scopes.forms import SafeModelMultipleChoiceField from i18nfield.forms import I18nFormField, I18nTextarea from pretix.api.models import WebHook @@ -149,6 +150,9 @@ class TeamForm(forms.ModelForm): 'data-inverse-dependency': '#id_all_events' }), } + field_classes = { + 'limit_events': SafeModelMultipleChoiceField + } def clean(self): data = super().clean() @@ -177,6 +181,9 @@ class DeviceForm(forms.ModelForm): 'data-inverse-dependency': '#id_all_events' }), } + field_classes = { + 'limit_events': SafeModelMultipleChoiceField + } class OrganizerSettingsForm(SettingsForm): @@ -307,3 +314,6 @@ class WebHookForm(forms.ModelForm): 'data-inverse-dependency': '#id_all_events' }), } + field_classes = { + 'limit_events': SafeModelMultipleChoiceField + } diff --git a/src/pretix/control/forms/vouchers.py b/src/pretix/control/forms/vouchers.py index d731675305..5288b855eb 100644 --- a/src/pretix/control/forms/vouchers.py +++ b/src/pretix/control/forms/vouchers.py @@ -3,6 +3,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models.functions import Lower from django.urls import reverse from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django_scopes.forms import SafeModelChoiceField from pretix.base.forms import I18nModelForm from pretix.base.models import Item, Voucher @@ -35,6 +36,7 @@ class VoucherForm(I18nModelForm): ] field_classes = { 'valid_until': SplitDateTimeField, + 'subevent': SafeModelChoiceField, } widgets = { 'valid_until': SplitDateTimePickerWidget(), @@ -199,6 +201,7 @@ class VoucherBulkForm(VoucherForm): ] field_classes = { 'valid_until': SplitDateTimeField, + 'subevent': SafeModelChoiceField, } widgets = { 'valid_until': SplitDateTimePickerWidget(), diff --git a/src/pretix/control/middleware.py b/src/pretix/control/middleware.py index 45d07d1a30..4eb26ed0bd 100644 --- a/src/pretix/control/middleware.py +++ b/src/pretix/control/middleware.py @@ -4,10 +4,11 @@ from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME, logout from django.http import Http404 from django.shortcuts import get_object_or_404, redirect, resolve_url +from django.template.response import TemplateResponse from django.urls import get_script_prefix, resolve, reverse -from django.utils.deprecation import MiddlewareMixin from django.utils.encoding import force_str from django.utils.translation import ugettext as _ +from django_scopes import scope from hijack.templatetags.hijack_tags import is_hijacked from pretix.base.models import Event, Organizer @@ -17,7 +18,7 @@ from pretix.helpers.security import ( ) -class PermissionMiddleware(MiddlewareMixin): +class PermissionMiddleware: """ This middleware enforces all requests to the control app to require login. Additionally, it enforces all requests to "control:event." URLs @@ -34,6 +35,10 @@ class PermissionMiddleware(MiddlewareMixin): "user.settings.notifications.off", ) + def __init__(self, get_response=None): + self.get_response = get_response + super().__init__() + def _login_redirect(self, request): # Taken from django/contrib/auth/decorators.py path = request.build_absolute_uri() @@ -52,19 +57,19 @@ class PermissionMiddleware(MiddlewareMixin): return redirect_to_login( path, resolved_login_url, REDIRECT_FIELD_NAME) - def process_request(self, request): + def __call__(self, request): url = resolve(request.path_info) url_name = url.url_name if not request.path.startswith(get_script_prefix() + 'control'): # This middleware should only touch the /control subpath - return + return self.get_response(request) if hasattr(request, 'organizer'): # If the user is on a organizer's subdomain, he should be redirected to pretix return redirect(urljoin(settings.SITE_URL, request.get_full_path())) if url_name in self.EXCEPTIONS: - return + return self.get_response(request) if not request.user.is_authenticated: return self._login_redirect(request) @@ -79,10 +84,11 @@ class PermissionMiddleware(MiddlewareMixin): return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path())) if 'event' in url.kwargs and 'organizer' in url.kwargs: - request.event = Event.objects.filter( - slug=url.kwargs['event'], - organizer__slug=url.kwargs['organizer'], - ).select_related('organizer').first() + with scope(organizer=None): + request.event = Event.objects.filter( + slug=url.kwargs['event'], + organizer__slug=url.kwargs['organizer'], + ).select_related('organizer').first() if not request.event or not request.user.has_event_permission(request.event.organizer, request.event, request=request): raise Http404(_("The selected event was not found or you " @@ -104,6 +110,12 @@ class PermissionMiddleware(MiddlewareMixin): else: request.orgapermset = request.user.get_organizer_permission_set(request.organizer) + with scope(organizer=getattr(request, 'organizer', None)): + r = self.get_response(request) + if isinstance(r, TemplateResponse): + r = r.render() + return r + class AuditLogMiddleware: diff --git a/src/pretix/plugins/badges/tasks.py b/src/pretix/plugins/badges/tasks.py index a1cd1a0174..15085ca1c7 100644 --- a/src/pretix/plugins/badges/tasks.py +++ b/src/pretix/plugins/badges/tasks.py @@ -7,6 +7,7 @@ from pretix.base.models import ( CachedFile, Event, OrderPosition, cachedfile_name, ) from pretix.base.services.orders import OrderError +from pretix.base.services.tasks import EventTask from pretix.celery_app import app from .exporters import render_pdf @@ -14,8 +15,8 @@ from .exporters import render_pdf logger = logging.getLogger(__name__) -@app.task(throws=(OrderError,)) -def badges_create_pdf(fileid: int, event: int, positions: List[int]) -> int: +@app.task(base=EventTask, throws=(OrderError,)) +def badges_create_pdf(event: int, fileid: int, positions: List[int]) -> int: file = CachedFile.objects.get(id=fileid) event = Event.objects.get(id=event) diff --git a/src/pretix/plugins/badges/views.py b/src/pretix/plugins/badges/views.py index a1911a89fb..bb79670fc4 100644 --- a/src/pretix/plugins/badges/views.py +++ b/src/pretix/plugins/badges/views.py @@ -223,7 +223,7 @@ class OrderPrintDo(EventPermissionRequiredMixin, AsyncAction, View): else: positions = [p.pk for p in order.positions.all()] return self.do( - str(cf.id), self.request.event.pk, + str(cf.id), positions, ) diff --git a/src/pretix/plugins/banktransfer/tasks.py b/src/pretix/plugins/banktransfer/tasks.py index 8d19e6fa1e..356fcbff81 100644 --- a/src/pretix/plugins/banktransfer/tasks.py +++ b/src/pretix/plugins/banktransfer/tasks.py @@ -9,6 +9,7 @@ from django.db import transaction from django.db.models import Q from django.utils.formats import date_format from django.utils.translation import ugettext, ugettext_noop +from django_scopes import scope, scopes_disabled from pretix.base.i18n import language from pretix.base.models import ( @@ -194,51 +195,53 @@ def _get_unknown_transactions(job: BankImportJob, data: list, event: Event=None, @app.task(base=TransactionAwareTask, bind=True, max_retries=5, default_retry_delay=1) def process_banktransfers(self, job: int, data: list) -> None: with language("en"): # We'll translate error messages at display time - job = BankImportJob.objects.get(pk=job) - job.state = BankImportJob.STATE_RUNNING - job.save() - prefixes = [] + with scopes_disabled(): + job = BankImportJob.objects.get(pk=job) + with scope(organizer=job.organizer or job.event.organizer): + job.state = BankImportJob.STATE_RUNNING + job.save() + prefixes = [] - try: - # Delete left-over transactions from a failed run before so they can reimported - BankTransaction.objects.filter(state=BankTransaction.STATE_UNCHECKED, **job.owner_kwargs).delete() - - transactions = _get_unknown_transactions(job, data, **job.owner_kwargs) - - code_len = settings.ENTROPY['order_code'] - if job.event: - pattern = re.compile(job.event.slug.upper() + r"[ \-_]*([A-Z0-9]{%s})" % code_len) - else: - if not prefixes: - prefixes = [e.slug.upper().replace(".", r"\.").replace("-", r"[\- ]*") - for e in job.organizer.events.all()] - pattern = re.compile("(%s)[ \\-_]*([A-Z0-9]{%s})" % ("|".join(prefixes), code_len)) - - for trans in transactions: - match = pattern.search(trans.reference.replace(" ", "").replace("\n", "").upper()) - - if match: - if job.event: - code = match.group(1) - _handle_transaction(trans, code, event=job.event) - else: - slug = match.group(1) - code = match.group(2) - _handle_transaction(trans, code, organizer=job.organizer, slug=slug) - else: - trans.state = BankTransaction.STATE_NOMATCH - trans.save() - except LockTimeoutException: try: - self.retry() - except MaxRetriesExceededError: - logger.exception('Maximum number of retries exceeded for task.') + # Delete left-over transactions from a failed run before so they can reimported + BankTransaction.objects.filter(state=BankTransaction.STATE_UNCHECKED, **job.owner_kwargs).delete() + + transactions = _get_unknown_transactions(job, data, **job.owner_kwargs) + + code_len = settings.ENTROPY['order_code'] + if job.event: + pattern = re.compile(job.event.slug.upper() + r"[ \-_]*([A-Z0-9]{%s})" % code_len) + else: + if not prefixes: + prefixes = [e.slug.upper().replace(".", r"\.").replace("-", r"[\- ]*") + for e in job.organizer.events.all()] + pattern = re.compile("(%s)[ \\-_]*([A-Z0-9]{%s})" % ("|".join(prefixes), code_len)) + + for trans in transactions: + match = pattern.search(trans.reference.replace(" ", "").replace("\n", "").upper()) + + if match: + if job.event: + code = match.group(1) + _handle_transaction(trans, code, event=job.event) + else: + slug = match.group(1) + code = match.group(2) + _handle_transaction(trans, code, organizer=job.organizer, slug=slug) + else: + trans.state = BankTransaction.STATE_NOMATCH + trans.save() + except LockTimeoutException: + try: + self.retry() + except MaxRetriesExceededError: + logger.exception('Maximum number of retries exceeded for task.') + job.state = BankImportJob.STATE_ERROR + job.save() + except Exception as e: job.state = BankImportJob.STATE_ERROR job.save() - except Exception as e: - job.state = BankImportJob.STATE_ERROR - job.save() - raise e - else: - job.state = BankImportJob.STATE_COMPLETED - job.save() + raise e + else: + job.state = BankImportJob.STATE_COMPLETED + job.save() diff --git a/src/pretix/plugins/paypal/views.py b/src/pretix/plugins/paypal/views.py index 1a00159808..31cf17d0f4 100644 --- a/src/pretix/plugins/paypal/views.py +++ b/src/pretix/plugins/paypal/views.py @@ -13,6 +13,7 @@ from django.utils.translation import ugettext_lazy as _ from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST +from django_scopes import scopes_disabled from paypalrestsdk.openid_connect import Tokeninfo from pretix.base.models import Event, Order, OrderPayment, OrderRefund, Quota @@ -133,6 +134,7 @@ def abort(request, *args, **kwargs): @csrf_exempt @require_POST +@scopes_disabled() def webhook(request, *args, **kwargs): event_body = request.body.decode('utf-8').strip() event_json = json.loads(event_body) diff --git a/src/pretix/plugins/pretixdroid/forms.py b/src/pretix/plugins/pretixdroid/forms.py index 508da8398e..c0eb3e9e08 100644 --- a/src/pretix/plugins/pretixdroid/forms.py +++ b/src/pretix/plugins/pretixdroid/forms.py @@ -1,6 +1,9 @@ from django import forms from django.urls import reverse from django.utils.translation import ugettext_lazy as _ +from django_scopes.forms import ( + SafeModelChoiceField, SafeModelMultipleChoiceField, +) from pretix.control.forms.widgets import Select2 from pretix.plugins.pretixdroid.models import AppConfiguration @@ -16,6 +19,10 @@ class AppConfigurationForm(forms.ModelForm): }), 'app': forms.RadioSelect } + field_classes = { + 'items': SafeModelMultipleChoiceField, + 'list': SafeModelChoiceField, + } def __init__(self, **kwargs): self.event = kwargs.pop('event') diff --git a/src/pretix/plugins/pretixdroid/views.py b/src/pretix/plugins/pretixdroid/views.py index 4dfd57b345..5523cbb154 100644 --- a/src/pretix/plugins/pretixdroid/views.py +++ b/src/pretix/plugins/pretixdroid/views.py @@ -17,6 +17,7 @@ from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from django.views.generic import TemplateView, View +from django_scopes import scope, scopes_disabled from pretix.base.models import Checkin, Event, Order, OrderPosition from pretix.base.models.event import SubEvent @@ -124,34 +125,35 @@ class ConfigView(EventPermissionRequiredMixin, TemplateView): class ApiView(View): @method_decorator(csrf_exempt) def dispatch(self, request, **kwargs): - try: - self.event = Event.objects.get( - slug=self.kwargs['event'], - organizer__slug=self.kwargs['organizer'] - ) - except Event.DoesNotExist: - return HttpResponseNotFound('Unknown event') + with scopes_disabled(): + try: + self.event = Event.objects.get( + slug=self.kwargs['event'], + organizer__slug=self.kwargs['organizer'] + ) + except Event.DoesNotExist: + return HttpResponseNotFound('Unknown event') + with scope(organizer=self.event.organizer): + try: + self.config = self.event.appconfiguration_set.get(key=request.GET.get("key", "-unset-")) + except AppConfiguration.DoesNotExist: + return HttpResponseForbidden('Invalid key') - try: - self.config = self.event.appconfiguration_set.get(key=request.GET.get("key", "-unset-")) - except AppConfiguration.DoesNotExist: - return HttpResponseForbidden('Invalid key') - - self.subevent = None - if self.event.has_subevents: - if self.config.list.subevent: - self.subevent = self.config.list.subevent - if 'subevent' in kwargs and kwargs['subevent'] != str(self.subevent.pk): - return HttpResponseForbidden('Invalid subevent selected.') - elif 'subevent' in kwargs: - self.subevent = get_object_or_404(SubEvent, event=self.event, pk=kwargs['subevent']) + self.subevent = None + if self.event.has_subevents: + if self.config.list.subevent: + self.subevent = self.config.list.subevent + if 'subevent' in kwargs and kwargs['subevent'] != str(self.subevent.pk): + return HttpResponseForbidden('Invalid subevent selected.') + elif 'subevent' in kwargs: + self.subevent = get_object_or_404(SubEvent, event=self.event, pk=kwargs['subevent']) + else: + return HttpResponseForbidden('No subevent selected.') else: - return HttpResponseForbidden('No subevent selected.') - else: - if 'subevent' in kwargs: - return HttpResponseForbidden('Subevents not enabled.') + if 'subevent' in kwargs: + return HttpResponseForbidden('Subevents not enabled.') - return super().dispatch(request, **kwargs) + return super().dispatch(request, **kwargs) class ApiRedeemView(ApiView): diff --git a/src/pretix/plugins/sendmail/tasks.py b/src/pretix/plugins/sendmail/tasks.py index 245cf205de..f56b3f245a 100644 --- a/src/pretix/plugins/sendmail/tasks.py +++ b/src/pretix/plugins/sendmail/tasks.py @@ -5,15 +5,14 @@ from i18nfield.strings import LazyI18nString from pretix.base.i18n import language from pretix.base.models import Event, InvoiceAddress, Order, User from pretix.base.services.mail import SendMailException, mail -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import ProfiledEventTask from pretix.celery_app import app from pretix.multidomain.urlreverse import build_absolute_uri -@app.task(base=ProfiledTask) -def send_mails(event: int, user: int, subject: dict, message: dict, orders: list, items: list, recipients: str) -> None: +@app.task(base=ProfiledEventTask) +def send_mails(event: Event, user: int, subject: dict, message: dict, orders: list, items: list, recipients: str) -> None: failures = [] - event = Event.objects.get(pk=event) user = User.objects.get(pk=user) if user else None orders = Order.objects.filter(pk__in=orders, event=event) subject = LazyI18nString(subject) diff --git a/src/pretix/plugins/stripe/management/commands/stripe_connect_fill_countries.py b/src/pretix/plugins/stripe/management/commands/stripe_connect_fill_countries.py index 295520479d..c60b55411e 100644 --- a/src/pretix/plugins/stripe/management/commands/stripe_connect_fill_countries.py +++ b/src/pretix/plugins/stripe/management/commands/stripe_connect_fill_countries.py @@ -1,5 +1,6 @@ import stripe from django.core.management.base import BaseCommand +from django_scopes import scopes_disabled from pretix.base.models import Event from pretix.base.settings import GlobalSettingsObject @@ -8,6 +9,7 @@ from pretix.base.settings import GlobalSettingsObject class Command(BaseCommand): help = "Detect country for Stripe Connect accounts connected with pretix 2.0 (required for payment request buttons)" + @scopes_disabled() def handle(self, *args, **options): cache = {} gs = GlobalSettingsObject() diff --git a/src/pretix/plugins/stripe/tasks.py b/src/pretix/plugins/stripe/tasks.py index 44d55b02fc..afd6c6bbc3 100644 --- a/src/pretix/plugins/stripe/tasks.py +++ b/src/pretix/plugins/stripe/tasks.py @@ -5,6 +5,7 @@ import stripe from django.conf import settings from pretix.base.models import Event +from pretix.base.services.tasks import EventTask from pretix.celery_app import app from pretix.multidomain.urlreverse import get_domain from pretix.plugins.stripe.models import RegisteredApplePayDomain @@ -27,7 +28,7 @@ def get_stripe_account_key(prov): return prov.settings.publishable_key -@app.task(max_retries=5, default_retry_delay=1) +@app.task(base=EventTask, max_retries=5, default_retry_delay=1) def stripe_verify_domain(event_id, domain): from pretix.plugins.stripe.payment import StripeCC event = Event.objects.get(pk=event_id) diff --git a/src/pretix/plugins/stripe/views.py b/src/pretix/plugins/stripe/views.py index 48d382b0fe..d50e77b49d 100644 --- a/src/pretix/plugins/stripe/views.py +++ b/src/pretix/plugins/stripe/views.py @@ -17,6 +17,7 @@ from django.views import View from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST +from django_scopes import scopes_disabled from pretix.base.models import Event, Order, OrderPayment, Quota from pretix.base.payment import PaymentException @@ -140,6 +141,7 @@ def oauth_return(request, *args, **kwargs): @csrf_exempt @require_POST +@scopes_disabled() def webhook(request, *args, **kwargs): event_json = json.loads(request.body.decode('utf-8')) diff --git a/src/pretix/presale/checkoutflow.py b/src/pretix/presale/checkoutflow.py index c6171b7217..c88ed7ffd8 100644 --- a/src/pretix/presale/checkoutflow.py +++ b/src/pretix/presale/checkoutflow.py @@ -12,6 +12,7 @@ from django.utils.translation import ( get_language, pgettext_lazy, ugettext_lazy as _, ) from django.views.generic.base import TemplateResponseMixin +from django_scopes import scopes_disabled from pretix.base.models import Order from pretix.base.models.orders import InvoiceAddress, OrderPayment @@ -114,7 +115,10 @@ class BaseCheckoutFlowStep: self.request._checkout_flow_invoice_address = InvoiceAddress() else: try: - self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) + with scopes_disabled(): + self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get( + pk=iapk, order__isnull=True + ) except InvoiceAddress.DoesNotExist: self.request._checkout_flow_invoice_address = InvoiceAddress() return self.request._checkout_flow_invoice_address diff --git a/src/pretix/presale/management/commands/updatestyles.py b/src/pretix/presale/management/commands/updatestyles.py index 3d4e708e05..993ece3808 100644 --- a/src/pretix/presale/management/commands/updatestyles.py +++ b/src/pretix/presale/management/commands/updatestyles.py @@ -4,6 +4,7 @@ from django.conf import settings from django.core.files.base import ContentFile, File from django.core.files.storage import default_storage from django.core.management.base import BaseCommand +from django_scopes import scopes_disabled from pretix.base.models import Event_SettingsStore, Organizer_SettingsStore from pretix.base.settings import GlobalSettingsObject @@ -15,6 +16,7 @@ from ...style import regenerate_css, regenerate_organizer_css class Command(BaseCommand): help = "Re-generate all custom stylesheets and scripts" + @scopes_disabled() def handle(self, *args, **options): for es in Organizer_SettingsStore.objects.filter(key="presale_css_file"): regenerate_organizer_css.apply_async(args=(es.object_id,)) diff --git a/src/pretix/presale/middleware.py b/src/pretix/presale/middleware.py index c7d468c221..09ab9bc01c 100644 --- a/src/pretix/presale/middleware.py +++ b/src/pretix/presale/middleware.py @@ -1,25 +1,32 @@ from django.urls import resolve -from django.utils.deprecation import MiddlewareMixin +from django_scopes import scope from pretix.presale.signals import process_response from .utils import _detect_event -class EventMiddleware(MiddlewareMixin): - def process_request(self, request): +class EventMiddleware: + def __init__(self, get_response=None): + self.get_response = get_response + super().__init__() + + def __call__(self, request): url = resolve(request.path_info) request._namespace = url.namespace if url.namespace != 'presale': - return + return self.get_response(request) if 'organizer' in url.kwargs or 'event' in url.kwargs: redirect = _detect_event(request, require_live=url.url_name != 'event.widget.productlist') if redirect: return redirect - def process_response(self, request, response): - if hasattr(request, '_namespace') and request._namespace == 'presale' and hasattr(request, 'event'): - for receiver, r in process_response.send(request.event, request=request, response=response): - response = r + with scope(organizer=getattr(request, 'organizer', None)): + response = self.get_response(request) + + if hasattr(request, '_namespace') and request._namespace == 'presale' and hasattr(request, 'event'): + for receiver, r in process_response.send(request.event, request=request, response=response): + response = r + return response diff --git a/src/pretix/presale/style.py b/src/pretix/presale/style.py index a7fff3e4b5..76deabefc8 100644 --- a/src/pretix/presale/style.py +++ b/src/pretix/presale/style.py @@ -11,9 +11,10 @@ from django.core.files.base import ContentFile from django.core.files.storage import default_storage from django.dispatch import Signal from django.templatetags.static import static as _static +from django_scopes import scope from pretix.base.models import Event, Event_SettingsStore, Organizer -from pretix.base.services.tasks import ProfiledTask +from pretix.base.services.tasks import ProfiledEventTask, ProfiledTask from pretix.celery_app import app from pretix.multidomain.urlreverse import get_domain from pretix.presale.signals import sass_postamble, sass_preamble @@ -78,10 +79,8 @@ def compile_scss(object, file="main.scss", fonts=True): return css, checksum -@app.task(base=ProfiledTask) -def regenerate_css(event_id: int): - event = Event.objects.select_related('organizer').get(pk=event_id) - +@app.task(base=ProfiledEventTask) +def regenerate_css(event): # main.scss css, checksum = compile_scss(event) fname = 'pub/{}/{}/presale.{}.css'.format(event.organizer.slug, event.slug, checksum[:16]) @@ -105,28 +104,29 @@ def regenerate_css(event_id: int): def regenerate_organizer_css(organizer_id: int): organizer = Organizer.objects.get(pk=organizer_id) - # main.scss - css, checksum = compile_scss(organizer) - fname = 'pub/{}/presale.{}.css'.format(organizer.slug, checksum[:16]) - if organizer.settings.get('presale_css_checksum', '') != checksum: - newname = default_storage.save(fname, ContentFile(css.encode('utf-8'))) - organizer.settings.set('presale_css_file', newname) - organizer.settings.set('presale_css_checksum', checksum) + with scope(organizer=organizer): + # main.scss + css, checksum = compile_scss(organizer) + fname = 'pub/{}/presale.{}.css'.format(organizer.slug, checksum[:16]) + if organizer.settings.get('presale_css_checksum', '') != checksum: + newname = default_storage.save(fname, ContentFile(css.encode('utf-8'))) + organizer.settings.set('presale_css_file', newname) + organizer.settings.set('presale_css_checksum', checksum) - # widget.scss - css, checksum = compile_scss(organizer, file='widget.scss', fonts=False) - fname = 'pub/{}/widget.{}.css'.format(organizer.slug, checksum[:16]) - if organizer.settings.get('presale_widget_css_checksum', '') != checksum: - newname = default_storage.save(fname, ContentFile(css.encode('utf-8'))) - organizer.settings.set('presale_widget_css_file', newname) - organizer.settings.set('presale_widget_css_checksum', checksum) + # widget.scss + css, checksum = compile_scss(organizer, file='widget.scss', fonts=False) + fname = 'pub/{}/widget.{}.css'.format(organizer.slug, checksum[:16]) + if organizer.settings.get('presale_widget_css_checksum', '') != checksum: + newname = default_storage.save(fname, ContentFile(css.encode('utf-8'))) + organizer.settings.set('presale_widget_css_file', newname) + organizer.settings.set('presale_widget_css_checksum', checksum) - non_inherited_events = set(Event_SettingsStore.objects.filter( - object__organizer=organizer, key__in=affected_keys - ).values_list('object_id', flat=True)) - for event in organizer.events.all(): - if event.pk not in non_inherited_events: - regenerate_css.apply_async(args=(event.pk,)) + non_inherited_events = set(Event_SettingsStore.objects.filter( + object__organizer=organizer, key__in=affected_keys + ).values_list('object_id', flat=True)) + for event in organizer.events.all(): + if event.pk not in non_inherited_events: + regenerate_css.apply_async(args=(event.pk,)) register_fonts = Signal() diff --git a/src/pretix/presale/utils.py b/src/pretix/presale/utils.py index ff6496599e..b240f93ed2 100644 --- a/src/pretix/presale/utils.py +++ b/src/pretix/presale/utils.py @@ -8,6 +8,7 @@ from django.http import Http404 from django.shortcuts import redirect from django.urls import resolve from django.utils.translation import ugettext_lazy as _ +from django_scopes import scope from pretix.base.middleware import LocaleMiddleware from pretix.base.models import Event, Organizer @@ -17,6 +18,7 @@ from pretix.presale.signals import process_request, process_response SessionStore = import_module(settings.SESSION_ENGINE).SessionStore +@scope(organizer=None) def _detect_event(request, require_live=True, require_plugin=None): if hasattr(request, '_event_detected'): return @@ -151,10 +153,11 @@ def _event_view(function=None, require_live=True, require_plugin=None): if ret: return ret else: - response = func(request=request, *args, **kwargs) - for receiver, r in process_response.send(request.event, request=request, response=response): - response = r - return response + with scope(organizer=getattr(request, 'organizer', None)): + response = func(request=request, *args, **kwargs) + for receiver, r in process_response.send(request.event, request=request, response=response): + response = r + return response for attrname in dir(func): # Preserve flags like csrf_exempt diff --git a/src/pretix/presale/views/__init__.py b/src/pretix/presale/views/__init__.py index ac85c2c116..76163a708e 100644 --- a/src/pretix/presale/views/__init__.py +++ b/src/pretix/presale/views/__init__.py @@ -9,6 +9,7 @@ from django.db.models import Prefetch, Sum from django.utils.decorators import available_attrs from django.utils.functional import cached_property from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.i18n import language from pretix.base.models import ( @@ -40,7 +41,10 @@ class CartMixin: self.request._checkout_flow_invoice_address = InvoiceAddress() else: try: - self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) + with scopes_disabled(): + self.request._checkout_flow_invoice_address = InvoiceAddress.objects.get( + pk=iapk, order__isnull=True + ) except InvoiceAddress.DoesNotExist: self.request._checkout_flow_invoice_address = InvoiceAddress() return self.request._checkout_flow_invoice_address @@ -215,7 +219,8 @@ def get_cart_invoice_address(request): request._checkout_flow_invoice_address = InvoiceAddress() else: try: - request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) + with scopes_disabled(): + request._checkout_flow_invoice_address = InvoiceAddress.objects.get(pk=iapk, order__isnull=True) except InvoiceAddress.DoesNotExist: request._checkout_flow_invoice_address = InvoiceAddress() return request._checkout_flow_invoice_address diff --git a/src/pretix/presale/views/cart.py b/src/pretix/presale/views/cart.py index 5174584a22..6977873037 100644 --- a/src/pretix/presale/views/cart.py +++ b/src/pretix/presale/views/cart.py @@ -17,6 +17,7 @@ from django.utils.timezone import now from django.utils.translation import ugettext as _ from django.views.decorators.clickjacking import xframe_options_exempt from django.views.generic import TemplateView, View +from django_scopes import scopes_disabled from pretix.base.models import ( CartPosition, InvoiceAddress, QuestionAnswer, SubEvent, Voucher, @@ -80,7 +81,8 @@ class CartActionMixin: return InvoiceAddress() try: - return InvoiceAddress.objects.get(pk=iapk, order__isnull=True) + with scopes_disabled(): + return InvoiceAddress.objects.get(pk=iapk, order__isnull=True) except InvoiceAddress.DoesNotExist: return InvoiceAddress() diff --git a/src/pretix/settings.py b/src/pretix/settings.py index c871b2b0e1..ecefc5244f 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -343,6 +343,7 @@ MIDDLEWARE = [ 'pretix.base.middleware.LocaleMiddleware', 'pretix.base.middleware.SecurityMiddleware', 'pretix.presale.middleware.EventMiddleware', + 'pretix.api.middleware.ApiScopeMiddleware', ] try: diff --git a/src/pretix/testutils/scope.py b/src/pretix/testutils/scope.py new file mode 100644 index 0000000000..dc61f1e67f --- /dev/null +++ b/src/pretix/testutils/scope.py @@ -0,0 +1,10 @@ +from django_scopes import scope + + +def classscope(attr='o'): + def wrap(fn): + def wrapped(self, *args, **kwargs): + with scope(organizer=getattr(self, attr)): + return fn(self, *args, **kwargs) + return wrapped + return wrap diff --git a/src/pretix/testutils/settings.py b/src/pretix/testutils/settings.py index a78a3e4ccf..bf3dde10e3 100644 --- a/src/pretix/testutils/settings.py +++ b/src/pretix/testutils/settings.py @@ -12,6 +12,7 @@ from pretix.settings import * # NOQA DATA_DIR = tmpdir.name LOG_DIR = os.path.join(DATA_DIR, 'logs') MEDIA_ROOT = os.path.join(DATA_DIR, 'media') +SITE_URL = "http://example.com" atexit.register(tmpdir.cleanup) diff --git a/src/requirements/production.txt b/src/requirements/production.txt index be498da42f..fe1b1f1240 100644 --- a/src/requirements/production.txt +++ b/src/requirements/production.txt @@ -9,6 +9,7 @@ django-formset-js-improved==0.5.0.2 django-compressor==2.2.* django-hierarkey==1.0.*,>=1.0.3 django-filter==2.1.* +django-scopes==1.1.* reportlab==3.5.* PyPDF2==1.26.* Pillow==5.* diff --git a/src/setup.py b/src/setup.py index 8c2e5dc00b..0077a28b10 100644 --- a/src/setup.py +++ b/src/setup.py @@ -97,6 +97,7 @@ setup( 'django-compressor==2.2.*', 'django-hierarkey==1.0.*,>=1.0.2', 'django-filter==2.1.*', + 'django-scopes==1.1.*', 'reportlab==3.5.*', 'Pillow==5.*', 'PyPDF2==1.26.*', diff --git a/src/tests/api/conftest.py b/src/tests/api/conftest.py index 5f2242a188..d61b86351d 100644 --- a/src/tests/api/conftest.py +++ b/src/tests/api/conftest.py @@ -1,7 +1,9 @@ from datetime import datetime import pytest +from django.test import utils from django.utils.timezone import now +from django_scopes import scopes_disabled from pytz import UTC from rest_framework.test import APIClient @@ -15,16 +17,19 @@ def client(): @pytest.fixture +@scopes_disabled() def organizer(): return Organizer.objects.create(name='Dummy', slug='dummy') @pytest.fixture +@scopes_disabled() def meta_prop(organizer): return organizer.meta_properties.create(name="type", default="Concert") @pytest.fixture +@scopes_disabled() def event(organizer, meta_prop): e = Event.objects.create( organizer=organizer, name='Dummy', slug='dummy', @@ -37,6 +42,7 @@ def event(organizer, meta_prop): @pytest.fixture +@scopes_disabled() def event2(organizer, meta_prop): e = Event.objects.create( organizer=organizer, name='Dummy2', slug='dummy2', @@ -48,6 +54,7 @@ def event2(organizer, meta_prop): @pytest.fixture +@scopes_disabled() def event3(organizer, meta_prop): e = Event.objects.create( organizer=organizer, name='Dummy3', slug='dummy3', @@ -59,6 +66,7 @@ def event3(organizer, meta_prop): @pytest.fixture +@scopes_disabled() def team(organizer): return Team.objects.create( organizer=organizer, @@ -73,6 +81,7 @@ def team(organizer): @pytest.fixture +@scopes_disabled() def device(organizer): return Device.objects.create( organizer=organizer, @@ -89,6 +98,7 @@ def user(): @pytest.fixture +@scopes_disabled() def user_client(client, team, user): team.can_view_orders = True team.can_view_vouchers = True @@ -100,6 +110,7 @@ def user_client(client, team, user): @pytest.fixture +@scopes_disabled() def token_client(client, team): team.can_view_orders = True team.can_view_vouchers = True @@ -117,6 +128,7 @@ def device_client(client, device): @pytest.fixture +@scopes_disabled() def subevent(event, meta_prop): event.has_subevents = True event.save() @@ -127,6 +139,7 @@ def subevent(event, meta_prop): @pytest.fixture +@scopes_disabled() def subevent2(event2, meta_prop): event2.has_subevents = True event2.save() @@ -137,10 +150,15 @@ def subevent2(event2, meta_prop): @pytest.fixture +@scopes_disabled() def taxrule(event): return event.tax_rules.create(name="VAT", rate=19) @pytest.fixture +@scopes_disabled() def taxrule2(event2): return event2.tax_rules.create(name="VAT", rate=25) + + +utils.setup_databases = scopes_disabled()(utils.setup_databases) diff --git a/src/tests/api/test_auth.py b/src/tests/api/test_auth.py index 4c2b3af6c0..d418728c9f 100644 --- a/src/tests/api/test_auth.py +++ b/src/tests/api/test_auth.py @@ -13,7 +13,6 @@ def test_no_auth(client): def test_session_auth_no_teams(client, user): client.login(email=user.email, password='dummy') resp = client.get('/api/v1/organizers/') - print(resp.data) assert resp.status_code == 200 assert len(resp.data['results']) == 0 diff --git a/src/tests/api/test_cart.py b/src/tests/api/test_cart.py index 7f07674e13..9852e1a921 100644 --- a/src/tests/api/test_cart.py +++ b/src/tests/api/test_cart.py @@ -5,6 +5,7 @@ from unittest import mock import pytest from django.utils.timezone import now +from django_scopes import scopes_disabled from pytz import UTC from pretix.base.models import Question @@ -175,7 +176,8 @@ def test_cartpos_create(token_client, organizer, event, item, quota, question): ), format='json', data=res ) assert resp.status_code == 201 - cp = CartPosition.objects.get(pk=resp.data['id']) + with scopes_disabled(): + cp = CartPosition.objects.get(pk=resp.data['id']) assert cp.price == Decimal('23.00') assert cp.item == item assert cp.attendee_name_parts == {'full_name': 'Peter'} @@ -193,7 +195,8 @@ def test_cartpos_create_name_optional(token_client, organizer, event, item, quot ), format='json', data=res ) assert resp.status_code == 201 - cp = CartPosition.objects.get(pk=resp.data['id']) + with scopes_disabled(): + cp = CartPosition.objects.get(pk=resp.data['id']) assert cp.price == Decimal('23.00') assert cp.item == item assert cp.attendee_name_parts == {} @@ -217,7 +220,8 @@ def test_cartpos_create_legacy_name(token_client, organizer, event, item, quota, ), format='json', data=res ) assert resp.status_code == 201 - cp = CartPosition.objects.get(pk=resp.data['id']) + with scopes_disabled(): + cp = CartPosition.objects.get(pk=resp.data['id']) assert cp.price == Decimal('23.00') assert cp.item == item assert cp.attendee_name_parts == {'_legacy': 'Peter'} @@ -247,7 +251,8 @@ def test_cartpos_cart_id_optional(token_client, organizer, event, item, quota, q ), format='json', data=res ) assert resp.status_code == 201 - cp = CartPosition.objects.get(pk=resp.data['id']) + with scopes_disabled(): + cp = CartPosition.objects.get(pk=resp.data['id']) assert cp.price == Decimal('23.00') assert cp.item == item assert len(cp.cart_id) > 48 @@ -300,7 +305,8 @@ def test_cartpos_create_item_validation(token_client, organizer, event, item, it assert resp.status_code == 400 assert resp.data == {'item': ['The specified item does not belong to this event.']} - var2 = item2.variations.create(value="A") + with scopes_disabled(): + var2 = item2.variations.create(value="A") res['item'] = item.pk res['variation'] = var2.pk @@ -312,7 +318,8 @@ def test_cartpos_create_item_validation(token_client, organizer, event, item, it assert resp.status_code == 400 assert resp.data == {'non_field_errors': ['You cannot specify a variation for this item.']} - var1 = item.variations.create(value="A") + with scopes_disabled(): + var1 = item.variations.create(value="A") res['item'] = item.pk res['variation'] = var1.pk resp = token_client.post( @@ -361,7 +368,8 @@ def test_cartpos_expires_optional(token_client, organizer, event, item, quota, q ), format='json', data=res ) assert resp.status_code == 201 - cp = CartPosition.objects.get(pk=resp.data['id']) + with scopes_disabled(): + cp = CartPosition.objects.get(pk=resp.data['id']) assert cp.price == Decimal('23.00') assert cp.item == item assert cp.expires - now() > datetime.timedelta(minutes=25) @@ -410,7 +418,8 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, assert resp.data == { 'answers': [{'non_field_errors': ['You need to specify options if the question is of a choice type.']}]} - question.options.create(answer="L") + with scopes_disabled(): + question.options.create(answer="L") res['answers'][0]['options'] = [ question.options.first().pk, question.options.last().pk, @@ -445,8 +454,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.question == question assert answ.answer == "XL, L" @@ -460,8 +470,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.answer == "3.45" question.type = Question.TYPE_NUMBER @@ -486,8 +497,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.answer == "True" question.type = Question.TYPE_BOOLEAN @@ -499,8 +511,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.answer == "False" question.type = Question.TYPE_BOOLEAN @@ -523,8 +536,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.answer == "2018-05-14" question.type = Question.TYPE_DATE @@ -548,8 +562,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.answer == "2018-05-14 13:00:00+00:00" question.type = Question.TYPE_DATETIME @@ -574,8 +589,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - pos = CartPosition.objects.get(pk=resp.data['id']) - answ = pos.answers.first() + with scopes_disabled(): + pos = CartPosition.objects.get(pk=resp.data['id']) + answ = pos.answers.first() assert answ.answer == "13:00:00" question.type = Question.TYPE_TIME diff --git a/src/tests/api/test_checkin.py b/src/tests/api/test_checkin.py index bf53da3902..7c1c615e1c 100644 --- a/src/tests/api/test_checkin.py +++ b/src/tests/api/test_checkin.py @@ -6,6 +6,7 @@ from unittest import mock import pytest from django.utils.timezone import now from django_countries.fields import Country +from django_scopes import scopes_disabled from i18nfield.strings import LazyI18nString from pytz import UTC @@ -157,7 +158,8 @@ def test_list_list(token_client, organizer, event, clist, item, subevent): resp = token_client.get( '/api/v1/organizers/{}/events/{}/checkinlists/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) assert [res] == resp.data['results'] - se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) + with scopes_disabled(): + se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) resp = token_client.get( '/api/v1/organizers/{}/events/{}/checkinlists/?subevent={}'.format(organizer.slug, event.slug, se2.pk)) assert [] == resp.data['results'] @@ -188,10 +190,11 @@ def test_list_create(token_client, organizer, event, item, item_on_wrong_event): format='json' ) assert resp.status_code == 201 - cl = CheckinList.objects.get(pk=resp.data['id']) - assert cl.name == "VIP" - assert cl.limit_products.count() == 1 - assert not cl.all_products + with scopes_disabled(): + cl = CheckinList.objects.get(pk=resp.data['id']) + assert cl.name == "VIP" + assert cl.limit_products.count() == 1 + assert not cl.all_products resp = token_client.post( '/api/v1/organizers/{}/events/{}/checkinlists/'.format(organizer.slug, event.slug), @@ -271,18 +274,20 @@ def test_list_update(token_client, organizer, event, clist): format='json' ) assert resp.status_code == 200 - cl = CheckinList.objects.get(pk=resp.data['id']) + with scopes_disabled(): + cl = CheckinList.objects.get(pk=resp.data['id']) assert cl.name == "VIP" @pytest.mark.django_db def test_list_all_items_positions(token_client, organizer, event, clist, clist_all, item, other_item, order): - p1 = dict(TEST_ORDERPOSITION1_RES) - p1["id"] = order.positions.first().pk - p1["item"] = item.pk - p2 = dict(TEST_ORDERPOSITION2_RES) - p2["id"] = order.positions.last().pk - p2["item"] = other_item.pk + with scopes_disabled(): + p1 = dict(TEST_ORDERPOSITION1_RES) + p1["id"] = order.positions.first().pk + p1["item"] = item.pk + p2 = dict(TEST_ORDERPOSITION2_RES) + p2["id"] = order.positions.last().pk + p2["item"] = other_item.pk # All items resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?ordering=positionid'.format( @@ -292,7 +297,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a assert [p1, p2] == resp.data['results'] # Check-ins on other list ignored - order.positions.first().checkins.create(list=clist) + with scopes_disabled(): + order.positions.first().checkins.create(list=clist) resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?ordering=positionid'.format( organizer.slug, event.slug, clist_all.pk )) @@ -305,7 +311,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a assert [] == resp.data['results'] # Only checked in - c = order.positions.first().checkins.create(list=clist_all) + with scopes_disabled(): + c = order.positions.first().checkins.create(list=clist_all) p1['checkins'] = [ { 'list': clist_all.pk, @@ -341,7 +348,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a # Order by checkin date time.sleep(1) - c = order.positions.last().checkins.create(list=clist_all) + with scopes_disabled(): + c = order.positions.last().checkins.create(list=clist_all) p2['checkins'] = [ { 'list': clist_all.pk, @@ -388,7 +396,8 @@ def test_list_all_items_positions(token_client, organizer, event, clist, clist_a @pytest.mark.django_db def test_list_limited_items_positions(token_client, organizer, event, clist, item, order): p1 = dict(TEST_ORDERPOSITION1_RES) - p1["id"] = order.positions.first().pk + with scopes_disabled(): + p1["id"] = order.positions.first().pk p1["item"] = item.pk # All items @@ -402,12 +411,13 @@ def test_list_limited_items_positions(token_client, organizer, event, clist, ite @pytest.mark.django_db def test_list_limited_items_position_detail(token_client, organizer, event, clist, item, order): p1 = dict(TEST_ORDERPOSITION1_RES) - p1["id"] = order.positions.first().pk + with scopes_disabled(): + p1["id"] = order.positions.first().pk p1["item"] = item.pk # All items resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p1["id"] )) assert resp.status_code == 200 assert p1 == resp.data @@ -415,12 +425,13 @@ def test_list_limited_items_position_detail(token_client, organizer, event, clis @pytest.mark.django_db def test_status(token_client, organizer, event, clist_all, item, other_item, order): - op = order.positions.first() - var1 = item.variations.create(value="XS") - var2 = item.variations.create(value="S") - op.variation = var1 - op.save() - Checkin.objects.create(position=op, list=clist_all) + with scopes_disabled(): + op = order.positions.first() + var1 = item.variations.create(value="XS") + var2 = item.variations.create(value="S") + op.variation = var1 + op.save() + Checkin.objects.create(position=op, list=clist_all) resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/status/'.format( organizer.slug, event.slug, clist_all.pk, )) @@ -464,21 +475,25 @@ def test_status(token_client, organizer, event, clist_all, item, other_item, ord def test_custom_datetime(token_client, organizer, clist, event, order): dt = now() - datetime.timedelta(days=1) dt = dt.replace(microsecond=0) + with scopes_disabled(): + p = order.positions.first().pk resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p ), { 'datetime': dt.isoformat() }, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' - assert Checkin.objects.last().datetime == dt + with scopes_disabled(): + assert Checkin.objects.last().datetime == dt @pytest.mark.django_db def test_name_fallback(token_client, organizer, clist, event, order): order.invoice_address.name_parts = {'_legacy': 'Paul'} order.invoice_address.save() - op = order.positions.first() + with scopes_disabled(): + op = order.positions.first() op.attendee_name_cached = None op.attendee_name_parts = {} op.save() @@ -493,8 +508,10 @@ def test_name_fallback(token_client, organizer, clist, event, order): @pytest.mark.django_db def test_by_secret(token_client, organizer, clist, event, order): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().secret + organizer.slug, event.slug, clist.pk, p.secret ), {}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' @@ -502,13 +519,15 @@ def test_by_secret(token_client, organizer, clist, event, order): @pytest.mark.django_db def test_only_once(token_client, organizer, clist, event, order): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'error' @@ -517,13 +536,15 @@ def test_only_once(token_client, organizer, clist, event, order): @pytest.mark.django_db def test_reupload_same_nonce(token_client, organizer, clist, event, order): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'nonce': 'foobar'}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'nonce': 'foobar'}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' @@ -531,13 +552,15 @@ def test_reupload_same_nonce(token_client, organizer, clist, event, order): @pytest.mark.django_db def test_multiple_different_list(token_client, organizer, clist, clist_all, event, order): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'nonce': 'foobar'}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist_all.pk, order.positions.first().pk + organizer.slug, event.slug, clist_all.pk, p.pk ), {'nonce': 'baz'}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' @@ -545,13 +568,15 @@ def test_multiple_different_list(token_client, organizer, clist, clist_all, even @pytest.mark.django_db def test_forced_multiple(token_client, organizer, clist, event, order): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'force': True}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' @@ -559,17 +584,19 @@ def test_forced_multiple(token_client, organizer, clist, event, order): @pytest.mark.django_db def test_require_paid(token_client, organizer, clist, event, order): + with scopes_disabled(): + p = order.positions.first() order.status = Order.STATUS_PENDING order.save() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'error' assert resp.data['reason'] == 'unpaid' resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'ignore_unpaid': True}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'error' @@ -579,14 +606,14 @@ def test_require_paid(token_client, organizer, clist, event, order): clist.save() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'error' assert resp.data['reason'] == 'unpaid' resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'ignore_unpaid': True}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' @@ -603,88 +630,105 @@ def question(event, item): @pytest.mark.django_db def test_question_number(token_client, organizer, clist, event, order, question): - question[0].options.all().delete() + with scopes_disabled(): + p = order.positions.first() + question[0].options.all().delete() question[0].type = 'N' question[0].save() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'answers': {question[0].pk: "3.24"}}, format='json') - print(resp.data) assert resp.status_code == 201 assert resp.data['status'] == 'ok' - assert order.positions.first().answers.get(question=question[0]).answer == '3.24' + with scopes_disabled(): + assert order.positions.first().answers.get(question=question[0]).answer == '3.24' @pytest.mark.django_db def test_question_choice(token_client, organizer, clist, event, order, question): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'answers': {question[0].pk: str(question[1].pk)}}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' - assert order.positions.first().answers.get(question=question[0]).answer == 'M' - assert list(order.positions.first().answers.get(question=question[0]).options.all()) == [question[1]] + with scopes_disabled(): + assert order.positions.first().answers.get(question=question[0]).answer == 'M' + assert list(order.positions.first().answers.get(question=question[0]).options.all()) == [question[1]] @pytest.mark.django_db def test_question_invalid(token_client, organizer, clist, event, order, question): + with scopes_disabled(): + p = order.positions.first() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'answers': {question[0].pk: "A"}}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] @pytest.mark.django_db def test_question_required(token_client, organizer, clist, event, order, question): + with scopes_disabled(): + p = order.positions.first() question[0].required = True question[0].save() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'answers': {question[0].pk: ""}}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] @pytest.mark.django_db def test_question_optional(token_client, organizer, clist, event, order, question): + with scopes_disabled(): + p = order.positions.first() question[0].required = False question[0].save() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'answers': {question[0].pk: ""}}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' @@ -692,20 +736,24 @@ def test_question_optional(token_client, organizer, clist, event, order, questio @pytest.mark.django_db def test_question_multiple_choice(token_client, organizer, clist, event, order, question): + with scopes_disabled(): + p = order.positions.first() question[0].type = 'M' question[0].save() resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {}, format='json') assert resp.status_code == 400 assert resp.data['status'] == 'incomplete' - assert resp.data['questions'] == [QuestionSerializer(question[0]).data] + with scopes_disabled(): + assert resp.data['questions'] == [QuestionSerializer(question[0]).data] resp = token_client.post('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/{}/redeem/'.format( - organizer.slug, event.slug, clist.pk, order.positions.first().pk + organizer.slug, event.slug, clist.pk, p.pk ), {'answers': {question[0].pk: "{},{}".format(question[1].pk, question[2].pk)}}, format='json') assert resp.status_code == 201 assert resp.data['status'] == 'ok' - assert order.positions.first().answers.get(question=question[0]).answer == 'M, L' - assert set(order.positions.first().answers.get(question=question[0]).options.all()) == {question[1], question[2]} + with scopes_disabled(): + assert order.positions.first().answers.get(question=question[0]).answer == 'M, L' + assert set(order.positions.first().answers.get(question=question[0]).options.all()) == {question[1], question[2]} diff --git a/src/tests/api/test_events.py b/src/tests/api/test_events.py index f75d45d35f..16b60ee942 100644 --- a/src/tests/api/test_events.py +++ b/src/tests/api/test_events.py @@ -5,6 +5,7 @@ from unittest import mock import pytest from django.conf import settings from django_countries.fields import Country +from django_scopes import scopes_disabled from pytz import UTC from pretix.base.models import Event, InvoiceAddress, Order, OrderPosition @@ -161,11 +162,12 @@ def test_event_create(token_client, organizer, event, meta_prop): format='json' ) assert resp.status_code == 201 - assert not organizer.events.get(slug="2030").testmode - assert organizer.events.get(slug="2030").meta_values.filter( - property__name=meta_prop.name, value="Conference" - ).exists() - assert organizer.events.get(slug="2030").plugins == settings.PRETIX_PLUGINS_DEFAULT + with scopes_disabled(): + assert not organizer.events.get(slug="2030").testmode + assert organizer.events.get(slug="2030").meta_values.filter( + property__name=meta_prop.name, value="Conference" + ).exists() + assert organizer.events.get(slug="2030").plugins == settings.PRETIX_PLUGINS_DEFAULT resp = token_client.post( '/api/v1/organizers/{}/events/'.format(organizer.slug), @@ -278,13 +280,14 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop): ) assert resp.status_code == 201 - cloned_event = Event.objects.get(organizer=organizer.pk, slug='2030') - assert cloned_event.plugins == 'pretix.plugins.ticketoutputpdf' - assert cloned_event.is_public is False - assert cloned_event.testmode - assert organizer.events.get(slug="2030").meta_values.filter( - property__name=meta_prop.name, value="Conference" - ).exists() + with scopes_disabled(): + cloned_event = Event.objects.get(organizer=organizer.pk, slug='2030') + assert cloned_event.plugins == 'pretix.plugins.ticketoutputpdf' + assert cloned_event.is_public is False + assert cloned_event.testmode + assert organizer.events.get(slug="2030").meta_values.filter( + property__name=meta_prop.name, value="Conference" + ).exists() resp = token_client.post( '/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug), @@ -310,12 +313,13 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop): ) assert resp.status_code == 201 - cloned_event = Event.objects.get(organizer=organizer.pk, slug='2031') - assert cloned_event.plugins == "pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf" - assert cloned_event.is_public is True - assert organizer.events.get(slug="2031").meta_values.filter( - property__name=meta_prop.name, value="Conference" - ).exists() + with scopes_disabled(): + cloned_event = Event.objects.get(organizer=organizer.pk, slug='2031') + assert cloned_event.plugins == "pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf" + assert cloned_event.is_public is True + assert organizer.events.get(slug="2031").meta_values.filter( + property__name=meta_prop.name, value="Conference" + ).exists() resp = token_client.post( '/api/v1/organizers/{}/events/{}/clone/'.format(organizer.slug, event.slug), @@ -339,8 +343,9 @@ def test_event_create_with_clone(token_client, organizer, event, meta_prop): ) assert resp.status_code == 201 - cloned_event = Event.objects.get(organizer=organizer.pk, slug='2032') - assert cloned_event.plugins == "" + with scopes_disabled(): + cloned_event = Event.objects.get(organizer=organizer.pk, slug='2032') + assert cloned_event.plugins == "" @pytest.mark.django_db @@ -388,11 +393,12 @@ def test_event_update(token_client, organizer, event, item, meta_prop): format='json' ) assert resp.status_code == 200 - event = Event.objects.get(organizer=organizer.pk, slug=resp.data['slug']) - assert event.currency == "DKK" - assert organizer.events.get(slug=resp.data['slug']).meta_values.filter( - property__name=meta_prop.name, value="Conference" - ).exists() + with scopes_disabled(): + event = Event.objects.get(organizer=organizer.pk, slug=resp.data['slug']) + assert event.currency == "DKK" + assert organizer.events.get(slug=resp.data['slug']).meta_values.filter( + property__name=meta_prop.name, value="Conference" + ).exists() resp = token_client.patch( '/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug), @@ -447,9 +453,10 @@ def test_event_update(token_client, organizer, event, item, meta_prop): format='json' ) assert resp.status_code == 200 - assert organizer.events.get(slug=resp.data['slug']).meta_values.filter( - property__name=meta_prop.name, value="Workshop" - ).exists() + with scopes_disabled(): + assert organizer.events.get(slug=resp.data['slug']).meta_values.filter( + property__name=meta_prop.name, value="Workshop" + ).exists() resp = token_client.patch( '/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug), @@ -460,9 +467,10 @@ def test_event_update(token_client, organizer, event, item, meta_prop): format='json' ) assert resp.status_code == 200 - assert not organizer.events.get(slug=resp.data['slug']).meta_values.filter( - property__name=meta_prop.name - ).exists() + with scopes_disabled(): + assert not organizer.events.get(slug=resp.data['slug']).meta_values.filter( + property__name=meta_prop.name + ).exists() resp = token_client.patch( '/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug), @@ -598,7 +606,8 @@ def test_event_detail(token_client, organizer, event, team): def test_event_delete(token_client, organizer, event): resp = token_client.delete('/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug)) assert resp.status_code == 204 - assert not organizer.events.filter(pk=event.id).exists() + with scopes_disabled(): + assert not organizer.events.filter(pk=event.id).exists() @pytest.mark.django_db @@ -607,4 +616,5 @@ def test_event_with_order_position_not_delete(token_client, organizer, event, it assert resp.status_code == 403 assert resp.content.decode() == '{"detail":"The event can not be deleted as it already contains orders. Please ' \ 'set \'live\' to false to hide the event and take the shop offline instead."}' - assert organizer.events.filter(pk=event.id).exists() + with scopes_disabled(): + assert organizer.events.filter(pk=event.id).exists() diff --git a/src/tests/api/test_items.py b/src/tests/api/test_items.py index e5547237e8..a070e8c5fa 100644 --- a/src/tests/api/test_items.py +++ b/src/tests/api/test_items.py @@ -5,6 +5,7 @@ from unittest import mock import pytest from django_countries.fields import Country +from django_scopes import scopes_disabled from pytz import UTC from pretix.base.models import ( @@ -169,7 +170,8 @@ def test_category_update(token_client, organizer, event, team, category): format='json' ) assert resp.status_code == 200 - assert ItemCategory.objects.get(pk=category.pk).name == {"en": "Test"} + with scopes_disabled(): + assert ItemCategory.objects.get(pk=category.pk).name == {"en": "Test"} @pytest.mark.django_db @@ -189,8 +191,9 @@ def test_category_delete(token_client, organizer, event, category3, item): resp = token_client.delete( '/api/v1/organizers/{}/events/{}/categories/{}/'.format(organizer.slug, event.slug, category3.pk)) assert resp.status_code == 204 - assert not event.categories.filter(pk=category3.id).exists() - assert Item.objects.get(pk=item.pk).category is None + with scopes_disabled(): + assert not event.categories.filter(pk=category3.id).exists() + assert Item.objects.get(pk=item.pk).category is None @pytest.fixture @@ -308,7 +311,8 @@ def test_item_detail(token_client, organizer, event, team, item): @pytest.mark.django_db def test_item_detail_variations(token_client, organizer, event, team, item): - var = item.variations.create(value="Children") + with scopes_disabled(): + var = item.variations.create(value="Children") res = dict(TEST_ITEM_RES) res["id"] = item.pk res["variations"] = [{ @@ -349,8 +353,9 @@ def test_item_detail_addons(token_client, organizer, event, team, item, category @pytest.mark.django_db def test_item_detail_bundles(token_client, organizer, event, team, item, category): - i = event.items.create(name="Included thing", default_price=2) - item.bundles.create(bundled_item=i, count=1, designated_price=2) + with scopes_disabled(): + i = event.items.create(name="Included thing", default_price=2) + item.bundles.create(bundled_item=i, count=1, designated_price=2) res = dict(TEST_ITEM_RES) res["id"] = item.pk @@ -398,7 +403,8 @@ def test_item_create(token_client, organizer, event, item, category, taxrule): format='json' ) assert resp.status_code == 201 - assert Item.objects.get(pk=resp.data['id']).sales_channels == ["web", "pretixpos"] + with scopes_disabled(): + assert Item.objects.get(pk=resp.data['id']).sales_channels == ["web", "pretixpos"] @pytest.mark.django_db @@ -445,9 +451,10 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego format='json' ) assert resp.status_code == 201 - new_item = Item.objects.get(pk=resp.data['id']) - assert new_item.variations.first().value.localize('de') == "Kommentar" - assert new_item.variations.first().value.localize('en') == "Comment" + with scopes_disabled(): + new_item = Item.objects.get(pk=resp.data['id']) + assert new_item.variations.first().value.localize('de') == "Kommentar" + assert new_item.variations.first().value.localize('en') == "Comment" @pytest.mark.django_db @@ -490,10 +497,11 @@ def test_item_create_with_addon(token_client, organizer, event, item, category, format='json' ) assert resp.status_code == 201 - item = Item.objects.get(pk=resp.data['id']) - assert item.addons.first().addon_category == category - assert item.addons.first().max_count == 10 - assert 2 == Item.objects.all().count() + with scopes_disabled(): + item = Item.objects.get(pk=resp.data['id']) + assert item.addons.first().addon_category == category + assert item.addons.first().max_count == 10 + assert 2 == Item.objects.all().count() resp = token_client.post( '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), @@ -534,7 +542,8 @@ def test_item_create_with_addon(token_client, organizer, event, item, category, ) assert resp.status_code == 400 assert resp.content.decode() == '{"addons":["The add-on\'s category must belong to the same event as the item."]}' - assert 2 == Item.objects.all().count() + with scopes_disabled(): + assert 2 == Item.objects.all().count() resp = token_client.post( '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), @@ -575,7 +584,8 @@ def test_item_create_with_addon(token_client, organizer, event, item, category, ) assert resp.status_code == 400 assert resp.content.decode() == '{"addons":["The maximum count needs to be greater than the minimum count."]}' - assert 2 == Item.objects.all().count() + with scopes_disabled(): + assert 2 == Item.objects.all().count() resp = token_client.post( '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), @@ -619,12 +629,14 @@ def test_item_create_with_addon(token_client, organizer, event, item, category, '{"addons":["The minimum count needs to be equal to or greater than zero."]}', '{"addons":[{"min_count":["Ensure this value is greater than or equal to 0."]}]}', # mysql ] - assert 2 == Item.objects.all().count() + with scopes_disabled(): + assert 2 == Item.objects.all().count() @pytest.mark.django_db def test_item_create_with_bundle(token_client, organizer, event, item, category, item2, taxrule): - i = event.items.create(name="Included thing", default_price=2) + with scopes_disabled(): + i = event.items.create(name="Included thing", default_price=2) resp = token_client.post( '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), { @@ -662,8 +674,9 @@ def test_item_create_with_bundle(token_client, organizer, event, item, category, format='json' ) assert resp.status_code == 201 - item = Item.objects.get(pk=resp.data['id']) - b = item.bundles.first() + with scopes_disabled(): + item = Item.objects.get(pk=resp.data['id']) + b = item.bundles.first() assert b.bundled_item == i assert b.bundled_variation is None assert b.count == 2 @@ -708,7 +721,8 @@ def test_item_create_with_bundle(token_client, organizer, event, item, category, assert resp.status_code == 400 assert resp.content.decode() == '{"bundles":["The bundled item must belong to the same event as the item."]}' - v = item2.variations.create(value="foo") + with scopes_disabled(): + v = item2.variations.create(value="foo") resp = token_client.post( '/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug), { @@ -760,7 +774,8 @@ def test_item_update(token_client, organizer, event, item, category, item2, cate format='json' ) assert resp.status_code == 200 - assert Item.objects.get(pk=item.pk).max_per_order == 2 + with scopes_disabled(): + assert Item.objects.get(pk=item.pk).max_per_order == 2 resp = token_client.patch( '/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk), @@ -896,21 +911,24 @@ def test_item_update_with_addon(token_client, organizer, event, item, category): def test_items_delete(token_client, organizer, event, item): resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) assert resp.status_code == 204 - assert not event.items.filter(pk=item.id).exists() + with scopes_disabled(): + assert not event.items.filter(pk=item.id).exists() @pytest.mark.django_db def test_items_with_order_position_not_delete(token_client, organizer, event, item, order_position): resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) assert resp.status_code == 403 - assert event.items.filter(pk=item.id).exists() + with scopes_disabled(): + assert event.items.filter(pk=item.id).exists() @pytest.mark.django_db def test_items_with_cart_position_delete(token_client, organizer, event, item, cart_position): resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk)) assert resp.status_code == 204 - assert not event.items.filter(pk=item.id).exists() + with scopes_disabled(): + assert not event.items.filter(pk=item.id).exists() @pytest.fixture @@ -996,7 +1014,8 @@ def test_variations_create(token_client, organizer, event, item, variation): format='json' ) assert resp.status_code == 201 - var = ItemVariation.objects.get(pk=resp.data['id']) + with scopes_disabled(): + var = ItemVariation.objects.get(pk=resp.data['id']) assert var.position == 1 assert var.price == 23.0 @@ -1060,40 +1079,47 @@ def test_variations_update(token_client, organizer, event, item, item3, variatio def test_variations_delete(token_client, organizer, event, item, variations, order): resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk)) assert resp.status_code == 204 - assert not item.variations.filter(pk=variations[0].pk).exists() + with scopes_disabled(): + assert not item.variations.filter(pk=variations[0].pk).exists() @pytest.mark.django_db def test_variations_with_order_position_not_delete(token_client, organizer, event, item, order, variations, order_position): - assert item.variations.filter(pk=variations[0].id).exists() + with scopes_disabled(): + assert item.variations.filter(pk=variations[0].id).exists() resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk)) assert resp.status_code == 403 assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it has already been ordered ' \ 'by a user or currently is in a users\'s cart. Please set the variation as ' \ '\'inactive\' instead."}' - assert item.variations.filter(pk=variations[0].id).exists() + with scopes_disabled(): + assert item.variations.filter(pk=variations[0].id).exists() @pytest.mark.django_db def test_variations_with_cart_position_not_delete(token_client, organizer, event, item, variations, cart_position): - assert item.variations.filter(pk=variations[0].id).exists() + with scopes_disabled(): + assert item.variations.filter(pk=variations[0].id).exists() resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variations[0].pk)) assert resp.status_code == 403 assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it has already been ordered ' \ 'by a user or currently is in a users\'s cart. Please set the variation as ' \ '\'inactive\' instead."}' - assert item.variations.filter(pk=variations[0].id).exists() + with scopes_disabled(): + assert item.variations.filter(pk=variations[0].id).exists() @pytest.mark.django_db def test_only_variation_not_delete(token_client, organizer, event, item, variation): - assert item.variations.filter(pk=variation.id).exists() + with scopes_disabled(): + assert item.variations.filter(pk=variation.id).exists() resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/variations/{}/'.format(organizer.slug, event.slug, item.pk, variation.pk)) assert resp.status_code == 403 assert resp.content.decode() == '{"detail":"This variation cannot be deleted because it is the only variation. ' \ 'Changing a product with variations to a product without variations is not ' \ 'allowed."}' - assert item.variations.filter(pk=variation.id).exists() + with scopes_disabled(): + assert item.variations.filter(pk=variation.id).exists() @pytest.fixture @@ -1144,7 +1170,8 @@ def test_bundles_create(token_client, organizer, event, item, item2, item3): format='json' ) assert resp.status_code == 201 - b = ItemBundle.objects.get(pk=resp.data['id']) + with scopes_disabled(): + b = ItemBundle.objects.get(pk=resp.data['id']) assert b.bundled_item == item3 assert b.bundled_variation is None assert b.designated_price == 1.5 @@ -1176,7 +1203,8 @@ def test_bundles_create(token_client, organizer, event, item, item2, item3): assert resp.status_code == 400 assert resp.content.decode() == '{"non_field_errors":["The bundled item must not be the same item as the bundling one."]}' - item3.bundles.create(bundled_item=item, count=1, designated_price=3) + with scopes_disabled(): + item3.bundles.create(bundled_item=item, count=1, designated_price=3) resp = token_client.post( '/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk), { @@ -1201,7 +1229,8 @@ def test_bundles_update(token_client, organizer, event, item, bundle): format='json' ) assert resp.status_code == 200 - a = ItemBundle.objects.get(pk=bundle.pk) + with scopes_disabled(): + a = ItemBundle.objects.get(pk=bundle.pk) assert a.count == 3 @@ -1210,7 +1239,8 @@ def test_bundles_delete(token_client, organizer, event, item, bundle): resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/bundles/{}/'.format(organizer.slug, event.slug, item.pk, bundle.pk)) assert resp.status_code == 204 - assert not item.bundles.filter(pk=bundle.id).exists() + with scopes_disabled(): + assert not item.bundles.filter(pk=bundle.id).exists() @pytest.fixture @@ -1270,7 +1300,8 @@ def test_addons_create(token_client, organizer, event, item, category, category2 format='json' ) assert resp.status_code == 201 - addon = ItemAddOn.objects.get(pk=resp.data['id']) + with scopes_disabled(): + addon = ItemAddOn.objects.get(pk=resp.data['id']) assert addon.position == 1 assert addon.addon_category == category @@ -1315,7 +1346,8 @@ def test_addons_update(token_client, organizer, event, item, addon): format='json' ) assert resp.status_code == 200 - a = ItemAddOn.objects.get(pk=addon.pk) + with scopes_disabled(): + a = ItemAddOn.objects.get(pk=addon.pk) assert a.min_count == 100 assert a.max_count == 101 @@ -1337,7 +1369,8 @@ def test_addons_delete(token_client, organizer, event, item, addon): resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/addons/{}/'.format(organizer.slug, event.slug, item.pk, addon.pk)) assert resp.status_code == 204 - assert not item.addons.filter(pk=addon.id).exists() + with scopes_disabled(): + assert not item.addons.filter(pk=addon.id).exists() @pytest.fixture @@ -1372,7 +1405,8 @@ def test_quota_list(token_client, organizer, event, quota, item, subevent): resp = token_client.get( '/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) assert [res] == resp.data['results'] - se2 = event.subevents.create(name="Foobar", date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) + with scopes_disabled(): + se2 = event.subevents.create(name="Foobar", date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) resp = token_client.get( '/api/v1/organizers/{}/events/{}/quotas/?subevent={}'.format(organizer.slug, event.slug, se2.pk)) assert [] == resp.data['results'] @@ -1404,7 +1438,8 @@ def test_quota_create(token_client, organizer, event, event2, item): format='json' ) assert resp.status_code == 201 - quota = Quota.objects.get(pk=resp.data['id']) + with scopes_disabled(): + quota = Quota.objects.get(pk=resp.data['id']) assert quota.name == "Ticket Quota" assert quota.size == 200 @@ -1550,7 +1585,8 @@ def test_quota_update(token_client, organizer, event, quota, item): format='json' ) assert resp.status_code == 200 - quota = Quota.objects.get(pk=resp.data['id']) + with scopes_disabled(): + quota = Quota.objects.get(pk=resp.data['id']) assert quota.name == "Ticket Quota Update" assert quota.size == 111 assert quota.all_logentries().count() == 1 @@ -1566,7 +1602,8 @@ def test_quota_update_unchanged(token_client, organizer, event, quota, item): format='json' ) assert resp.status_code == 200 - quota = Quota.objects.get(pk=resp.data['id']) + with scopes_disabled(): + quota = Quota.objects.get(pk=resp.data['id']) assert quota.size == 200 assert quota.all_logentries().count() == 0 @@ -1575,7 +1612,8 @@ def test_quota_update_unchanged(token_client, organizer, event, quota, item): def test_quota_delete(token_client, organizer, event, quota): resp = token_client.delete('/api/v1/organizers/{}/events/{}/quotas/{}/'.format(organizer.slug, event.slug, quota.pk)) assert resp.status_code == 204 - assert not event.quotas.filter(pk=quota.id).exists() + with scopes_disabled(): + assert not event.quotas.filter(pk=quota.id).exists() @pytest.mark.django_db @@ -1690,11 +1728,12 @@ def test_question_create(token_client, organizer, event, event2, item): format='json' ) assert resp.status_code == 201 - question = Question.objects.get(pk=resp.data['id']) - assert question.question == "What's your name?" - assert question.type == "S" - assert question.identifier is not None - assert len(question.items.all()) == 1 + with scopes_disabled(): + question = Question.objects.get(pk=resp.data['id']) + assert question.question == "What's your name?" + assert question.type == "S" + assert question.identifier is not None + assert len(question.items.all()) == 1 resp = token_client.post( '/api/v1/organizers/{}/events/{}/questions/'.format(organizer.slug, event2.slug), @@ -1784,7 +1823,8 @@ def test_question_create(token_client, organizer, event, event2, item): format='json' ) assert resp.status_code == 201 - q2 = Question.objects.get(pk=resp.data['id']) + with scopes_disabled(): + q2 = Question.objects.get(pk=resp.data['id']) assert q2.dependency_question == question @@ -1799,14 +1839,16 @@ def test_question_update(token_client, organizer, event, question): format='json' ) assert resp.status_code == 200 - question = Question.objects.get(pk=resp.data['id']) + with scopes_disabled(): + question = Question.objects.get(pk=resp.data['id']) assert question.question == "What's your shoe size?" assert question.type == "N" @pytest.mark.django_db def test_question_update_circular_dependency(token_client, organizer, event, question): - q2 = event.questions.create(question="T-Shirt size", type="B", identifier="FOO", dependency_question=question) + with scopes_disabled(): + q2 = event.questions.create(question="T-Shirt size", type="B", identifier="FOO", dependency_question=question) resp = token_client.patch( '/api/v1/organizers/{}/events/{}/questions/{}/'.format(organizer.slug, event.slug, question.pk), { @@ -1836,7 +1878,8 @@ def test_question_update_options(token_client, organizer, event, question, item) def test_question_delete(token_client, organizer, event, question): resp = token_client.delete('/api/v1/organizers/{}/events/{}/questions/{}/'.format(organizer.slug, event.slug, question.pk)) assert resp.status_code == 204 - assert not event.questions.filter(pk=question.id).exists() + with scopes_disabled(): + assert not event.questions.filter(pk=question.id).exists() TEST_OPTIONS_RES = { @@ -1881,7 +1924,8 @@ def test_options_create(token_client, organizer, event, question): format='json' ) assert resp.status_code == 201 - option = QuestionOption.objects.get(pk=resp.data['id']) + with scopes_disabled(): + option = QuestionOption.objects.get(pk=resp.data['id']) assert option.answer == "A" resp = token_client.post( @@ -1907,7 +1951,8 @@ def test_options_update(token_client, organizer, event, question, option): format='json' ) assert resp.status_code == 200 - a = QuestionOption.objects.get(pk=option.pk) + with scopes_disabled(): + a = QuestionOption.objects.get(pk=option.pk) assert a.answer == "B" @@ -1917,7 +1962,8 @@ def test_options_delete(token_client, organizer, event, question, option): organizer.slug, event.slug, question.pk, option.pk )) assert resp.status_code == 204 - assert not question.options.filter(pk=option.id).exists() + with scopes_disabled(): + assert not question.options.filter(pk=option.id).exists() @pytest.mark.django_db @@ -1948,11 +1994,12 @@ def test_question_create_with_option(token_client, organizer, event, item): format='json' ) assert resp.status_code == 201 - question = Question.objects.get(pk=resp.data['id']) - assert str(question.options.first().answer) == "A" - assert question.options.first().identifier is not None - assert str(question.options.last().answer) == "B" - assert 2 == question.options.count() + with scopes_disabled(): + question = Question.objects.get(pk=resp.data['id']) + assert str(question.options.first().answer) == "A" + assert question.options.first().identifier is not None + assert str(question.options.last().answer) == "B" + assert 2 == question.options.count() resp = token_client.post( '/api/v1/organizers/{}/events/{}/questions/'.format(organizer.slug, event.slug), diff --git a/src/tests/api/test_orders.py b/src/tests/api/test_orders.py index 077eb242c8..c81834cda8 100644 --- a/src/tests/api/test_orders.py +++ b/src/tests/api/test_orders.py @@ -8,6 +8,7 @@ import pytest from django.core import mail as djmail from django.utils.timezone import now from django_countries.fields import Country +from django_scopes import scopes_disabled from pytz import UTC from stripe.error import APIConnectionError from tests.plugins.stripe.test_provider import MockedCharge @@ -229,7 +230,8 @@ TEST_ORDER_RES = { @pytest.mark.django_db def test_order_list(token_client, organizer, event, order, item, taxrule, question): res = dict(TEST_ORDER_RES) - res["positions"][0]["id"] = order.positions.first().pk + with scopes_disabled(): + res["positions"][0]["id"] = order.positions.first().pk res["positions"][0]["item"] = item.pk res["positions"][0]["answers"][0]["question"] = question.pk res["last_modified"] = order.last_modified.isoformat().replace('+00:00', 'Z') @@ -285,7 +287,8 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi @pytest.mark.django_db def test_order_detail(token_client, organizer, event, order, item, taxrule, question): res = dict(TEST_ORDER_RES) - res["positions"][0]["id"] = order.positions.first().pk + with scopes_disabled(): + res["positions"][0]["id"] = order.positions.first().pk res["positions"][0]["item"] = item.pk res["fees"][0]["tax_rule"] = taxrule.pk res["positions"][0]["answers"][0]["question"] = question.pk @@ -338,7 +341,8 @@ def test_payment_confirm(token_client, organizer, event, order): resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/confirm/'.format( organizer.slug, event.slug, order.code ), format='json', data={'force': True}) - p = order.payments.get(local_id=2) + with scopes_disabled(): + p = order.payments.get(local_id=2) assert resp.status_code == 200 assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED @@ -353,7 +357,8 @@ def test_payment_cancel(token_client, organizer, event, order): resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/cancel/'.format( organizer.slug, event.slug, order.code )) - p = order.payments.get(local_id=2) + with scopes_disabled(): + p = order.payments.get(local_id=2) assert resp.status_code == 200 assert p.state == OrderPayment.PAYMENT_STATE_CANCELED @@ -365,7 +370,8 @@ def test_payment_cancel(token_client, organizer, event, order): @pytest.mark.django_db def test_payment_refund_fail(token_client, organizer, event, order, monkeypatch): - order.payments.last().confirm() + with scopes_disabled(): + order.payments.last().confirm() resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/2/refund/'.format( organizer.slug, event.slug, order.code ), format='json', data={ @@ -424,15 +430,16 @@ def test_payment_refund_success(token_client, organizer, event, order, monkeypat c.refunds.create = refund_create return c - p1 = order.payments.create( - provider='stripe', - state='confirmed', - amount=Decimal('23.00'), - payment_date=order.datetime, - info=json.dumps({ - 'id': 'ch_123345345' - }) - ) + with scopes_disabled(): + p1 = order.payments.create( + provider='stripe', + state='confirmed', + amount=Decimal('23.00'), + payment_date=order.datetime, + info=json.dumps({ + 'id': 'ch_123345345' + }) + ) monkeypatch.setattr("stripe.Charge.retrieve", charge_retr) resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/{}/refund/'.format( organizer.slug, event.slug, order.code, p1.local_id @@ -441,10 +448,11 @@ def test_payment_refund_success(token_client, organizer, event, order, monkeypat 'mark_canceled': False, }) assert resp.status_code == 200 - r = order.refunds.get(local_id=resp.data['local_id']) - assert r.provider == "stripe" - assert r.state == OrderRefund.REFUND_STATE_DONE - assert r.source == OrderRefund.REFUND_SOURCE_ADMIN + with scopes_disabled(): + r = order.refunds.get(local_id=resp.data['local_id']) + assert r.provider == "stripe" + assert r.state == OrderRefund.REFUND_STATE_DONE + assert r.source == OrderRefund.REFUND_SOURCE_ADMIN @pytest.mark.django_db @@ -457,15 +465,16 @@ def test_payment_refund_unavailable(token_client, organizer, event, order, monke c.refunds.create = refund_create return c - p1 = order.payments.create( - provider='stripe', - state='confirmed', - amount=Decimal('23.00'), - payment_date=order.datetime, - info=json.dumps({ - 'id': 'ch_123345345' - }) - ) + with scopes_disabled(): + p1 = order.payments.create( + provider='stripe', + state='confirmed', + amount=Decimal('23.00'), + payment_date=order.datetime, + info=json.dumps({ + 'id': 'ch_123345345' + }) + ) monkeypatch.setattr("stripe.Charge.retrieve", charge_retr) resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/payments/{}/refund/'.format( organizer.slug, event.slug, order.code, p1.local_id @@ -475,7 +484,8 @@ def test_payment_refund_unavailable(token_client, organizer, event, order, monke }) assert resp.status_code == 400 assert resp.data == {'detail': 'External error: We had trouble communicating with Stripe. Please try again and contact support if the problem persists.'} - r = order.refunds.last() + with scopes_disabled(): + r = order.refunds.last() assert r.provider == "stripe" assert r.state == OrderRefund.REFUND_STATE_FAILED assert r.source == OrderRefund.REFUND_SOURCE_ADMIN @@ -499,13 +509,15 @@ def test_refund_detail(token_client, organizer, event, order): @pytest.mark.django_db def test_refund_done(token_client, organizer, event, order): - r = order.refunds.get(local_id=1) + with scopes_disabled(): + r = order.refunds.get(local_id=1) r.state = 'transit' r.save() resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/done/'.format( organizer.slug, event.slug, order.code )) - r = order.refunds.get(local_id=1) + with scopes_disabled(): + r = order.refunds.get(local_id=1) assert resp.status_code == 200 assert r.state == OrderRefund.REFUND_STATE_DONE @@ -517,12 +529,14 @@ def test_refund_done(token_client, organizer, event, order): @pytest.mark.django_db def test_refund_process_mark_refunded(token_client, organizer, event, order): - p = order.payments.get(local_id=1) - p.create_external_refund() + with scopes_disabled(): + p = order.payments.get(local_id=1) + p.create_external_refund() resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/2/process/'.format( organizer.slug, event.slug, order.code ), format='json', data={'mark_canceled': True}) - r = order.refunds.get(local_id=1) + with scopes_disabled(): + r = order.refunds.get(local_id=1) assert resp.status_code == 200 assert r.state == OrderRefund.REFUND_STATE_DONE order.refresh_from_db() @@ -536,12 +550,14 @@ def test_refund_process_mark_refunded(token_client, organizer, event, order): @pytest.mark.django_db def test_refund_process_mark_pending(token_client, organizer, event, order): - p = order.payments.get(local_id=1) - p.create_external_refund() + with scopes_disabled(): + p = order.payments.get(local_id=1) + p.create_external_refund() resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/2/process/'.format( organizer.slug, event.slug, order.code ), format='json', data={'mark_canceled': False}) - r = order.refunds.get(local_id=1) + with scopes_disabled(): + r = order.refunds.get(local_id=1) assert resp.status_code == 200 assert r.state == OrderRefund.REFUND_STATE_DONE order.refresh_from_db() @@ -550,13 +566,15 @@ def test_refund_process_mark_pending(token_client, organizer, event, order): @pytest.mark.django_db def test_refund_cancel(token_client, organizer, event, order): - r = order.refunds.get(local_id=1) + with scopes_disabled(): + r = order.refunds.get(local_id=1) r.state = 'transit' r.save() resp = token_client.post('/api/v1/organizers/{}/events/{}/orders/{}/refunds/1/cancel/'.format( organizer.slug, event.slug, order.code )) - r = order.refunds.get(local_id=1) + with scopes_disabled(): + r = order.refunds.get(local_id=1) assert resp.status_code == 200 assert r.state == OrderRefund.REFUND_STATE_CANCELED @@ -571,10 +589,11 @@ def test_orderposition_list(token_client, organizer, event, order, item, subeven i2 = copy.copy(item) i2.pk = None i2.save() - var = item.variations.create(value="Children") - var2 = item.variations.create(value="Children") - res = dict(TEST_ORDERPOSITION_RES) - op = order.positions.first() + with scopes_disabled(): + var = item.variations.create(value="Children") + var2 = item.variations.create(value="Children") + res = dict(TEST_ORDERPOSITION_RES) + op = order.positions.first() op.variation = var op.save() res["id"] = op.pk @@ -665,8 +684,9 @@ def test_orderposition_list(token_client, organizer, event, order, item, subeven '/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug)) assert [] == resp.data['results'] - cl = event.checkin_lists.create(name="Default") - op.checkins.create(datetime=datetime.datetime(2017, 12, 26, 10, 0, 0, tzinfo=UTC), list=cl) + with scopes_disabled(): + cl = event.checkin_lists.create(name="Default") + op.checkins.create(datetime=datetime.datetime(2017, 12, 26, 10, 0, 0, tzinfo=UTC), list=cl) res['checkins'] = [{'datetime': '2017-12-26T10:00:00Z', 'list': cl.pk}] resp = token_client.get( '/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug)) @@ -692,7 +712,8 @@ def test_orderposition_list(token_client, organizer, event, order, item, subeven @pytest.mark.django_db def test_orderposition_detail(token_client, organizer, event, order, item, question): res = dict(TEST_ORDERPOSITION_RES) - op = order.positions.first() + with scopes_disabled(): + op = order.positions.first() res["id"] = op.pk res["item"] = item.pk res["answers"][0]["question"] = question.pk @@ -711,7 +732,8 @@ def test_orderposition_detail(token_client, organizer, event, order, item, quest @pytest.mark.django_db def test_orderposition_detail_no_canceled(token_client, organizer, event, order, item, question): - op = order.all_positions.filter(canceled=True).first() + with scopes_disabled(): + op = order.all_positions.filter(canceled=True).first() resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(organizer.slug, event.slug, op.pk)) assert resp.status_code == 404 @@ -719,33 +741,36 @@ def test_orderposition_detail_no_canceled(token_client, organizer, event, order, @pytest.mark.django_db def test_orderposition_delete(token_client, organizer, event, order, item, question): - op = order.positions.first() + with scopes_disabled(): + op = order.positions.first() resp = token_client.delete('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format( organizer.slug, event.slug, op.pk )) assert resp.status_code == 400 assert resp.data == ['This operation would leave the order empty. Please cancel the order itself instead.'] - op2 = OrderPosition.objects.create( - order=order, - item=item, - variation=None, - price=Decimal("23"), - attendee_name_parts={"full_name": "Peter", "_scheme": "full"}, - secret="foobar", - pseudonymization_id="BAZ", - ) - order.refresh_from_db() - order.total = Decimal('46') - order.save() - assert order.positions.count() == 2 + with scopes_disabled(): + op2 = OrderPosition.objects.create( + order=order, + item=item, + variation=None, + price=Decimal("23"), + attendee_name_parts={"full_name": "Peter", "_scheme": "full"}, + secret="foobar", + pseudonymization_id="BAZ", + ) + order.refresh_from_db() + order.total = Decimal('46') + order.save() + assert order.positions.count() == 2 resp = token_client.delete('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format( organizer.slug, event.slug, op2.pk )) assert resp.status_code == 204 - assert order.positions.count() == 1 - assert order.all_positions.count() == 3 + with scopes_disabled(): + assert order.positions.count() == 1 + assert order.all_positions.count() == 3 order.refresh_from_db() assert order.total == Decimal('23.25') @@ -822,7 +847,8 @@ def test_invoice_list(token_client, organizer, event, order, invoice): organizer.slug, event.slug)) assert [] == resp.data['results'] - ic = generate_cancellation(invoice) + with scopes_disabled(): + ic = generate_cancellation(invoice) resp = token_client.get('/api/v1/organizers/{}/events/{}/invoices/?is_cancellation=false'.format( organizer.slug, event.slug)) @@ -854,7 +880,8 @@ def test_invoice_detail(token_client, organizer, event, invoice): @pytest.mark.django_db def test_invoice_regenerate(token_client, organizer, event, invoice): - InvoiceAddress.objects.filter(order=invoice.order).update(company="ACME Ltd") + with scopes_disabled(): + InvoiceAddress.objects.filter(order=invoice.order).update(company="ACME Ltd") resp = token_client.post('/api/v1/organizers/{}/events/{}/invoices/{}/regenerate/'.format( organizer.slug, event.slug, invoice.number @@ -866,7 +893,8 @@ def test_invoice_regenerate(token_client, organizer, event, invoice): @pytest.mark.django_db def test_invoice_reissue(token_client, organizer, event, invoice): - InvoiceAddress.objects.filter(order=invoice.order).update(company="ACME Ltd") + with scopes_disabled(): + InvoiceAddress.objects.filter(order=invoice.order).update(company="ACME Ltd") resp = token_client.post('/api/v1/organizers/{}/events/{}/invoices/{}/reissue/'.format( organizer.slug, event.slug, invoice.number @@ -874,8 +902,9 @@ def test_invoice_reissue(token_client, organizer, event, invoice): assert resp.status_code == 204 invoice.refresh_from_db() assert "ACME Ltd" not in invoice.invoice_to - assert invoice.order.invoices.count() == 3 - invoice = invoice.order.invoices.last() + with scopes_disabled(): + assert invoice.order.invoices.count() == 3 + invoice = invoice.order.invoices.last() assert "ACME Ltd" in invoice.invoice_to @@ -1009,7 +1038,8 @@ def test_order_mark_canceled_expired(token_client, organizer, event, order): def test_order_mark_paid_canceled_keep_fee(token_client, organizer, event, order): order.status = Order.STATUS_PAID order.save() - order.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=order.total) + with scopes_disabled(): + order.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=order.total) resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/{}/mark_canceled/'.format( organizer.slug, event.slug, order.code @@ -1186,7 +1216,8 @@ def test_order_extend_expired_quota_waiting_list(token_client, organizer, event, order.save() quota.size = 1 quota.save() - event.waitinglistentries.create(item=item, email='foo@bar.com') + with scopes_disabled(): + event.waitinglistentries.create(item=item, email='foo@bar.com') newdate = (now() + datetime.timedelta(days=20)).strftime("%Y-%m-%d") resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/{}/extend/'.format( @@ -1353,7 +1384,8 @@ def test_order_create(token_client, organizer, event, item, quota, question): ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) assert o.email == "dummy@dummy.test" assert o.locale == "en" assert o.total == Decimal('23.25') @@ -1361,24 +1393,28 @@ def test_order_create(token_client, organizer, event, item, quota, question): assert o.sales_channel == "web" assert not o.testmode - p = o.payments.first() + with scopes_disabled(): + p = o.payments.first() assert p.provider == "banktransfer" assert p.amount == o.total assert p.state == "created" - fee = o.fees.first() + with scopes_disabled(): + fee = o.fees.first() assert fee.fee_type == "payment" assert fee.value == Decimal('0.25') ia = o.invoice_address assert ia.company == "Sample company" assert ia.name_parts == {"full_name": "Fo", "_scheme": "full"} assert ia.name_cached == "Fo" - assert o.positions.count() == 1 - pos = o.positions.first() + with scopes_disabled(): + assert o.positions.count() == 1 + pos = o.positions.first() assert pos.item == item assert pos.price == Decimal("23.00") assert pos.attendee_name_parts == {"full_name": "Peter", "_scheme": "full"} - answ = pos.answers.first() + with scopes_disabled(): + answ = pos.answers.first() assert answ.question == question assert answ.answer == "S" @@ -1395,9 +1431,10 @@ def test_order_create_invoice_address_optional(token_client, organizer, event, i ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - with pytest.raises(InvoiceAddress.DoesNotExist): - o.invoice_address + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + with pytest.raises(InvoiceAddress.DoesNotExist): + o.invoice_address @pytest.mark.django_db @@ -1412,7 +1449,8 @@ def test_order_create_sales_channel_optional(token_client, organizer, event, ite ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) assert o.sales_channel == "web" @@ -1443,7 +1481,8 @@ def test_order_create_in_test_mode(token_client, organizer, event, item, quota, ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) assert o.testmode @@ -1460,8 +1499,9 @@ def test_order_create_attendee_name_optional(token_client, organizer, event, ite ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - assert o.positions.first().attendee_name_parts == {} + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert o.positions.first().attendee_name_parts == {} @pytest.mark.django_db @@ -1484,8 +1524,10 @@ def test_order_create_legacy_attendee_name(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - assert o.positions.first().attendee_name_parts == {"_legacy": "Peter"} + + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert o.positions.first().attendee_name_parts == {"_legacy": "Peter"} @pytest.mark.django_db @@ -1508,8 +1550,9 @@ def test_order_create_legacy_invoice_name(token_client, organizer, event, item, ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - assert o.invoice_address.name_parts == {"_legacy": "Peter"} + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert o.invoice_address.name_parts == {"_legacy": "Peter"} @pytest.mark.django_db @@ -1524,7 +1567,8 @@ def test_order_create_code_optional(token_client, organizer, event, item, quota, ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) assert o.code == "ABCDE" resp = token_client.post( @@ -1557,7 +1601,8 @@ def test_order_email_optional(token_client, organizer, event, item, quota, quest ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) assert not o.email @@ -1572,7 +1617,6 @@ def test_order_create_payment_info_optional(token_client, organizer, event, item ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) res['payment_info'] = { 'foo': { @@ -1586,9 +1630,10 @@ def test_order_create_payment_info_optional(token_client, organizer, event, item ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) - p = o.payments.first() + p = o.payments.first() assert p.provider == "banktransfer" assert p.amount == o.total assert json.loads(p.info) == res['payment_info'] @@ -1605,8 +1650,9 @@ def test_order_create_position_secret_optional(token_client, organizer, event, i ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - assert o.positions.first().secret + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert o.positions.first().secret res['positions'][0]['secret'] = "aaa" resp = token_client.post( @@ -1615,8 +1661,9 @@ def test_order_create_position_secret_optional(token_client, organizer, event, i ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - assert o.positions.first().secret == "aaa" + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert o.positions.first().secret == "aaa" resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/'.format( @@ -1642,15 +1689,17 @@ def test_order_create_tax_rules(token_client, organizer, event, item, quota, que ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - fee = o.fees.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + fee = o.fees.first() assert fee.fee_type == "payment" assert fee.value == Decimal('0.25') assert fee.tax_rate == Decimal('19.00') assert fee.tax_rule == taxrule ia = o.invoice_address assert ia.company == "Sample company" - pos = o.positions.first() + with scopes_disabled(): + pos = o.positions.first() assert pos.item == item assert pos.tax_rate == Decimal('19.00') assert pos.tax_value == Decimal('3.67') @@ -1765,8 +1814,9 @@ def test_order_create_item_validation(token_client, organizer, event, item, item assert resp.status_code == 400 assert resp.data == {'positions': [{'item': ['The specified item does not belong to this event.']}]} - var2 = item2.variations.create(value="A") - quota.variations.add(var2) + with scopes_disabled(): + var2 = item2.variations.create(value="A") + quota.variations.add(var2) res['positions'][0]['item'] = item.pk res['positions'][0]['variation'] = var2.pk @@ -1778,7 +1828,8 @@ def test_order_create_item_validation(token_client, organizer, event, item, item assert resp.status_code == 400 assert resp.data == {'positions': [{'variation': ['You cannot specify a variation for this item.']}]} - var1 = item.variations.create(value="A") + with scopes_disabled(): + var1 = item.variations.create(value="A") res['positions'][0]['item'] = item.pk res['positions'][0]['variation'] = var1.pk resp = token_client.post( @@ -1789,7 +1840,8 @@ def test_order_create_item_validation(token_client, organizer, event, item, item assert resp.status_code == 400 assert resp.data == {'positions': [{'item': ['The product "Budget Ticket" is not assigned to a quota.']}]} - quota.variations.add(var1) + with scopes_disabled(): + quota.variations.add(var1) resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/'.format( organizer.slug, event.slug @@ -1850,9 +1902,10 @@ def test_order_create_positionids_addons(token_client, organizer, event, item, q ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos1 = o.positions.first() - pos2 = o.positions.last() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos1 = o.positions.first() + pos2 = o.positions.last() assert pos2.addon_to == pos1 @@ -2046,11 +2099,13 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu assert resp.data == {'positions': [ {'answers': [{'non_field_errors': ['You need to specify options if the question is of a choice type.']}]}]} - question.options.create(answer="L") - res['positions'][0]['answers'][0]['options'] = [ - question.options.first().pk, - question.options.last().pk, - ] + with scopes_disabled(): + question.options.create(answer="L") + with scopes_disabled(): + res['positions'][0]['answers'][0]['options'] = [ + question.options.first().pk, + question.options.last().pk, + ] resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/'.format( organizer.slug, event.slug @@ -2073,19 +2128,21 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu question.type = Question.TYPE_CHOICE_MULTIPLE question.save() - res['positions'][0]['answers'][0]['options'] = [ - question.options.first().pk, - question.options.last().pk, - ] + with scopes_disabled(): + res['positions'][0]['answers'][0]['options'] = [ + question.options.first().pk, + question.options.last().pk, + ] resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/'.format( organizer.slug, event.slug ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.question == question assert answ.answer == "XL, L" @@ -2099,9 +2156,10 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.answer == "3.45" question.type = Question.TYPE_NUMBER @@ -2126,9 +2184,10 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.answer == "True" question.type = Question.TYPE_BOOLEAN @@ -2140,9 +2199,10 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.answer == "False" question.type = Question.TYPE_BOOLEAN @@ -2166,9 +2226,10 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.answer == "2018-05-14" question.type = Question.TYPE_DATE @@ -2192,9 +2253,10 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.answer == "2018-05-14 13:00:00+00:00" question.type = Question.TYPE_DATETIME @@ -2219,9 +2281,10 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - pos = o.positions.first() - answ = pos.answers.first() + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + pos = o.positions.first() + answ = pos.answers.first() assert answ.answer == "13:00:00" question.type = Question.TYPE_TIME @@ -2310,11 +2373,12 @@ def test_order_create_quota_consume_cart(token_client, organizer, event, item, q res['positions'][0]['item'] = item.pk res['positions'][0]['answers'][0]['question'] = question.pk - cr = CartPosition.objects.create( - event=event, cart_id="uxLJBUMEcnxOLI2EuxLYN1hWJq9GKu4yWL9FEgs2m7M0vdFi@api", item=item, - price=23, - expires=now() + datetime.timedelta(hours=3) - ) + with scopes_disabled(): + cr = CartPosition.objects.create( + event=event, cart_id="uxLJBUMEcnxOLI2EuxLYN1hWJq9GKu4yWL9FEgs2m7M0vdFi@api", item=item, + price=23, + expires=now() + datetime.timedelta(hours=3) + ) quota.size = 1 quota.save() @@ -2337,7 +2401,8 @@ def test_order_create_quota_consume_cart(token_client, organizer, event, item, q ), format='json', data=res ) assert resp.status_code == 201 - assert not CartPosition.objects.filter(pk=cr.pk).exists() + with scopes_disabled(): + assert not CartPosition.objects.filter(pk=cr.pk).exists() @pytest.mark.django_db @@ -2353,11 +2418,13 @@ def test_order_create_free(token_client, organizer, event, item, quota, question ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) assert o.total == Decimal('0.00') assert o.status == Order.STATUS_PAID - p = o.payments.first() + with scopes_disabled(): + p = o.payments.first() assert p.provider == "free" assert p.amount == o.total assert p.state == "confirmed" @@ -2437,10 +2504,11 @@ def test_order_create_paid_generate_invoice(token_client, organizer, event, item ), format='json', data=res ) assert resp.status_code == 201 - o = Order.objects.get(code=resp.data['code']) - assert o.invoices.count() == 1 + with scopes_disabled(): + o = Order.objects.get(code=resp.data['code']) + assert o.invoices.count() == 1 - p = o.payments.first() + p = o.payments.first() assert p.provider == "banktransfer" assert p.amount == o.total assert p.state == "confirmed" @@ -2472,7 +2540,8 @@ def test_refund_create(token_client, organizer, event, order): ), format='json', data=res ) assert resp.status_code == 201 - r = order.refunds.get(local_id=resp.data['local_id']) + with scopes_disabled(): + r = order.refunds.get(local_id=resp.data['local_id']) assert r.provider == "manual" assert r.amount == Decimal("23.00") assert r.state == "created" @@ -2493,7 +2562,8 @@ def test_refund_create_mark_refunded(token_client, organizer, event, order): ), format='json', data=res ) assert resp.status_code == 201 - r = order.refunds.get(local_id=resp.data['local_id']) + with scopes_disabled(): + r = order.refunds.get(local_id=resp.data['local_id']) assert r.provider == "manual" assert r.amount == Decimal("23.00") assert r.state == "created" @@ -2515,7 +2585,8 @@ def test_refund_optional_fields(token_client, organizer, event, order): ), format='json', data=res ) assert resp.status_code == 201 - r = order.refunds.get(local_id=resp.data['local_id']) + with scopes_disabled(): + r = order.refunds.get(local_id=resp.data['local_id']) assert r.provider == "manual" assert r.amount == Decimal("23.00") assert r.state == "created" @@ -2562,19 +2633,21 @@ def test_order_delete_test_mode(token_client, organizer, event, order): ) ) assert resp.status_code == 204 - assert not Order.objects.filter(code=order.code).exists() + with scopes_disabled(): + assert not Order.objects.filter(code=order.code).exists() @pytest.mark.django_db def test_order_delete_test_mode_voucher(token_client, organizer, event, order, item): order.testmode = True order.save() - q = event.quotas.create(name="Quota") - q.items.add(item) - voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=1) - op = order.positions.first() - op.voucher = voucher - op.save() + with scopes_disabled(): + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=1) + op = order.positions.first() + op.voucher = voucher + op.save() assert voucher.redeemed == 1 @@ -2584,7 +2657,8 @@ def test_order_delete_test_mode_voucher(token_client, organizer, event, order, i ) ) assert resp.status_code == 204 - assert not Order.objects.filter(code=order.code).exists() + with scopes_disabled(): + assert not Order.objects.filter(code=order.code).exists() voucher.refresh_from_db() assert voucher.redeemed == 0 @@ -2593,12 +2667,13 @@ def test_order_delete_test_mode_voucher(token_client, organizer, event, order, i def test_order_delete_test_mode_voucher_cancelled_position(token_client, organizer, event, order, item): order.testmode = True order.save() - q = event.quotas.create(name="Quota") - q.items.add(item) - voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42) - op = order.all_positions.last() - op.voucher = voucher - op.save() + with scopes_disabled(): + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42) + op = order.all_positions.last() + op.voucher = voucher + op.save() resp = token_client.delete( '/api/v1/organizers/{}/events/{}/orders/{}/'.format( @@ -2606,22 +2681,24 @@ def test_order_delete_test_mode_voucher_cancelled_position(token_client, organiz ) ) assert resp.status_code == 204 - assert not Order.objects.filter(code=order.code).exists() + with scopes_disabled(): + assert not Order.objects.filter(code=order.code).exists() voucher.refresh_from_db() assert voucher.redeemed == 42 @pytest.mark.django_db def test_order_delete_test_mode_voucher_cancelled_order(token_client, organizer, event, order, item): - order.testmode = True - order.status = Order.STATUS_CANCELED - order.save() - q = event.quotas.create(name="Quota") - q.items.add(item) - voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42) - op = order.positions.first() - op.voucher = voucher - op.save() + with scopes_disabled(): + order.testmode = True + order.status = Order.STATUS_CANCELED + order.save() + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q, redeemed=42) + op = order.positions.first() + op.voucher = voucher + op.save() resp = token_client.delete( '/api/v1/organizers/{}/events/{}/orders/{}/'.format( @@ -2629,7 +2706,8 @@ def test_order_delete_test_mode_voucher_cancelled_order(token_client, organizer, ) ) assert resp.status_code == 204 - assert not Order.objects.filter(code=order.code).exists() + with scopes_disabled(): + assert not Order.objects.filter(code=order.code).exists() voucher.refresh_from_db() assert voucher.redeemed == 42 @@ -2697,11 +2775,12 @@ def test_order_update_allowed_fields(token_client, organizer, event, order): assert str(order.invoice_address.country) == "FR" assert not order.invoice_address.vat_id_validated assert order.invoice_address.city == "Paris" - assert order.all_logentries().get(action_type='pretix.event.order.comment') - assert order.all_logentries().get(action_type='pretix.event.order.checkin_attention') - assert order.all_logentries().get(action_type='pretix.event.order.contact.changed') - assert order.all_logentries().get(action_type='pretix.event.order.locale.changed') - assert order.all_logentries().get(action_type='pretix.event.order.modified') + with scopes_disabled(): + assert order.all_logentries().get(action_type='pretix.event.order.comment') + assert order.all_logentries().get(action_type='pretix.event.order.checkin_attention') + assert order.all_logentries().get(action_type='pretix.event.order.contact.changed') + assert order.all_logentries().get(action_type='pretix.event.order.locale.changed') + assert order.all_logentries().get(action_type='pretix.event.order.modified') @pytest.mark.django_db @@ -2847,7 +2926,8 @@ def test_order_create_invoice(token_client, organizer, event, order): @pytest.mark.django_db def test_order_regenerate_secrets(token_client, organizer, event, order): s = order.secret - ps = order.positions.first().secret + with scopes_disabled(): + ps = order.positions.first().secret resp = token_client.post( '/api/v1/organizers/{}/events/{}/orders/{}/regenerate_secrets/'.format( organizer.slug, event.slug, order.code @@ -2856,7 +2936,8 @@ def test_order_regenerate_secrets(token_client, organizer, event, order): assert resp.status_code == 200 order.refresh_from_db() assert s != order.secret - assert ps != order.positions.first().secret + with scopes_disabled(): + assert ps != order.positions.first().secret @pytest.mark.django_db @@ -2882,7 +2963,8 @@ def test_order_resend_link(token_client, organizer, event, order): @pytest.mark.django_db def test_orderposition_price_calculation(token_client, organizer, event, order, item): - op = order.positions.first() + with scopes_disabled(): + op = order.positions.first() resp = token_client.post( '/api/v1/organizers/{}/events/{}/orderpositions/{}/price_calc/'.format(organizer.slug, event.slug, op.pk), data={ @@ -2901,8 +2983,9 @@ def test_orderposition_price_calculation(token_client, organizer, event, order, @pytest.mark.django_db def test_orderposition_price_calculation_item_with_tax(token_client, organizer, event, order, item, taxrule): - item2 = event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule) + op = order.positions.first() resp = token_client.post( '/api/v1/organizers/{}/events/{}/orderpositions/{}/price_calc/'.format(organizer.slug, event.slug, op.pk), data={ @@ -2922,9 +3005,10 @@ def test_orderposition_price_calculation_item_with_tax(token_client, organizer, @pytest.mark.django_db def test_orderposition_price_calculation_item_with_variation(token_client, organizer, event, order): - item2 = event.items.create(name="Budget Ticket", default_price=23) - var = item2.variations.create(default_price=12, value="XS") - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=23) + var = item2.variations.create(default_price=12, value="XS") + op = order.positions.first() resp = token_client.post( '/api/v1/organizers/{}/events/{}/orderpositions/{}/price_calc/'.format(organizer.slug, event.slug, op.pk), data={ @@ -2945,8 +3029,9 @@ def test_orderposition_price_calculation_item_with_variation(token_client, organ @pytest.mark.django_db def test_orderposition_price_calculation_subevent(token_client, organizer, event, order, subevent): - item2 = event.items.create(name="Budget Ticket", default_price=23) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=23) + op = order.positions.first() op.subevent = subevent op.save() resp = token_client.post( @@ -2969,10 +3054,11 @@ def test_orderposition_price_calculation_subevent(token_client, organizer, event @pytest.mark.django_db def test_orderposition_price_calculation_subevent_with_override(token_client, organizer, event, order, subevent): - item2 = event.items.create(name="Budget Ticket", default_price=23) - se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) - se2.subeventitem_set.create(item=item2, price=12) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=23) + se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) + se2.subeventitem_set.create(item=item2, price=12) + op = order.positions.first() op.subevent = subevent op.save() resp = token_client.post( @@ -2995,12 +3081,13 @@ def test_orderposition_price_calculation_subevent_with_override(token_client, or @pytest.mark.django_db def test_orderposition_price_calculation_voucher_matching(token_client, organizer, event, order, subevent, item): - item2 = event.items.create(name="Budget Ticket", default_price=23) - q = event.quotas.create(name="Quota") - q.items.add(item) - q.items.add(item2) - voucher = event.vouchers.create(price_mode="set", value=15, quota=q) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=23) + q = event.quotas.create(name="Quota") + q.items.add(item) + q.items.add(item2) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q) + op = order.positions.first() op.voucher = voucher op.save() resp = token_client.post( @@ -3022,11 +3109,12 @@ def test_orderposition_price_calculation_voucher_matching(token_client, organize @pytest.mark.django_db def test_orderposition_price_calculation_voucher_not_matching(token_client, organizer, event, order, subevent, item): - item2 = event.items.create(name="Budget Ticket", default_price=23) - q = event.quotas.create(name="Quota") - q.items.add(item) - voucher = event.vouchers.create(price_mode="set", value=15, quota=q) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=23) + q = event.quotas.create(name="Quota") + q.items.add(item) + voucher = event.vouchers.create(price_mode="set", value=15, quota=q) + op = order.positions.first() op.voucher = voucher op.save() resp = token_client.post( @@ -3050,8 +3138,9 @@ def test_orderposition_price_calculation_voucher_not_matching(token_client, orga def test_orderposition_price_calculation_net_price(token_client, organizer, event, order, subevent, item, taxrule): taxrule.price_includes_tax = False taxrule.save() - item2 = event.items.create(name="Budget Ticket", default_price=10, tax_rule=taxrule) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=10, tax_rule=taxrule) + op = order.positions.first() resp = token_client.post( '/api/v1/organizers/{}/events/{}/orderpositions/{}/price_calc/'.format(organizer.slug, event.slug, op.pk), data={ @@ -3080,8 +3169,9 @@ def test_orderposition_price_calculation_reverse_charge(token_client, organizer, order.invoice_address.vat_id_validated = True order.invoice_address.country = Country('AT') order.invoice_address.save() - item2 = event.items.create(name="Budget Ticket", default_price=10, tax_rule=taxrule) - op = order.positions.first() + with scopes_disabled(): + item2 = event.items.create(name="Budget Ticket", default_price=10, tax_rule=taxrule) + op = order.positions.first() resp = token_client.post( '/api/v1/organizers/{}/events/{}/orderpositions/{}/price_calc/'.format(organizer.slug, event.slug, op.pk), data={ diff --git a/src/tests/api/test_subevents.py b/src/tests/api/test_subevents.py index d8c5a1e532..d4f716472e 100644 --- a/src/tests/api/test_subevents.py +++ b/src/tests/api/test_subevents.py @@ -4,6 +4,7 @@ from unittest import mock import pytest from django_countries.fields import Country +from django_scopes import scopes_disabled from pytz import UTC from pretix.base.models import InvoiceAddress, Order, OrderPosition @@ -159,9 +160,10 @@ def test_subevent_create(token_client, organizer, event, subevent, meta_prop, it ) assert resp.status_code == 201 assert not subevent.active - assert subevent.meta_values.filter( - property__name=meta_prop.name, value="Workshop" - ).exists() + with scopes_disabled(): + assert subevent.meta_values.filter( + property__name=meta_prop.name, value="Workshop" + ).exists() resp = token_client.post( '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug), @@ -217,7 +219,8 @@ def test_subevent_create(token_client, organizer, event, subevent, meta_prop, it ) assert resp.status_code == 201 assert item.default_price == Decimal('23.00') - assert event.subevents.get(id=resp.data['id']).item_price_overrides[item.pk] == Decimal('23.42') + with scopes_disabled(): + assert event.subevents.get(id=resp.data['id']).item_price_overrides[item.pk] == Decimal('23.42') resp = token_client.post( '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug), @@ -261,7 +264,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - subevent = event.subevents.get(id=subevent.id) + with scopes_disabled(): + subevent = event.subevents.get(id=subevent.id) assert subevent.date_from == datetime(2018, 12, 27, 10, 0, tzinfo=UTC) assert subevent.date_to == datetime(2018, 12, 28, 10, 0, tzinfo=UTC) @@ -297,9 +301,10 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert organizer.events.get(slug=event.slug).subevents.get(id=resp.data['id']).meta_values.filter( - property__name=meta_prop.name, value="Conference" - ).exists() + with scopes_disabled(): + assert organizer.events.get(slug=event.slug).subevents.get(id=resp.data['id']).meta_values.filter( + property__name=meta_prop.name, value="Conference" + ).exists() resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -310,9 +315,10 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert not subevent.meta_values.filter( - property__name=meta_prop.name - ).exists() + with scopes_disabled(): + assert not subevent.meta_values.filter( + property__name=meta_prop.name + ).exists() resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -339,7 +345,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert subevent.items.get(id=item.pk).default_price == Decimal('23.00') + with scopes_disabled(): + assert subevent.items.get(id=item.pk).default_price == Decimal('23.00') assert subevent.item_price_overrides[item.pk] == Decimal('99.99') resp = token_client.patch( @@ -355,7 +362,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('88.88') + with scopes_disabled(): + assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('88.88') resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -370,7 +378,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides + with scopes_disabled(): + assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -385,7 +394,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('12.34') + with scopes_disabled(): + assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('12.34') resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -395,7 +405,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides + with scopes_disabled(): + assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -440,8 +451,9 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert subevent.variations.get(id=variations[0].pk).default_price == Decimal('12.00') - assert subevent.var_price_overrides[variations[0].pk] == Decimal('99.99') + with scopes_disabled(): + assert subevent.variations.get(id=variations[0].pk).default_price == Decimal('12.00') + assert subevent.var_price_overrides[variations[0].pk] == Decimal('99.99') resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -456,7 +468,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('88.88') + with scopes_disabled(): + assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('88.88') resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -471,7 +484,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides + with scopes_disabled(): + assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -486,7 +500,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('12.34') + with scopes_disabled(): + assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('12.34') resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -496,7 +511,8 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2, format='json' ) assert resp.status_code == 200 - assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides + with scopes_disabled(): + assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides resp = token_client.patch( '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk), @@ -544,7 +560,8 @@ def test_subevent_delete(token_client, organizer, event, subevent): resp = token_client.delete('/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk)) assert resp.status_code == 204 - assert not event.subevents.filter(pk=subevent.id).exists() + with scopes_disabled(): + assert not event.subevents.filter(pk=subevent.id).exists() @pytest.mark.django_db @@ -554,4 +571,5 @@ def test_subevent_with_order_position_not_delete(token_client, organizer, event, assert resp.status_code == 403 assert resp.content.decode() == '{"detail":"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."}' - assert event.subevents.filter(pk=subevent.id).exists() + with scopes_disabled(): + assert event.subevents.filter(pk=subevent.id).exists() diff --git a/src/tests/api/test_taxrules.py b/src/tests/api/test_taxrules.py index 05c072027e..3899df9763 100644 --- a/src/tests/api/test_taxrules.py +++ b/src/tests/api/test_taxrules.py @@ -1,6 +1,7 @@ from decimal import Decimal import pytest +from django_scopes import scopes_disabled from pretix.base.models import TaxRule @@ -80,7 +81,8 @@ def test_rule_delete(token_client, organizer, event, taxrule): @pytest.mark.django_db def test_rule_delete_forbidden(token_client, organizer, event, taxrule): - event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule) + with scopes_disabled(): + event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule) resp = token_client.delete( '/api/v1/organizers/{}/events/{}/taxrules/{}/'.format(organizer.slug, event.slug, taxrule.pk), ) diff --git a/src/tests/api/test_vouchers.py b/src/tests/api/test_vouchers.py index 8707e41872..4fe0906a52 100644 --- a/src/tests/api/test_vouchers.py +++ b/src/tests/api/test_vouchers.py @@ -5,6 +5,7 @@ from decimal import Decimal import pytest from django.utils import timezone from django.utils.timezone import now +from django_scopes import scopes_disabled from pytz import UTC from pretix.base.models import Event, Voucher @@ -58,7 +59,8 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota, sube i2 = copy.copy(item) i2.pk = None i2.save() - var2 = i2.variations.create(value="foo") + with scopes_disabled(): + var2 = i2.variations.create(value="foo") resp = token_client.get('/api/v1/organizers/{}/events/{}/vouchers/'.format(organizer.slug, event.slug)) assert resp.status_code == 200 @@ -136,9 +138,10 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota, sube ) assert [] == resp.data['results'] - var = item.variations.create(value='VIP') - voucher.variation = var - voucher.save() + with scopes_disabled(): + var = item.variations.create(value='VIP') + voucher.variation = var + voucher.save() res['variation'] = var.pk resp = token_client.get( '/api/v1/organizers/{}/events/{}/vouchers/?variation={}'.format(organizer.slug, event.slug, var.pk) @@ -208,7 +211,8 @@ def test_voucher_list(token_client, organizer, event, voucher, item, quota, sube resp = token_client.get( '/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) assert [res] == resp.data['results'] - se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) + with scopes_disabled(): + se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) resp = token_client.get( '/api/v1/organizers/{}/events/{}/vouchers/?subevent={}'.format(organizer.slug, event.slug, se2.pk)) @@ -237,7 +241,8 @@ def create_voucher(token_client, organizer, event, data, expected_failure=False) assert resp.status_code == 400 else: assert resp.status_code == 201 - return Voucher.objects.get(pk=resp.data['id']) + with scopes_disabled(): + return Voucher.objects.get(pk=resp.data['id']) @pytest.mark.django_db @@ -324,7 +329,8 @@ def test_create_non_blocking_item_voucher(token_client, organizer, event, item): @pytest.mark.django_db def test_create_non_blocking_variation_voucher(token_client, organizer, event, item): - variation = item.variations.create(value="XL") + with scopes_disabled(): + variation = item.variations.create(value="XL") v = create_voucher( token_client, organizer, event, data={ @@ -394,7 +400,8 @@ def test_create_blocking_item_voucher_quota_full_invalid(token_client, organizer @pytest.mark.django_db def test_create_blocking_variation_voucher_quota_free(token_client, organizer, event, item, quota): - variation = item.variations.create(value="XL") + with scopes_disabled(): + variation = item.variations.create(value="XL") quota.variations.add(variation) v = create_voucher( token_client, organizer, event, @@ -421,7 +428,8 @@ def test_create_short_code(token_client, organizer, event, item): @pytest.mark.django_db def test_create_blocking_variation_voucher_quota_full(token_client, organizer, event, item, quota): - variation = item.variations.create(value="XL") + with scopes_disabled(): + variation = item.variations.create(value="XL") quota.variations.add(variation) quota.size = 0 quota.save() @@ -463,7 +471,8 @@ def test_create_blocking_quota_voucher_quota_full(token_client, organizer, event @pytest.mark.django_db def test_create_duplicate_code(token_client, organizer, event, quota): - v = event.vouchers.create(quota=quota) + with scopes_disabled(): + v = event.vouchers.create(quota=quota) create_voucher( token_client, organizer, event, data={ @@ -501,11 +510,12 @@ def test_subevent_required_for_blocking(token_client, organizer, event, item, su @pytest.mark.django_db def test_subevent_blocking_quota_free(token_client, organizer, event, item, quota, subevent): - se2 = event.subevents.create(name="Bar", date_from=now()) - quota.subevent = subevent - quota.save() - q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2) - q2.items.add(item) + with scopes_disabled(): + se2 = event.subevents.create(name="Bar", date_from=now()) + quota.subevent = subevent + quota.save() + q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2) + q2.items.add(item) v = create_voucher( token_client, organizer, event, @@ -521,12 +531,13 @@ def test_subevent_blocking_quota_free(token_client, organizer, event, item, quot @pytest.mark.django_db def test_subevent_blocking_quota_full(token_client, organizer, event, item, quota, subevent): - se2 = event.subevents.create(name="Bar", date_from=now()) - quota.subevent = subevent - quota.size = 0 - quota.save() - q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2) - q2.items.add(item) + with scopes_disabled(): + se2 = event.subevents.create(name="Bar", date_from=now()) + quota.subevent = subevent + quota.size = 0 + quota.save() + q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2) + q2.items.add(item) create_voucher( token_client, organizer, event, @@ -553,15 +564,16 @@ def change_voucher(token_client, organizer, event, voucher, data, expected_failu @pytest.mark.django_db def test_change_to_item_of_other_event(token_client, organizer, event, item): - e2 = Event.objects.create( - organizer=organizer, - name='Dummy2', - slug='dummy2', - date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC), - plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf' - ) - ticket2 = e2.items.create(name='Late-bird ticket', default_price=23) - v = event.vouchers.create(item=item) + with scopes_disabled(): + e2 = Event.objects.create( + organizer=organizer, + name='Dummy2', + slug='dummy2', + date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC), + plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf' + ) + ticket2 = e2.items.create(name='Late-bird ticket', default_price=23) + v = event.vouchers.create(item=item) change_voucher( token_client, organizer, event, v, data={ @@ -575,7 +587,8 @@ def test_change_to_item_of_other_event(token_client, organizer, event, item): @pytest.mark.django_db def test_change_non_blocking_voucher(token_client, organizer, event, item, quota): - v = event.vouchers.create(item=item) + with scopes_disabled(): + v = event.vouchers.create(item=item) change_voucher( token_client, organizer, event, v, data={ @@ -589,7 +602,8 @@ def test_change_non_blocking_voucher(token_client, organizer, event, item, quota @pytest.mark.django_db def test_change_voucher_reduce_max_usages(token_client, organizer, event, item, quota): - v = event.vouchers.create(item=item, max_usages=5, redeemed=3) + with scopes_disabled(): + v = event.vouchers.create(item=item, max_usages=5, redeemed=3) change_voucher( token_client, organizer, event, v, data={ @@ -604,7 +618,8 @@ def test_change_voucher_reduce_max_usages(token_client, organizer, event, item, def test_change_blocking_voucher_unchanged_quota_full(token_client, organizer, event, item, quota): quota.size = 0 quota.save() - v = event.vouchers.create(item=item, block_quota=True) + with scopes_disabled(): + v = event.vouchers.create(item=item, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -620,7 +635,8 @@ def test_change_blocking_voucher_unchanged_quota_full(token_client, organizer, e def test_change_voucher_to_blocking_quota_full(token_client, organizer, event, item, quota): quota.size = 0 quota.save() - v = event.vouchers.create(item=item) + with scopes_disabled(): + v = event.vouchers.create(item=item) change_voucher( token_client, organizer, event, v, data={ @@ -632,7 +648,8 @@ def test_change_voucher_to_blocking_quota_full(token_client, organizer, event, i @pytest.mark.django_db def test_change_voucher_to_blocking_quota_free(token_client, organizer, event, item, quota): - v = event.vouchers.create(item=item) + with scopes_disabled(): + v = event.vouchers.create(item=item) change_voucher( token_client, organizer, event, v, data={ @@ -646,8 +663,9 @@ def test_change_voucher_to_blocking_quota_free(token_client, organizer, event, i def test_change_voucher_validity_to_valid_quota_full(token_client, organizer, event, item, quota): quota.size = 0 quota.save() - v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3), - block_quota=True) + with scopes_disabled(): + v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3), + block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -660,8 +678,9 @@ def test_change_voucher_validity_to_valid_quota_full(token_client, organizer, ev @pytest.mark.django_db def test_change_voucher_validity_to_valid_quota_free(token_client, organizer, event, item, quota): - v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3), - block_quota=True) + with scopes_disabled(): + v = event.vouchers.create(item=item, valid_until=now() - datetime.timedelta(days=3), + block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -673,9 +692,10 @@ def test_change_voucher_validity_to_valid_quota_free(token_client, organizer, ev @pytest.mark.django_db def test_change_item_of_blocking_voucher_quota_free(token_client, organizer, event, item, quota): - ticket2 = event.items.create(name='Late-bird ticket', default_price=23) - quota.items.add(ticket2) - v = event.vouchers.create(item=item, block_quota=True) + with scopes_disabled(): + ticket2 = event.items.create(name='Late-bird ticket', default_price=23) + quota.items.add(ticket2) + v = event.vouchers.create(item=item, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -687,10 +707,11 @@ def test_change_item_of_blocking_voucher_quota_free(token_client, organizer, eve @pytest.mark.django_db def test_change_item_of_blocking_voucher_quota_full(token_client, organizer, event, item, quota): - ticket2 = event.items.create(name='Late-bird ticket', default_price=23) - quota2 = event.quotas.create(name='Late', size=0) - quota2.items.add(ticket2) - v = event.vouchers.create(item=item, block_quota=True) + with scopes_disabled(): + ticket2 = event.items.create(name='Late-bird ticket', default_price=23) + quota2 = event.quotas.create(name='Late', size=0) + quota2.items.add(ticket2) + v = event.vouchers.create(item=item, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -702,14 +723,15 @@ def test_change_item_of_blocking_voucher_quota_full(token_client, organizer, eve @pytest.mark.django_db def test_change_variation_of_blocking_voucher_quota_free(token_client, organizer, event): - shirt = event.items.create(name='Shirt', default_price=23) - vs = shirt.variations.create(value='S') - vm = shirt.variations.create(value='M') - qs = event.quotas.create(name='S', size=2) - qs.variations.add(vs) - qm = event.quotas.create(name='M', size=2) - qm.variations.add(vm) - v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) + with scopes_disabled(): + shirt = event.items.create(name='Shirt', default_price=23) + vs = shirt.variations.create(value='S') + vm = shirt.variations.create(value='M') + qs = event.quotas.create(name='S', size=2) + qs.variations.add(vs) + qm = event.quotas.create(name='M', size=2) + qm.variations.add(vm) + v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -721,13 +743,14 @@ def test_change_variation_of_blocking_voucher_quota_free(token_client, organizer @pytest.mark.django_db def test_change_variation_of_blocking_voucher_without_quota_change(token_client, organizer, event): - shirt = event.items.create(name='Shirt', default_price=23) - vs = shirt.variations.create(value='S') - vm = shirt.variations.create(value='M') - q = event.quotas.create(name='S', size=0) - q.variations.add(vs) - q.variations.add(vm) - v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) + with scopes_disabled(): + shirt = event.items.create(name='Shirt', default_price=23) + vs = shirt.variations.create(value='S') + vm = shirt.variations.create(value='M') + q = event.quotas.create(name='S', size=0) + q.variations.add(vs) + q.variations.add(vm) + v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -739,14 +762,15 @@ def test_change_variation_of_blocking_voucher_without_quota_change(token_client, @pytest.mark.django_db def test_change_variation_of_blocking_voucher_quota_full(token_client, organizer, event): - shirt = event.items.create(name='Shirt', default_price=23) - vs = shirt.variations.create(value='S') - vm = shirt.variations.create(value='M') - qs = event.quotas.create(name='S', size=2) - qs.variations.add(vs) - qm = event.quotas.create(name='M', size=0) - qm.variations.add(vm) - v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) + with scopes_disabled(): + shirt = event.items.create(name='Shirt', default_price=23) + vs = shirt.variations.create(value='S') + vm = shirt.variations.create(value='M') + qs = event.quotas.create(name='S', size=2) + qs.variations.add(vs) + qm = event.quotas.create(name='M', size=0) + qm.variations.add(vm) + v = event.vouchers.create(item=shirt, variation=vs, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -758,9 +782,10 @@ def test_change_variation_of_blocking_voucher_quota_full(token_client, organizer @pytest.mark.django_db def test_change_quota_of_blocking_voucher_quota_free(token_client, organizer, event): - qs = event.quotas.create(name='S', size=2) - qm = event.quotas.create(name='M', size=2) - v = event.vouchers.create(quota=qs, block_quota=True) + with scopes_disabled(): + qs = event.quotas.create(name='S', size=2) + qm = event.quotas.create(name='M', size=2) + v = event.vouchers.create(quota=qs, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -772,9 +797,10 @@ def test_change_quota_of_blocking_voucher_quota_free(token_client, organizer, ev @pytest.mark.django_db def test_change_quota_of_blocking_voucher_quota_full(token_client, organizer, event): - qs = event.quotas.create(name='S', size=2) - qm = event.quotas.create(name='M', size=0) - v = event.vouchers.create(quota=qs, block_quota=True) + with scopes_disabled(): + qs = event.quotas.create(name='S', size=2) + qm = event.quotas.create(name='M', size=0) + v = event.vouchers.create(quota=qs, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -786,11 +812,12 @@ def test_change_quota_of_blocking_voucher_quota_full(token_client, organizer, ev @pytest.mark.django_db def test_change_item_of_blocking_voucher_without_quota_change(token_client, organizer, event, item, quota): - quota.size = 0 - quota.save() - ticket2 = event.items.create(name='Standard Ticket', default_price=23) - quota.items.add(ticket2) - v = event.vouchers.create(item=item, block_quota=True) + with scopes_disabled(): + quota.size = 0 + quota.save() + ticket2 = event.items.create(name='Standard Ticket', default_price=23) + quota.items.add(ticket2) + v = event.vouchers.create(item=item, block_quota=True) change_voucher( token_client, organizer, event, v, data={ @@ -802,8 +829,9 @@ def test_change_item_of_blocking_voucher_without_quota_change(token_client, orga @pytest.mark.django_db def test_change_code_to_duplicate(token_client, organizer, event, item, quota): - v1 = event.vouchers.create(quota=quota) - v2 = event.vouchers.create(quota=quota) + with scopes_disabled(): + v1 = event.vouchers.create(quota=quota) + v2 = event.vouchers.create(quota=quota) change_voucher( token_client, organizer, event, v1, data={ @@ -815,13 +843,14 @@ def test_change_code_to_duplicate(token_client, organizer, event, item, quota): @pytest.mark.django_db def test_change_subevent_blocking_quota_free(token_client, organizer, event, item, quota, subevent): - quota.subevent = subevent - quota.save() - se2 = event.subevents.create(name="Bar", date_from=now()) - q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2) - q2.items.add(item) + with scopes_disabled(): + quota.subevent = subevent + quota.save() + se2 = event.subevents.create(name="Bar", date_from=now()) + q2 = event.quotas.create(event=event, name='Tickets', size=5, subevent=se2) + q2.items.add(item) - v = event.vouchers.create(item=item, block_quota=True, subevent=subevent) + v = event.vouchers.create(item=item, block_quota=True, subevent=subevent) change_voucher( token_client, organizer, event, v, data={ @@ -833,13 +862,14 @@ def test_change_subevent_blocking_quota_free(token_client, organizer, event, ite @pytest.mark.django_db def test_change_subevent_blocking_quota_full(token_client, organizer, event, item, quota, subevent): - quota.subevent = subevent - quota.save() - se2 = event.subevents.create(name="Bar", date_from=now()) - q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2) - q2.items.add(item) + with scopes_disabled(): + quota.subevent = subevent + quota.save() + se2 = event.subevents.create(name="Bar", date_from=now()) + q2 = event.quotas.create(event=event, name='Tickets', size=0, subevent=se2) + q2.items.add(item) - v = event.vouchers.create(item=item, block_quota=True, subevent=subevent) + v = event.vouchers.create(item=item, block_quota=True, subevent=subevent) change_voucher( token_client, organizer, event, v, data={ @@ -851,27 +881,32 @@ def test_change_subevent_blocking_quota_full(token_client, organizer, event, ite @pytest.mark.django_db def test_delete_voucher(token_client, organizer, event, quota): - v = event.vouchers.create(quota=quota) + with scopes_disabled(): + v = event.vouchers.create(quota=quota) resp = token_client.delete( '/api/v1/organizers/{}/events/{}/vouchers/{}/'.format(organizer.slug, event.slug, v.pk), ) assert resp.status_code == 204 - assert not event.vouchers.filter(pk=v.id).exists() + with scopes_disabled(): + assert not event.vouchers.filter(pk=v.id).exists() @pytest.mark.django_db def test_delete_voucher_redeemed(token_client, organizer, event, quota): - v = event.vouchers.create(quota=quota, redeemed=1) + with scopes_disabled(): + v = event.vouchers.create(quota=quota, redeemed=1) resp = token_client.delete( '/api/v1/organizers/{}/events/{}/vouchers/{}/'.format(organizer.slug, event.slug, v.pk), ) assert resp.status_code == 403 - assert event.vouchers.filter(pk=v.id).exists() + with scopes_disabled(): + assert event.vouchers.filter(pk=v.id).exists() @pytest.mark.django_db def test_redeemed_is_not_writable(token_client, organizer, event, item): - v = event.vouchers.create(item=item) + with scopes_disabled(): + v = event.vouchers.create(item=item) change_voucher( token_client, organizer, event, v, data={ @@ -919,13 +954,14 @@ def test_create_multiple_vouchers(token_client, organizer, event, item): ], format='json' ) assert resp.status_code == 201 - assert Voucher.objects.count() == 2 - assert resp.data[0]['code'] == 'ABCDEFGHI' - v1 = Voucher.objects.get(code='ABCDEFGHI') - assert not v1.block_quota - assert resp.data[1]['code'] == 'JKLMNOPQR' - v2 = Voucher.objects.get(code='JKLMNOPQR') - assert v2.block_quota + with scopes_disabled(): + assert Voucher.objects.count() == 2 + assert resp.data[0]['code'] == 'ABCDEFGHI' + v1 = Voucher.objects.get(code='ABCDEFGHI') + assert not v1.block_quota + assert resp.data[1]['code'] == 'JKLMNOPQR' + v2 = Voucher.objects.get(code='JKLMNOPQR') + assert v2.block_quota @pytest.mark.django_db @@ -967,7 +1003,8 @@ def test_create_multiple_vouchers_one_invalid(token_client, organizer, event, it ) assert resp.status_code == 400 assert resp.data == [{}, {'code': ['Ensure this field has at least 5 characters.']}] - assert Voucher.objects.count() == 0 + with scopes_disabled(): + assert Voucher.objects.count() == 0 @pytest.mark.django_db @@ -1009,4 +1046,5 @@ def test_create_multiple_vouchers_duplicate_code(token_client, organizer, event, ) assert resp.status_code == 400 assert resp.data == [{}, {'code': ['Duplicate voucher code in request.']}] - assert Voucher.objects.count() == 0 + with scopes_disabled(): + assert Voucher.objects.count() == 0 diff --git a/src/tests/api/test_waitinglist.py b/src/tests/api/test_waitinglist.py index affec85638..809d1276f2 100644 --- a/src/tests/api/test_waitinglist.py +++ b/src/tests/api/test_waitinglist.py @@ -3,6 +3,7 @@ import datetime from unittest import mock import pytest +from django_scopes import scopes_disabled from pytz import UTC from pretix.base.models import WaitingListEntry @@ -44,8 +45,9 @@ TEST_WLE_RES = { @pytest.mark.django_db def test_wle_list(token_client, organizer, event, wle, item, subevent): - var = item.variations.create(value="Children") - var2 = item.variations.create(value="Children") + with scopes_disabled(): + var = item.variations.create(value="Children") + var2 = item.variations.create(value="Children") res = dict(TEST_WLE_RES) wle.variation = var wle.save() @@ -97,7 +99,8 @@ def test_wle_list(token_client, organizer, event, wle, item, subevent): '/api/v1/organizers/{}/events/{}/waitinglistentries/?has_voucher=true'.format(organizer.slug, event.slug)) assert [] == resp.data['results'] - v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') + with scopes_disabled(): + v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') wle.voucher = v wle.save() res['voucher'] = v.pk @@ -112,7 +115,8 @@ def test_wle_list(token_client, organizer, event, wle, item, subevent): resp = token_client.get( '/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug, subevent.pk)) assert [res] == resp.data['results'] - se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) + with scopes_disabled(): + se2 = event.subevents.create(name="Foobar", date_from=datetime.datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC)) resp = token_client.get( '/api/v1/organizers/{}/events/{}/waitinglistentries/?subevent={}'.format(organizer.slug, event.slug, se2.pk)) @@ -136,19 +140,22 @@ def test_delete_wle(token_client, organizer, event, wle, item): '/api/v1/organizers/{}/events/{}/waitinglistentries/{}/'.format(organizer.slug, event.slug, wle.pk), ) assert resp.status_code == 204 - assert not event.waitinglistentries.filter(pk=wle.id).exists() + with scopes_disabled(): + assert not event.waitinglistentries.filter(pk=wle.id).exists() @pytest.mark.django_db def test_delete_wle_assigned(token_client, organizer, event, wle, item): - v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') + with scopes_disabled(): + v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') wle.voucher = v wle.save() resp = token_client.delete( '/api/v1/organizers/{}/events/{}/waitinglistentries/{}/'.format(organizer.slug, event.slug, wle.pk), ) assert resp.status_code == 403 - assert event.waitinglistentries.filter(pk=wle.id).exists() + with scopes_disabled(): + assert event.waitinglistentries.filter(pk=wle.id).exists() def create_wle(token_client, organizer, event, data, expected_failure=False): @@ -159,9 +166,9 @@ def create_wle(token_client, organizer, event, data, expected_failure=False): if expected_failure: assert resp.status_code == 400 else: - print(resp.data) assert resp.status_code == 201 - return WaitingListEntry.objects.get(pk=resp.data['id']) + with scopes_disabled(): + return WaitingListEntry.objects.get(pk=resp.data['id']) @pytest.mark.django_db @@ -205,7 +212,8 @@ def test_wle_require_fields(token_client, organizer, event, item, quota): }, expected_failure=True ) - v = item.variations.create(value="S") + with scopes_disabled(): + v = item.variations.create(value="S") create_wle( token_client, organizer, event, data={ @@ -300,7 +308,8 @@ def test_wle_change_email(token_client, organizer, event, item, wle, quota): @pytest.mark.django_db def test_wle_change_assigned(token_client, organizer, event, item, wle, quota): - v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') + with scopes_disabled(): + v = event.vouchers.create(item=item, price_mode='set', value=12, tag='Foo') wle.voucher = v wle.save() change_wle( @@ -315,8 +324,9 @@ def test_wle_change_assigned(token_client, organizer, event, item, wle, quota): @pytest.mark.django_db def test_wle_change_to_available_item(token_client, organizer, event, item, wle, quota): - i = event.items.create(name="Budget Ticket", default_price=23) - q = event.quotas.create(name="Budget Ticket", size=1) + with scopes_disabled(): + i = event.items.create(name="Budget Ticket", default_price=23) + q = event.quotas.create(name="Budget Ticket", size=1) q.items.add(i) change_wle( token_client, organizer, event, wle, @@ -330,9 +340,10 @@ def test_wle_change_to_available_item(token_client, organizer, event, item, wle, @pytest.mark.django_db def test_wle_change_to_unavailable_item(token_client, organizer, event, item, wle, quota): - i = event.items.create(name="Budget Ticket", default_price=23) - v = i.variations.create(value="S") - q = event.quotas.create(name="Budget Ticket", size=0) + with scopes_disabled(): + i = event.items.create(name="Budget Ticket", default_price=23) + v = i.variations.create(value="S") + q = event.quotas.create(name="Budget Ticket", size=0) q.items.add(i) q.variations.add(v) change_wle( @@ -349,9 +360,10 @@ def test_wle_change_to_unavailable_item(token_client, organizer, event, item, wl @pytest.mark.django_db def test_wle_change_to_unavailable_item_missing_var(token_client, organizer, event, item, wle, quota): - i = event.items.create(name="Budget Ticket", default_price=23) - v = i.variations.create(value="S") - q = event.quotas.create(name="Budget Ticket", size=0) + with scopes_disabled(): + i = event.items.create(name="Budget Ticket", default_price=23) + v = i.variations.create(value="S") + q = event.quotas.create(name="Budget Ticket", size=0) q.items.add(i) q.variations.add(v) change_wle( diff --git a/src/tests/api/test_webhooks.py b/src/tests/api/test_webhooks.py index 4c3551e1ac..3eaaf44413 100644 --- a/src/tests/api/test_webhooks.py +++ b/src/tests/api/test_webhooks.py @@ -1,6 +1,7 @@ import copy import pytest +from django_scopes import scopes_disabled from pretix.api.models import WebHook @@ -64,12 +65,13 @@ def test_hook_create(token_client, organizer, event): format='json' ) assert resp.status_code == 201 - cl = WebHook.objects.get(pk=resp.data['id']) - assert cl.target_url == "https://google.com" - assert cl.limit_events.count() == 1 - assert set(cl.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', - 'pretix.event.order.paid'} - assert not cl.all_events + with scopes_disabled(): + cl = WebHook.objects.get(pk=resp.data['id']) + assert cl.target_url == "https://google.com" + assert cl.limit_events.count() == 1 + assert set(cl.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', + 'pretix.event.order.paid'} + assert not cl.all_events @pytest.mark.django_db @@ -136,9 +138,10 @@ def test_hook_patch_url(token_client, organizer, event, webhook): assert resp.status_code == 200 webhook.refresh_from_db() assert webhook.target_url == "https://pretix.eu" - assert webhook.limit_events.count() == 1 - assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', - 'pretix.event.order.paid'} + with scopes_disabled(): + assert webhook.limit_events.count() == 1 + assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', + 'pretix.event.order.paid'} assert webhook.enabled @@ -153,9 +156,10 @@ def test_hook_patch_types(token_client, organizer, event, webhook): ) assert resp.status_code == 200 webhook.refresh_from_db() - assert webhook.limit_events.count() == 1 - assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', - 'pretix.event.order.canceled'} + with scopes_disabled(): + assert webhook.limit_events.count() == 1 + assert set(webhook.listeners.values_list('action_type', flat=True)) == {'pretix.event.order.placed', + 'pretix.event.order.canceled'} assert webhook.enabled diff --git a/src/tests/base/__init__.py b/src/tests/base/__init__.py index 2bfc4affc7..6b5caff927 100644 --- a/src/tests/base/__init__.py +++ b/src/tests/base/__init__.py @@ -6,13 +6,13 @@ class SoupTest(TestCase): def get_doc(self, *args, **kwargs): response = self.client.get(*args, **kwargs) - return BeautifulSoup(response.rendered_content, "lxml") + return BeautifulSoup(response.render().content, "lxml") def post_doc(self, *args, **kwargs): kwargs['follow'] = True response = self.client.post(*args, **kwargs) try: - return BeautifulSoup(response.rendered_content, "lxml") + return BeautifulSoup(response.render().content, "lxml") except AttributeError: return BeautifulSoup(response.content, "lxml") diff --git a/src/tests/base/test_invoices.py b/src/tests/base/test_invoices.py index 744574a4d7..a15a7e03cd 100644 --- a/src/tests/base/test_invoices.py +++ b/src/tests/base/test_invoices.py @@ -7,6 +7,7 @@ from django.core.serializers.json import DjangoJSONEncoder from django.db import DatabaseError, transaction from django.utils.timezone import now from django_countries.fields import Country +from django_scopes import scope, scopes_disabled from pretix.base.models import ( Event, Invoice, InvoiceAddress, Item, ItemVariation, Order, OrderPosition, @@ -24,72 +25,74 @@ from pretix.base.settings import GlobalSettingsObject @pytest.fixture def env(): o = Organizer.objects.create(name='Dummy', slug='dummy') - event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', - date_from=now(), plugins='pretix.plugins.banktransfer' - ) - o = Order.objects.create( - code='FOO', event=event, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + timedelta(days=10), - total=0, locale='en' - ) - tr = event.tax_rules.create(rate=Decimal('19.00')) - o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'), - tax_value=Decimal('0.05'), tax_rule=tr) - ticket = Item.objects.create(event=event, name='Early-bird ticket', - category=None, default_price=23, tax_rule=tr, - admission=True) - t_shirt = Item.objects.create(event=event, name='T-Shirt', - category=None, default_price=42, tax_rule=tr, - admission=True) - variation = ItemVariation.objects.create(value='M', item=t_shirt) - OrderPosition.objects.create( - order=o, - item=ticket, - variation=None, - price=Decimal("23.00"), - positionid=1, - ) - OrderPosition.objects.create( - order=o, - item=t_shirt, - variation=variation, - price=Decimal("42.00"), - positionid=2, - ) - OrderPosition.objects.create( - order=o, - item=t_shirt, - variation=variation, - price=Decimal("42.00"), - positionid=3, - canceled=True - ) - gs = GlobalSettingsObject() - gs.settings.ecb_rates_date = date.today() - gs.settings.ecb_rates_dict = json.dumps({ - "USD": "1.1648", - "RON": "4.5638", - "CZK": "26.024", - "BGN": "1.9558", - "HRK": "7.4098", - "EUR": "1.0000", - "NOK": "9.3525", - "HUF": "305.15", - "DKK": "7.4361", - "PLN": "4.2408", - "GBP": "0.89350", - "SEK": "9.5883" - }, cls=DjangoJSONEncoder) - return event, o + with scope(organizer=o): + event = Event.objects.create( + organizer=o, name='Dummy', slug='dummy', + date_from=now(), plugins='pretix.plugins.banktransfer' + ) + o = Order.objects.create( + code='FOO', event=event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + timedelta(days=10), + total=0, locale='en' + ) + tr = event.tax_rules.create(rate=Decimal('19.00')) + o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'), + tax_value=Decimal('0.05'), tax_rule=tr) + ticket = Item.objects.create(event=event, name='Early-bird ticket', + category=None, default_price=23, tax_rule=tr, + admission=True) + t_shirt = Item.objects.create(event=event, name='T-Shirt', + category=None, default_price=42, tax_rule=tr, + admission=True) + variation = ItemVariation.objects.create(value='M', item=t_shirt) + OrderPosition.objects.create( + order=o, + item=ticket, + variation=None, + price=Decimal("23.00"), + positionid=1, + ) + OrderPosition.objects.create( + order=o, + item=t_shirt, + variation=variation, + price=Decimal("42.00"), + positionid=2, + ) + OrderPosition.objects.create( + order=o, + item=t_shirt, + variation=variation, + price=Decimal("42.00"), + positionid=3, + canceled=True + ) + gs = GlobalSettingsObject() + gs.settings.ecb_rates_date = date.today() + gs.settings.ecb_rates_dict = json.dumps({ + "USD": "1.1648", + "RON": "4.5638", + "CZK": "26.024", + "BGN": "1.9558", + "HRK": "7.4098", + "EUR": "1.0000", + "NOK": "9.3525", + "HUF": "305.15", + "DKK": "7.4361", + "PLN": "4.2408", + "GBP": "0.89350", + "SEK": "9.5883" + }, cls=DjangoJSONEncoder) + yield event, o @pytest.mark.django_db def test_locale_setting(env): event, order = env event.settings.set('invoice_language', 'de') - inv = generate_invoice(order) + with scopes_disabled(): + inv = generate_invoice(order) assert inv.locale == 'de' diff --git a/src/tests/base/test_locking.py b/src/tests/base/test_locking.py index 320cd6cf03..7e94f16a2e 100644 --- a/src/tests/base/test_locking.py +++ b/src/tests/base/test_locking.py @@ -2,6 +2,7 @@ import time import pytest from django.utils.timezone import now +from django_scopes import scope, scopes_disabled from pretix.base.models import Event, Organizer from pretix.base.services import locking @@ -17,16 +18,18 @@ def event(): organizer=o, name='Dummy', slug='dummy', date_from=now() ) - return event + with scope(organizer=o): + yield event @pytest.mark.django_db def test_locking_exclusive(event): with event.lock(): with pytest.raises(LockTimeoutException): - ev = Event.objects.get(id=event.id) - with ev.lock(): - pass + with scopes_disabled(): + ev = Event.objects.get(id=event.id) + with ev.lock(): + pass @pytest.mark.django_db diff --git a/src/tests/base/test_mail.py b/src/tests/base/test_mail.py index aa5d590ace..ab7ea62313 100644 --- a/src/tests/base/test_mail.py +++ b/src/tests/base/test_mail.py @@ -5,6 +5,7 @@ from django.conf import settings from django.core import mail as djmail from django.utils.timezone import now from django.utils.translation import ugettext_lazy as _ +from django_scopes import scope from pretix.base.models import Event, Organizer, User from pretix.base.services.mail import mail @@ -20,7 +21,8 @@ def env(): user = User.objects.create_user('dummy@dummy.dummy', 'dummy') user.email = 'dummy@dummy.dummy' user.save() - return event, user, o + with scope(organizer=o): + yield event, user, o @pytest.mark.django_db diff --git a/src/tests/base/test_models.py b/src/tests/base/test_models.py index 6068a47ea7..97bb556096 100644 --- a/src/tests/base/test_models.py +++ b/src/tests/base/test_models.py @@ -12,6 +12,7 @@ from django.core.files.storage import default_storage from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from django.utils.timezone import now +from django_scopes import scope from pretix.base.i18n import language from pretix.base.models import ( @@ -25,6 +26,7 @@ from pretix.base.models.items import ( ) from pretix.base.reldate import RelativeDate, RelativeDateWrapper from pretix.base.services.orders import OrderError, cancel_order, perform_order +from pretix.testutils.scope import classscope class UserTestCase(TestCase): @@ -44,9 +46,9 @@ class UserTestCase(TestCase): class BaseQuotaTestCase(TestCase): def setUp(self): - o = Organizer.objects.create(name='Dummy', slug='dummy') + self.o = Organizer.objects.create(name='Dummy', slug='dummy') self.event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', + organizer=self.o, name='Dummy', slug='dummy', date_from=now(), plugins='tests.testdummy' ) self.quota = Quota.objects.create(name="Test", size=2, event=self.event) @@ -60,6 +62,7 @@ class BaseQuotaTestCase(TestCase): class QuotaTestCase(BaseQuotaTestCase): + @classscope(attr='o') def test_available(self): self.quota.items.add(self.item1) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 2)) @@ -72,6 +75,7 @@ class QuotaTestCase(BaseQuotaTestCase): pass self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 2)) + @classscope(attr='o') def test_sold_out(self): self.quota.items.add(self.item1) order = Order.objects.create(event=self.event, status=Order.STATUS_PAID, @@ -93,6 +97,7 @@ class QuotaTestCase(BaseQuotaTestCase): OrderPosition.objects.create(order=order, item=self.item2, variation=self.var1, price=2) self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_GONE, 0)) + @classscope(attr='o') def test_ordered(self): self.quota.items.add(self.item1) order = Order.objects.create(event=self.event, status=Order.STATUS_PAID, @@ -115,6 +120,7 @@ class QuotaTestCase(BaseQuotaTestCase): order.save() self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_ordered_multi_quota(self): quota2 = Quota.objects.create(name="Test", size=2, event=self.event) quota2.items.add(self.item2) @@ -129,6 +135,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(quota2.availability(), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_position_canceled(self): self.quota.items.add(self.item1) self.quota.size = 3 @@ -142,6 +149,7 @@ class QuotaTestCase(BaseQuotaTestCase): op.save() self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 3)) + @classscope(attr='o') def test_reserved(self): self.quota.items.add(self.item1) self.quota.size = 3 @@ -172,6 +180,7 @@ class QuotaTestCase(BaseQuotaTestCase): price=2, expires=now() + timedelta(days=3)) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_RESERVED, 0)) + @classscope(attr='o') def test_multiple(self): self.quota.items.add(self.item1) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 2)) @@ -184,6 +193,7 @@ class QuotaTestCase(BaseQuotaTestCase): quota2.save() self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_GONE, 0)) + @classscope(attr='o') def test_ignore_quotas(self): self.quota.items.add(self.item1) quota2 = Quota.objects.create(event=self.event, name="Test 2", size=0) @@ -193,6 +203,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.item1.check_quotas(ignored_quotas=[self.quota, quota2]), (Quota.AVAILABILITY_OK, sys.maxsize)) + @classscope(attr='o') def test_unlimited(self): self.quota.items.add(self.item1) order = Order.objects.create(event=self.event, status=Order.STATUS_PAID, @@ -206,6 +217,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.quota.save() self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, None)) + @classscope(attr='o') def test_voucher_product(self): self.quota.items.add(self.item1) self.quota.size = 1 @@ -219,6 +231,7 @@ class QuotaTestCase(BaseQuotaTestCase): v.save() self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) + @classscope(attr='o') def test_voucher_variation(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -232,6 +245,7 @@ class QuotaTestCase(BaseQuotaTestCase): v.save() self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) + @classscope(attr='o') def test_voucher_quota(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -245,6 +259,7 @@ class QuotaTestCase(BaseQuotaTestCase): v.save() self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) + @classscope(attr='o') def test_voucher_quota_multiuse(self): self.quota.size = 5 self.quota.variations.add(self.var1) @@ -254,12 +269,14 @@ class QuotaTestCase(BaseQuotaTestCase): Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, max_usages=2) self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) + @classscope(attr='o') def test_voucher_multiuse_count_overredeemed(self): if 'sqlite' not in settings.DATABASES['default']['ENGINE']: pytest.xfail('This should raise a type error on most databases') Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, max_usages=2, redeemed=4) self.assertEqual(self.quota.count_blocking_vouchers(), 0) + @classscope(attr='o') def test_voucher_quota_multiuse_multiproduct(self): q2 = Quota.objects.create(event=self.event, name="foo", size=10) q2.items.add(self.item1) @@ -278,6 +295,7 @@ class QuotaTestCase(BaseQuotaTestCase): redeemed=2) self.assertEqual(self.quota.count_blocking_vouchers(), 9) + @classscope(attr='o') def test_voucher_quota_expiring_soon(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -286,6 +304,7 @@ class QuotaTestCase(BaseQuotaTestCase): block_quota=True) self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) + @classscope(attr='o') def test_voucher_quota_expired(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -295,6 +314,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) self.assertFalse(v.is_active()) + @classscope(attr='o') def test_blocking_voucher_in_cart(self): self.quota.items.add(self.item1) v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() + timedelta(days=5), @@ -306,6 +326,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.quota.count_in_cart(), 0) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_blocking_voucher_in_cart_inifinitely_valid(self): self.quota.items.add(self.item1) v = Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True) @@ -315,6 +336,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.quota.count_in_cart(), 0) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_blocking_expired_voucher_in_cart(self): self.quota.items.add(self.item1) v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() - timedelta(days=5), @@ -325,6 +347,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.quota.count_in_cart(), 1) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_nonblocking_voucher_in_cart(self): self.quota.items.add(self.item1) v = Voucher.objects.create(quota=self.quota, event=self.event) @@ -334,6 +357,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.quota.count_in_cart(), 1) self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_waitinglist_item_active(self): self.quota.items.add(self.item1) self.quota.size = 1 @@ -344,6 +368,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.item1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) self.assertEqual(self.item1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_waitinglist_variation_active(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -354,6 +379,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0)) self.assertEqual(self.var1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_waitinglist_variation_fulfilled(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -365,6 +391,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) self.assertEqual(self.var1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_waitinglist_variation_other(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -375,6 +402,7 @@ class QuotaTestCase(BaseQuotaTestCase): self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1)) self.assertEqual(self.var1.check_quotas(count_waitinglist=False), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_quota_cache(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -396,6 +424,7 @@ class QuotaTestCase(BaseQuotaTestCase): with self.assertNumQueries(1): self.assertEqual(self.var1.check_quotas(_cache=cache, count_waitinglist=False), (Quota.AVAILABILITY_OK, 1)) + @classscope(attr='o') def test_subevent_isolation(self): self.event.has_subevents = True self.event.save() @@ -480,17 +509,21 @@ class BundleQuotaTestCase(BaseQuotaTestCase): count=1 ) + @classscope(attr='o') def test_only_respect_with_flag(self): assert self.item1.check_quotas() == (Quota.AVAILABILITY_OK, 5) + @classscope(attr='o') def test_do_not_exceed(self): assert self.item1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 5) + @classscope(attr='o') def test_limited_by_bundled_quita(self): self.transquota.size = 3 self.transquota.save() assert self.item1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 3) + @classscope(attr='o') def test_multiple_bundles(self): ItemBundle.objects.create( base_item=self.item1, @@ -502,6 +535,7 @@ class BundleQuotaTestCase(BaseQuotaTestCase): self.transquota.save() assert self.item1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 1) + @classscope(attr='o') def test_bundle_count(self): self.bundle1.count = 2 self.bundle1.save() @@ -509,29 +543,35 @@ class BundleQuotaTestCase(BaseQuotaTestCase): self.transquota.save() assert self.item1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 1) + @classscope(attr='o') def test_bundled_unlimited(self): self.transquota.size = None self.transquota.save() assert self.item1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 5) assert self.var1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 5) + @classscope(attr='o') def test_item_unlimited(self): self.quota.size = None self.quota.save() assert self.item1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 10) assert self.var1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 10) + @classscope(attr='o') def test_var_only_respect_with_flag(self): assert self.var1.check_quotas() == (Quota.AVAILABILITY_OK, 5) + @classscope(attr='o') def test_var_do_not_exceed(self): assert self.var1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 5) + @classscope(attr='o') def test_var_limited_by_bundled_quita(self): self.transquota.size = 3 self.transquota.save() assert self.var1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 3) + @classscope(attr='o') def test_var_multiple_bundles(self): ItemBundle.objects.create( base_item=self.item2, @@ -543,6 +583,7 @@ class BundleQuotaTestCase(BaseQuotaTestCase): self.transquota.save() assert self.var1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 1) + @classscope(attr='o') def test_var_bundle_count(self): self.bundle2.count = 2 self.bundle2.save() @@ -550,6 +591,7 @@ class BundleQuotaTestCase(BaseQuotaTestCase): self.transquota.save() assert self.var1.check_quotas(include_bundled=True) == (Quota.AVAILABILITY_OK, 1) + @classscope(attr='o') def test_bundled_variation(self): v = self.trans.variations.create(value="foo", default_price=4) self.transquota.variations.add(v) @@ -562,6 +604,7 @@ class BundleQuotaTestCase(BaseQuotaTestCase): class WaitingListTestCase(BaseQuotaTestCase): + @classscope(attr='o') def test_duplicate(self): w1 = WaitingListEntry.objects.create( event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com' @@ -573,6 +616,7 @@ class WaitingListTestCase(BaseQuotaTestCase): with self.assertRaises(ValidationError): w2.clean() + @classscope(attr='o') def test_duplicate_of_successful(self): v = Voucher.objects.create(quota=self.quota, event=self.event, block_quota=True, redeemed=1) w1 = WaitingListEntry.objects.create( @@ -585,6 +629,7 @@ class WaitingListTestCase(BaseQuotaTestCase): ) w2.clean() + @classscope(attr='o') def test_missing_variation(self): w2 = WaitingListEntry( event=self.event, item=self.item2, email='foo@bar.com' @@ -595,6 +640,7 @@ class WaitingListTestCase(BaseQuotaTestCase): class VoucherTestCase(BaseQuotaTestCase): + @classscope(attr='o') def test_voucher_reuse(self): self.quota.items.add(self.item1) v = Voucher.objects.create(quota=self.quota, event=self.event, valid_until=now() + timedelta(days=5)) @@ -631,18 +677,21 @@ class VoucherTestCase(BaseQuotaTestCase): expires=now() + timedelta(days=3), voucher=v) perform_order(event=self.event.id, payment_provider='free', positions=[cart.id]) + @classscope(attr='o') def test_voucher_applicability_quota(self): self.quota.items.add(self.item1) v = Voucher.objects.create(quota=self.quota, event=self.event) self.assertTrue(v.applies_to(self.item1)) self.assertFalse(v.applies_to(self.item2)) + @classscope(attr='o') def test_voucher_applicability_item(self): v = Voucher.objects.create(item=self.var1.item, event=self.event) self.assertFalse(v.applies_to(self.item1)) self.assertTrue(v.applies_to(self.var1.item)) self.assertTrue(v.applies_to(self.var1.item, self.var1)) + @classscope(attr='o') def test_voucher_applicability_variation(self): v = Voucher.objects.create(item=self.var1.item, variation=self.var1, event=self.event) self.assertFalse(v.applies_to(self.item1)) @@ -650,6 +699,7 @@ class VoucherTestCase(BaseQuotaTestCase): self.assertTrue(v.applies_to(self.var1.item, self.var1)) self.assertFalse(v.applies_to(self.var1.item, self.var2)) + @classscope(attr='o') def test_voucher_applicability_variation_through_quota(self): self.quota.variations.add(self.var1) self.quota.items.add(self.var1.item) @@ -659,51 +709,62 @@ class VoucherTestCase(BaseQuotaTestCase): self.assertTrue(v.applies_to(self.var1.item, self.var1)) self.assertFalse(v.applies_to(self.var1.item, self.var2)) + @classscope(attr='o') def test_voucher_no_item_with_quota(self): with self.assertRaises(ValidationError): v = Voucher(quota=self.quota, item=self.item1, event=self.event) v.clean() + @classscope(attr='o') def test_voucher_item_with_no_variation(self): with self.assertRaises(ValidationError): v = Voucher(item=self.item1, variation=self.var1, event=self.event) v.clean() + @classscope(attr='o') def test_voucher_item_does_not_match_variation(self): with self.assertRaises(ValidationError): v = Voucher(item=self.item2, variation=self.var3, event=self.event) v.clean() + @classscope(attr='o') def test_voucher_specify_variation_for_block_quota(self): with self.assertRaises(ValidationError): v = Voucher(item=self.item2, block_quota=True, event=self.event) v.clean() + @classscope(attr='o') def test_voucher_no_item_but_variation(self): with self.assertRaises(ValidationError): v = Voucher(variation=self.var1, event=self.event) v.clean() + @classscope(attr='o') def test_calculate_price_none(self): v = Voucher.objects.create(event=self.event, price_mode='none', value=Decimal('10.00')) assert v.calculate_price(Decimal('23.42')) == Decimal('23.42') + @classscope(attr='o') def test_calculate_price_set_empty(self): v = Voucher.objects.create(event=self.event, price_mode='set') assert v.calculate_price(Decimal('23.42')) == Decimal('23.42') + @classscope(attr='o') def test_calculate_price_set(self): v = Voucher.objects.create(event=self.event, price_mode='set', value=Decimal('10.00')) assert v.calculate_price(Decimal('23.42')) == Decimal('10.00') + @classscope(attr='o') def test_calculate_price_set_zero(self): v = Voucher.objects.create(event=self.event, price_mode='set', value=Decimal('0.00')) assert v.calculate_price(Decimal('23.42')) == Decimal('0.00') + @classscope(attr='o') def test_calculate_price_subtract(self): v = Voucher.objects.create(event=self.event, price_mode='subtract', value=Decimal('10.00')) assert v.calculate_price(Decimal('23.42')) == Decimal('13.42') + @classscope(attr='o') def test_calculate_price_percent(self): v = Voucher.objects.create(event=self.event, price_mode='percent', value=Decimal('23.00')) assert v.calculate_price(Decimal('100.00')) == Decimal('77.00') @@ -712,18 +773,20 @@ class VoucherTestCase(BaseQuotaTestCase): class OrderTestCase(BaseQuotaTestCase): def setUp(self): super().setUp() - self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') - self.order = Order.objects.create( - status=Order.STATUS_PENDING, event=self.event, - datetime=now() - timedelta(days=5), - expires=now() + timedelta(days=5), total=46, - ) - self.quota.items.add(self.item1) - self.op1 = OrderPosition.objects.create(order=self.order, item=self.item1, - variation=None, price=23) - self.op2 = OrderPosition.objects.create(order=self.order, item=self.item1, - variation=None, price=23) + with scope(organizer=self.o): + self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') + self.order = Order.objects.create( + status=Order.STATUS_PENDING, event=self.event, + datetime=now() - timedelta(days=5), + expires=now() + timedelta(days=5), total=46, + ) + self.quota.items.add(self.item1) + self.op1 = OrderPosition.objects.create(order=self.order, item=self.item1, + variation=None, price=23) + self.op2 = OrderPosition.objects.create(order=self.order, item=self.item1, + variation=None, price=23) + @classscope(attr='o') def test_paid_in_time(self): self.quota.size = 0 self.quota.save() @@ -734,6 +797,7 @@ class OrderTestCase(BaseQuotaTestCase): self.assertEqual(self.order.status, Order.STATUS_PAID) assert not self.order.all_logentries().filter(action_type='pretix.event.order.overpaid').exists() + @classscope(attr='o') def test_paid_expired_available(self): self.event.settings.payment_term_last = (now() + timedelta(days=2)).strftime('%Y-%m-%d') self.order.status = Order.STATUS_EXPIRED @@ -745,6 +809,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_PAID) + @classscope(attr='o') def test_paid_expired_after_last_date(self): self.event.settings.payment_term_last = (now() - timedelta(days=2)).strftime('%Y-%m-%d') self.order.status = Order.STATUS_EXPIRED @@ -757,6 +822,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_EXPIRED) + @classscope(attr='o') def test_paid_expired_after_last_date_subevent_relative(self): self.event.has_subevents = True self.event.save() @@ -782,6 +848,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.has_subevents = False self.event.save() + @classscope(attr='o') def test_paid_expired_late_not_allowed(self): self.event.settings.payment_term_accept_late = False self.order.status = Order.STATUS_EXPIRED @@ -794,6 +861,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_EXPIRED) + @classscope(attr='o') def test_paid_expired_unavailable(self): self.event.settings.payment_term_accept_late = True self.order.expires = now() - timedelta(days=2) @@ -808,6 +876,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertIn(self.order.status, (Order.STATUS_PENDING, Order.STATUS_EXPIRED)) + @classscope(attr='o') def test_paid_after_deadline_but_not_expired(self): self.event.settings.payment_term_accept_late = True self.order.expires = now() - timedelta(days=2) @@ -818,6 +887,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_PAID) + @classscope(attr='o') def test_paid_expired_unavailable_force(self): self.event.settings.payment_term_accept_late = True self.order.expires = now() - timedelta(days=2) @@ -831,6 +901,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_PAID) + @classscope(attr='o') def test_paid_expired_unavailable_waiting_list(self): self.event.settings.payment_term_accept_late = True self.event.waitinglistentries.create(item=self.item1, email='foo@bar.com') @@ -846,6 +917,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_EXPIRED) + @classscope(attr='o') def test_paid_expired_unavailable_waiting_list_ignore(self): self.event.waitinglistentries.create(item=self.item1, email='foo@bar.com') self.order.expires = now() - timedelta(days=2) @@ -859,6 +931,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(id=self.order.id) self.assertEqual(self.order.status, Order.STATUS_PAID) + @classscope(attr='o') def test_paid_overpaid(self): self.quota.size = 2 self.quota.save() @@ -869,6 +942,7 @@ class OrderTestCase(BaseQuotaTestCase): self.assertEqual(self.order.status, Order.STATUS_PAID) assert self.order.all_logentries().filter(action_type='pretix.event.order.overpaid').exists() + @classscope(attr='o') def test_can_modify_answers(self): self.event.settings.set('invoice_address_asked', False) self.event.settings.set('attendee_names_asked', True) @@ -887,6 +961,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.settings.set('last_order_modification_date', now() - timedelta(days=1)) assert not self.order.can_modify_answers + @classscope(attr='o') def test_can_modify_answers_subevent(self): self.event.has_subevents = True self.event.save() @@ -907,6 +982,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.has_subevents = False self.event.save() + @classscope(attr='o') def test_payment_term_last_relative(self): self.event.settings.set('payment_term_last', date(2017, 5, 3)) assert self.order.payment_term_last == datetime.datetime(2017, 5, 3, 23, 59, 59, tzinfo=pytz.UTC) @@ -917,6 +993,7 @@ class OrderTestCase(BaseQuotaTestCase): )) assert self.order.payment_term_last == datetime.datetime(2017, 5, 1, 23, 59, 59, tzinfo=pytz.UTC) + @classscope(attr='o') def test_payment_term_last_subevent(self): self.event.has_subevents = True self.event.save() @@ -937,6 +1014,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.has_subevents = False self.event.save() + @classscope(attr='o') def test_ticket_download_date_relative(self): self.event.settings.set('ticket_download_date', datetime.datetime(2017, 5, 3, 12, 59, 59, tzinfo=pytz.UTC)) assert self.order.ticket_download_date == datetime.datetime(2017, 5, 3, 12, 59, 59, tzinfo=pytz.UTC) @@ -947,6 +1025,7 @@ class OrderTestCase(BaseQuotaTestCase): )) assert self.order.ticket_download_date == datetime.datetime(2017, 5, 1, 12, 0, 0, tzinfo=pytz.UTC) + @classscope(attr='o') def test_ticket_download_date_subevent(self): self.event.has_subevents = True self.event.save() @@ -967,6 +1046,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.has_subevents = False self.event.save() + @classscope(attr='o') def test_can_cancel_order(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=True) @@ -976,6 +1056,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.settings.cancel_allow_user = False assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_can_cancel_order_free(self): self.order.status = Order.STATUS_PAID self.order.total = Decimal('0.00') @@ -984,6 +1065,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.settings.cancel_allow_user = False assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_can_cancel_order_paid(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -992,6 +1074,7 @@ class OrderTestCase(BaseQuotaTestCase): self.event.settings.cancel_allow_user_paid = True assert self.order.user_cancel_allowed + @classscope(attr='o') def test_can_cancel_checked_in(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1004,6 +1087,7 @@ class OrderTestCase(BaseQuotaTestCase): ) assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_can_cancel_order_multiple(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=True) @@ -1015,6 +1099,7 @@ class OrderTestCase(BaseQuotaTestCase): variation=None, price=23) assert self.order.user_cancel_allowed + @classscope(attr='o') def test_can_not_cancel_order(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=False) @@ -1022,6 +1107,7 @@ class OrderTestCase(BaseQuotaTestCase): variation=None, price=23) assert self.order.user_cancel_allowed is False + @classscope(attr='o') def test_can_not_cancel_order_multiple(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=False) @@ -1033,6 +1119,7 @@ class OrderTestCase(BaseQuotaTestCase): variation=None, price=23) assert self.order.user_cancel_allowed is False + @classscope(attr='o') def test_can_not_cancel_order_multiple_mixed(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=False) @@ -1044,6 +1131,7 @@ class OrderTestCase(BaseQuotaTestCase): variation=None, price=23) assert self.order.user_cancel_allowed is False + @classscope(attr='o') def test_no_duplicate_position_secret(self): item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, admission=True, allow_cancel=False) @@ -1054,6 +1142,7 @@ class OrderTestCase(BaseQuotaTestCase): assert p1.secret != p2.secret assert self.order.user_cancel_allowed is False + @classscope(attr='o') def test_user_cancel_absolute_deadline_unpaid_no_subevents(self): assert self.order.user_cancel_deadline is None self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper( @@ -1069,6 +1158,7 @@ class OrderTestCase(BaseQuotaTestCase): assert self.order.user_cancel_deadline < now() assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_user_cancel_relative_deadline_unpaid_no_subevents(self): self.event.date_from = now() + timedelta(days=3) self.event.save() @@ -1087,6 +1177,7 @@ class OrderTestCase(BaseQuotaTestCase): assert self.order.user_cancel_deadline < now() assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_user_cancel_absolute_deadline_paid_no_subevents(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1105,6 +1196,7 @@ class OrderTestCase(BaseQuotaTestCase): assert self.order.user_cancel_deadline < now() assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_user_cancel_relative_deadline_paid_no_subevents(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1126,6 +1218,7 @@ class OrderTestCase(BaseQuotaTestCase): assert self.order.user_cancel_deadline < now() assert not self.order.user_cancel_allowed + @classscope(attr='o') def test_user_cancel_relative_deadline_to_subevents(self): self.event.date_from = now() + timedelta(days=3) self.event.has_subevents = True @@ -1147,6 +1240,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(pk=self.order.pk) assert self.order.user_cancel_deadline > now() + @classscope(attr='o') def test_user_cancel_fee(self): self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, value=Decimal('2.00')) self.order.total = 48 @@ -1166,6 +1260,7 @@ class OrderTestCase(BaseQuotaTestCase): self.order = Order.objects.get(pk=self.order.pk) assert self.order.user_cancel_fee == Decimal('9.30') + @classscope(attr='o') def test_paid_order_underpaid(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1186,6 +1281,7 @@ class OrderTestCase(BaseQuotaTestCase): assert not o.has_pending_refund assert not o.has_external_refund + @classscope(attr='o') def test_pending_order_underpaid(self): self.order.payments.create( amount=Decimal('46.00'), @@ -1204,6 +1300,7 @@ class OrderTestCase(BaseQuotaTestCase): assert not o.has_pending_refund assert not o.has_external_refund + @classscope(attr='o') def test_canceled_order_overpaid(self): self.order.status = Order.STATUS_CANCELED self.order.save() @@ -1224,6 +1321,7 @@ class OrderTestCase(BaseQuotaTestCase): assert not o.has_pending_refund assert not o.has_external_refund + @classscope(attr='o') def test_paid_order_external_refund(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1244,6 +1342,7 @@ class OrderTestCase(BaseQuotaTestCase): assert not o.has_pending_refund assert o.has_external_refund + @classscope(attr='o') def test_pending_order_pending_refund(self): self.order.status = Order.STATUS_CANCELED self.order.save() @@ -1264,6 +1363,7 @@ class OrderTestCase(BaseQuotaTestCase): assert o.has_pending_refund assert not o.has_external_refund + @classscope(attr='o') def test_paid_order_overpaid(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1284,6 +1384,7 @@ class OrderTestCase(BaseQuotaTestCase): assert not o.has_pending_refund assert not o.has_external_refund + @classscope(attr='o') def test_pending_order_overpaid(self): self.order.status = Order.STATUS_PENDING self.order.save() @@ -1305,6 +1406,7 @@ class OrderTestCase(BaseQuotaTestCase): assert not o.has_pending_refund assert not o.has_external_refund + @classscope(attr='o') def test_canceled_positions(self): self.op1.canceled = True self.op1.save() @@ -1313,6 +1415,7 @@ class OrderTestCase(BaseQuotaTestCase): assert self.order.positions.count() == 1 assert self.order.all_positions.count() == 2 + @classscope(attr='o') def test_propose_auto_refunds(self): p1 = self.order.payments.create( amount=Decimal('23.00'), @@ -1358,12 +1461,13 @@ class ItemCategoryTest(TestCase): @classmethod def setUpTestData(cls): - o = Organizer.objects.create(name='Dummy', slug='dummy') + cls.o = Organizer.objects.create(name='Dummy', slug='dummy') cls.event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', + organizer=cls.o, name='Dummy', slug='dummy', date_from=now(), ) + @classscope(attr='o') def test_sorting(self): c1 = ItemCategory.objects.create(event=self.event) c2 = ItemCategory.objects.create(event=self.event) @@ -1386,12 +1490,13 @@ class ItemTest(TestCase): @classmethod def setUpTestData(cls): - o = Organizer.objects.create(name='Dummy', slug='dummy') + cls.o = Organizer.objects.create(name='Dummy', slug='dummy') cls.event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', + organizer=cls.o, name='Dummy', slug='dummy', date_from=now(), ) + @classscope(attr='o') def test_is_available(self): i = Item.objects.create( event=self.event, name="Ticket", default_price=23, @@ -1412,6 +1517,7 @@ class ItemTest(TestCase): i.active = False assert not i.is_available() + @classscope(attr='o') def test_availability_filter(self): i = Item.objects.create( event=self.event, name="Ticket", default_price=23, @@ -1463,6 +1569,7 @@ class EventTest(TestCase): def setUpTestData(cls): cls.organizer = Organizer.objects.create(name='Dummy', slug='dummy') + @classscope(attr='organizer') def test_event_end_before_start(self): event = Event( organizer=self.organizer, name='Dummy', slug='dummy', @@ -1473,6 +1580,7 @@ class EventTest(TestCase): self.assertIn('date_to', str(context.exception)) + @classscope(attr='organizer') def test_presale_end_before_start(self): event = Event( organizer=self.organizer, name='Dummy', slug='dummy', @@ -1483,6 +1591,7 @@ class EventTest(TestCase): self.assertIn('presale_end', str(context.exception)) + @classscope(attr='organizer') def test_slug_validation(self): event = Event( organizer=self.organizer, name='Download', slug='download', @@ -1493,6 +1602,7 @@ class EventTest(TestCase): self.assertIn('slug', str(context.exception)) + @classscope(attr='organizer') def test_copy(self): event1 = Event.objects.create( organizer=self.organizer, name='Download', slug='ab1234', @@ -1547,6 +1657,7 @@ class EventTest(TestCase): assert event2.checkin_lists.count() == 1 assert [i.pk for i in event2.checkin_lists.first().limit_products.all()] == [i1new.pk] + @classscope(attr='organizer') def test_presale_has_ended(self): event = Event( organizer=self.organizer, name='Download', slug='download', @@ -1579,6 +1690,7 @@ class EventTest(TestCase): assert event.presale_has_ended assert not event.presale_is_running + @classscope(attr='organizer') def test_active_quotas_annotation(self): event = Event.objects.create( organizer=self.organizer, name='Download', slug='download', @@ -1592,6 +1704,7 @@ class EventTest(TestCase): assert Event.annotated(Event.objects).first().active_quotas == [q] assert Event.annotated(Event.objects, 'foo').first().active_quotas == [] + @classscope(attr='organizer') def test_active_quotas_annotation_product_inactive(self): event = Event.objects.create( organizer=self.organizer, name='Download', slug='download', @@ -1602,6 +1715,7 @@ class EventTest(TestCase): q.items.add(item) assert Event.annotated(Event.objects).first().active_quotas == [] + @classscope(attr='organizer') def test_active_quotas_annotation_product_addon(self): event = Event.objects.create( organizer=self.organizer, name='Download', slug='download', @@ -1617,6 +1731,7 @@ class EventTest(TestCase): q.items.add(item) assert Event.annotated(Event.objects).first().active_quotas == [] + @classscope(attr='organizer') def test_active_quotas_annotation_product_unavailable(self): event = Event.objects.create( organizer=self.organizer, name='Download', slug='download', @@ -1627,6 +1742,7 @@ class EventTest(TestCase): q.items.add(item) assert Event.annotated(Event.objects).first().active_quotas == [] + @classscope(attr='organizer') def test_active_quotas_annotation_variation_not_in_quota(self): event = Event.objects.create( organizer=self.organizer, name='Download', slug='download', @@ -1638,6 +1754,7 @@ class EventTest(TestCase): q.items.add(item) assert Event.annotated(Event.objects).first().active_quotas == [] + @classscope(attr='organizer') def test_active_quotas_annotation_variation(self): event = Event.objects.create( organizer=self.organizer, name='Download', slug='download', @@ -1687,6 +1804,7 @@ class SubEventTest(TestCase): name='Testsub', date_from=now(), event=cls.event ) + @classscope(attr='organizer') def test_override_prices(self): i = Item.objects.create( event=self.event, name="Ticket", default_price=23, @@ -1697,6 +1815,7 @@ class SubEventTest(TestCase): i.pk: Decimal('30.00') } + @classscope(attr='organizer') def test_override_var_prices(self): i = Item.objects.create( event=self.event, name="Ticket", default_price=23, @@ -1708,6 +1827,7 @@ class SubEventTest(TestCase): v.pk: Decimal('30.00') } + @classscope(attr='organizer') def test_active_quotas_annotation(self): q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=self.se) @@ -1716,6 +1836,7 @@ class SubEventTest(TestCase): assert SubEvent.annotated(SubEvent.objects).first().active_quotas == [q] assert SubEvent.annotated(SubEvent.objects, 'foo').first().active_quotas == [] + @classscope(attr='organizer') def test_active_quotas_annotation_no_interference(self): se2 = SubEvent.objects.create( name='Testsub', date_from=now(), event=self.event @@ -1727,6 +1848,7 @@ class SubEventTest(TestCase): assert SubEvent.annotated(SubEvent.objects).filter(pk=self.se.pk).first().active_quotas == [] assert SubEvent.annotated(SubEvent.objects).filter(pk=se2.pk).first().active_quotas == [q] + @classscope(attr='organizer') def test_best_availability(self): q = Quota.objects.create(event=self.event, name='Quota', size=0, subevent=self.se) @@ -1768,68 +1890,70 @@ class CheckinListTestCase(TestCase): @classmethod def setUpTestData(cls): cls.organizer = Organizer.objects.create(name='Dummy', slug='dummy') - cls.event = Event.objects.create( - organizer=cls.organizer, name='Dummy', slug='dummy', - date_from=now(), date_to=now() - timedelta(hours=1), - ) - cls.item1 = cls.event.items.create(name="Ticket", default_price=12) - cls.item2 = cls.event.items.create(name="Shirt", default_price=6) - cls.cl_all = cls.event.checkin_lists.create( - name='All', all_products=True - ) - cls.cl_all_pending = cls.event.checkin_lists.create( - name='Z Pending', all_products=True, include_pending=True - ) - cls.cl_both = cls.event.checkin_lists.create( - name='Both', all_products=False - ) - cls.cl_both.limit_products.add(cls.item1) - cls.cl_both.limit_products.add(cls.item2) - cls.cl_tickets = cls.event.checkin_lists.create( - name='Tickets', all_products=False - ) - cls.cl_tickets.limit_products.add(cls.item1) - o = Order.objects.create( - code='FOO', event=cls.event, email='dummy@dummy.test', - status=Order.STATUS_PAID, - datetime=now(), expires=now() + timedelta(days=10), - total=Decimal("30"), locale='en' - ) - OrderPosition.objects.create( - order=o, - item=cls.item1, - variation=None, - price=Decimal("12"), - ) - op2 = OrderPosition.objects.create( - order=o, - item=cls.item1, - variation=None, - price=Decimal("12"), - ) - op3 = OrderPosition.objects.create( - order=o, - item=cls.item2, - variation=None, - price=Decimal("6"), - ) - op2.checkins.create(list=cls.cl_tickets) - op3.checkins.create(list=cls.cl_both) + with scope(organizer=cls.organizer): + cls.event = Event.objects.create( + organizer=cls.organizer, name='Dummy', slug='dummy', + date_from=now(), date_to=now() - timedelta(hours=1), + ) + cls.item1 = cls.event.items.create(name="Ticket", default_price=12) + cls.item2 = cls.event.items.create(name="Shirt", default_price=6) + cls.cl_all = cls.event.checkin_lists.create( + name='All', all_products=True + ) + cls.cl_all_pending = cls.event.checkin_lists.create( + name='Z Pending', all_products=True, include_pending=True + ) + cls.cl_both = cls.event.checkin_lists.create( + name='Both', all_products=False + ) + cls.cl_both.limit_products.add(cls.item1) + cls.cl_both.limit_products.add(cls.item2) + cls.cl_tickets = cls.event.checkin_lists.create( + name='Tickets', all_products=False + ) + cls.cl_tickets.limit_products.add(cls.item1) + o = Order.objects.create( + code='FOO', event=cls.event, email='dummy@dummy.test', + status=Order.STATUS_PAID, + datetime=now(), expires=now() + timedelta(days=10), + total=Decimal("30"), locale='en' + ) + OrderPosition.objects.create( + order=o, + item=cls.item1, + variation=None, + price=Decimal("12"), + ) + op2 = OrderPosition.objects.create( + order=o, + item=cls.item1, + variation=None, + price=Decimal("12"), + ) + op3 = OrderPosition.objects.create( + order=o, + item=cls.item2, + variation=None, + price=Decimal("6"), + ) + op2.checkins.create(list=cls.cl_tickets) + op3.checkins.create(list=cls.cl_both) - o = Order.objects.create( - code='FOO', event=cls.event, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + timedelta(days=10), - total=Decimal("30"), locale='en' - ) - op4 = OrderPosition.objects.create( - order=o, - item=cls.item2, - variation=None, - price=Decimal("6"), - ) - op4.checkins.create(list=cls.cl_all_pending) + o = Order.objects.create( + code='FOO', event=cls.event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + timedelta(days=10), + total=Decimal("30"), locale='en' + ) + op4 = OrderPosition.objects.create( + order=o, + item=cls.item2, + variation=None, + price=Decimal("6"), + ) + op4.checkins.create(list=cls.cl_all_pending) + @classscope(attr='organizer') def test_annotated(self): lists = list(CheckinList.annotate_with_numbers(self.event.checkin_lists.order_by('name'), self.event)) assert lists == [self.cl_all, self.cl_both, self.cl_tickets, self.cl_all_pending] @@ -1881,19 +2005,20 @@ class CheckinListTestCase(TestCase): ]) def test_question_answer_validation(qtype, answer, expected): o = Organizer.objects.create(name='Dummy', slug='dummy') - event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', - date_from=now(), - ) - event.settings.timezone = 'Europe/Berlin' - q = Question(type=qtype, event=event) - if isinstance(expected, type) and issubclass(expected, Exception): - with pytest.raises(expected): - q.clean_answer(answer) - elif callable(expected): - assert expected(q.clean_answer(answer)) - else: - assert q.clean_answer(answer) == expected + with scope(organizer=o): + event = Event.objects.create( + organizer=o, name='Dummy', slug='dummy', + date_from=now(), + ) + event.settings.timezone = 'Europe/Berlin' + q = Question(type=qtype, event=event) + if isinstance(expected, type) and issubclass(expected, Exception): + with pytest.raises(expected): + q.clean_answer(answer) + elif callable(expected): + assert expected(q.clean_answer(answer)) + else: + assert q.clean_answer(answer) == expected @pytest.mark.django_db @@ -1906,45 +2031,47 @@ def test_question_answer_validation_localized_decimal(): @pytest.mark.django_db def test_question_answer_validation_choice(): organizer = Organizer.objects.create(name='Dummy', slug='dummy') - event = Event.objects.create( - organizer=organizer, name='Dummy', slug='dummy', - date_from=now(), date_to=now() - timedelta(hours=1), - ) - q = Question.objects.create(type='C', event=event, question='Q') - o1 = q.options.create(answer='A') - o2 = q.options.create(answer='B') - q2 = Question.objects.create(type='C', event=event, question='Q2') - o3 = q2.options.create(answer='C') - assert q.clean_answer(str(o1.pk)) == o1 - assert q.clean_answer(o1.pk) == o1 - assert q.clean_answer(str(o2.pk)) == o2 - assert q.clean_answer(o2.pk) == o2 - with pytest.raises(ValidationError): - q.clean_answer(str(o2.pk + 1000)) - with pytest.raises(ValidationError): - q.clean_answer('FOO') - with pytest.raises(ValidationError): - q.clean_answer(str(o3.pk)) + with scope(organizer=organizer): + event = Event.objects.create( + organizer=organizer, name='Dummy', slug='dummy', + date_from=now(), date_to=now() - timedelta(hours=1), + ) + q = Question.objects.create(type='C', event=event, question='Q') + o1 = q.options.create(answer='A') + o2 = q.options.create(answer='B') + q2 = Question.objects.create(type='C', event=event, question='Q2') + o3 = q2.options.create(answer='C') + assert q.clean_answer(str(o1.pk)) == o1 + assert q.clean_answer(o1.pk) == o1 + assert q.clean_answer(str(o2.pk)) == o2 + assert q.clean_answer(o2.pk) == o2 + with pytest.raises(ValidationError): + q.clean_answer(str(o2.pk + 1000)) + with pytest.raises(ValidationError): + q.clean_answer('FOO') + with pytest.raises(ValidationError): + q.clean_answer(str(o3.pk)) @pytest.mark.django_db def test_question_answer_validation_multiple_choice(): organizer = Organizer.objects.create(name='Dummy', slug='dummy') - event = Event.objects.create( - organizer=organizer, name='Dummy', slug='dummy', - date_from=now(), date_to=now() - timedelta(hours=1), - ) - q = Question.objects.create(type='M', event=event, question='Q') - o1 = q.options.create(answer='A') - o2 = q.options.create(answer='B') - q.options.create(answer='D') - q2 = Question.objects.create(type='M', event=event, question='Q2') - o3 = q2.options.create(answer='C') - assert q.clean_answer("{},{}".format(str(o1.pk), str(o2.pk))) == [o1, o2] - assert q.clean_answer([str(o1.pk), str(o2.pk)]) == [o1, o2] - assert q.clean_answer([str(o1.pk)]) == [o1] - assert q.clean_answer([o1.pk]) == [o1] - assert q.clean_answer([o1.pk, o3.pk]) == [o1] - assert q.clean_answer([o1.pk, o3.pk + 1000]) == [o1] - with pytest.raises(ValidationError): - assert q.clean_answer([o1.pk, 'FOO']) == [o1] + with scope(organizer=organizer): + event = Event.objects.create( + organizer=organizer, name='Dummy', slug='dummy', + date_from=now(), date_to=now() - timedelta(hours=1), + ) + q = Question.objects.create(type='M', event=event, question='Q') + o1 = q.options.create(answer='A') + o2 = q.options.create(answer='B') + q.options.create(answer='D') + q2 = Question.objects.create(type='M', event=event, question='Q2') + o3 = q2.options.create(answer='C') + assert q.clean_answer("{},{}".format(str(o1.pk), str(o2.pk))) == [o1, o2] + assert q.clean_answer([str(o1.pk), str(o2.pk)]) == [o1, o2] + assert q.clean_answer([str(o1.pk)]) == [o1] + assert q.clean_answer([o1.pk]) == [o1] + assert q.clean_answer([o1.pk, o3.pk]) == [o1] + assert q.clean_answer([o1.pk, o3.pk + 1000]) == [o1] + with pytest.raises(ValidationError): + assert q.clean_answer([o1.pk, 'FOO']) == [o1] diff --git a/src/tests/base/test_notifications.py b/src/tests/base/test_notifications.py index 96fffd7640..68acf15e1a 100644 --- a/src/tests/base/test_notifications.py +++ b/src/tests/base/test_notifications.py @@ -5,6 +5,7 @@ import pytest from django.core import mail as djmail from django.db import transaction from django.utils.timezone import now +from django_scopes import scope from pretix.base.models import ( Event, Item, Order, OrderPosition, Organizer, User, @@ -18,7 +19,8 @@ def event(): organizer=o, name='Dummy', slug='dummy', date_from=now() ) - return event + with scope(organizer=o): + yield event @pytest.fixture diff --git a/src/tests/base/test_orders.py b/src/tests/base/test_orders.py index 073cfbaeea..679660276d 100644 --- a/src/tests/base/test_orders.py +++ b/src/tests/base/test_orders.py @@ -7,6 +7,7 @@ from django.core import mail as djmail from django.test import TestCase from django.utils.timezone import make_aware, now from django_countries.fields import Country +from django_scopes import scope from pretix.base.decimal import round_decimal from pretix.base.models import ( @@ -21,9 +22,10 @@ from pretix.base.services.orders import ( OrderChangeManager, OrderError, _create_order, approve_order, cancel_order, deny_order, expire_orders, send_download_reminders, send_expiry_warnings, ) +from pretix.testutils.scope import classscope -@pytest.fixture +@pytest.fixture(scope='function') def event(): o = Organizer.objects.create(name='Dummy', slug='dummy') event = Event.objects.create( @@ -31,7 +33,8 @@ def event(): date_from=now(), plugins='pretix.plugins.banktransfer' ) - return event + with scope(organizer=o): + yield event @pytest.mark.django_db @@ -312,42 +315,47 @@ def test_deny(event): class PaymentReminderTests(TestCase): def setUp(self): super().setUp() - o = Organizer.objects.create(name='Dummy', slug='dummy') - self.event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', - date_from=now() + timedelta(days=2), - plugins='pretix.plugins.banktransfer' - ) - self.order = Order.objects.create( - code='FOO', event=self.event, email='dummy@dummy.test', - status=Order.STATUS_PENDING, locale='en', - datetime=now() - timedelta(hours=4), - expires=now() - timedelta(hours=4) + timedelta(days=10), - total=Decimal('46.00'), - ) - self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', - default_price=Decimal('23.00'), admission=True) - self.op1 = OrderPosition.objects.create( - order=self.order, item=self.ticket, variation=None, - price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 - ) - djmail.outbox = [] + self.o = Organizer.objects.create(name='Dummy', slug='dummy') + with scope(organizer=self.o): + self.event = Event.objects.create( + organizer=self.o, name='Dummy', slug='dummy', + date_from=now() + timedelta(days=2), + plugins='pretix.plugins.banktransfer' + ) + self.order = Order.objects.create( + code='FOO', event=self.event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, locale='en', + datetime=now() - timedelta(hours=4), + expires=now() - timedelta(hours=4) + timedelta(days=10), + total=Decimal('46.00'), + ) + self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', + default_price=Decimal('23.00'), admission=True) + self.op1 = OrderPosition.objects.create( + order=self.order, item=self.ticket, variation=None, + price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 + ) + djmail.outbox = [] + @classscope(attr='o') def test_disabled(self): send_expiry_warnings(sender=self.event) assert len(djmail.outbox) == 0 + @classscope(attr='o') def test_sent_once(self): self.event.settings.mail_days_order_expire_warning = 12 send_expiry_warnings(sender=self.event) assert len(djmail.outbox) == 1 + @classscope(attr='o') def test_paid(self): self.order.status = Order.STATUS_PAID self.order.save() send_expiry_warnings(sender=self.event) assert len(djmail.outbox) == 0 + @classscope(attr='o') def test_sent_days(self): self.event.settings.mail_days_order_expire_warning = 9 send_expiry_warnings(sender=self.event) @@ -356,6 +364,7 @@ class PaymentReminderTests(TestCase): send_expiry_warnings(sender=self.event) assert len(djmail.outbox) == 1 + @classscope(attr='o') def test_sent_not_immediately_after_purchase(self): self.order.datetime = now() self.order.expires = now() + timedelta(hours=3) @@ -368,31 +377,34 @@ class PaymentReminderTests(TestCase): class DownloadReminderTests(TestCase): def setUp(self): super().setUp() - o = Organizer.objects.create(name='Dummy', slug='dummy') - self.event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', - date_from=now() + timedelta(days=2), - plugins='pretix.plugins.banktransfer' - ) - self.order = Order.objects.create( - code='FOO', event=self.event, email='dummy@dummy.test', - status=Order.STATUS_PAID, locale='en', - datetime=now() - timedelta(hours=4), - expires=now() - timedelta(hours=4) + timedelta(days=10), - total=Decimal('46.00'), - ) - self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', - default_price=Decimal('23.00'), admission=True) - self.op1 = OrderPosition.objects.create( - order=self.order, item=self.ticket, variation=None, - price=Decimal("23.00"), attendee_name_parts={"full_name": "Peter"}, positionid=1 - ) - djmail.outbox = [] + self.o = Organizer.objects.create(name='Dummy', slug='dummy') + with scope(organizer=self.o): + self.event = Event.objects.create( + organizer=self.o, name='Dummy', slug='dummy', + date_from=now() + timedelta(days=2), + plugins='pretix.plugins.banktransfer' + ) + self.order = Order.objects.create( + code='FOO', event=self.event, email='dummy@dummy.test', + status=Order.STATUS_PAID, locale='en', + datetime=now() - timedelta(hours=4), + expires=now() - timedelta(hours=4) + timedelta(days=10), + total=Decimal('46.00'), + ) + self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', + default_price=Decimal('23.00'), admission=True) + self.op1 = OrderPosition.objects.create( + order=self.order, item=self.ticket, variation=None, + price=Decimal("23.00"), attendee_name_parts={"full_name": "Peter"}, positionid=1 + ) + djmail.outbox = [] + @classscope(attr='o') def test_disabled(self): send_download_reminders(sender=self.event) assert len(djmail.outbox) == 0 + @classscope(attr='o') def test_sent_once(self): self.event.settings.mail_days_download_reminder = 2 send_download_reminders(sender=self.event) @@ -401,6 +413,7 @@ class DownloadReminderTests(TestCase): send_download_reminders(sender=self.event) assert len(djmail.outbox) == 1 + @classscope(attr='o') def test_send_to_attendees(self): self.event.settings.mail_send_download_reminder_attendee = True self.event.settings.mail_days_download_reminder = 2 @@ -413,6 +426,7 @@ class DownloadReminderTests(TestCase): assert '/ticket/' in djmail.outbox[1].body assert '/order/' not in djmail.outbox[1].body + @classscope(attr='o') def test_send_not_to_attendees_with_same_address(self): self.event.settings.mail_send_download_reminder_attendee = True self.event.settings.mail_days_download_reminder = 2 @@ -423,6 +437,7 @@ class DownloadReminderTests(TestCase): assert djmail.outbox[0].to == ['dummy@dummy.test'] assert '/order/' in djmail.outbox[0].body + @classscope(attr='o') def test_sent_paid_only(self): self.event.settings.mail_days_download_reminder = 2 self.order.status = Order.STATUS_PENDING @@ -430,11 +445,13 @@ class DownloadReminderTests(TestCase): send_download_reminders(sender=self.event) assert len(djmail.outbox) == 0 + @classscope(attr='o') def test_not_sent_too_early(self): self.event.settings.mail_days_download_reminder = 1 send_download_reminders(sender=self.event) assert len(djmail.outbox) == 0 + @classscope(attr='o') def test_not_sent_too_soon_after_purchase(self): self.order.datetime = now() self.order.save() @@ -446,42 +463,47 @@ class DownloadReminderTests(TestCase): class OrderCancelTests(TestCase): def setUp(self): super().setUp() - o = Organizer.objects.create(name='Dummy', slug='dummy') - self.event = Event.objects.create(organizer=o, name='Dummy', slug='dummy', date_from=now(), - plugins='tests.testdummy') - self.order = Order.objects.create( - code='FOO', event=self.event, email='dummy@dummy.test', - status=Order.STATUS_PENDING, locale='en', - datetime=now(), expires=now() + timedelta(days=10), - total=Decimal('46.00'), - ) - self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', - default_price=Decimal('23.00'), admission=True) - self.op1 = OrderPosition.objects.create( - order=self.order, item=self.ticket, variation=None, - price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 - ) - self.op2 = OrderPosition.objects.create( - order=self.order, item=self.ticket, variation=None, - price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2 - ) - generate_invoice(self.order) - djmail.outbox = [] + self.o = Organizer.objects.create(name='Dummy', slug='dummy') + with scope(organizer=self.o): + self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(), + plugins='tests.testdummy') + self.order = Order.objects.create( + code='FOO', event=self.event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, locale='en', + datetime=now(), expires=now() + timedelta(days=10), + total=Decimal('46.00'), + ) + self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', + default_price=Decimal('23.00'), admission=True) + self.op1 = OrderPosition.objects.create( + order=self.order, item=self.ticket, variation=None, + price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 + ) + self.op2 = OrderPosition.objects.create( + order=self.order, item=self.ticket, variation=None, + price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2 + ) + generate_invoice(self.order) + djmail.outbox = [] + @classscope(attr='o') def test_cancel_canceled(self): self.order.status = Order.STATUS_CANCELED self.order.save() with pytest.raises(OrderError): cancel_order(self.order.pk) + @classscope(attr='o') def test_cancel_send_mail(self): cancel_order(self.order.pk, send_mail=True) assert len(djmail.outbox) == 1 + @classscope(attr='o') def test_cancel_send_no_mail(self): cancel_order(self.order.pk, send_mail=False) assert len(djmail.outbox) == 0 + @classscope(attr='o') def test_cancel_unpaid(self): cancel_order(self.order.pk) self.order.refresh_from_db() @@ -489,6 +511,7 @@ class OrderCancelTests(TestCase): assert self.order.all_logentries().last().action_type == 'pretix.event.order.canceled' assert self.order.invoices.count() == 2 + @classscope(attr='o') def test_cancel_unpaid_with_voucher(self): self.op1.voucher = self.event.vouchers.create(item=self.ticket, redeemed=1) self.op1.save() @@ -500,6 +523,7 @@ class OrderCancelTests(TestCase): assert self.op1.voucher.redeemed == 0 assert self.order.invoices.count() == 2 + @classscope(attr='o') def test_cancel_paid(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -509,6 +533,7 @@ class OrderCancelTests(TestCase): assert self.order.all_logentries().last().action_type == 'pretix.event.order.canceled' assert self.order.invoices.count() == 2 + @classscope(attr='o') def test_cancel_paid_with_too_high_fee(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -519,6 +544,7 @@ class OrderCancelTests(TestCase): assert self.order.status == Order.STATUS_PAID assert self.order.total == 46 + @classscope(attr='o') def test_cancel_paid_with_fee(self): f = self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, value=2.5) self.order.status = Order.STATUS_PAID @@ -543,6 +569,7 @@ class OrderCancelTests(TestCase): assert self.order.invoices.count() == 3 assert not self.order.invoices.last().is_cancellation + @classscope(attr='o') def test_auto_refund_possible(self): p1 = self.order.payments.create( amount=Decimal('46.00'), @@ -558,6 +585,7 @@ class OrderCancelTests(TestCase): assert self.order.all_logentries().filter(action_type='pretix.event.order.refund.created').exists() assert not self.order.all_logentries().filter(action_type='pretix.event.order.refund.requested').exists() + @classscope(attr='o') def test_auto_refund_impossible(self): self.order.payments.create( amount=Decimal('46.00'), @@ -572,39 +600,40 @@ class OrderCancelTests(TestCase): class OrderChangeManagerTests(TestCase): def setUp(self): super().setUp() - o = Organizer.objects.create(name='Dummy', slug='dummy') - self.event = Event.objects.create(organizer=o, name='Dummy', slug='dummy', date_from=now(), - plugins='pretix.plugins.banktransfer') - self.order = Order.objects.create( - code='FOO', event=self.event, email='dummy@dummy.test', - status=Order.STATUS_PENDING, locale='en', - datetime=now(), expires=now() + timedelta(days=10), - total=Decimal('46.00'), - ) - self.order.payments.create( - provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=self.order.total - ) - self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00')) - self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00')) - self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7, - default_price=Decimal('23.00'), admission=True) - self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rule=self.tr7, - default_price=Decimal('23.00'), admission=True) - self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rule=self.tr19, - default_price=Decimal('12.00')) - self.op1 = OrderPosition.objects.create( - order=self.order, item=self.ticket, variation=None, - price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 - ) - self.op2 = OrderPosition.objects.create( - order=self.order, item=self.ticket, variation=None, - price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2 - ) - self.ocm = OrderChangeManager(self.order, None) - self.quota = self.event.quotas.create(name='Test', size=None) - self.quota.items.add(self.ticket) - self.quota.items.add(self.ticket2) - self.quota.items.add(self.shirt) + self.o = Organizer.objects.create(name='Dummy', slug='dummy') + with scope(organizer=self.o): + self.event = Event.objects.create(organizer=self.o, name='Dummy', slug='dummy', date_from=now(), + plugins='pretix.plugins.banktransfer') + self.order = Order.objects.create( + code='FOO', event=self.event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, locale='en', + datetime=now(), expires=now() + timedelta(days=10), + total=Decimal('46.00'), + ) + self.order.payments.create( + provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED, amount=self.order.total + ) + self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00')) + self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00')) + self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7, + default_price=Decimal('23.00'), admission=True) + self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rule=self.tr7, + default_price=Decimal('23.00'), admission=True) + self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rule=self.tr19, + default_price=Decimal('12.00')) + self.op1 = OrderPosition.objects.create( + order=self.order, item=self.ticket, variation=None, + price=Decimal("23.00"), attendee_name_parts={'full_name': "Peter"}, positionid=1 + ) + self.op2 = OrderPosition.objects.create( + order=self.order, item=self.ticket, variation=None, + price=Decimal("23.00"), attendee_name_parts={'full_name': "Dieter"}, positionid=2 + ) + self.ocm = OrderChangeManager(self.order, None) + self.quota = self.event.quotas.create(name='Test', size=None) + self.quota.items.add(self.ticket) + self.quota.items.add(self.ticket2) + self.quota.items.add(self.shirt) def _enable_reverse_charge(self): self.tr7.eu_reverse_charge = True @@ -618,6 +647,7 @@ class OrderChangeManagerTests(TestCase): country=Country('AT') ) + @classscope(attr='o') def test_multiple_commits_forbidden(self): self.ocm.change_price(self.op1, Decimal('10.00')) self.ocm.commit() @@ -625,6 +655,7 @@ class OrderChangeManagerTests(TestCase): with self.assertRaises(OrderError): self.ocm.commit() + @classscope(attr='o') def test_change_subevent_quota_required(self): self.event.has_subevents = True self.event.save() @@ -637,6 +668,7 @@ class OrderChangeManagerTests(TestCase): with self.assertRaises(OrderError): self.ocm.change_subevent(self.op1, se2) + @classscope(attr='o') def test_change_subevent_success(self): self.event.has_subevents = True self.event.save() @@ -656,6 +688,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.price == Decimal('23.00') assert self.order.total == self.op1.price + self.op2.price + @classscope(attr='o') def test_change_subevent_with_price_success(self): self.event.has_subevents = True self.event.save() @@ -676,6 +709,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.price == Decimal('12.00') assert self.order.total == self.op1.price + self.op2.price + @classscope(attr='o') def test_change_subevent_sold_out(self): self.event.has_subevents = True self.event.save() @@ -693,11 +727,13 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.subevent == se1 + @classscope(attr='o') def test_change_item_quota_required(self): self.quota.delete() with self.assertRaises(OrderError): self.ocm.change_item(self.op1, self.shirt, None) + @classscope(attr='o') def test_change_item_keep_price(self): p = self.op1.price self.ocm.change_item(self.op1, self.shirt, None) @@ -709,6 +745,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.tax_value == Decimal('3.67') assert self.op1.tax_rule == self.shirt.tax_rule + @classscope(attr='o') def test_change_item_success(self): self.ocm.change_item(self.op1, self.shirt, None) self.ocm.commit() @@ -720,6 +757,7 @@ class OrderChangeManagerTests(TestCase): assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert self.order.total == self.op1.price + self.op2.price + @classscope(attr='o') def test_change_item_with_price_success(self): self.ocm.change_item(self.op1, self.shirt, None) self.ocm.change_price(self.op1, Decimal('12.00')) @@ -732,6 +770,7 @@ class OrderChangeManagerTests(TestCase): assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert self.order.total == self.op1.price + self.op2.price + @classscope(attr='o') def test_change_price_success(self): self.ocm.change_price(self.op1, Decimal('24.00')) self.ocm.commit() @@ -742,6 +781,7 @@ class OrderChangeManagerTests(TestCase): assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert self.order.total == self.op1.price + self.op2.price + @classscope(attr='o') def test_change_price_net_success(self): self.tr7.price_includes_tax = False self.tr7.save() @@ -754,6 +794,7 @@ class OrderChangeManagerTests(TestCase): assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value assert self.order.total == self.op1.price + self.op2.price + @classscope(attr='o') def test_cancel_success(self): self.ocm.cancel(self.op1) self.ocm.commit() @@ -763,6 +804,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.canceled + @classscope(attr='o') def test_cancel_with_addon(self): self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True) self.ticket.addons.create(addon_category=self.shirt.category) @@ -781,6 +823,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.canceled assert self.op1.addons.first().canceled + @classscope(attr='o') def test_free_to_paid(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -796,6 +839,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.price == Decimal('24.00') assert self.order.status == Order.STATUS_PENDING + @classscope(attr='o') def test_cancel_all_in_order(self): self.ocm.cancel(self.op1) self.ocm.cancel(self.op2) @@ -803,9 +847,11 @@ class OrderChangeManagerTests(TestCase): self.ocm.commit() assert self.order.positions.count() == 2 + @classscope(attr='o') def test_empty(self): self.ocm.commit() + @classscope(attr='o') def test_quota_unlimited(self): q = self.event.quotas.create(name='Test', size=None) q.items.add(self.shirt) @@ -814,6 +860,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.shirt + @classscope(attr='o') def test_quota_full(self): q = self.event.quotas.create(name='Test', size=0) q.items.add(self.shirt) @@ -823,6 +870,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.ticket + @classscope(attr='o') def test_quota_ignore(self): q = self.event.quotas.create(name='Test', size=0) q.items.add(self.shirt) @@ -831,6 +879,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.shirt + @classscope(attr='o') def test_quota_full_but_in_same(self): q = self.event.quotas.create(name='Test', size=0) q.items.add(self.shirt) @@ -840,6 +889,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.shirt + @classscope(attr='o') def test_multiple_quotas_shared_full(self): q1 = self.event.quotas.create(name='Test', size=0) q2 = self.event.quotas.create(name='Test', size=2) @@ -851,6 +901,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.shirt + @classscope(attr='o') def test_multiple_quotas_unshared_full(self): q1 = self.event.quotas.create(name='Test', size=2) q2 = self.event.quotas.create(name='Test', size=0) @@ -863,6 +914,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.ticket + @classscope(attr='o') def test_multiple_items_success(self): q1 = self.event.quotas.create(name='Test', size=2) q1.items.add(self.shirt) @@ -874,6 +926,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.item == self.shirt assert self.op2.item == self.shirt + @classscope(attr='o') def test_multiple_items_quotas_partially_full(self): q1 = self.event.quotas.create(name='Test', size=1) q1.items.add(self.shirt) @@ -886,6 +939,7 @@ class OrderChangeManagerTests(TestCase): assert self.op1.item == self.ticket assert self.op2.item == self.ticket + @classscope(attr='o') def test_payment_fee_calculation(self): self.event.settings.set('tax_rate_default', self.tr19.pk) prov = self.ocm._get_payment_provider() @@ -899,6 +953,7 @@ class OrderChangeManagerTests(TestCase): assert fee.tax_rate == Decimal('19.00') assert round_decimal(fee.value * (1 - 100 / (100 + fee.tax_rate))) == fee.tax_value + @classscope(attr='o') def test_pending_free_order_stays_pending(self): self.event.settings.set('tax_rate_default', self.tr19.pk) self.ocm.change_price(self.op1, Decimal('0.00')) @@ -914,6 +969,7 @@ class OrderChangeManagerTests(TestCase): self.order.refresh_from_db() assert self.order.status == Order.STATUS_PENDING + @classscope(attr='o') def test_require_pending(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -922,6 +978,7 @@ class OrderChangeManagerTests(TestCase): self.op1.refresh_from_db() assert self.op1.item == self.shirt + @classscope(attr='o') def test_change_price_to_free_marked_as_paid(self): self.ocm.change_price(self.op1, Decimal('0.00')) self.ocm.change_price(self.op2, Decimal('0.00')) @@ -931,6 +988,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.status == Order.STATUS_PAID assert self.order.payments.last().provider == 'free' + @classscope(attr='o') def test_change_price_to_free_require_approval(self): self.order.require_approval = True self.order.save() @@ -942,6 +1000,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.total == 0 assert self.order.status == Order.STATUS_PENDING + @classscope(attr='o') def test_change_paid_same_price(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -951,6 +1010,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.total == 46 assert self.order.status == Order.STATUS_PAID + @classscope(attr='o') def test_change_paid_different_price(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -960,6 +1020,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.total == Decimal('28.00') assert self.order.status == Order.STATUS_PAID + @classscope(attr='o') def test_change_paid_to_pending(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -975,6 +1036,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.pending_sum == Decimal('2.00') assert self.order.status == Order.STATUS_PENDING + @classscope(attr='o') def test_change_paid_stays_paid_when_overpaid(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -996,11 +1058,13 @@ class OrderChangeManagerTests(TestCase): assert self.order.pending_sum == Decimal('0.00') assert self.order.status == Order.STATUS_PAID + @classscope(attr='o') def test_add_item_quota_required(self): self.quota.delete() with self.assertRaises(OrderError): self.ocm.add_position(self.shirt, None, None, None) + @classscope(attr='o') def test_add_item_success(self): self.ocm.add_position(self.shirt, None, None, None) self.ocm.commit() @@ -1014,6 +1078,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.total == self.op1.price + self.op2.price + nop.price assert nop.positionid == 3 + @classscope(attr='o') def test_add_item_net_price_success(self): self.tr19.price_includes_tax = False self.tr19.save() @@ -1029,6 +1094,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.total == self.op1.price + self.op2.price + nop.price assert nop.positionid == 3 + @classscope(attr='o') def test_add_item_reverse_charge(self): self._enable_reverse_charge() self.ocm.add_position(self.shirt, None, None, None) @@ -1043,6 +1109,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.total == self.op1.price + self.op2.price + nop.price assert nop.positionid == 3 + @classscope(attr='o') def test_add_item_custom_price(self): self.ocm.add_position(self.shirt, None, Decimal('13.00'), None) self.ocm.commit() @@ -1055,6 +1122,7 @@ class OrderChangeManagerTests(TestCase): assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value assert self.order.total == self.op1.price + self.op2.price + nop.price + @classscope(attr='o') def test_add_item_custom_price_tax_always_included(self): self.tr19.price_includes_tax = False self.tr19.save() @@ -1069,6 +1137,7 @@ class OrderChangeManagerTests(TestCase): assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value assert self.order.total == self.op1.price + self.op2.price + nop.price + @classscope(attr='o') def test_add_item_quota_full(self): q1 = self.event.quotas.create(name='Test', size=0) q1.items.add(self.shirt) @@ -1077,6 +1146,7 @@ class OrderChangeManagerTests(TestCase): self.ocm.commit() assert self.order.positions.count() == 2 + @classscope(attr='o') def test_add_item_addon(self): self.shirt.category = self.event.categories.create(name='Add-ons', is_addon=True) self.ticket.addons.create(addon_category=self.shirt.category) @@ -1088,6 +1158,7 @@ class OrderChangeManagerTests(TestCase): assert nop.item == self.shirt assert nop.addon_to == self.op1 + @classscope(attr='o') def test_add_item_addon_invalid(self): with self.assertRaises(OrderError): self.ocm.add_position(self.shirt, None, Decimal('13.00'), self.op1) @@ -1095,12 +1166,14 @@ class OrderChangeManagerTests(TestCase): with self.assertRaises(OrderError): self.ocm.add_position(self.shirt, None, Decimal('13.00'), None) + @classscope(attr='o') def test_add_item_subevent_required(self): self.event.has_subevents = True self.event.save() with self.assertRaises(OrderError): self.ocm.add_position(self.ticket, None, None, None) + @classscope(attr='o') def test_add_item_subevent_price(self): self.event.has_subevents = True self.event.save() @@ -1118,6 +1191,7 @@ class OrderChangeManagerTests(TestCase): assert nop.price == Decimal('12.00') assert nop.subevent == se1 + @classscope(attr='o') def test_reissue_invoice(self): generate_invoice(self.order) assert self.order.invoices.count() == 1 @@ -1125,6 +1199,7 @@ class OrderChangeManagerTests(TestCase): self.ocm.commit() assert self.order.invoices.count() == 3 + @classscope(attr='o') def test_dont_reissue_invoice_on_free_product_changes(self): self.event.settings.invoice_include_free = False generate_invoice(self.order) @@ -1133,6 +1208,7 @@ class OrderChangeManagerTests(TestCase): self.ocm.commit() assert self.order.invoices.count() == 1 + @classscope(attr='o') def test_recalculate_reverse_charge(self): self.event.settings.set('tax_rate_default', self.tr19.pk) prov = self.ocm._get_payment_provider() @@ -1179,6 +1255,7 @@ class OrderChangeManagerTests(TestCase): assert fee.tax_rate == Decimal('19.00') assert fee.tax_value == Decimal('0.05') + @classscope(attr='o') def test_split_simple(self): old_secret = self.op2.secret self.ocm.split(self.op2) @@ -1198,6 +1275,7 @@ class OrderChangeManagerTests(TestCase): assert not self.order.invoices.exists() assert not o2.invoices.exists() + @classscope(attr='o') def test_split_require_approval(self): self.op2.item.require_approval = True self.op2.item.save() @@ -1222,6 +1300,7 @@ class OrderChangeManagerTests(TestCase): assert not self.order.invoices.exists() assert not o2.invoices.exists() + @classscope(attr='o') def test_split_pending_payment_fees(self): # Set payment fees self.event.settings.set('tax_rate_default', self.tr19.pk) @@ -1262,6 +1341,7 @@ class OrderChangeManagerTests(TestCase): assert o2.positions.count() == 1 assert o2.fees.count() == 1 + @classscope(attr='o') def test_split_paid_no_payment_fees(self): self.order.status = Order.STATUS_PAID self.order.save() @@ -1299,6 +1379,7 @@ class OrderChangeManagerTests(TestCase): assert p.amount == Decimal('23.00') assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED + @classscope(attr='o') def test_split_invoice_address(self): ia = InvoiceAddress.objects.create( order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True, @@ -1325,6 +1406,7 @@ class OrderChangeManagerTests(TestCase): assert o2.invoice_address != ia assert o2.invoice_address.company == 'Sample' + @classscope(attr='o') def test_change_price_of_pending_order_with_payment(self): self.order.status = Order.STATUS_PENDING self.order.save() @@ -1337,6 +1419,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.payments.last().state == OrderPayment.PAYMENT_STATE_CANCELED assert self.order.payments.last().amount == Decimal('46.00') + @classscope(attr='o') def test_split_reverse_charge(self): ia = self._enable_reverse_charge() @@ -1393,6 +1476,7 @@ class OrderChangeManagerTests(TestCase): assert o2.invoice_address != ia assert o2.invoice_address.vat_id_validated is True + @classscope(attr='o') def test_split_other_fees(self): # Check if reverse charge is active self.order.fees.create(fee_type=OrderFee.FEE_TYPE_SHIPPING, tax_rule=self.tr19, value=Decimal('2.50')) @@ -1424,12 +1508,14 @@ class OrderChangeManagerTests(TestCase): assert o2.positions.first().price == Decimal('23.00') assert o2.fees.count() == 1 + @classscope(attr='o') def test_split_to_empty(self): self.ocm.split(self.op1) self.ocm.split(self.op2) with self.assertRaises(OrderError): self.ocm.commit() + @classscope(attr='o') def test_split_paid_payment_fees(self): # Set payment fees self.event.settings.set('tax_rate_default', self.tr19.pk) @@ -1472,6 +1558,7 @@ class OrderChangeManagerTests(TestCase): assert o2.total == Decimal('23.00') assert o2.fees.count() == 0 + @classscope(attr='o') def test_split_invoice(self): generate_invoice(self.order) assert self.order.invoices.count() == 1 @@ -1487,6 +1574,7 @@ class OrderChangeManagerTests(TestCase): assert o2.invoices.count() == 1 assert o2.invoices.last().lines.count() == 1 + @classscope(attr='o') def test_split_to_free_invoice(self): self.event.settings.invoice_include_free = False self.ocm.change_price(self.op2, Decimal('0.00')) @@ -1508,6 +1596,7 @@ class OrderChangeManagerTests(TestCase): assert self.order.invoices.last().lines.count() == 1 assert o2.invoices.count() == 0 + @classscope(attr='o') def test_split_to_original_free(self): self.ocm.change_price(self.op2, Decimal('0.00')) self.ocm.commit() @@ -1525,6 +1614,7 @@ class OrderChangeManagerTests(TestCase): assert o2.total == Decimal('23.00') assert o2.status == Order.STATUS_PENDING + @classscope(attr='o') def test_split_to_new_free(self): self.ocm.change_price(self.op2, Decimal('0.00')) self.ocm.commit() diff --git a/src/tests/base/test_payment.py b/src/tests/base/test_payment.py index b2321020d7..fff0eeceb7 100644 --- a/src/tests/base/test_payment.py +++ b/src/tests/base/test_payment.py @@ -4,6 +4,7 @@ from decimal import Decimal import pytest import pytz from django.utils.timezone import now +from django_scopes import scope from tests.testdummy.payment import DummyPaymentProvider from pretix.base.models import ( @@ -19,7 +20,8 @@ def event(): organizer=o, name='Dummy', slug='dummy', date_from=now() ) - return event + with scope(organizer=o): + yield event @pytest.mark.django_db diff --git a/src/tests/base/test_permissions.py b/src/tests/base/test_permissions.py index 9ab39cace5..2a2da25403 100644 --- a/src/tests/base/test_permissions.py +++ b/src/tests/base/test_permissions.py @@ -1,6 +1,7 @@ import pytest from django.test import RequestFactory from django.utils.timezone import now +from django_scopes import scope from pretix.base.models import Event, Organizer, Team, User from pretix.multidomain.middlewares import SessionMiddleware @@ -8,7 +9,9 @@ from pretix.multidomain.middlewares import SessionMiddleware @pytest.fixture def organizer(): - return Organizer.objects.create(name='Dummy', slug='dummy') + o = Organizer.objects.create(name='Dummy', slug='dummy') + with scope(organizer=o): + yield o @pytest.fixture @@ -251,25 +254,26 @@ def test_list_of_events(event, user, admin, admin_request): team2.limit_events.add(event) team3.limit_events.add(event3) - events = list(user.get_events_with_any_permission(request=admin_request)) - assert event in events - assert event2 in events - assert event3 in events - assert event4 not in events + with scope(organizer=[event.organizer, orga2]): + events = list(user.get_events_with_any_permission(request=admin_request)) + assert event in events + assert event2 in events + assert event3 in events + assert event4 not in events - events = list(user.get_events_with_permission('can_change_event_settings', request=admin_request)) - assert event not in events - assert event2 not in events - assert event3 in events - assert event4 not in events + events = list(user.get_events_with_permission('can_change_event_settings', request=admin_request)) + assert event not in events + assert event2 not in events + assert event3 in events + assert event4 not in events - assert set(event.get_users_with_any_permission()) == {user} - assert set(event2.get_users_with_any_permission()) == {user} - assert set(event3.get_users_with_any_permission()) == {user} - assert set(event4.get_users_with_any_permission()) == set() + assert set(event.get_users_with_any_permission()) == {user} + assert set(event2.get_users_with_any_permission()) == {user} + assert set(event3.get_users_with_any_permission()) == {user} + assert set(event4.get_users_with_any_permission()) == set() - assert set(event.get_users_with_permission('can_change_event_settings')) == set() - assert set(event2.get_users_with_permission('can_change_event_settings')) == set() - assert set(event3.get_users_with_permission('can_change_event_settings')) == {user} - assert set(event4.get_users_with_permission('can_change_event_settings')) == set() - assert set(event.get_users_with_permission('can_change_orders')) == {user} + assert set(event.get_users_with_permission('can_change_event_settings')) == set() + assert set(event2.get_users_with_permission('can_change_event_settings')) == set() + assert set(event3.get_users_with_permission('can_change_event_settings')) == {user} + assert set(event4.get_users_with_permission('can_change_event_settings')) == set() + assert set(event.get_users_with_permission('can_change_orders')) == {user} diff --git a/src/tests/base/test_reldate.py b/src/tests/base/test_reldate.py index 2f99482087..ac3c2e98e8 100644 --- a/src/tests/base/test_reldate.py +++ b/src/tests/base/test_reldate.py @@ -2,6 +2,7 @@ from datetime import datetime, time import pytest import pytz +from django_scopes import scope from pretix.base.models import Event, Organizer from pretix.base.reldate import RelativeDate, RelativeDateWrapper @@ -41,27 +42,28 @@ def test_relative_date_without_time(event): @pytest.mark.django_db def test_relative_date_other_base_point(event): - rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start')) - assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0)) - assert rdw.to_string() == 'RELDATE/1/-/presale_start/' + with scope(organizer=event.organizer): + rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start')) + assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0)) + assert rdw.to_string() == 'RELDATE/1/-/presale_start/' - # presale_end is unset, defaults to date_from - rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end')) - assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 12, 26, 5, 0, 0)) - assert rdw.to_string() == 'RELDATE/1/-/presale_end/' + # presale_end is unset, defaults to date_from + rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end')) + assert rdw.datetime(event) == TOKYO.localize(datetime(2017, 12, 26, 5, 0, 0)) + assert rdw.to_string() == 'RELDATE/1/-/presale_end/' - # subevent base - se = event.subevents.create(name="SE1", date_from=TOKYO.localize(datetime(2017, 11, 27, 5, 0, 0))) - rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from')) - assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0)) + # subevent base + se = event.subevents.create(name="SE1", date_from=TOKYO.localize(datetime(2017, 11, 27, 5, 0, 0))) + rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from')) + assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0)) - # presale_start is unset on subevent, default to event - rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start')) - assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0)) + # presale_start is unset on subevent, default to event + rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start')) + assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 30, 5, 0, 0)) - # presale_end is unset on all, default to date_from of subevent - rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end')) - assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0)) + # presale_end is unset on all, default to date_from of subevent + rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end')) + assert rdw.datetime(se) == TOKYO.localize(datetime(2017, 11, 26, 5, 0, 0)) @pytest.mark.django_db diff --git a/src/tests/base/test_settings.py b/src/tests/base/test_settings.py index 2a01b429bf..5e6e75b59c 100644 --- a/src/tests/base/test_settings.py +++ b/src/tests/base/test_settings.py @@ -1,5 +1,6 @@ from django.test import TestCase from django.utils.timezone import now +from django_scopes import scopes_disabled from i18nfield.strings import LazyI18nString from pretix.base import settings @@ -43,7 +44,8 @@ class SettingsTestCase(TestCase): sandbox['bar'] = 'baz' sandbox.baz = 42 - self.event = Event.objects.get(id=self.event.id) + with scopes_disabled(): + self.event = Event.objects.get(id=self.event.id) sandbox = SettingsSandbox('testing', 'foo', self.event) self.assertEqual(sandbox['bar'], 'baz') self.assertEqual(sandbox.baz, '42') diff --git a/src/tests/base/test_shredders.py b/src/tests/base/test_shredders.py index 1066c25f4e..33968c67ef 100644 --- a/src/tests/base/test_shredders.py +++ b/src/tests/base/test_shredders.py @@ -6,6 +6,7 @@ from decimal import Decimal import pytest from django.core.files.base import ContentFile from django.utils.timezone import now +from django_scopes import scope from pretix.base.models import ( CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order, @@ -27,7 +28,8 @@ def event(): organizer=o, name='Dummy', slug='dummy', date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.ticketoutputpdf' ) - return event + with scope(organizer=o): + yield event @pytest.fixture diff --git a/src/tests/base/test_taxrules.py b/src/tests/base/test_taxrules.py index d597121f54..1e1d7b2d29 100644 --- a/src/tests/base/test_taxrules.py +++ b/src/tests/base/test_taxrules.py @@ -4,6 +4,7 @@ from decimal import Decimal import pytest from django.utils.timezone import now from django_countries.fields import Country +from django_scopes import scope from pretix.base.models import Event, InvoiceAddress, Organizer, TaxRule @@ -15,7 +16,8 @@ def event(): organizer=o, name='Dummy', slug='dummy', date_from=now() ) - return event + with scope(organizer=o): + yield event @pytest.mark.django_db diff --git a/src/tests/base/test_timeline.py b/src/tests/base/test_timeline.py index ab8f409ccf..42d9fdd542 100644 --- a/src/tests/base/test_timeline.py +++ b/src/tests/base/test_timeline.py @@ -3,6 +3,7 @@ from decimal import Decimal import pytest import pytz +from django_scopes import scope from pretix.base.models import Event, Organizer from pretix.base.timeline import timeline_for_event @@ -29,7 +30,8 @@ def event(): date_from=datetime(2017, 10, 22, 12, 0, 0, tzinfo=tz), date_to=datetime(2017, 10, 23, 23, 0, 0, tzinfo=tz), ) - return event + with scope(organizer=o): + yield event @pytest.fixture diff --git a/src/tests/base/test_waitinglist.py b/src/tests/base/test_waitinglist.py index 4377931a2f..1d87b40065 100644 --- a/src/tests/base/test_waitinglist.py +++ b/src/tests/base/test_waitinglist.py @@ -3,6 +3,7 @@ from datetime import timedelta from django.core import mail as djmail from django.test import TestCase from django.utils.timezone import now +from django_scopes import scope from pretix.base.models import ( Event, Item, ItemVariation, Organizer, Quota, Voucher, WaitingListEntry, @@ -11,28 +12,31 @@ from pretix.base.models.waitinglist import WaitingListException from pretix.base.services.waitinglist import ( assign_automatically, process_waitinglist, ) +from pretix.testutils.scope import classscope class WaitingListTestCase(TestCase): @classmethod def setUpTestData(cls): - o = Organizer.objects.create(name='Dummy', slug='dummy') + cls.o = Organizer.objects.create(name='Dummy', slug='dummy') cls.event = Event.objects.create( - organizer=o, name='Dummy', slug='dummy', + organizer=cls.o, name='Dummy', slug='dummy', date_from=now(), live=True ) def setUp(self): djmail.outbox = [] - self.quota = Quota.objects.create(name="Test", size=2, event=self.event) - self.item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, - admission=True) - self.item2 = Item.objects.create(event=self.event, name="T-Shirt", default_price=23) - self.item3 = Item.objects.create(event=self.event, name="Goodie", default_price=23) - self.var1 = ItemVariation.objects.create(item=self.item2, value='S') - self.var2 = ItemVariation.objects.create(item=self.item2, value='M') - self.var3 = ItemVariation.objects.create(item=self.item3, value='Fancy') + with scope(organizer=self.o): + self.quota = Quota.objects.create(name="Test", size=2, event=self.event) + self.item1 = Item.objects.create(event=self.event, name="Ticket", default_price=23, + admission=True) + self.item2 = Item.objects.create(event=self.event, name="T-Shirt", default_price=23) + self.item3 = Item.objects.create(event=self.event, name="Goodie", default_price=23) + self.var1 = ItemVariation.objects.create(item=self.item2, value='S') + self.var2 = ItemVariation.objects.create(item=self.item2, value='M') + self.var3 = ItemVariation.objects.create(item=self.item3, value='Fancy') + @classscope(attr='o') def test_send_unavailable(self): self.quota.items.add(self.item1) self.quota.size = 0 @@ -43,6 +47,7 @@ class WaitingListTestCase(TestCase): with self.assertRaises(WaitingListException): wle.send_voucher() + @classscope(attr='o') def test_send_double(self): self.quota.variations.add(self.var1) self.quota.size = 1 @@ -54,6 +59,7 @@ class WaitingListTestCase(TestCase): with self.assertRaises(WaitingListException): wle.send_voucher() + @classscope(attr='o') def test_send_variation(self): wle = WaitingListEntry.objects.create( event=self.event, item=self.item2, variation=self.var1, email='foo@bar.com' @@ -72,6 +78,7 @@ class WaitingListTestCase(TestCase): assert len(djmail.outbox) == 1 assert djmail.outbox[0].to == [wle.email] + @classscope(attr='o') def test_send_custom_validity(self): self.event.settings.set('waiting_list_hours', 24) wle = WaitingListEntry.objects.create( @@ -83,103 +90,117 @@ class WaitingListTestCase(TestCase): assert 3600 * 23 < (wle.voucher.valid_until - now()).seconds < 3600 * 24 def test_send_auto(self): - self.quota.variations.add(self.var1) - self.quota.size = 7 - self.quota.save() - for i in range(10): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) - ) - WaitingListEntry.objects.create( - event=self.event, item=self.item1, email='bar{}@bar.com'.format(i) - ) + with scope(organizer=self.o): + self.quota.variations.add(self.var1) + self.quota.size = 7 + self.quota.save() + for i in range(10): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) + ) + WaitingListEntry.objects.create( + event=self.event, item=self.item1, email='bar{}@bar.com'.format(i) + ) assign_automatically.apply(args=(self.event.pk,)) - assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3 - assert Voucher.objects.count() == 17 - assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [ - 'foo7@bar.com', 'foo8@bar.com', 'foo9@bar.com' - ] + with scope(organizer=self.o): + assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3 + assert Voucher.objects.count() == 17 + assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [ + 'foo7@bar.com', 'foo8@bar.com', 'foo9@bar.com' + ] def test_send_auto_respect_priority(self): - self.quota.variations.add(self.var1) - self.quota.size = 7 - self.quota.save() - for i in range(10): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i), - priority=i - ) - WaitingListEntry.objects.create( - event=self.event, item=self.item1, email='bar{}@bar.com'.format(i), - priority=i - ) + with scope(organizer=self.o): + self.quota.variations.add(self.var1) + self.quota.size = 7 + self.quota.save() + for i in range(10): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i), + priority=i + ) + WaitingListEntry.objects.create( + event=self.event, item=self.item1, email='bar{}@bar.com'.format(i), + priority=i + ) assign_automatically.apply(args=(self.event.pk,)) - assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3 - assert Voucher.objects.count() == 17 - assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [ - 'foo0@bar.com', 'foo1@bar.com', 'foo2@bar.com' - ] + with scope(organizer=self.o): + assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 3 + assert Voucher.objects.count() == 17 + assert sorted(list(WaitingListEntry.objects.filter(voucher__isnull=True).values_list('email', flat=True))) == [ + 'foo0@bar.com', 'foo1@bar.com', 'foo2@bar.com' + ] def test_send_auto_quota_infinite(self): - self.quota.variations.add(self.var1) - self.quota.size = None - self.quota.save() - for i in range(10): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) - ) - WaitingListEntry.objects.create( - event=self.event, item=self.item1, email='bar{}@bar.com'.format(i) - ) + with scope(organizer=self.o): + self.quota.variations.add(self.var1) + self.quota.size = None + self.quota.save() + for i in range(10): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) + ) + WaitingListEntry.objects.create( + event=self.event, item=self.item1, email='bar{}@bar.com'.format(i) + ) assign_automatically.apply(args=(self.event.pk,)) - assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 10 - assert Voucher.objects.count() == 10 + with scope(organizer=self.o): + assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 10 + assert Voucher.objects.count() == 10 def test_send_periodic_event_over(self): self.event.settings.set('waiting_list_enabled', True) self.event.settings.set('waiting_list_auto', True) self.event.presale_end = now() - timedelta(days=1) self.event.save() - for i in range(5): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) - ) + with scope(organizer=self.o): + for i in range(5): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) + ) process_waitinglist(None) - assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5 - assert Voucher.objects.count() == 0 - self.event.presale_end = now() + timedelta(days=1) - self.event.save() + with scope(organizer=self.o): + assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5 + assert Voucher.objects.count() == 0 + self.event.presale_end = now() + timedelta(days=1) + self.event.save() def test_send_periodic(self): self.event.settings.set('waiting_list_enabled', True) self.event.settings.set('waiting_list_auto', True) - for i in range(5): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) - ) + with scope(organizer=self.o): + for i in range(5): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) + ) process_waitinglist(None) - assert Voucher.objects.count() == 5 + with scope(organizer=self.o): + assert Voucher.objects.count() == 5 def test_send_periodic_disabled(self): self.event.settings.set('waiting_list_enabled', True) self.event.settings.set('waiting_list_auto', False) - for i in range(5): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) - ) + with scope(organizer=self.o): + for i in range(5): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) + ) process_waitinglist(None) - assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5 - assert Voucher.objects.count() == 0 + with scope(organizer=self.o): + assert WaitingListEntry.objects.filter(voucher__isnull=True).count() == 5 + assert Voucher.objects.count() == 0 def test_send_periodic_disabled2(self): self.event.settings.set('waiting_list_enabled', False) self.event.settings.set('waiting_list_auto', True) - for i in range(5): - WaitingListEntry.objects.create( - event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) - ) + with scope(organizer=self.o): + for i in range(5): + WaitingListEntry.objects.create( + event=self.event, item=self.item2, variation=self.var1, email='foo{}@bar.com'.format(i) + ) process_waitinglist(None) - assert Voucher.objects.count() == 5 + with scope(organizer=self.o): + assert Voucher.objects.count() == 5 diff --git a/src/tests/base/test_webhooks.py b/src/tests/base/test_webhooks.py index d472eaa12f..a11c5e7f5e 100644 --- a/src/tests/base/test_webhooks.py +++ b/src/tests/base/test_webhooks.py @@ -6,6 +6,7 @@ import pytest import responses from django.db import transaction from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.models import Event, Item, Order, OrderPosition, Organizer @@ -83,13 +84,14 @@ def test_webhook_trigger_event_specific(event, order, webhook, monkeypatch_on_co "code": "FOO", "action": "pretix.event.order.paid" } - first = webhook.calls.last() - assert first.webhook == webhook - assert first.target_url == 'https://google.com' - assert first.action_type == 'pretix.event.order.paid' - assert not first.is_retry - assert first.return_code == 200 - assert first.success + with scopes_disabled(): + first = webhook.calls.last() + assert first.webhook == webhook + assert first.target_url == 'https://google.com' + assert first.action_type == 'pretix.event.order.paid' + assert not first.is_retry + assert first.return_code == 200 + assert first.success @pytest.mark.django_db @@ -170,8 +172,9 @@ def test_webhook_retry(event, order, webhook, monkeypatch_on_commit): with transaction.atomic(): order.log_action('pretix.event.order.paid', {}) assert len(responses.calls) == 2 - second = webhook.objects.first() - first = webhook.objects.last() + with scopes_disabled(): + second = webhook.objects.first() + first = webhook.objects.last() assert first.webhook == webhook assert first.target_url == 'https://google.com' diff --git a/src/tests/conftest.py b/src/tests/conftest.py index 77acb14605..084bdcdd90 100644 --- a/src/tests/conftest.py +++ b/src/tests/conftest.py @@ -1,4 +1,7 @@ +import inspect + import pytest +from django_scopes import scopes_disabled from xdist.dsession import DSession CRASHED_ITEMS = set() @@ -31,3 +34,16 @@ def pytest_configure(config): self.sched.check_schedule(node) DSession.handle_crashitem = _handle_crashitem + + +@pytest.hookimpl(hookwrapper=True) +def pytest_fixture_setup(fixturedef, request): + """ + This hack automatically disables django-scopes for all fixtures which are not yield fixtures. + This saves us a *lot* of decorcators… + """ + if inspect.isgeneratorfunction(fixturedef.func): + yield + else: + with scopes_disabled(): + yield diff --git a/src/tests/control/test_auth.py b/src/tests/control/test_auth.py index e09a188c3c..340668a2f3 100644 --- a/src/tests/control/test_auth.py +++ b/src/tests/control/test_auth.py @@ -239,7 +239,7 @@ class Login2FAFormTest(TestCase): def test_totp_invalid(self): response = self.client.get('/control/login/2fa') - assert 'token' in response.rendered_content + assert 'token' in response.content.decode() d = TOTPDevice.objects.create(user=self.user, name='test') totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift) totp.time = time.time() @@ -251,7 +251,7 @@ class Login2FAFormTest(TestCase): def test_totp_valid(self): response = self.client.get('/control/login/2fa') - assert 'token' in response.rendered_content + assert 'token' in response.content.decode() d = TOTPDevice.objects.create(user=self.user, name='test') totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift) totp.time = time.time() @@ -274,7 +274,7 @@ class Login2FAFormTest(TestCase): d = U2FDevice.objects.create(user=self.user, name='test', json_data="{}") response = self.client.get('/control/login/2fa') - assert 'token' in response.rendered_content + assert 'token' in response.content.decode() response = self.client.post('/control/login/2fa'.format(d.pk), { 'token': '{"response": "true"}' }) @@ -291,7 +291,7 @@ class Login2FAFormTest(TestCase): d = U2FDevice.objects.create(user=self.user, name='test', json_data="{}") response = self.client.get('/control/login/2fa') - assert 'token' in response.rendered_content + assert 'token' in response.content.decode() response = self.client.post('/control/login/2fa'.format(d.pk), { 'token': '{"response": "true"}' }) diff --git a/src/tests/control/test_checkins.py b/src/tests/control/test_checkins.py index ae809982da..72be86ac51 100644 --- a/src/tests/control/test_checkins.py +++ b/src/tests/control/test_checkins.py @@ -3,6 +3,7 @@ from decimal import Decimal import pytest from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.models import ( Checkin, Event, Item, ItemAddOn, ItemCategory, LogEntry, Order, @@ -58,12 +59,14 @@ def dashboard_env(): @pytest.mark.django_db +@scopes_disabled() def test_dashboard(dashboard_env): c = checkin_widget(dashboard_env[0]) assert '0/2' in c[0]['content'] @pytest.mark.django_db +@scopes_disabled() def test_dashboard_pending_not_count(dashboard_env): c = checkin_widget(dashboard_env[0]) order_pending = Order.objects.create( @@ -83,6 +86,7 @@ def test_dashboard_pending_not_count(dashboard_env): @pytest.mark.django_db +@scopes_disabled() def test_dashboard_with_checkin(dashboard_env): op = OrderPosition.objects.get( order=dashboard_env[3], @@ -256,11 +260,13 @@ def test_checkins_list_mixed(client, checkin_list_env, query, expected): @pytest.mark.django_db def test_manual_checkins(client, checkin_list_env): client.login(email='dummy@dummy.dummy', password='dummy') - assert not checkin_list_env[5][3].checkins.exists() + with scopes_disabled(): + assert not checkin_list_env[5][3].checkins.exists() client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), { 'checkin': [checkin_list_env[5][3].pk] }) - assert checkin_list_env[5][3].checkins.exists() + with scopes_disabled(): + assert checkin_list_env[5][3].checkins.exists() assert LogEntry.objects.filter( action_type='pretix.event.checkin', object_id=checkin_list_env[5][3].order.pk ).exists() @@ -269,7 +275,8 @@ def test_manual_checkins(client, checkin_list_env): @pytest.mark.django_db def test_manual_checkins_revert(client, checkin_list_env): client.login(email='dummy@dummy.dummy', password='dummy') - assert not checkin_list_env[5][3].checkins.exists() + with scopes_disabled(): + assert not checkin_list_env[5][3].checkins.exists() client.post('/control/event/dummy/dummy/checkinlists/{}/'.format(checkin_list_env[6].pk), { 'checkin': [checkin_list_env[5][3].pk] }) @@ -277,7 +284,8 @@ def test_manual_checkins_revert(client, checkin_list_env): 'checkin': [checkin_list_env[5][3].pk], 'revert': 'true' }) - assert not checkin_list_env[5][3].checkins.exists() + with scopes_disabled(): + assert not checkin_list_env[5][3].checkins.exists() assert LogEntry.objects.filter( action_type='pretix.event.checkin', object_id=checkin_list_env[5][3].order.pk ).exists() @@ -381,11 +389,11 @@ def test_checkins_attendee_name_from_addon_available(client, checkin_list_with_a class CheckinListFormTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.orga1 = Organizer.objects.create(name='CCC', slug='ccc') - self.orga2 = Organizer.objects.create(name='MRM', slug='mrm') self.event1 = Event.objects.create( organizer=self.orga1, name='30C3', slug='30c3', date_from=datetime(2013, 12, 26, tzinfo=timezone.utc), @@ -404,12 +412,14 @@ class CheckinListFormTest(SoupTest): doc = self.post_doc('/control/event/%s/%s/checkinlists/add' % (self.orga1.slug, self.event1.slug), form_data) assert doc.select(".alert-success") self.assertIn("All", doc.select("#page-wrapper table")[0].text) - assert self.event1.checkin_lists.get( - name='All', all_products=True - ) + with scopes_disabled(): + assert self.event1.checkin_lists.get( + name='All', all_products=True + ) def test_update(self): - cl = self.event1.checkin_lists.create(name='All', all_products=True) + with scopes_disabled(): + cl = self.event1.checkin_lists.create(name='All', all_products=True) doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/change' % (self.orga1.slug, self.event1.slug, cl.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['all_products'] = '' @@ -419,14 +429,17 @@ class CheckinListFormTest(SoupTest): assert doc.select(".alert-success") cl.refresh_from_db() assert not cl.all_products - assert list(cl.limit_products.all()) == [self.item_ticket] + with scopes_disabled(): + assert list(cl.limit_products.all()) == [self.item_ticket] def test_delete(self): - cl = self.event1.checkin_lists.create(name='All', all_products=True) + with scopes_disabled(): + cl = self.event1.checkin_lists.create(name='All', all_products=True) doc = self.get_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/checkinlists/%s/delete' % (self.orga1.slug, self.event1.slug, cl.id), form_data) assert doc.select(".alert-success") self.assertNotIn("VAT", doc.select("#page-wrapper")[0].text) - assert not self.event1.checkin_lists.exists() + with scopes_disabled(): + assert not self.event1.checkin_lists.exists() diff --git a/src/tests/control/test_devices.py b/src/tests/control/test_devices.py index 1c8d061b0e..5bcc257ab3 100644 --- a/src/tests/control/test_devices.py +++ b/src/tests/control/test_devices.py @@ -1,5 +1,6 @@ import pytest from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.models import Device, Event, Organizer, Team, User from pretix.base.models.devices import generate_api_token @@ -40,7 +41,7 @@ def admin_team(organizer): def test_list_of_devices(event, admin_user, client, device): client.login(email='dummy@dummy.dummy', password='dummy') resp = client.get('/control/organizer/dummy/devices') - assert 'Cashdesk' in resp.rendered_content + assert 'Cashdesk' in resp.content.decode() @pytest.mark.django_db @@ -50,11 +51,13 @@ def test_create_device(event, admin_user, admin_team, client): 'name': 'Foo', 'limit_events': str(event.pk), }, follow=True) - d = Device.objects.last() - assert d.name == 'Foo' - assert not d.all_events - assert list(d.limit_events.all()) == [event] - assert d.initialization_token in resp.content.decode() + print(resp.status_code, resp.content) + with scopes_disabled(): + d = Device.objects.last() + assert d.name == 'Foo' + assert not d.all_events + assert list(d.limit_events.all()) == [event] + assert d.initialization_token in resp.content.decode() @pytest.mark.django_db @@ -67,13 +70,15 @@ def test_update_device(event, admin_user, admin_team, device, client): device.refresh_from_db() assert device.name == 'Cashdesk 2' assert not device.all_events - assert list(device.limit_events.all()) == [event] + with scopes_disabled(): + assert list(device.limit_events.all()) == [event] @pytest.mark.django_db def test_revoke_device(event, admin_user, admin_team, device, client): client.login(email='dummy@dummy.dummy', password='dummy') - device.api_token = generate_api_token() + with scopes_disabled(): + device.api_token = generate_api_token() device.initialized = now() device.save() diff --git a/src/tests/control/test_events.py b/src/tests/control/test_events.py index 04b0e5a618..6c561237ac 100644 --- a/src/tests/control/test_events.py +++ b/src/tests/control/test_events.py @@ -3,6 +3,7 @@ from decimal import Decimal import pytz from django.utils.timezone import now +from django_scopes import scopes_disabled from i18nfield.strings import LazyI18nString from pytz import timezone from tests.base import SoupTest, extract_form_fields @@ -15,6 +16,7 @@ from pretix.testutils.mock import mocker_context class EventsTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') @@ -49,7 +51,8 @@ class EventsTest(SoupTest): self.assertNotIn("MRMCD14", tabletext) def test_quick_setup_later(self): - self.event1.quotas.create(name='foo', size=2) + with scopes_disabled(): + self.event1.quotas.create(name='foo', size=2) resp = self.client.get('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug)) self.assertRedirects(resp, '/control/event/%s/%s/' % (self.orga1.slug, self.event1.slug)) @@ -86,18 +89,19 @@ class EventsTest(SoupTest): assert self.event1.settings.payment_banktransfer__enabled assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo" assert 'pretix.plugins.banktransfer' in self.event1.plugins - assert self.event1.items.count() == 2 - i = self.event1.items.first() - assert str(i.name) == "Normal ticket" - assert i.default_price == Decimal('13.90') - i = self.event1.items.last() - assert str(i.name) == "Reduced ticket" - assert i.default_price == Decimal('13.20') - assert self.event1.quotas.count() == 1 - q = self.event1.quotas.first() - assert q.name == 'Tickets' - assert q.size == 300 - assert q.items.count() == 2 + with scopes_disabled(): + assert self.event1.items.count() == 2 + i = self.event1.items.first() + assert str(i.name) == "Normal ticket" + assert i.default_price == Decimal('13.90') + i = self.event1.items.last() + assert str(i.name) == "Reduced ticket" + assert i.default_price == Decimal('13.20') + assert self.event1.quotas.count() == 1 + q = self.event1.quotas.first() + assert q.name == 'Tickets' + assert q.size == 300 + assert q.items.count() == 2 def test_quick_setup_single_quota(self): doc = self.get_doc('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug)) @@ -132,22 +136,23 @@ class EventsTest(SoupTest): assert self.event1.settings.payment_banktransfer__enabled assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo" assert 'pretix.plugins.banktransfer' in self.event1.plugins - assert self.event1.items.count() == 2 - i = self.event1.items.first() - assert str(i.name) == "Normal ticket" - assert i.default_price == Decimal('13.90') - i = self.event1.items.last() - assert str(i.name) == "Reduced ticket" - assert i.default_price == Decimal('13.20') - assert self.event1.quotas.count() == 2 - q = self.event1.quotas.first() - assert q.name == 'Normal ticket' - assert q.size == 100 - assert q.items.count() == 1 - q = self.event1.quotas.last() - assert q.name == 'Reduced ticket' - assert q.size == 50 - assert q.items.count() == 1 + with scopes_disabled(): + assert self.event1.items.count() == 2 + i = self.event1.items.first() + assert str(i.name) == "Normal ticket" + assert i.default_price == Decimal('13.90') + i = self.event1.items.last() + assert str(i.name) == "Reduced ticket" + assert i.default_price == Decimal('13.20') + assert self.event1.quotas.count() == 2 + q = self.event1.quotas.first() + assert q.name == 'Normal ticket' + assert q.size == 100 + assert q.items.count() == 1 + q = self.event1.quotas.last() + assert q.name == 'Reduced ticket' + assert q.size == 50 + assert q.items.count() == 1 def test_quick_setup_dual_quota(self): doc = self.get_doc('/control/event/%s/%s/quickstart/' % (self.orga1.slug, self.event1.slug)) @@ -182,22 +187,23 @@ class EventsTest(SoupTest): assert self.event1.settings.payment_banktransfer__enabled assert self.event1.settings.get('payment_banktransfer_bank_details', as_type=LazyI18nString).localize('en') == "Foo" assert 'pretix.plugins.banktransfer' in self.event1.plugins - assert self.event1.items.count() == 2 - i = self.event1.items.first() - assert str(i.name) == "Normal ticket" - assert i.default_price == Decimal('13.90') - i = self.event1.items.last() - assert str(i.name) == "Reduced ticket" - assert i.default_price == Decimal('13.20') - assert self.event1.quotas.count() == 3 - q = self.event1.quotas.first() - assert q.name == 'Normal ticket' - assert q.size == 100 - assert q.items.count() == 1 - q = self.event1.quotas.last() - assert q.name == 'Tickets' - assert q.size == 120 - assert q.items.count() == 2 + with scopes_disabled(): + assert self.event1.items.count() == 2 + i = self.event1.items.first() + assert str(i.name) == "Normal ticket" + assert i.default_price == Decimal('13.90') + i = self.event1.items.last() + assert str(i.name) == "Reduced ticket" + assert i.default_price == Decimal('13.20') + assert self.event1.quotas.count() == 3 + q = self.event1.quotas.first() + assert q.name == 'Normal ticket' + assert q.size == 100 + assert q.items.count() == 1 + q = self.event1.quotas.last() + assert q.name == 'Tickets' + assert q.size == 120 + assert q.items.count() == 2 def test_settings(self): doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug)) @@ -257,48 +263,52 @@ class EventsTest(SoupTest): assert self.event1.testmode def test_testmode_disable(self): - o = Order.objects.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en', testmode=True - ) - o2 = Order.objects.create( - code='FOO2', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en' - ) - self.event1.testmode = True - self.event1.save() + with scopes_disabled(): + o = Order.objects.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en', testmode=True + ) + o2 = Order.objects.create( + code='FOO2', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en' + ) + self.event1.testmode = True + self.event1.save() self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug), {'testmode': 'false'}) self.event1.refresh_from_db() assert not self.event1.testmode - assert Order.objects.filter(pk=o.pk).exists() - assert Order.objects.filter(pk=o2.pk).exists() + with scopes_disabled(): + assert Order.objects.filter(pk=o.pk).exists() + assert Order.objects.filter(pk=o2.pk).exists() def test_testmode_disable_delete(self): - o = Order.objects.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en', testmode=True - ) - o2 = Order.objects.create( - code='FOO2', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en' - ) - self.event1.testmode = True - self.event1.save() + with scopes_disabled(): + o = Order.objects.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en', testmode=True + ) + o2 = Order.objects.create( + code='FOO2', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en' + ) + self.event1.testmode = True + self.event1.save() self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug), {'testmode': 'false', 'delete': 'yes'}) self.event1.refresh_from_db() assert not self.event1.testmode - assert not Order.objects.filter(pk=o.pk).exists() - assert Order.objects.filter(pk=o2.pk).exists() + with scopes_disabled(): + assert not Order.objects.filter(pk=o.pk).exists() + assert Order.objects.filter(pk=o2.pk).exists() def test_live_disable(self): self.event1.live = True @@ -309,9 +319,10 @@ class EventsTest(SoupTest): assert not self.event1.live def test_live_ok(self): - self.event1.items.create(name='Test', default_price=5) - self.event1.settings.set('payment_banktransfer__enabled', True) - self.event1.quotas.create(name='Test quota') + with scopes_disabled(): + self.event1.items.create(name='Test', default_price=5) + self.event1.settings.set('payment_banktransfer__enabled', True) + self.event1.quotas.create(name='Test quota') doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug)) assert len(doc.select("input[name=live]")) self.post_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug), @@ -320,16 +331,18 @@ class EventsTest(SoupTest): assert self.event1.live def test_live_dont_require_payment_method_free(self): - self.event1.items.create(name='Test', default_price=0) - self.event1.settings.set('payment_banktransfer__enabled', False) - self.event1.quotas.create(name='Test quota') + with scopes_disabled(): + self.event1.items.create(name='Test', default_price=0) + self.event1.settings.set('payment_banktransfer__enabled', False) + self.event1.quotas.create(name='Test quota') doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug)) assert len(doc.select("input[name=live]")) def test_live_require_payment_method(self): - self.event1.items.create(name='Test', default_price=5) - self.event1.settings.set('payment_banktransfer__enabled', False) - self.event1.quotas.create(name='Test quota') + with scopes_disabled(): + self.event1.items.create(name='Test', default_price=5) + self.event1.settings.set('payment_banktransfer__enabled', False) + self.event1.quotas.create(name='Test quota') doc = self.get_doc('/control/event/%s/%s/live/' % (self.orga1.slug, self.event1.slug)) assert len(doc.select("input[name=live]")) == 0 @@ -378,7 +391,8 @@ class EventsTest(SoupTest): self.event1.save(update_fields=['presale_end']) def test_payment_settings_relative_date_payment_after_presale_end(self): - tr19 = self.event1.tax_rules.create(rate=Decimal('19.00')) + with scopes_disabled(): + tr19 = self.event1.tax_rules.create(rate=Decimal('19.00')) self.event1.presale_end = self.event1.date_from - datetime.timedelta(days=5) self.event1.save(update_fields=['presale_end']) doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), { @@ -578,23 +592,24 @@ class EventsTest(SoupTest): 'copy-copy_from_event': '' }) - ev = Event.objects.get(slug='33c3') - assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) - assert ev.settings.locales == ['en', 'de'] - assert ev.settings.locale == 'en' - assert ev.currency == 'EUR' - assert ev.settings.timezone == 'Europe/Berlin' - assert ev.organizer == self.orga1 - assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) - assert Team.objects.filter(limit_events=ev, members=self.user).exists() + with scopes_disabled(): + ev = Event.objects.get(slug='33c3') + assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) + assert ev.settings.locales == ['en', 'de'] + assert ev.settings.locale == 'en' + assert ev.currency == 'EUR' + assert ev.settings.timezone == 'Europe/Berlin' + assert ev.organizer == self.orga1 + assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) + assert Team.objects.filter(limit_events=ev, members=self.user).exists() - berlin_tz = timezone('Europe/Berlin') - assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) - assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) - assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) - assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) + berlin_tz = timezone('Europe/Berlin') + assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) + assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) + assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) + assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) - assert ev.tax_rules.filter(rate=Decimal('19.00')).exists() + assert ev.tax_rules.filter(rate=Decimal('19.00')).exists() def test_create_event_with_subevents_success(self): doc = self.get_doc('/control/events/add') @@ -635,20 +650,22 @@ class EventsTest(SoupTest): 'event_wizard-prefix': 'event_wizard', 'copy-copy_from_event': '' }) - ev = Event.objects.get(slug='33c3') - assert ev.has_subevents - assert ev.subevents.count() == 1 + with scopes_disabled(): + ev = Event.objects.get(slug='33c3') + assert ev.has_subevents + assert ev.subevents.count() == 1 def test_create_event_copy_success(self): - tr = self.event1.tax_rules.create( - rate=19, name="VAT" - ) - self.event1.items.create( - name='Early-bird ticket', - category=None, default_price=23, tax_rule=tr, - admission=True - ) - self.event1.settings.tax_rate_default = tr + with scopes_disabled(): + tr = self.event1.tax_rules.create( + rate=19, name="VAT" + ) + self.event1.items.create( + name='Early-bird ticket', + category=None, default_price=23, tax_rule=tr, + admission=True + ) + self.event1.settings.tax_rate_default = tr doc = self.get_doc('/control/events/add') doc = self.post_doc('/control/events/add', { @@ -688,34 +705,36 @@ class EventsTest(SoupTest): 'copy-copy_from_event': self.event1.pk }) - ev = Event.objects.get(slug='33c3') - assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) - assert ev.settings.locales == ['en', 'de'] - assert ev.settings.locale == 'en' - assert ev.currency == 'EUR' - assert ev.settings.timezone == 'Europe/Berlin' - assert ev.organizer == self.orga1 - assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) - assert Team.objects.filter(limit_events=ev, members=self.user).exists() - assert ev.items.count() == 1 + with scopes_disabled(): + ev = Event.objects.get(slug='33c3') + assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) + assert ev.settings.locales == ['en', 'de'] + assert ev.settings.locale == 'en' + assert ev.currency == 'EUR' + assert ev.settings.timezone == 'Europe/Berlin' + assert ev.organizer == self.orga1 + assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) + assert Team.objects.filter(limit_events=ev, members=self.user).exists() + assert ev.items.count() == 1 - berlin_tz = timezone('Europe/Berlin') - assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) - assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) - assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) - assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) + berlin_tz = timezone('Europe/Berlin') + assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) + assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) + assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) + assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) - assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1 + assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1 def test_create_event_clone_success(self): - tr = self.event1.tax_rules.create( - rate=19, name="VAT" - ) - self.event1.items.create( - name='Early-bird ticket', - category=None, default_price=23, tax_rule=tr, - admission=True - ) + with scopes_disabled(): + tr = self.event1.tax_rules.create( + rate=19, name="VAT" + ) + self.event1.items.create( + name='Early-bird ticket', + category=None, default_price=23, tax_rule=tr, + admission=True + ) self.event1.settings.tax_rate_default = tr doc = self.get_doc('/control/events/add?clone=' + str(self.event1.pk)) tabletext = doc.select("form")[0].text @@ -754,24 +773,25 @@ class EventsTest(SoupTest): assert not doc.select("#id_copy-copy_from_event_1") - ev = Event.objects.get(slug='33c3') - assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) - assert ev.settings.locales == ['en', 'de'] - assert ev.settings.locale == 'en' - assert ev.currency == 'EUR' - assert ev.settings.timezone == 'Europe/Berlin' - assert ev.organizer == self.orga1 - assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) - assert Team.objects.filter(limit_events=ev, members=self.user).exists() - assert ev.items.count() == 1 + with scopes_disabled(): + ev = Event.objects.get(slug='33c3') + assert ev.name == LazyI18nString({'de': '33C3', 'en': '33C3'}) + assert ev.settings.locales == ['en', 'de'] + assert ev.settings.locale == 'en' + assert ev.currency == 'EUR' + assert ev.settings.timezone == 'Europe/Berlin' + assert ev.organizer == self.orga1 + assert ev.location == LazyI18nString({'de': 'Hamburg', 'en': 'Hamburg'}) + assert Team.objects.filter(limit_events=ev, members=self.user).exists() + assert ev.items.count() == 1 - berlin_tz = timezone('Europe/Berlin') - assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) - assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) - assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) - assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) + berlin_tz = timezone('Europe/Berlin') + assert ev.date_from == berlin_tz.localize(datetime.datetime(2016, 12, 27, 10, 0, 0)).astimezone(pytz.utc) + assert ev.date_to == berlin_tz.localize(datetime.datetime(2016, 12, 30, 19, 0, 0)).astimezone(pytz.utc) + assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc) + assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc) - assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1 + assert ev.tax_rules.filter(rate=Decimal('19.00')).count() == 1 def test_create_event_only_date_from(self): # date_to, presale_start & presale_end are optional fields @@ -806,19 +826,20 @@ class EventsTest(SoupTest): 'copy-copy_from_event': '' }) - ev = Event.objects.get(slug='33c3') - assert ev.name == LazyI18nString({'en': '33C3'}) - assert ev.settings.locales == ['en'] - assert ev.settings.locale == 'en' - assert ev.currency == 'EUR' - assert ev.settings.timezone == 'UTC' - assert ev.organizer == self.orga1 - assert ev.location == LazyI18nString({'en': 'Hamburg'}) - assert Team.objects.filter(limit_events=ev, members=self.user).exists() - assert ev.date_from == datetime.datetime(2016, 12, 27, 10, 0, 0, tzinfo=pytz.utc) - assert ev.date_to is None - assert ev.presale_start is None - assert ev.presale_end is None + with scopes_disabled(): + ev = Event.objects.get(slug='33c3') + assert ev.name == LazyI18nString({'en': '33C3'}) + assert ev.settings.locales == ['en'] + assert ev.settings.locale == 'en' + assert ev.currency == 'EUR' + assert ev.settings.timezone == 'UTC' + assert ev.organizer == self.orga1 + assert ev.location == LazyI18nString({'en': 'Hamburg'}) + assert Team.objects.filter(limit_events=ev, members=self.user).exists() + assert ev.date_from == datetime.datetime(2016, 12, 27, 10, 0, 0, tzinfo=pytz.utc) + assert ev.date_to is None + assert ev.presale_start is None + assert ev.presale_end is None def test_create_event_missing_date_from(self): # date_from is mandatory @@ -909,6 +930,7 @@ class EventsTest(SoupTest): class SubEventsTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') @@ -967,22 +989,23 @@ class SubEventsTest(SoupTest): 'item-%d-price' % self.ticket.pk: '12' }) assert doc.select(".alert-success") - se = self.event1.subevents.first() - assert str(se.name) == "SE2" - assert se.active - assert se.date_from.isoformat() == "2017-07-01T10:00:00+00:00" - assert se.date_to.isoformat() == "2017-07-01T12:00:00+00:00" - assert str(se.location) == "Hamburg" - assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00" - assert not se.presale_end - assert se.quotas.count() == 1 - q = se.quotas.last() - assert q.name == "Q1" - assert q.size == 50 - assert list(q.items.all()) == [self.ticket] - sei = SubEventItem.objects.get(subevent=se, item=self.ticket) - assert sei.price == 12 - assert se.checkinlist_set.count() == 1 + with scopes_disabled(): + se = self.event1.subevents.first() + assert str(se.name) == "SE2" + assert se.active + assert se.date_from.isoformat() == "2017-07-01T10:00:00+00:00" + assert se.date_to.isoformat() == "2017-07-01T12:00:00+00:00" + assert str(se.location) == "Hamburg" + assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00" + assert not se.presale_end + assert se.quotas.count() == 1 + q = se.quotas.last() + assert q.name == "Q1" + assert q.size == 50 + assert list(q.items.all()) == [self.ticket] + sei = SubEventItem.objects.get(subevent=se, item=self.ticket) + assert sei.price == 12 + assert se.checkinlist_set.count() == 1 def test_modify(self): doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk) @@ -1022,14 +1045,15 @@ class SubEventsTest(SoupTest): assert str(se.location) == "Hamburg" assert se.presale_start.isoformat() == "2017-06-20T10:00:00+00:00" assert not se.presale_end - assert se.quotas.count() == 1 - q = se.quotas.last() - assert q.name == "Q1" - assert q.size == 50 - assert list(q.items.all()) == [self.ticket] - sei = SubEventItem.objects.get(subevent=se, item=self.ticket) - assert sei.price == 12 - assert se.checkinlist_set.count() == 1 + with scopes_disabled(): + assert se.quotas.count() == 1 + q = se.quotas.last() + assert q.name == "Q1" + assert q.size == 50 + assert list(q.items.all()) == [self.ticket] + sei = SubEventItem.objects.get(subevent=se, item=self.ticket) + assert sei.price == 12 + assert se.checkinlist_set.count() == 1 def test_delete(self): doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk) @@ -1039,30 +1063,34 @@ class SubEventsTest(SoupTest): # deleting the second event doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent2.pk, {}) assert doc.select(".alert-success") - assert not SubEvent.objects.filter(pk=self.subevent2.pk).exists() - assert not SubEvent.objects.filter(pk=self.subevent1.pk).exists() + with scopes_disabled(): + assert not SubEvent.objects.filter(pk=self.subevent2.pk).exists() + assert not SubEvent.objects.filter(pk=self.subevent1.pk).exists() def test_delete_with_orders(self): - o = Order.objects.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en' - ) - OrderPosition.objects.create( - order=o, - item=self.ticket, - subevent=self.subevent1, - price=Decimal("14"), - ) + with scopes_disabled(): + o = Order.objects.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en' + ) + OrderPosition.objects.create( + order=o, + item=self.ticket, + subevent=self.subevent1, + price=Decimal("14"), + ) doc = self.get_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, follow=True) assert doc.select(".alert-danger") doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/delete' % self.subevent1.pk, {}, follow=True) assert doc.select(".alert-danger") - assert self.event1.subevents.filter(pk=self.subevent1.pk).exists() + with scopes_disabled(): + assert self.event1.subevents.filter(pk=self.subevent1.pk).exists() def test_create_bulk(self): - self.event1.subevents.all().delete() + with scopes_disabled(): + self.event1.subevents.all().delete() self.event1.settings.timezone = 'Europe/Berlin' doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add') @@ -1120,7 +1148,8 @@ class SubEventsTest(SoupTest): 'checkinlist_set-0-limit_products': str(self.ticket.pk), }) assert doc.select(".alert-success") - ses = list(self.event1.subevents.order_by('date_from')) + with scopes_disabled(): + ses = list(self.event1.subevents.order_by('date_from')) assert len(ses) == 10 assert str(ses[0].name) == "Foo" @@ -1128,25 +1157,28 @@ class SubEventsTest(SoupTest): assert ses[0].date_to.isoformat() == "2018-04-03T13:29:31+00:00" assert not ses[0].presale_start assert ses[0].presale_end.isoformat() == "2018-04-02T11:29:31+00:00" - assert ses[0].quotas.count() == 1 - assert list(ses[0].quotas.first().items.all()) == [self.ticket] - assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16 - assert ses[0].checkinlist_set.count() == 1 + with scopes_disabled(): + assert ses[0].quotas.count() == 1 + assert list(ses[0].quotas.first().items.all()) == [self.ticket] + assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16 + assert ses[0].checkinlist_set.count() == 1 assert str(ses[1].name) == "Foo" assert ses[1].date_from.isoformat() == "2019-04-03T11:29:31+00:00" assert ses[1].date_to.isoformat() == "2019-04-03T13:29:31+00:00" assert not ses[1].presale_start assert ses[1].presale_end.isoformat() == "2019-04-02T11:29:31+00:00" - assert ses[1].quotas.count() == 1 - assert list(ses[1].quotas.first().items.all()) == [self.ticket] - assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16 - assert ses[1].checkinlist_set.count() == 1 + with scopes_disabled(): + assert ses[1].quotas.count() == 1 + assert list(ses[1].quotas.first().items.all()) == [self.ticket] + assert SubEventItem.objects.get(subevent=ses[0], item=self.ticket).price == 16 + assert ses[1].checkinlist_set.count() == 1 assert ses[-1].date_from.isoformat() == "2027-04-03T11:29:31+00:00" def test_create_bulk_daily_interval(self): - self.event1.subevents.all().delete() + with scopes_disabled(): + self.event1.subevents.all().delete() self.event1.settings.timezone = 'Europe/Berlin' doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add') @@ -1194,7 +1226,8 @@ class SubEventsTest(SoupTest): 'checkinlist_set-MAX_NUM_FORMS': '1000', }) assert doc.select(".alert-success") - ses = list(self.event1.subevents.order_by('date_from')) + with scopes_disabled(): + ses = list(self.event1.subevents.order_by('date_from')) assert len(ses) == 183 assert ses[0].date_from.isoformat() == "2018-04-03T11:29:31+00:00" @@ -1202,7 +1235,8 @@ class SubEventsTest(SoupTest): assert ses[-1].date_from.isoformat() == "2019-04-02T11:29:31+00:00" def test_create_bulk_exclude(self): - self.event1.subevents.all().delete() + with scopes_disabled(): + self.event1.subevents.all().delete() self.event1.settings.timezone = 'Europe/Berlin' doc = self.get_doc('/control/event/ccc/30c3/subevents/bulk_add') @@ -1265,7 +1299,8 @@ class SubEventsTest(SoupTest): 'checkinlist_set-MAX_NUM_FORMS': '1000', }) assert doc.select(".alert-success") - ses = list(self.event1.subevents.order_by('date_from')) + with scopes_disabled(): + ses = list(self.event1.subevents.order_by('date_from')) assert len(ses) == 314 assert ses[0].date_from.isoformat() == "2018-04-03T11:29:31+00:00" @@ -1273,7 +1308,8 @@ class SubEventsTest(SoupTest): assert ses[6].date_from.isoformat() == "2018-04-10T11:29:31+00:00" def test_create_bulk_monthly_interval(self): - self.event1.subevents.all().delete() + with scopes_disabled(): + self.event1.subevents.all().delete() self.event1.settings.timezone = 'Europe/Berlin' doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_add', { @@ -1320,7 +1356,8 @@ class SubEventsTest(SoupTest): 'checkinlist_set-MAX_NUM_FORMS': '1000', }) assert doc.select(".alert-success") - ses = list(self.event1.subevents.order_by('date_from')) + with scopes_disabled(): + ses = list(self.event1.subevents.order_by('date_from')) assert len(ses) == 12 assert ses[0].date_from.isoformat() == "2018-04-30T11:29:31+00:00" @@ -1328,7 +1365,8 @@ class SubEventsTest(SoupTest): assert ses[-1].date_from.isoformat() == "2019-03-29T12:29:31+00:00" def test_create_bulk_weekly_interval(self): - self.event1.subevents.all().delete() + with scopes_disabled(): + self.event1.subevents.all().delete() self.event1.settings.timezone = 'Europe/Berlin' doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_add', { @@ -1375,7 +1413,8 @@ class SubEventsTest(SoupTest): 'checkinlist_set-MAX_NUM_FORMS': '1000', }) assert doc.select(".alert-success") - ses = list(self.event1.subevents.order_by('date_from')) + with scopes_disabled(): + ses = list(self.event1.subevents.order_by('date_from')) assert len(ses) == 52 assert ses[0].date_from.isoformat() == "2018-04-05T11:29:31+00:00" @@ -1385,25 +1424,27 @@ class SubEventsTest(SoupTest): def test_delete_bulk(self): self.subevent2.active = True self.subevent2.save() - o = Order.objects.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en' - ) - OrderPosition.objects.create( - order=o, - item=self.ticket, - subevent=self.subevent1, - price=Decimal("14"), - ) + with scopes_disabled(): + o = Order.objects.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en' + ) + OrderPosition.objects.create( + order=o, + item=self.ticket, + subevent=self.subevent1, + price=Decimal("14"), + ) doc = self.post_doc('/control/event/ccc/30c3/subevents/bulk_action', { 'subevent': [str(self.subevent1.pk), str(self.subevent2.pk)], 'action': 'delete_confirm' }, follow=True) assert doc.select(".alert-success") - assert not self.event1.subevents.filter(pk=self.subevent2.pk).exists() - assert self.event1.subevents.get(pk=self.subevent1.pk).active is False + with scopes_disabled(): + assert not self.event1.subevents.filter(pk=self.subevent2.pk).exists() + assert self.event1.subevents.get(pk=self.subevent1.pk).active is False def test_disable_bulk(self): self.subevent2.active = True @@ -1413,7 +1454,8 @@ class SubEventsTest(SoupTest): 'action': 'disable' }, follow=True) assert doc.select(".alert-success") - assert self.event1.subevents.get(pk=self.subevent2.pk).active is False + with scopes_disabled(): + assert self.event1.subevents.get(pk=self.subevent2.pk).active is False def test_enable_bulk(self): self.subevent2.active = False @@ -1423,10 +1465,12 @@ class SubEventsTest(SoupTest): 'action': 'enable' }, follow=True) assert doc.select(".alert-success") - assert self.event1.subevents.get(pk=self.subevent2.pk).active is True + with scopes_disabled(): + assert self.event1.subevents.get(pk=self.subevent2.pk).active is True class EventDeletionTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') @@ -1454,21 +1498,24 @@ class EventDeletionTest(SoupTest): 'slug': '30c3' }) - assert not self.orga1.events.exists() + with scopes_disabled(): + assert not self.orga1.events.exists() def test_delete_wrong_slug(self): self.post_doc('/control/event/ccc/30c3/delete/', { 'user_pw': 'dummy', 'slug': '31c3' }) - assert self.orga1.events.exists() + with scopes_disabled(): + assert self.orga1.events.exists() def test_delete_wrong_pw(self): self.post_doc('/control/event/ccc/30c3/delete/', { 'user_pw': 'invalid', 'slug': '30c3' }) - assert self.orga1.events.exists() + with scopes_disabled(): + assert self.orga1.events.exists() def test_delete_orders(self): Order.objects.create( @@ -1481,4 +1528,5 @@ class EventDeletionTest(SoupTest): 'user_pw': 'dummy', 'slug': '30c3' }) - assert self.orga1.events.exists() + with scopes_disabled(): + assert self.orga1.events.exists() diff --git a/src/tests/control/test_items.py b/src/tests/control/test_items.py index 97e88f2916..fea6872126 100644 --- a/src/tests/control/test_items.py +++ b/src/tests/control/test_items.py @@ -2,6 +2,7 @@ import datetime from decimal import Decimal from django.utils.timezone import now +from django_scopes import scopes_disabled from tests.base import SoupTest, extract_form_fields from pretix.base.models import ( @@ -11,6 +12,7 @@ from pretix.base.models import ( class ItemFormTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') @@ -47,11 +49,13 @@ class CategoriesTest(ItemFormTest): assert doc.select(".alert-success") self.assertIn("T-Shirts", doc.select("#page-wrapper table")[0].text) self.assertNotIn("Entry tickets", doc.select("#page-wrapper table")[0].text) - assert str(ItemCategory.objects.get(id=c.id).name) == 'T-Shirts' + with scopes_disabled(): + assert str(ItemCategory.objects.get(id=c.id).name) == 'T-Shirts' def test_sort(self): - c1 = ItemCategory.objects.create(event=self.event1, name="Entry tickets", position=0) - ItemCategory.objects.create(event=self.event1, name="T-Shirts", position=1) + with scopes_disabled(): + c1 = ItemCategory.objects.create(event=self.event1, name="Entry tickets", position=0) + ItemCategory.objects.create(event=self.event1, name="T-Shirts", position=1) doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug)) self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text) self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text) @@ -67,14 +71,16 @@ class CategoriesTest(ItemFormTest): self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text) def test_delete(self): - c = ItemCategory.objects.create(event=self.event1, name="Entry tickets") + with scopes_disabled(): + c = ItemCategory.objects.create(event=self.event1, name="Entry tickets") doc = self.get_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id), form_data) assert doc.select(".alert-success") self.assertNotIn("Entry tickets", doc.select("#page-wrapper")[0].text) - assert not ItemCategory.objects.filter(id=c.id).exists() + with scopes_disabled(): + assert not ItemCategory.objects.filter(id=c.id).exists() class QuestionsTest(ItemFormTest): @@ -90,8 +96,9 @@ class QuestionsTest(ItemFormTest): self.assertIn("shoe size", doc.select("#page-wrapper table")[0].text) def test_update_choices(self): - c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) - o1 = c.options.create(answer='Germany') + with scopes_disabled(): + c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) + o1 = c.options.create(answer='Germany') doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['form-TOTAL_FORMS'] = '1' @@ -104,12 +111,14 @@ class QuestionsTest(ItemFormTest): self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id), form_data) c.refresh_from_db() - assert c.options.exists() - assert str(c.options.first().answer) == 'England' + with scopes_disabled(): + assert c.options.exists() + assert str(c.options.first().answer) == 'England' def test_delete_choices(self): - c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) - o1 = c.options.create(answer='Germany') + with scopes_disabled(): + c = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) + o1 = c.options.create(answer='Germany') doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['form-TOTAL_FORMS'] = '1' @@ -123,10 +132,12 @@ class QuestionsTest(ItemFormTest): self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id), form_data) c.refresh_from_db() - assert not c.options.exists() + with scopes_disabled(): + assert not c.options.exists() def test_add_choices(self): - c = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True) + with scopes_disabled(): + c = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['type'] = 'C' @@ -139,12 +150,14 @@ class QuestionsTest(ItemFormTest): form_data['form-0-answer_0'] = 'Germany' self.post_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id), form_data) - c = Question.objects.get(id=c.id) - assert c.options.exists() - assert str(c.options.first().answer) == 'Germany' + with scopes_disabled(): + c = Question.objects.get(id=c.id) + assert c.options.exists() + assert str(c.options.first().answer) == 'Germany' def test_update(self): - c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) + with scopes_disabled(): + c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['items'] = self.item1.id @@ -153,13 +166,15 @@ class QuestionsTest(ItemFormTest): form_data) self.assertIn("How old", doc.select("#page-wrapper table")[0].text) self.assertNotIn("shoe size", doc.select("#page-wrapper table")[0].text) - c = Question.objects.get(id=c.id) - self.assertTrue(c.required) - assert str(Question.objects.get(id=c.id).question) == 'How old are you?' + with scopes_disabled(): + c = Question.objects.get(id=c.id) + self.assertTrue(c.required) + assert str(Question.objects.get(id=c.id).question) == 'How old are you?' def test_sort(self): - q1 = Question.objects.create(event=self.event1, question="Vegetarian?", type="N", required=True, position=0) - Question.objects.create(event=self.event1, question="Food allergies?", position=1) + with scopes_disabled(): + q1 = Question.objects.create(event=self.event1, question="Vegetarian?", type="N", required=True, position=0) + Question.objects.create(event=self.event1, question="Food allergies?", position=1) doc = self.get_doc('/control/event/%s/%s/questions/' % (self.orga1.slug, self.event1.slug)) self.assertIn("Vegetarian?", doc.select("table > tbody > tr")[0].text) self.assertIn("Food allergies?", doc.select("table > tbody > tr")[1].text) @@ -175,32 +190,35 @@ class QuestionsTest(ItemFormTest): self.assertIn("Food allergies?", doc.select("table > tbody > tr")[1].text) def test_delete(self): - c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) + with scopes_disabled(): + c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) doc = self.get_doc('/control/event/%s/%s/questions/%s/delete' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/questions/%s/delete' % (self.orga1.slug, self.event1.slug, c.id), form_data) assert doc.select(".alert-success") self.assertNotIn("shoe size", doc.select("#page-wrapper")[0].text) - assert not Question.objects.filter(id=c.id).exists() + with scopes_disabled(): + assert not Question.objects.filter(id=c.id).exists() def test_question_view(self): - c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) + with scopes_disabled(): + c = Question.objects.create(event=self.event1, question="What is your shoe size?", type="N", required=True) - item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1) - o = Order.objects.create(code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, datetime=now(), - expires=now() + datetime.timedelta(days=10), - total=14, locale='en') - op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), - attendee_name_parts={'full_name': "Peter"}) - op.answers.create(question=c, answer='42') - op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), - attendee_name_parts={'full_name': "Michael"}) - op.answers.create(question=c, answer='42') - op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), - attendee_name_parts={'full_name': "Petra"}) - op.answers.create(question=c, answer='39') + item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0, position=1) + o = Order.objects.create(code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, datetime=now(), + expires=now() + datetime.timedelta(days=10), + total=14, locale='en') + op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), + attendee_name_parts={'full_name': "Peter"}) + op.answers.create(question=c, answer='42') + op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), + attendee_name_parts={'full_name': "Michael"}) + op.answers.create(question=c, answer='42') + op = OrderPosition.objects.create(order=o, item=item1, variation=None, price=Decimal("14"), + attendee_name_parts={'full_name': "Petra"}) + op.answers.create(question=c, answer='39') doc = self.get_doc('/control/event/%s/%s/questions/%s/' % (self.orga1.slug, self.event1.slug, c.id)) tbl = doc.select('.container-fluid table.table-bordered tbody')[0] @@ -219,9 +237,10 @@ class QuestionsTest(ItemFormTest): assert tbl.select('tr')[0].select('td')[0].text.strip() == '42' def test_set_dependency(self): - q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) - q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True) - o1 = q1.options.create(answer='Germany') + with scopes_disabled(): + q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) + q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True) + o1 = q1.options.create(answer='Germany') doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q2.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['items'] = self.item1.id @@ -235,10 +254,11 @@ class QuestionsTest(ItemFormTest): assert q2.dependency_value == o1.identifier def test_set_dependency_circular(self): - q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) - o1 = q1.options.create(answer='Germany') - q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="C", required=True, - dependency_question=q1, dependency_value=o1.identifier) + with scopes_disabled(): + q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="C", required=True) + o1 = q1.options.create(answer='Germany') + q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="C", required=True, + dependency_question=q1, dependency_value=o1.identifier) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q1.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['dependency_question'] = q2.pk @@ -248,8 +268,9 @@ class QuestionsTest(ItemFormTest): assert not doc.select(".alert-success") def test_set_dependency_to_non_choice(self): - q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True) - q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True) + with scopes_disabled(): + q1 = Question.objects.create(event=self.event1, question="What country are you from?", type="N", required=True) + q2 = Question.objects.create(event=self.event1, question="What city are you from?", type="T", required=True) doc = self.get_doc('/control/event/%s/%s/questions/%s/change' % (self.orga1.slug, self.event1.slug, q2.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['dependency_question'] = q1.pk @@ -271,11 +292,12 @@ class QuotaTest(ItemFormTest): self.assertIn("Full house", doc.select("#page-wrapper table")[0].text) def test_update(self): - c = Quota.objects.create(event=self.event1, name="Full house", size=500) - item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0) - item2 = Item.objects.create(event=self.event1, name="Business", default_price=0) - ItemVariation.objects.create(item=item2, value="Silver") - ItemVariation.objects.create(item=item2, value="Gold") + with scopes_disabled(): + c = Quota.objects.create(event=self.event1, name="Full house", size=500) + item1 = Item.objects.create(event=self.event1, name="Standard", default_price=0) + item2 = Item.objects.create(event=self.event1, name="Business", default_price=0) + ItemVariation.objects.create(item=item2, value="Silver") + ItemVariation.objects.create(item=item2, value="Gold") doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) [i for i in doc.select('[name=itemvars]') if i.get('value') == str(item1.id)][0]['checked'] = 'checked' form_data = extract_form_fields(doc.select('.container-fluid form')[0]) @@ -285,35 +307,41 @@ class QuotaTest(ItemFormTest): doc = self.get_doc('/control/event/%s/%s/quotas/' % (self.orga1.slug, self.event1.slug)) self.assertIn("350", doc.select("#page-wrapper table")[0].text) self.assertNotIn("500", doc.select("#page-wrapper table")[0].text) - assert Quota.objects.get(id=c.id).size == 350 - assert item1 in Quota.objects.get(id=c.id).items.all() + with scopes_disabled(): + assert Quota.objects.get(id=c.id).size == 350 + assert item1 in Quota.objects.get(id=c.id).items.all() def test_update_subevent(self): self.event1.has_subevents = True self.event1.save() - se1 = self.event1.subevents.create(name="Foo", date_from=now()) - se2 = self.event1.subevents.create(name="Bar", date_from=now()) - c = Quota.objects.create(event=self.event1, name="Full house", size=500, subevent=se1) + with scopes_disabled(): + se1 = self.event1.subevents.create(name="Foo", date_from=now()) + se2 = self.event1.subevents.create(name="Bar", date_from=now()) + c = Quota.objects.create(event=self.event1, name="Full house", size=500, subevent=se1) doc = self.get_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['subevent'] = se2.pk self.post_doc('/control/event/%s/%s/quotas/%s/change' % (self.orga1.slug, self.event1.slug, c.id), form_data) - assert Quota.objects.get(id=c.id).subevent == se2 + with scopes_disabled(): + assert Quota.objects.get(id=c.id).subevent == se2 def test_delete(self): - c = Quota.objects.create(event=self.event1, name="Full house", size=500) + with scopes_disabled(): + c = Quota.objects.create(event=self.event1, name="Full house", size=500) doc = self.get_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/quotas/%s/delete' % (self.orga1.slug, self.event1.slug, c.id), form_data) assert doc.select(".alert-success") self.assertNotIn("Full house", doc.select("#page-wrapper")[0].text) - assert not Quota.objects.filter(id=c.id).exists() + with scopes_disabled(): + assert not Quota.objects.filter(id=c.id).exists() class ItemsTest(ItemFormTest): + @scopes_disabled() def setUp(self): super().setUp() self.item2 = Item.objects.create(event=self.event1, name="Business", default_price=0, position=2, @@ -341,7 +369,7 @@ class ItemsTest(ItemFormTest): 'tax_rate': '19.00' }) resp = self.client.get('/control/event/%s/%s/items/' % (self.orga1.slug, self.event1.slug)) - assert 'T-Shirt' in resp.rendered_content + assert 'T-Shirt' in resp.content.decode() def test_update(self): self.client.post('/control/event/%s/%s/items/%d/' % (self.orga1.slug, self.event1.slug, self.item1.id), { @@ -366,20 +394,23 @@ class ItemsTest(ItemFormTest): 'form-0-min_count': '1', 'form-0-max_count': '2', }) - assert self.item2.addons.exists() - assert self.item2.addons.first().addon_category == self.addoncat + with scopes_disabled(): + assert self.item2.addons.exists() + assert self.item2.addons.first().addon_category == self.addoncat + a = self.item2.addons.first() self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), { 'form-TOTAL_FORMS': '1', 'form-INITIAL_FORMS': '1', 'form-MIN_NUM_FORMS': '0', 'form-MAX_NUM_FORMS': '1000', - 'form-0-id': str(self.item2.addons.first().pk), + 'form-0-id': str(a.pk), 'form-0-addon_category': str(self.addoncat.pk), 'form-0-min_count': '1', 'form-0-max_count': '2', 'form-0-DELETE': 'on', }) - assert not self.item2.addons.exists() + with scopes_disabled(): + assert not self.item2.addons.exists() # Do not allow duplicates self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), { @@ -396,7 +427,8 @@ class ItemsTest(ItemFormTest): 'form-1-min_count': '1', 'form-1-max_count': '2', }) - assert not self.item2.addons.exists() + with scopes_disabled(): + assert not self.item2.addons.exists() def test_manipulate_bundles(self): self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), { @@ -409,8 +441,9 @@ class ItemsTest(ItemFormTest): 'form-0-count': '2', 'form-0-designated_price': '2.00', }) - assert self.item2.bundles.exists() - assert self.item2.bundles.first().bundled_item == self.item1 + with scopes_disabled(): + assert self.item2.bundles.exists() + assert self.item2.bundles.first().bundled_item == self.item1 self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), { 'form-TOTAL_FORMS': '1', 'form-INITIAL_FORMS': '1', @@ -422,7 +455,8 @@ class ItemsTest(ItemFormTest): 'form-0-designated_price': '2.00', 'form-0-DELETE': 'on', }) - assert not self.item2.bundles.exists() + with scopes_disabled(): + assert not self.item2.bundles.exists() # Do not allow self-reference self.client.post('/control/event/%s/%s/items/%d/addons' % (self.orga1.slug, self.event1.slug, self.item2.id), { @@ -435,10 +469,12 @@ class ItemsTest(ItemFormTest): 'form-0-count': '2', 'form-0-designated_price': '2.00', }) - assert not self.item2.bundles.exists() + with scopes_disabled(): + assert not self.item2.bundles.exists() # Do not allow multi-level bundles - self.item1.bundles.create(bundled_item=self.item1, count=1, designated_price=0) + with scopes_disabled(): + self.item1.bundles.create(bundled_item=self.item1, count=1, designated_price=0) self.client.post('/control/event/%s/%s/items/%d/bundles' % (self.orga1.slug, self.event1.slug, self.item2.id), { 'form-TOTAL_FORMS': '1', 'form-INITIAL_FORMS': '0', @@ -449,7 +485,8 @@ class ItemsTest(ItemFormTest): 'form-0-count': '2', 'form-0-designated_price': '2.00', }) - assert not self.item2.bundles.exists() + with scopes_disabled(): + assert not self.item2.bundles.exists() def test_update_variations(self): self.client.post('/control/event/%s/%s/items/%d/variations' % (self.orga1.slug, self.event1.slug, self.item2.id), { @@ -491,39 +528,45 @@ class ItemsTest(ItemFormTest): 'active': 'yes', 'allow_cancel': 'yes' }) - assert not self.item2.variations.filter(pk=self.var2.pk).exists() + with scopes_disabled(): + assert not self.item2.variations.filter(pk=self.var2.pk).exists() def test_delete(self): self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item1.id), {}) - assert not self.event1.items.filter(pk=self.item1.pk).exists() + with scopes_disabled(): + assert not self.event1.items.filter(pk=self.item1.pk).exists() self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item2.id), {}) - assert not self.event1.items.filter(pk=self.item2.pk).exists() + with scopes_disabled(): + assert not self.event1.items.filter(pk=self.item2.pk).exists() def test_delete_ordered(self): - o = Order.objects.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en' - ) - OrderPosition.objects.create( - order=o, - item=self.item1, - variation=None, - price=Decimal("14"), - attendee_name_parts={'full_name': "Peter"} - ) + with scopes_disabled(): + o = Order.objects.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en' + ) + OrderPosition.objects.create( + order=o, + item=self.item1, + variation=None, + price=Decimal("14"), + attendee_name_parts={'full_name': "Peter"} + ) self.client.post('/control/event/%s/%s/items/%d/delete' % (self.orga1.slug, self.event1.slug, self.item1.id), {}) - assert self.event1.items.filter(pk=self.item1.pk).exists() + with scopes_disabled(): + assert self.event1.items.filter(pk=self.item1.pk).exists() self.item1.refresh_from_db() assert not self.item1.active def test_create_copy(self): - q = Question.objects.create(event=self.event1, question="Size", type="N") - q.items.add(self.item2) + with scopes_disabled(): + q = Question.objects.create(event=self.event1, question="Size", type="N") + q.items.add(self.item2) self.item2.sales_channels = ["web", "bar"] self.client.post('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), { @@ -533,22 +576,24 @@ class ItemsTest(ItemFormTest): 'copy_from': str(self.item2.pk), 'has_variations': '1' }) - i_old = Item.objects.get(name__icontains='Business') - i_new = Item.objects.get(name__icontains='Intermediate') - assert i_new.category == i_old.category - assert i_new.description == i_old.description - assert i_new.active == i_old.active - assert i_new.available_from == i_old.available_from - assert i_new.available_until == i_old.available_until - assert i_new.require_voucher == i_old.require_voucher - assert i_new.hide_without_voucher == i_old.hide_without_voucher - assert i_new.allow_cancel == i_old.allow_cancel - assert i_new.sales_channels == i_old.sales_channels - assert set(i_new.questions.all()) == set(i_old.questions.all()) - assert set([str(v.value) for v in i_new.variations.all()]) == set([str(v.value) for v in i_old.variations.all()]) + with scopes_disabled(): + i_old = Item.objects.get(name__icontains='Business') + i_new = Item.objects.get(name__icontains='Intermediate') + assert i_new.category == i_old.category + assert i_new.description == i_old.description + assert i_new.active == i_old.active + assert i_new.available_from == i_old.available_from + assert i_new.available_until == i_old.available_until + assert i_new.require_voucher == i_old.require_voucher + assert i_new.hide_without_voucher == i_old.hide_without_voucher + assert i_new.allow_cancel == i_old.allow_cancel + assert i_new.sales_channels == i_old.sales_channels + assert set(i_new.questions.all()) == set(i_old.questions.all()) + assert set([str(v.value) for v in i_new.variations.all()]) == set([str(v.value) for v in i_old.variations.all()]) def test_add_to_existing_quota(self): - q = Quota.objects.create(event=self.event1, name="New Test Quota", size=50) + with scopes_disabled(): + q = Quota.objects.create(event=self.event1, name="New Test Quota", size=50) doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) @@ -558,10 +603,11 @@ class ItemsTest(ItemFormTest): form_data['quota_add_existing'] = str(q.pk) doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data) - i = Item.objects.get(name__icontains='Existing') + with scopes_disabled(): + i = Item.objects.get(name__icontains='Existing') - assert doc.select(".alert-success") - assert q.items.filter(pk=i.pk).exists() + assert doc.select(".alert-success") + assert q.items.filter(pk=i.pk).exists() def test_add_to_new_quota(self): doc = self.get_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug)) @@ -574,8 +620,9 @@ class ItemsTest(ItemFormTest): doc = self.post_doc('/control/event/%s/%s/items/add' % (self.orga1.slug, self.event1.slug), form_data) assert doc.select(".alert-success") - assert Quota.objects.filter(name__icontains='New Quota').exists() - assert Item.objects.filter(name__icontains='New Item').exists() - i = Item.objects.get(name__icontains='New Item') - q = Quota.objects.get(name__icontains='New Quota') - assert q.items.filter(pk=i.pk).exists() + with scopes_disabled(): + assert Quota.objects.filter(name__icontains='New Quota').exists() + assert Item.objects.filter(name__icontains='New Item').exists() + i = Item.objects.get(name__icontains='New Item') + q = Quota.objects.get(name__icontains='New Quota') + assert q.items.filter(pk=i.pk).exists() diff --git a/src/tests/control/test_orders.py b/src/tests/control/test_orders.py index 01bcecd6e6..bf38623ce2 100644 --- a/src/tests/control/test_orders.py +++ b/src/tests/control/test_orders.py @@ -7,6 +7,7 @@ from bs4 import BeautifulSoup from django.core import mail from django.utils.timezone import now from django_countries.fields import Country +from django_scopes import scopes_disabled from tests.base import SoupTest from tests.plugins.stripe.test_provider import MockedCharge @@ -66,84 +67,87 @@ def env(): @pytest.mark.django_db def test_order_list(client, env): - otherticket = Item.objects.create(event=env[0], name='Early-bird ticket', - category=None, default_price=23, - admission=True) + with scopes_disabled(): + otherticket = Item.objects.create(event=env[0], name='Early-bird ticket', + category=None, default_price=23, + admission=True) client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?query=peter') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?query=hans') - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?query=dummy') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?status=p') - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?status=n') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?status=ne') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?item=%s' % otherticket.id) - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?item=%s' % env[3].id) - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?provider=free') - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?provider=banktransfer') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?status=o') - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() env[2].expires = now() - timedelta(days=10) env[2].save() response = client.get('/control/event/dummy/dummy/orders/?status=o') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?status=pa') - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() env[2].require_approval = True env[2].save() response = client.get('/control/event/dummy/dummy/orders/?status=pa') - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() - q = Question.objects.create(event=env[0], question="Q", type="N", required=True) - q.items.add(env[3]) - op = env[2].positions.first() - qa = QuestionAnswer.objects.create(question=q, orderposition=op, answer="12") + with scopes_disabled(): + q = Question.objects.create(event=env[0], question="Q", type="N", required=True) + q.items.add(env[3]) + op = env[2].positions.first() + qa = QuestionAnswer.objects.create(question=q, orderposition=op, answer="12") response = client.get('/control/event/dummy/dummy/orders/?question=%d&answer=12' % q.pk) - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?question=%d&answer=13' % q.pk) - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() q.type = "C" q.save() - qo1 = q.options.create(answer="Foo") - qo2 = q.options.create(answer="Bar") - qa.options.add(qo1) + with scopes_disabled(): + qo1 = q.options.create(answer="Foo") + qo2 = q.options.create(answer="Bar") + qa.options.add(qo1) response = client.get('/control/event/dummy/dummy/orders/?question=%d&answer=%d' % (q.pk, qo1.pk)) - assert 'FOO' in response.rendered_content + assert 'FOO' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?question=%d&answer=%d' % (q.pk, qo2.pk)) - assert 'FOO' not in response.rendered_content + assert 'FOO' not in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/?status=testmode') - assert 'FOO' not in response.rendered_content - assert 'TEST MODE' not in response.rendered_content + assert 'FOO' not in response.content.decode() + assert 'TEST MODE' not in response.content.decode() env[2].testmode = True env[2].save() response = client.get('/control/event/dummy/dummy/orders/?status=testmode') - assert 'FOO' in response.rendered_content - assert 'TEST MODE' in response.rendered_content + assert 'FOO' in response.content.decode() + assert 'TEST MODE' in response.content.decode() @pytest.mark.django_db def test_order_detail(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/FOO/') - assert 'Early-bird' in response.rendered_content - assert 'Peter' in response.rendered_content - assert 'Lukas Gelöscht' in response.rendered_content - assert 'TEST MODE' not in response.rendered_content + assert 'Early-bird' in response.content.decode() + assert 'Peter' in response.content.decode() + assert 'Lukas Gelöscht' in response.content.decode() + assert 'TEST MODE' not in response.content.decode() @pytest.mark.django_db @@ -152,72 +156,83 @@ def test_order_detail_show_test_mode(client, env): env[2].save() client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/FOO/') - assert 'TEST MODE' in response.rendered_content + assert 'TEST MODE' in response.content.decode() @pytest.mark.django_db def test_order_set_contact(client, env): - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/contact', { 'email': 'admin@rami.io' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.email == 'admin@rami.io' @pytest.mark.django_db def test_order_set_locale(client, env): - q = Quota.objects.create(event=env[0], size=0) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/locale', { 'locale': 'de' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.locale == 'de' @pytest.mark.django_db def test_order_set_locale_with_invalid_locale_value(client, env): - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/locale', { 'locale': 'fr' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.locale == 'en' @pytest.mark.django_db def test_order_set_comment(client, env): - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/comment', { 'comment': 'Foo' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.comment == 'Foo' @pytest.mark.django_db def test_order_transition_to_expired_success(client, env): - q = Quota.objects.create(event=env[0], size=0) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'e' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_EXPIRED @pytest.mark.django_db def test_order_transition_to_paid_in_time_success(client, env): - q = Quota.objects.create(event=env[0], size=0) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/transition', { @@ -225,16 +240,18 @@ def test_order_transition_to_paid_in_time_success(client, env): 'payment_date': now().date().isoformat(), 'status': 'p' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_PAID @pytest.mark.django_db def test_order_transition_to_paid_expired_quota_left(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_EXPIRED - o.save() - q = Quota.objects.create(event=env[0], size=10) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.save() + q = Quota.objects.create(event=env[0], size=10) q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') res = client.post('/control/event/dummy/dummy/orders/FOO/transition', { @@ -242,23 +259,26 @@ def test_order_transition_to_paid_expired_quota_left(client, env): 'payment_date': now().date().isoformat(), 'amount': str(o.pending_sum), }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert res.status_code < 400 assert o.status == Order.STATUS_PAID @pytest.mark.django_db def test_order_approve(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_PENDING - o.require_approval = True - o.save() - q = Quota.objects.create(event=env[0], size=10) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_PENDING + o.require_approval = True + o.save() + q = Quota.objects.create(event=env[0], size=10) q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') res = client.post('/control/event/dummy/dummy/orders/FOO/approve', { }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert res.status_code < 400 assert o.status == Order.STATUS_PENDING assert not o.require_approval @@ -266,16 +286,18 @@ def test_order_approve(client, env): @pytest.mark.django_db def test_order_deny(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_PENDING - o.require_approval = True - o.save() - q = Quota.objects.create(event=env[0], size=10) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_PENDING + o.require_approval = True + o.save() + q = Quota.objects.create(event=env[0], size=10) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') res = client.post('/control/event/dummy/dummy/orders/FOO/deny', { }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert res.status_code < 400 assert o.status == Order.STATUS_CANCELED assert o.require_approval @@ -285,20 +307,23 @@ def test_order_deny(client, env): def test_order_delete_require_testmode(client, env): client.login(email='dummy@dummy.dummy', password='dummy') res = client.get('/control/event/dummy/dummy/orders/FOO/delete', {}, follow=True) - assert 'alert-danger' in res.rendered_content - assert 'Only orders created in test mode can be deleted' in res.rendered_content + assert 'alert-danger' in res.content.decode() + assert 'Only orders created in test mode can be deleted' in res.content.decode() client.post('/control/event/dummy/dummy/orders/FOO/delete', {}, follow=True) - assert Order.objects.get(id=env[2].id) + with scopes_disabled(): + assert Order.objects.get(id=env[2].id) @pytest.mark.django_db def test_order_delete(client, env): - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) o.testmode = True o.save() client.login(email='dummy@dummy.dummy', password='dummy') client.post('/control/event/dummy/dummy/orders/FOO/delete', {}, follow=True) - assert not Order.objects.filter(id=env[2].id).exists() + with scopes_disabled(): + assert not Order.objects.filter(id=env[2].id).exists() @pytest.mark.django_db @@ -317,7 +342,8 @@ def test_order_delete(client, env): (Order.STATUS_PENDING, Order.STATUS_EXPIRED, True), ]) def test_order_transition(client, env, process): - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) o.status = process[0] o.save() client.login(email='dummy@dummy.dummy', password='dummy') @@ -327,7 +353,8 @@ def test_order_transition(client, env, process): 'payment_date': now().date().isoformat(), 'status': process[1] }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) if process[2]: assert o.status == process[1] else: @@ -336,7 +363,8 @@ def test_order_transition(client, env, process): @pytest.mark.django_db def test_order_cancel_free(client, env): - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) o.status = Order.STATUS_PAID o.total = Decimal('0.00') o.save() @@ -345,28 +373,31 @@ def test_order_cancel_free(client, env): client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'c' }) - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_CANCELED @pytest.mark.django_db def test_order_cancel_paid_keep_fee(client, env): - o = Order.objects.get(id=env[2].id) - o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total) - o.status = Order.STATUS_PAID - o.save() - tr7 = o.event.tax_rules.create(rate=Decimal('7.00')) - o.event.settings.tax_rate_default = tr7 + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total) + o.status = Order.STATUS_PAID + o.save() + tr7 = o.event.tax_rules.create(rate=Decimal('7.00')) + o.event.settings.tax_rate_default = tr7 client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/transition?status=c') client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'c', 'cancellation_fee': '6.00' }) - o = Order.objects.get(id=env[2].id) - assert not o.positions.exists() - assert o.all_positions.exists() - f = o.fees.get() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert not o.positions.exists() + assert o.all_positions.exists() + f = o.fees.get() assert f.fee_type == OrderFee.FEE_TYPE_CANCELLATION assert f.value == Decimal('6.00') assert f.tax_value == Decimal('0.39') @@ -379,20 +410,22 @@ def test_order_cancel_paid_keep_fee(client, env): @pytest.mark.django_db def test_order_cancel_pending_keep_fee(client, env): - o = Order.objects.get(id=env[2].id) - o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('8.00')) - o.status = Order.STATUS_PENDING - o.save() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('8.00')) + o.status = Order.STATUS_PENDING + o.save() client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/transition?status=c') client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'c', 'cancellation_fee': '6.00' }) - o = Order.objects.get(id=env[2].id) - assert not o.positions.exists() - assert o.all_positions.exists() - f = o.fees.get() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert not o.positions.exists() + assert o.all_positions.exists() + f = o.fees.get() assert f.fee_type == OrderFee.FEE_TYPE_CANCELLATION assert f.value == Decimal('6.00') assert o.status == Order.STATUS_PAID @@ -402,19 +435,21 @@ def test_order_cancel_pending_keep_fee(client, env): @pytest.mark.django_db def test_order_cancel_pending_fee_too_high(client, env): - o = Order.objects.get(id=env[2].id) - o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('4.00')) - o.status = Order.STATUS_PENDING - o.save() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=Decimal('4.00')) + o.status = Order.STATUS_PENDING + o.save() client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/transition?status=c') client.post('/control/event/dummy/dummy/orders/FOO/transition', { 'status': 'c', 'cancellation_fee': '6.00' }) - o = Order.objects.get(id=env[2].id) - assert o.positions.exists() - assert not o.fees.exists() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.positions.exists() + assert not o.fees.exists() assert o.status == Order.STATUS_PENDING assert o.total == Decimal('14.00') @@ -427,9 +462,10 @@ def test_order_cancel_unpaid_no_fees_allowed(client, env): 'status': 'c', 'cancellation_fee': '6.00' }) - o = Order.objects.get(id=env[2].id) - assert o.positions.exists() - assert not o.fees.exists() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.positions.exists() + assert not o.fees.exists() assert o.status == Order.STATUS_CANCELED assert o.total == Decimal('14.00') @@ -439,16 +475,17 @@ def test_order_invoice_create_forbidden(client, env): client.login(email='dummy@dummy.dummy', password='dummy') env[0].settings.set('invoice_generate', 'no') response = client.post('/control/event/dummy/dummy/orders/FOO/invoice', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_order_invoice_create_duplicate(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - generate_invoice(env[2]) + with scopes_disabled(): + generate_invoice(env[2]) env[0].settings.set('invoice_generate', 'admin') response = client.post('/control/event/dummy/dummy/orders/FOO/invoice', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db @@ -456,68 +493,75 @@ def test_order_invoice_create_ok(client, env): client.login(email='dummy@dummy.dummy', password='dummy') env[0].settings.set('invoice_generate', 'admin') response = client.post('/control/event/dummy/dummy/orders/FOO/invoice', {}, follow=True) - assert 'alert-success' in response.rendered_content - assert env[2].invoices.exists() + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + assert env[2].invoices.exists() @pytest.mark.django_db def test_order_invoice_regenerate(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - i = generate_invoice(env[2]) - InvoiceAddress.objects.create(name_parts={'full_name': 'Foo', "_scheme": "full"}, order=env[2]) - env[0].settings.set('invoice_generate', 'admin') + with scopes_disabled(): + i = generate_invoice(env[2]) + InvoiceAddress.objects.create(name_parts={'full_name': 'Foo', "_scheme": "full"}, order=env[2]) + env[0].settings.set('invoice_generate', 'admin') response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/regenerate' % i.pk, {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() i.refresh_from_db() assert 'Foo' in i.invoice_to - assert env[2].invoices.exists() + with scopes_disabled(): + assert env[2].invoices.exists() @pytest.mark.django_db def test_order_invoice_regenerate_canceled(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - i = generate_invoice(env[2]) - generate_cancellation(i) + with scopes_disabled(): + i = generate_invoice(env[2]) + generate_cancellation(i) response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/regenerate' % i.pk, {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_order_invoice_regenerate_unknown(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/regenerate' % 3, {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_order_invoice_reissue(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - i = generate_invoice(env[2]) - InvoiceAddress.objects.create(name_parts={'full_name': 'Foo', "_scheme": "full"}, order=env[2]) - env[0].settings.set('invoice_generate', 'admin') + with scopes_disabled(): + i = generate_invoice(env[2]) + InvoiceAddress.objects.create(name_parts={'full_name': 'Foo', "_scheme": "full"}, order=env[2]) + env[0].settings.set('invoice_generate', 'admin') response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/reissue' % i.pk, {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() i.refresh_from_db() - assert env[2].invoices.count() == 3 - assert 'Foo' not in env[2].invoices.all()[0].invoice_to - assert 'Foo' not in env[2].invoices.all()[1].invoice_to - assert 'Foo' in env[2].invoices.all()[2].invoice_to + with scopes_disabled(): + assert env[2].invoices.count() == 3 + assert 'Foo' not in env[2].invoices.all()[0].invoice_to + assert 'Foo' not in env[2].invoices.all()[1].invoice_to + assert 'Foo' in env[2].invoices.all()[2].invoice_to @pytest.mark.django_db def test_order_invoice_reissue_canceled(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - i = generate_invoice(env[2]) - generate_cancellation(i) + with scopes_disabled(): + i = generate_invoice(env[2]) + generate_cancellation(i) response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/reissue' % i.pk, {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_order_invoice_reissue_unknown(client, env): client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/invoices/%d/reissue' % 3, {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db @@ -525,124 +569,138 @@ def test_order_resend_link(client, env): mail.outbox = [] client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/resend', {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() assert 'FOO' in mail.outbox[0].body @pytest.mark.django_db def test_order_extend_not_pending(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_PAID - o.save() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_PAID + o.save() client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/FOO/extend', follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() response = client.post('/control/event/dummy/dummy/orders/FOO/extend', follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_order_extend_not_expired(client, env): - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { 'expires': newdate }, follow=True) - assert 'alert-success' in response.rendered_content - o = Order.objects.get(id=env[2].id) - assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" @pytest.mark.django_db def test_order_extend_overdue_quota_empty(client, env): - o = Order.objects.get(id=env[2].id) - o.expires = now() - timedelta(days=5) - o.save() - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.expires = now() - timedelta(days=5) + o.save() + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { 'expires': newdate }, follow=True) - assert 'alert-success' in response.rendered_content - o = Order.objects.get(id=env[2].id) - assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" @pytest.mark.django_db def test_order_extend_overdue_quota_blocked_by_waiting_list(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_EXPIRED - o.expires = now() - timedelta(days=5) - o.save() - q = Quota.objects.create(event=env[0], size=1) - q.items.add(env[3]) - env[0].waitinglistentries.create(item=env[3], email='foo@bar.com') + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.expires = now() - timedelta(days=5) + o.save() + q = Quota.objects.create(event=env[0], size=1) + q.items.add(env[3]) + env[0].waitinglistentries.create(item=env[3], email='foo@bar.com') newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { 'expires': newdate }, follow=True) - assert 'alert-success' in response.rendered_content - o = Order.objects.get(id=env[2].id) - assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" - assert o.status == Order.STATUS_PENDING + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" + assert o.status == Order.STATUS_PENDING @pytest.mark.django_db def test_order_extend_expired_quota_left(client, env): - o = Order.objects.get(id=env[2].id) - o.expires = now() - timedelta(days=5) - o.status = Order.STATUS_EXPIRED - o.save() - generate_cancellation(generate_invoice(o)) - q = Quota.objects.create(event=env[0], size=3) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.expires = now() - timedelta(days=5) + o.status = Order.STATUS_EXPIRED + o.save() + generate_cancellation(generate_invoice(o)) + q = Quota.objects.create(event=env[0], size=3) + q.items.add(env[3]) newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') - assert o.invoices.count() == 2 + with scopes_disabled(): + assert o.invoices.count() == 2 response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { 'expires': newdate }, follow=True) assert b'alert-success' in response.content - o = Order.objects.get(id=env[2].id) - assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" - assert o.status == Order.STATUS_PENDING - assert o.invoices.count() == 3 + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == newdate[:10] + " 23:59:59" + assert o.status == Order.STATUS_PENDING + assert o.invoices.count() == 3 @pytest.mark.django_db def test_order_extend_expired_quota_empty(client, env): - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) o.expires = now() - timedelta(days=5) o.status = Order.STATUS_EXPIRED olddate = o.expires o.save() - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { 'expires': newdate }, follow=True) assert b'alert-danger' in response.content - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == olddate.strftime("%Y-%m-%d %H:%M:%S") assert o.status == Order.STATUS_EXPIRED @pytest.mark.django_db def test_order_extend_expired_quota_empty_ignore(client, env): - o = Order.objects.get(id=env[2].id) - o.expires = now() - timedelta(days=5) - o.status = Order.STATUS_EXPIRED - o.save() - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.expires = now() - timedelta(days=5) + o.status = Order.STATUS_EXPIRED + o.save() + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { @@ -650,46 +708,50 @@ def test_order_extend_expired_quota_empty_ignore(client, env): 'quota_ignore': 'on' }, follow=True) assert b'alert-success' in response.content - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_PENDING @pytest.mark.django_db def test_order_extend_expired_quota_partial(client, env): - o = Order.objects.get(id=env[2].id) - OrderPosition.objects.create( - order=o, - item=env[3], - variation=None, - price=Decimal("14"), - attendee_name_parts={'full_name': "Peter", "_scheme": "full"} - ) - o.expires = now() - timedelta(days=5) - o.status = Order.STATUS_EXPIRED - olddate = o.expires - o.save() - q = Quota.objects.create(event=env[0], size=1) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + OrderPosition.objects.create( + order=o, + item=env[3], + variation=None, + price=Decimal("14"), + attendee_name_parts={'full_name': "Peter", "_scheme": "full"} + ) + o.expires = now() - timedelta(days=5) + o.status = Order.STATUS_EXPIRED + olddate = o.expires + o.save() + q = Quota.objects.create(event=env[0], size=1) + q.items.add(env[3]) newdate = (now() + timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S") client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/extend', { 'expires': newdate }, follow=True) assert b'alert-danger' in response.content - o = Order.objects.get(id=env[2].id) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.expires.strftime("%Y-%m-%d %H:%M:%S") == olddate.strftime("%Y-%m-%d %H:%M:%S") assert o.status == Order.STATUS_EXPIRED @pytest.mark.django_db def test_order_mark_paid_overdue_quota_blocked_by_waiting_list(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_EXPIRED - o.expires = now() - timedelta(days=5) - o.save() - q = Quota.objects.create(event=env[0], size=1) - q.items.add(env[3]) - env[0].waitinglistentries.create(item=env[3], email='foo@bar.com') + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.expires = now() - timedelta(days=5) + o.save() + q = Quota.objects.create(event=env[0], size=1) + q.items.add(env[3]) + env[0].waitinglistentries.create(item=env[3], email='foo@bar.com') client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { @@ -697,19 +759,21 @@ def test_order_mark_paid_overdue_quota_blocked_by_waiting_list(client, env): 'payment_date': now().date().isoformat(), 'amount': str(o.pending_sum), }, follow=True) - assert 'alert-success' in response.rendered_content - o = Order.objects.get(id=env[2].id) + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_PAID @pytest.mark.django_db def test_order_mark_paid_blocked(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_EXPIRED - o.expires = now() - timedelta(days=5) - o.save() - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.expires = now() - timedelta(days=5) + o.save() + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { @@ -717,21 +781,23 @@ def test_order_mark_paid_blocked(client, env): 'payment_date': now().date().isoformat(), 'status': 'p' }, follow=True) - assert 'alert-danger' in response.rendered_content - o = Order.objects.get(id=env[2].id) + assert 'alert-danger' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_EXPIRED @pytest.mark.django_db -def test_order_mark_paid_overpaid_epxired(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_EXPIRED - o.expires = now() - timedelta(days=5) - o.save() - o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total * 2) - assert o.pending_sum == -1 * o.total - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) +def test_order_mark_paid_overpaid_expired(client, env): + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.expires = now() - timedelta(days=5) + o.save() + o.payments.create(state=OrderPayment.PAYMENT_STATE_CONFIRMED, amount=o.total * 2) + assert o.pending_sum == -1 * o.total + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { @@ -740,21 +806,23 @@ def test_order_mark_paid_overpaid_epxired(client, env): 'amount': '0.00', 'force': 'on' }, follow=True) - assert 'alert-success' in response.rendered_content - o = Order.objects.get(id=env[2].id) - assert o.status == Order.STATUS_PAID - assert o.payments.last().amount == 0 - assert o.pending_sum == -1 * o.total + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + assert o.status == Order.STATUS_PAID + assert o.payments.last().amount == 0 + assert o.pending_sum == -1 * o.total @pytest.mark.django_db def test_order_mark_paid_forced(client, env): - o = Order.objects.get(id=env[2].id) - o.status = Order.STATUS_EXPIRED - o.expires = now() - timedelta(days=5) - o.save() - q = Quota.objects.create(event=env[0], size=0) - q.items.add(env[3]) + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) + o.status = Order.STATUS_EXPIRED + o.expires = now() - timedelta(days=5) + o.save() + q = Quota.objects.create(event=env[0], size=0) + q.items.add(env[3]) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/transition', { @@ -763,8 +831,9 @@ def test_order_mark_paid_forced(client, env): 'amount': str(o.pending_sum), 'force': 'on' }, follow=True) - assert 'alert-success' in response.rendered_content - o = Order.objects.get(id=env[2].id) + assert 'alert-success' in response.content.decode() + with scopes_disabled(): + o = Order.objects.get(id=env[2].id) assert o.status == Order.STATUS_PAID @@ -831,7 +900,7 @@ def test_order_sendmail_simple_case(client, order_url, env): follow=True) assert response.status_code == 200 - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() assert len(mail.outbox) == 1 assert mail.outbox[0].to == [order.email] @@ -842,7 +911,7 @@ def test_order_sendmail_simple_case(client, order_url, env): response = client.get(mail_history_url) assert response.status_code == 200 - assert 'Test subject' in response.rendered_content + assert 'Test subject' in response.content.decode() @pytest.mark.django_db @@ -862,7 +931,7 @@ def test_order_sendmail_preview(client, order_url, env): follow=True) assert response.status_code == 200 - assert 'E-mail preview' in response.rendered_content + assert 'E-mail preview' in response.content.decode() assert len(mail.outbox) == 0 @@ -880,17 +949,18 @@ def test_order_sendmail_invalid_data(client, order_url, env): }, follow=True) - assert 'has-error' in response.rendered_content + assert 'has-error' in response.content.decode() assert len(mail.outbox) == 0 mail_history_url = order_url + '/mail_history' response = client.get(mail_history_url) assert response.status_code == 200 - assert 'Test invalid mail' not in response.rendered_content + assert 'Test invalid mail' not in response.content.decode() class OrderChangeTests(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() o = Organizer.objects.create(name='Dummy', slug='dummy') @@ -934,9 +1004,9 @@ class OrderChangeTests(SoupTest): r = self.client.get('/control/event/{}/{}/orders/{}/change'.format( self.event.organizer.slug, self.event.slug, self.order.code )) - assert self.op1.secret[:5] in r.rendered_content - assert self.op2.secret[:5] in r.rendered_content - assert self.op3.secret[:5] not in r.rendered_content + assert self.op1.secret[:5] in r.content.decode() + assert self.op2.secret[:5] in r.content.decode() + assert self.op3.secret[:5] not in r.content.decode() def test_change_item_success(self): self.client.post('/control/event/{}/{}/orders/{}/change'.format( @@ -956,17 +1026,18 @@ class OrderChangeTests(SoupTest): def test_change_subevent_success(self): self.event.has_subevents = True self.event.save() - se1 = self.event.subevents.create(name='Foo', date_from=now()) - se2 = self.event.subevents.create(name='Bar', date_from=now()) - self.op1.subevent = se1 - self.op1.save() - self.op2.subevent = se1 - self.op2.save() - self.quota.subevent = se1 - self.quota.save() - q2 = self.event.quotas.create(name='Q2', size=100, subevent=se2) - q2.items.add(self.ticket) - q2.items.add(self.shirt) + with scopes_disabled(): + se1 = self.event.subevents.create(name='Foo', date_from=now()) + se2 = self.event.subevents.create(name='Bar', date_from=now()) + self.op1.subevent = se1 + self.op1.save() + self.op2.subevent = se1 + self.op2.save() + self.quota.subevent = se1 + self.quota.save() + q2 = self.event.quotas.create(name='Q2', size=100, subevent=se2) + q2.items.add(self.ticket) + q2.items.add(self.shirt) self.client.post('/control/event/{}/{}/orders/{}/change'.format( self.event.organizer.slug, self.event.slug, self.order.code ), { @@ -1005,7 +1076,8 @@ class OrderChangeTests(SoupTest): 'add-itemvar': str(self.ticket.pk), }) self.order.refresh_from_db() - assert self.order.positions.count() == 1 + with scopes_disabled(): + assert self.order.positions.count() == 1 assert self.order.total == self.op2.price def test_add_item_success(self): @@ -1016,9 +1088,10 @@ class OrderChangeTests(SoupTest): 'add-do': 'on', 'add-price': '14.00', }) - assert self.order.positions.count() == 3 - assert self.order.positions.last().item == self.shirt - assert self.order.positions.last().price == 14 + with scopes_disabled(): + assert self.order.positions.count() == 3 + assert self.order.positions.last().item == self.shirt + assert self.order.positions.last().price == 14 def test_recalculate_reverse_charge(self): self.tr7.eu_reverse_charge = True @@ -1027,10 +1100,11 @@ class OrderChangeTests(SoupTest): self.tr19.eu_reverse_charge = True self.tr19.home_country = Country('DE') self.tr19.save() - InvoiceAddress.objects.create( - order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True, - country=Country('AT') - ) + with scopes_disabled(): + InvoiceAddress.objects.create( + order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True, + country=Country('AT') + ) self.client.post('/control/event/{}/{}/orders/{}/change'.format( self.event.organizer.slug, self.event.slug, self.order.code @@ -1045,7 +1119,8 @@ class OrderChangeTests(SoupTest): 'op-{}-price'.format(self.op1.pk): str(self.op1.price), }) - ops = list(self.order.positions.all()) + with scopes_disabled(): + ops = list(self.order.positions.all()) for op in ops: assert op.price == Decimal('21.50') assert op.tax_value == Decimal('0.00') @@ -1055,11 +1130,12 @@ class OrderChangeTests(SoupTest): @pytest.mark.django_db def test_check_vatid(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT')) + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT')) with mock.patch('vat_moss.id.validate') as mock_validate: mock_validate.return_value = ('AT', 'AT123456', 'Foo') response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() ia.refresh_from_db() assert ia.vat_id_validated @@ -1067,11 +1143,12 @@ def test_check_vatid(client, env): @pytest.mark.django_db def test_check_vatid_no_entered(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, country=Country('AT')) + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, country=Country('AT')) with mock.patch('vat_moss.id.validate') as mock_validate: mock_validate.return_value = ('AT', 'AT123456', 'Foo') response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() ia.refresh_from_db() assert not ia.vat_id_validated @@ -1079,11 +1156,12 @@ def test_check_vatid_no_entered(client, env): @pytest.mark.django_db def test_check_vatid_invalid_country(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('FR')) + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('FR')) with mock.patch('vat_moss.id.validate') as mock_validate: mock_validate.return_value = ('AT', 'AT123456', 'Foo') response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() ia.refresh_from_db() assert not ia.vat_id_validated @@ -1091,11 +1169,12 @@ def test_check_vatid_invalid_country(client, env): @pytest.mark.django_db def test_check_vatid_noneu_country(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='CHU1234567', country=Country('CH')) + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='CHU1234567', country=Country('CH')) with mock.patch('vat_moss.id.validate') as mock_validate: mock_validate.return_value = ('AT', 'AT123456', 'Foo') response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() ia.refresh_from_db() assert not ia.vat_id_validated @@ -1103,11 +1182,12 @@ def test_check_vatid_noneu_country(client, env): @pytest.mark.django_db def test_check_vatid_no_country(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567') + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567') with mock.patch('vat_moss.id.validate') as mock_validate: mock_validate.return_value = ('AT', 'AT123456', 'Foo') response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() ia.refresh_from_db() assert not ia.vat_id_validated @@ -1118,13 +1198,14 @@ def test_check_vatid_no_invoiceaddress(client, env): with mock.patch('vat_moss.id.validate') as mock_validate: mock_validate.return_value = ('AT', 'AT123456', 'Foo') response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_check_vatid_invalid(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT')) + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT')) with mock.patch('vat_moss.id.validate') as mock_validate: def raiser(*args, **kwargs): import vat_moss.errors @@ -1132,7 +1213,7 @@ def test_check_vatid_invalid(client, env): mock_validate.side_effect = raiser response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() ia.refresh_from_db() assert not ia.vat_id_validated @@ -1140,7 +1221,8 @@ def test_check_vatid_invalid(client, env): @pytest.mark.django_db def test_check_vatid_unavailable(client, env): client.login(email='dummy@dummy.dummy', password='dummy') - ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT')) + with scopes_disabled(): + ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT')) with mock.patch('vat_moss.id.validate') as mock_validate: def raiser(*args, **kwargs): import vat_moss.errors @@ -1148,57 +1230,60 @@ def test_check_vatid_unavailable(client, env): mock_validate.side_effect = raiser response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() ia.refresh_from_db() assert not ia.vat_id_validated @pytest.mark.django_db def test_cancel_payment(client, env): - p = env[2].payments.last() + with scopes_disabled(): + p = env[2].payments.last() client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/payments/{}/cancel'.format(p.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CANCELED response = client.post('/control/event/dummy/dummy/orders/FOO/payments/{}/cancel'.format(p.pk), {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() @pytest.mark.django_db def test_cancel_refund(client, env): - r = env[2].refunds.create( - provider='stripe', - state='transit', - source='admin', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + r = env[2].refunds.create( + provider='stripe', + state='transit', + source='admin', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/cancel'.format(r.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_CANCELED r.state = OrderRefund.REFUND_STATE_DONE r.save() response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/cancel'.format(r.pk), {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_DONE @pytest.mark.django_db def test_process_refund(client, env): - r = env[2].refunds.create( - provider='stripe', - state='external', - source='external', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + r = env[2].refunds.create( + provider='stripe', + state='external', + source='external', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/process'.format(r.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_DONE env[2].refresh_from_db() @@ -1207,24 +1292,25 @@ def test_process_refund(client, env): @pytest.mark.django_db def test_process_refund_overpaid_externally(client, env): - env[2].payments.first().confirm() - env[2].payments.create( - state='confirmed', - provider='stripe', - amount=Decimal('14.00'), - payment_date=now() - ) - assert env[2].pending_sum == -14 - r = env[2].refunds.create( - provider='stripe', - state='external', - source='external', - amount=Decimal('14.00'), - execution_date=now(), - ) + with scopes_disabled(): + env[2].payments.first().confirm() + env[2].payments.create( + state='confirmed', + provider='stripe', + amount=Decimal('14.00'), + payment_date=now() + ) + assert env[2].pending_sum == -14 + r = env[2].refunds.create( + provider='stripe', + state='external', + source='external', + amount=Decimal('14.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/process'.format(r.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_DONE env[2].refresh_from_db() @@ -1234,33 +1320,35 @@ def test_process_refund_overpaid_externally(client, env): @pytest.mark.django_db def test_process_refund_invalid_state(client, env): - r = env[2].refunds.create( - provider='stripe', - state='canceled', - source='external', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + r = env[2].refunds.create( + provider='stripe', + state='canceled', + source='external', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/process'.format(r.pk), {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_CANCELED @pytest.mark.django_db def test_process_refund_mark_refunded(client, env): - r = env[2].refunds.create( - provider='stripe', - state='external', - source='external', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + r = env[2].refunds.create( + provider='stripe', + state='external', + source='external', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/process'.format(r.pk), {'action': 'r'}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_DONE env[2].refresh_from_db() @@ -1269,42 +1357,45 @@ def test_process_refund_mark_refunded(client, env): @pytest.mark.django_db def test_done_refund(client, env): - r = env[2].refunds.create( - provider='stripe', - state='transit', - source='admin', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + r = env[2].refunds.create( + provider='stripe', + state='transit', + source='admin', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/done'.format(r.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_DONE @pytest.mark.django_db def test_done_refund_invalid_state(client, env): - r = env[2].refunds.create( - provider='stripe', - state='external', - source='external', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + r = env[2].refunds.create( + provider='stripe', + state='external', + source='external', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/refunds/{}/done'.format(r.pk), {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() r.refresh_from_db() assert r.state == OrderRefund.REFUND_STATE_EXTERNAL @pytest.mark.django_db def test_confirm_payment(client, env): - p = env[2].payments.last() + with scopes_disabled(): + p = env[2].payments.last() client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/payments/{}/confirm'.format(p.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() @@ -1313,12 +1404,13 @@ def test_confirm_payment(client, env): @pytest.mark.django_db def test_confirm_payment_invalid_state(client, env): - p = env[2].payments.last() + with scopes_disabled(): + p = env[2].payments.last() p.state = OrderPayment.PAYMENT_STATE_FAILED p.save() client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/payments/{}/confirm'.format(p.pk), {}, follow=True) - assert 'alert-danger' in response.rendered_content + assert 'alert-danger' in response.content.decode() p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_FAILED env[2].refresh_from_db() @@ -1327,12 +1419,13 @@ def test_confirm_payment_invalid_state(client, env): @pytest.mark.django_db def test_confirm_payment_partal_amount(client, env): - p = env[2].payments.last() + with scopes_disabled(): + p = env[2].payments.last() p.amount -= Decimal(5.00) p.save() client.login(email='dummy@dummy.dummy', password='dummy') response = client.post('/control/event/dummy/dummy/orders/FOO/payments/{}/confirm'.format(p.pk), {}, follow=True) - assert 'alert-success' in response.rendered_content + assert 'alert-success' in response.content.decode() p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() @@ -1341,11 +1434,12 @@ def test_confirm_payment_partal_amount(client, env): @pytest.mark.django_db def test_refund_paid_order_fully_mark_as_refunded(client, env): - p = env[2].payments.last() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/FOO/refund') - doc = BeautifulSoup(response.content, "lxml") + doc = BeautifulSoup(response.content.decode(), "lxml") assert doc.select("input[name$=partial_amount]")[0]["value"] == "14.00" client.post('/control/event/dummy/dummy/orders/FOO/refund', { 'start-partial_amount': '14.00', @@ -1361,22 +1455,24 @@ def test_refund_paid_order_fully_mark_as_refunded(client, env): 'perform': 'on' }, follow=True) p.refresh_from_db() - assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED - env[2].refresh_from_db() - r = env[2].refunds.last() - assert r.provider == "manual" - assert r.state == OrderRefund.REFUND_STATE_DONE - assert r.amount == Decimal('14.00') - assert env[2].status == Order.STATUS_CANCELED + with scopes_disabled(): + assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED + env[2].refresh_from_db() + r = env[2].refunds.last() + assert r.provider == "manual" + assert r.state == OrderRefund.REFUND_STATE_DONE + assert r.amount == Decimal('14.00') + assert env[2].status == Order.STATUS_CANCELED @pytest.mark.django_db def test_refund_paid_order_fully_mark_as_pending(client, env): - p = env[2].payments.last() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/FOO/refund') - doc = BeautifulSoup(response.content, "lxml") + doc = BeautifulSoup(response.content.decode(), "lxml") assert doc.select("input[name$=partial_amount]")[0]["value"] == "14.00" client.post('/control/event/dummy/dummy/orders/FOO/refund', { 'start-partial_amount': '14.00', @@ -1389,7 +1485,8 @@ def test_refund_paid_order_fully_mark_as_pending(client, env): p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() - r = env[2].refunds.last() + with scopes_disabled(): + r = env[2].refunds.last() assert r.provider == "manual" assert r.state == OrderRefund.REFUND_STATE_CREATED assert r.amount == Decimal('14.00') @@ -1398,11 +1495,12 @@ def test_refund_paid_order_fully_mark_as_pending(client, env): @pytest.mark.django_db def test_refund_paid_order_partially_mark_as_pending(client, env): - p = env[2].payments.last() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/FOO/refund') - doc = BeautifulSoup(response.content, "lxml") + doc = BeautifulSoup(response.content.decode(), "lxml") assert doc.select("input[name$=partial_amount]")[0]["value"] == "14.00" client.post('/control/event/dummy/dummy/orders/FOO/refund', { 'start-partial_amount': '7.00', @@ -1420,7 +1518,8 @@ def test_refund_paid_order_partially_mark_as_pending(client, env): p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() - r = env[2].refunds.last() + with scopes_disabled(): + r = env[2].refunds.last() assert r.provider == "manual" assert r.state == OrderRefund.REFUND_STATE_CREATED assert r.amount == Decimal('7.00') @@ -1429,12 +1528,13 @@ def test_refund_paid_order_partially_mark_as_pending(client, env): @pytest.mark.django_db def test_refund_propose_lower_payment(client, env): - p = env[2].payments.last() - p.amount = Decimal('8.00') - p.confirm() - p2 = env[2].payments.create( - amount=Decimal('6.00'), provider='stripe', state=OrderPayment.PAYMENT_STATE_CONFIRMED - ) + with scopes_disabled(): + p = env[2].payments.last() + p.amount = Decimal('8.00') + p.confirm() + p2 = env[2].payments.create( + amount=Decimal('6.00'), provider='stripe', state=OrderPayment.PAYMENT_STATE_CONFIRMED + ) client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/refund') response = client.post('/control/event/dummy/dummy/orders/FOO/refund', { @@ -1442,19 +1542,20 @@ def test_refund_propose_lower_payment(client, env): 'start-mode': 'partial', 'start-action': 'mark_pending' }, follow=True) - doc = BeautifulSoup(response.content, "lxml") + doc = BeautifulSoup(response.content.decode(), "lxml") assert doc.select("input[name=refund-{}]".format(p2.pk))[0]['value'] == '6.00' assert doc.select("input[name=refund-manual]".format(p2.pk))[0]['value'] == '1.00' @pytest.mark.django_db def test_refund_propose_equal_payment(client, env): - p = env[2].payments.last() - p.amount = Decimal('7.00') - p.confirm() - p2 = env[2].payments.create( - amount=Decimal('7.00'), provider='stripe', state=OrderPayment.PAYMENT_STATE_CONFIRMED - ) + with scopes_disabled(): + p = env[2].payments.last() + p.amount = Decimal('7.00') + p.confirm() + p2 = env[2].payments.create( + amount=Decimal('7.00'), provider='stripe', state=OrderPayment.PAYMENT_STATE_CONFIRMED + ) client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/refund') response = client.post('/control/event/dummy/dummy/orders/FOO/refund', { @@ -1462,19 +1563,20 @@ def test_refund_propose_equal_payment(client, env): 'start-mode': 'partial', 'start-action': 'mark_pending' }, follow=True) - doc = BeautifulSoup(response.content, "lxml") + doc = BeautifulSoup(response.content.decode(), "lxml") assert doc.select("input[name=refund-{}]".format(p2.pk))[0]['value'] == '7.00' assert doc.select("input[name=refund-manual]".format(p2.pk))[0]['value'] == '0.00' @pytest.mark.django_db def test_refund_propose_higher_payment(client, env): - p = env[2].payments.last() - p.amount = Decimal('6.00') - p.confirm() - p2 = env[2].payments.create( - amount=Decimal('8.00'), provider='stripe', state=OrderPayment.PAYMENT_STATE_CONFIRMED - ) + with scopes_disabled(): + p = env[2].payments.last() + p.amount = Decimal('6.00') + p.confirm() + p2 = env[2].payments.create( + amount=Decimal('8.00'), provider='stripe', state=OrderPayment.PAYMENT_STATE_CONFIRMED + ) client.login(email='dummy@dummy.dummy', password='dummy') client.get('/control/event/dummy/dummy/orders/FOO/refund') response = client.post('/control/event/dummy/dummy/orders/FOO/refund', { @@ -1482,15 +1584,16 @@ def test_refund_propose_higher_payment(client, env): 'start-mode': 'partial', 'start-action': 'mark_pending' }, follow=True) - doc = BeautifulSoup(response.content, "lxml") + doc = BeautifulSoup(response.content.decode(), "lxml") assert doc.select("input[name=refund-{}]".format(p2.pk))[0]['value'] == '7.00' assert doc.select("input[name=refund-manual]".format(p2.pk))[0]['value'] == '0.00' @pytest.mark.django_db def test_refund_amount_does_not_match_or_invalid(client, env): - p = env[2].payments.last() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') resp = client.post('/control/event/dummy/dummy/orders/FOO/refund', { 'start-partial_amount': '7.00', @@ -1540,13 +1643,14 @@ def test_refund_amount_does_not_match_or_invalid(client, env): @pytest.mark.django_db def test_refund_paid_order_automatically_failed(client, env, monkeypatch): - p = env[2].payments.last() - p.provider = 'stripe' - p.info_data = { - 'id': 'foo' - } - p.save() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.provider = 'stripe' + p.info_data = { + 'id': 'foo' + } + p.save() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') def charge_retr(*args, **kwargs): @@ -1571,7 +1675,8 @@ def test_refund_paid_order_automatically_failed(client, env, monkeypatch): p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() - r = env[2].refunds.last() + with scopes_disabled(): + r = env[2].refunds.last() assert r.provider == "stripe" assert r.state == OrderRefund.REFUND_STATE_FAILED assert r.amount == Decimal('7.00') @@ -1580,13 +1685,14 @@ def test_refund_paid_order_automatically_failed(client, env, monkeypatch): @pytest.mark.django_db def test_refund_paid_order_automatically(client, env, monkeypatch): - p = env[2].payments.last() - p.provider = 'stripe' - p.info_data = { - 'id': 'foo' - } - p.save() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.provider = 'stripe' + p.info_data = { + 'id': 'foo' + } + p.save() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') def charge_retr(*args, **kwargs): @@ -1613,7 +1719,8 @@ def test_refund_paid_order_automatically(client, env, monkeypatch): p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() - r = env[2].refunds.last() + with scopes_disabled(): + r = env[2].refunds.last() assert r.provider == "stripe" assert r.state == OrderRefund.REFUND_STATE_DONE assert r.amount == Decimal('7.00') @@ -1622,8 +1729,9 @@ def test_refund_paid_order_automatically(client, env, monkeypatch): @pytest.mark.django_db def test_refund_paid_order_offsetting_to_unknown(client, env): - p = env[2].payments.last() - p.confirm() + with scopes_disabled(): + p = env[2].payments.last() + p.confirm() client.login(email='dummy@dummy.dummy', password='dummy') r = client.post('/control/event/dummy/dummy/orders/FOO/refund', { @@ -1640,15 +1748,16 @@ def test_refund_paid_order_offsetting_to_unknown(client, env): @pytest.mark.django_db def test_refund_paid_order_offsetting(client, env): - p = env[2].payments.last() - p.confirm() - client.login(email='dummy@dummy.dummy', password='dummy') - o = Order.objects.create( - code='BAZ', event=env[0], email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + timedelta(days=10), - total=5, locale='en' - ) + with scopes_disabled(): + p = env[2].payments.last() + p.confirm() + client.login(email='dummy@dummy.dummy', password='dummy') + o = Order.objects.create( + code='BAZ', event=env[0], email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + timedelta(days=10), + total=5, locale='en' + ) client.post('/control/event/dummy/dummy/orders/FOO/refund', { 'start-partial_amount': '5.00', @@ -1662,51 +1771,53 @@ def test_refund_paid_order_offsetting(client, env): p.refresh_from_db() assert p.state == OrderPayment.PAYMENT_STATE_CONFIRMED env[2].refresh_from_db() - r = env[2].refunds.last() - assert r.provider == "offsetting" - assert r.state == OrderRefund.REFUND_STATE_DONE - assert r.amount == Decimal('5.00') - assert env[2].status == Order.STATUS_PENDING - o.refresh_from_db() - assert o.status == Order.STATUS_PAID - p2 = o.payments.first() - assert p2.provider == "offsetting" - assert p2.amount == Decimal('5.00') - assert p2.state == OrderPayment.PAYMENT_STATE_CONFIRMED + with scopes_disabled(): + r = env[2].refunds.last() + assert r.provider == "offsetting" + assert r.state == OrderRefund.REFUND_STATE_DONE + assert r.amount == Decimal('5.00') + assert env[2].status == Order.STATUS_PENDING + o.refresh_from_db() + assert o.status == Order.STATUS_PAID + p2 = o.payments.first() + assert p2.provider == "offsetting" + assert p2.amount == Decimal('5.00') + assert p2.state == OrderPayment.PAYMENT_STATE_CONFIRMED @pytest.mark.django_db def test_refund_list(client, env): - env[2].refunds.create( - provider='banktransfer', - state='done', - source='admin', - amount=Decimal('23.00'), - execution_date=now(), - ) - env[2].refunds.create( - provider='manual', - state='created', - source='admin', - amount=Decimal('23.00'), - execution_date=now(), - ) + with scopes_disabled(): + env[2].refunds.create( + provider='banktransfer', + state='done', + source='admin', + amount=Decimal('23.00'), + execution_date=now(), + ) + env[2].refunds.create( + provider='manual', + state='created', + source='admin', + amount=Decimal('23.00'), + execution_date=now(), + ) client.login(email='dummy@dummy.dummy', password='dummy') response = client.get('/control/event/dummy/dummy/orders/refunds/') - assert 'R-1' not in response.rendered_content - assert 'R-2' in response.rendered_content + assert 'R-1' not in response.content.decode() + assert 'R-2' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/refunds/?status=all') - assert 'R-1' in response.rendered_content - assert 'R-2' in response.rendered_content + assert 'R-1' in response.content.decode() + assert 'R-2' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/refunds/?status=created') - assert 'R-1' not in response.rendered_content - assert 'R-2' in response.rendered_content + assert 'R-1' not in response.content.decode() + assert 'R-2' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/refunds/?status=done') - assert 'R-1' in response.rendered_content - assert 'R-2' not in response.rendered_content + assert 'R-1' in response.content.decode() + assert 'R-2' not in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/refunds/?status=all&provider=manual') - assert 'R-1' not in response.rendered_content - assert 'R-2' in response.rendered_content + assert 'R-1' not in response.content.decode() + assert 'R-2' in response.content.decode() response = client.get('/control/event/dummy/dummy/orders/refunds/?status=all&provider=banktransfer') - assert 'R-1' in response.rendered_content - assert 'R-2' not in response.rendered_content + assert 'R-1' in response.content.decode() + assert 'R-2' not in response.content.decode() diff --git a/src/tests/control/test_organizer.py b/src/tests/control/test_organizer.py index 11e9425458..b2abff98b3 100644 --- a/src/tests/control/test_organizer.py +++ b/src/tests/control/test_organizer.py @@ -1,11 +1,13 @@ import datetime +from django_scopes import scopes_disabled from tests.base import SoupTest, extract_form_fields from pretix.base.models import Event, Organizer, Team, User class OrganizerTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') diff --git a/src/tests/control/test_search.py b/src/tests/control/test_search.py index a554e609f9..c97ed7f90b 100644 --- a/src/tests/control/test_search.py +++ b/src/tests/control/test_search.py @@ -2,6 +2,7 @@ import datetime from decimal import Decimal from django.utils.timezone import now +from django_scopes import scopes_disabled from tests.base import SoupTest from pretix.base.models import ( @@ -10,6 +11,7 @@ from pretix.base.models import ( class OrderSearchTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') @@ -67,21 +69,21 @@ class OrderSearchTest(SoupTest): self.client.login(email='dummy@dummy.dummy', password='dummy') def test_team_limit_event(self): - resp = self.client.get('/control/search/orders/').rendered_content + resp = self.client.get('/control/search/orders/').content.decode() assert 'FO1' in resp assert 'FO2' not in resp def test_team_limit_event_wrong_permission(self): self.team.can_view_orders = False self.team.save() - resp = self.client.get('/control/search/orders/').rendered_content + resp = self.client.get('/control/search/orders/').content.decode() assert 'FO1' not in resp assert 'FO2' not in resp def test_team_all_events(self): self.team.all_events = True self.team.save() - resp = self.client.get('/control/search/orders/').rendered_content + resp = self.client.get('/control/search/orders/').content.decode() assert 'FO1' in resp assert 'FO2' in resp @@ -89,13 +91,13 @@ class OrderSearchTest(SoupTest): self.team.all_events = True self.team.can_view_orders = False self.team.save() - resp = self.client.get('/control/search/orders/').rendered_content + resp = self.client.get('/control/search/orders/').content.decode() assert 'FO1' not in resp assert 'FO2' not in resp def test_team_none(self): self.team.members.clear() - resp = self.client.get('/control/search/orders/').rendered_content + resp = self.client.get('/control/search/orders/').content.decode() assert 'FO1' not in resp assert 'FO2' not in resp @@ -104,44 +106,44 @@ class OrderSearchTest(SoupTest): self.user.staffsession_set.create(date_start=now(), session_key=self.client.session.session_key) self.user.save() self.team.members.clear() - resp = self.client.get('/control/search/orders/').rendered_content + resp = self.client.get('/control/search/orders/').content.decode() assert 'FO1' in resp assert 'FO2' in resp def test_filter_email(self): - resp = self.client.get('/control/search/orders/?query=dummy1@dummy').rendered_content + resp = self.client.get('/control/search/orders/?query=dummy1@dummy').content.decode() assert 'FO1' in resp - resp = self.client.get('/control/search/orders/?query=dummynope').rendered_content + resp = self.client.get('/control/search/orders/?query=dummynope').content.decode() assert 'FO1' not in resp def test_filter_attendee_name(self): - resp = self.client.get('/control/search/orders/?query=Pete').rendered_content + resp = self.client.get('/control/search/orders/?query=Pete').content.decode() assert 'FO1' in resp - resp = self.client.get('/control/search/orders/?query=Mark').rendered_content + resp = self.client.get('/control/search/orders/?query=Mark').content.decode() assert 'FO1' not in resp def test_filter_attendee_email(self): - resp = self.client.get('/control/search/orders/?query=att.com').rendered_content + resp = self.client.get('/control/search/orders/?query=att.com').content.decode() assert 'FO1' in resp - resp = self.client.get('/control/search/orders/?query=nope.com').rendered_content + resp = self.client.get('/control/search/orders/?query=nope.com').content.decode() assert 'FO1' not in resp def test_filter_invoice_address(self): - resp = self.client.get('/control/search/orders/?query=Ltd').rendered_content + resp = self.client.get('/control/search/orders/?query=Ltd').content.decode() assert 'FO1' in resp - resp = self.client.get('/control/search/orders/?query=Miller').rendered_content + resp = self.client.get('/control/search/orders/?query=Miller').content.decode() assert 'FO1' in resp def test_filter_code(self): - resp = self.client.get('/control/search/orders/?query=FO1').rendered_content + resp = self.client.get('/control/search/orders/?query=FO1').content.decode() assert '30C3-FO1' in resp - resp = self.client.get('/control/search/orders/?query=30c3-FO1').rendered_content + resp = self.client.get('/control/search/orders/?query=30c3-FO1').content.decode() assert '30C3-FO1' in resp - resp = self.client.get('/control/search/orders/?query=30C3-fO1A').rendered_content + resp = self.client.get('/control/search/orders/?query=30C3-fO1A').content.decode() assert '30C3-FO1' in resp - resp = self.client.get('/control/search/orders/?query=30C3-fo14').rendered_content + resp = self.client.get('/control/search/orders/?query=30C3-fo14').content.decode() assert '30C3-FO1' in resp - resp = self.client.get('/control/search/orders/?query=31c3-FO1').rendered_content + resp = self.client.get('/control/search/orders/?query=31c3-FO1').content.decode() assert '30C3-FO1' not in resp - resp = self.client.get('/control/search/orders/?query=FO2').rendered_content + resp = self.client.get('/control/search/orders/?query=FO2').content.decode() assert '30C3-FO1' not in resp diff --git a/src/tests/control/test_settings.py b/src/tests/control/test_settings.py index 026c4eb028..6080e80050 100644 --- a/src/tests/control/test_settings.py +++ b/src/tests/control/test_settings.py @@ -2,12 +2,14 @@ import datetime import json import re +from django_scopes import scopes_disabled from tests.base import SoupTest from pretix.base.models import Event, Organizer, Team, User class MailSettingPreviewTest(SoupTest): + @scopes_disabled() def setUp(self): self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') self.orga1 = Organizer.objects.create(name='CCC', slug='ccc') @@ -32,10 +34,11 @@ class MailSettingPreviewTest(SoupTest): self.target = '/control/event/{}/{}/settings/email/preview' def test_permission(self): - self.event2 = Event.objects.create( - organizer=self.orga2, name='30M3', slug='30m3', - date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), - ) + with scopes_disabled(): + self.event2 = Event.objects.create( + organizer=self.orga2, name='30M3', slug='30m3', + date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc), + ) response = self.client.post(self.target.format( self.orga2.slug, self.event2.slug), { 'test': 'test1' diff --git a/src/tests/control/test_shredders.py b/src/tests/control/test_shredders.py index 8939483634..9f63709086 100644 --- a/src/tests/control/test_shredders.py +++ b/src/tests/control/test_shredders.py @@ -4,12 +4,14 @@ from io import BytesIO from zipfile import ZipFile from django.utils.timezone import now +from django_scopes import scopes_disabled from tests.base import SoupTest from pretix.base.models import Event, Order, Organizer, Team, User class EventShredderTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') diff --git a/src/tests/control/test_taxrates.py b/src/tests/control/test_taxrates.py index d999945f92..0b911d1366 100644 --- a/src/tests/control/test_taxrates.py +++ b/src/tests/control/test_taxrates.py @@ -2,6 +2,7 @@ import datetime from decimal import Decimal from django.utils.timezone import now +from django_scopes import scopes_disabled from tests.base import SoupTest, extract_form_fields from pretix.base.models import Event, Order, Organizer, Team, User @@ -9,6 +10,7 @@ from pretix.base.models.orders import OrderFee class TaxRateFormTest(SoupTest): + @scopes_disabled() def setUp(self): super().setUp() self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy') @@ -32,12 +34,14 @@ class TaxRateFormTest(SoupTest): doc = self.post_doc('/control/event/%s/%s/settings/tax/add' % (self.orga1.slug, self.event1.slug), form_data) assert doc.select(".alert-success") self.assertIn("VAT", doc.select("#page-wrapper table")[0].text) - assert self.event1.tax_rules.get( - rate=19, price_includes_tax=True, eu_reverse_charge=False - ) + with scopes_disabled(): + assert self.event1.tax_rules.get( + rate=19, price_includes_tax=True, eu_reverse_charge=False + ) def test_update(self): - tr = self.event1.tax_rules.create(rate=19, name="VAT") + with scopes_disabled(): + tr = self.event1.tax_rules.create(rate=19, name="VAT") doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/' % (self.orga1.slug, self.event1.slug, tr.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) form_data['rate'] = '20.00' @@ -48,67 +52,77 @@ class TaxRateFormTest(SoupTest): assert tr.rate == Decimal('20.00') def test_delete(self): - tr = self.event1.tax_rules.create(rate=19, name="VAT") + with scopes_disabled(): + tr = self.event1.tax_rules.create(rate=19, name="VAT") doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id), form_data) assert doc.select(".alert-success") self.assertNotIn("VAT", doc.select("#page-wrapper")[0].text) - assert not self.event1.tax_rules.exists() + with scopes_disabled(): + assert not self.event1.tax_rules.exists() def test_delete_item_existing(self): - tr = self.event1.tax_rules.create(rate=19, name="VAT") - self.event1.items.create(name="foo", default_price=12, tax_rule=tr) + with scopes_disabled(): + tr = self.event1.tax_rules.create(rate=19, name="VAT") + self.event1.items.create(name="foo", default_price=12, tax_rule=tr) doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id), form_data) self.assertIn("VAT", doc.select("#page-wrapper")[0].text) - assert self.event1.tax_rules.exists() + with scopes_disabled(): + assert self.event1.tax_rules.exists() def test_delete_default_rule(self): - tr = self.event1.tax_rules.create(rate=19, name="VAT") + with scopes_disabled(): + tr = self.event1.tax_rules.create(rate=19, name="VAT") self.event1.settings.tax_rate_default = tr doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id), form_data) self.assertIn("VAT", doc.select("#page-wrapper")[0].text) - assert self.event1.tax_rules.exists() + with scopes_disabled(): + assert self.event1.tax_rules.exists() def test_delete_fee_existing(self): - tr = self.event1.tax_rules.create(rate=19, name="VAT") - o = self.event1.orders.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=14, locale='en', - ) - o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'), - tax_value=Decimal('0.05'), tax_rule=tr) + with scopes_disabled(): + tr = self.event1.tax_rules.create(rate=19, name="VAT") + o = self.event1.orders.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=14, locale='en', + ) + o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'), + tax_value=Decimal('0.05'), tax_rule=tr) doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id), form_data) self.assertIn("VAT", doc.select("#page-wrapper")[0].text) - assert self.event1.tax_rules.exists() + with scopes_disabled(): + assert self.event1.tax_rules.exists() def test_delete_orderpos_existing(self): - tr = self.event1.tax_rules.create(rate=19, name="VAT") - i = self.event1.items.create(name="foo", default_price=12) - o = self.event1.orders.create( - code='FOO', event=self.event1, email='dummy@dummy.test', - status=Order.STATUS_PENDING, - datetime=now(), expires=now() + datetime.timedelta(days=10), - total=12, locale='en' - ) - o.positions.create( - item=i, price=12, tax_rule=tr, tax_rate=19, tax_value=12 - 12 / 1.19 - ) + with scopes_disabled(): + tr = self.event1.tax_rules.create(rate=19, name="VAT") + i = self.event1.items.create(name="foo", default_price=12) + o = self.event1.orders.create( + code='FOO', event=self.event1, email='dummy@dummy.test', + status=Order.STATUS_PENDING, + datetime=now(), expires=now() + datetime.timedelta(days=10), + total=12, locale='en' + ) + o.positions.create( + item=i, price=12, tax_rule=tr, tax_rate=19, tax_value=12 - 12 / 1.19 + ) doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id)) form_data = extract_form_fields(doc.select('.container-fluid form')[0]) doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id), form_data) self.assertIn("VAT", doc.select("#page-wrapper")[0].text) - assert self.event1.tax_rules.exists() + with scopes_disabled(): + assert self.event1.tax_rules.exists() diff --git a/src/tests/control/test_teams.py b/src/tests/control/test_teams.py index 398b5664ad..cbaa2676b2 100644 --- a/src/tests/control/test_teams.py +++ b/src/tests/control/test_teams.py @@ -1,6 +1,7 @@ import pytest from django.core import mail as djmail from django.utils.timezone import now +from django_scopes import scopes_disabled from pretix.base.models import Event, Organizer, Team, User @@ -35,15 +36,15 @@ def admin_user(admin_team): def test_list_of_teams(event, admin_user, client): client.login(email='dummy@dummy.dummy', password='dummy') resp = client.get('/control/organizer/dummy/teams') - assert 'Admin team' in resp.rendered_content + assert 'Admin team' in resp.content.decode() @pytest.mark.django_db def test_team_detail_view(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') resp = client.get('/control/organizer/dummy/team/{}/'.format(admin_team.pk)) - assert 'Admin team' in resp.rendered_content - assert admin_user.email in resp.rendered_content + assert 'Admin team' in resp.content.decode() + assert admin_user.email in resp.content.decode() @pytest.mark.django_db @@ -55,10 +56,11 @@ def test_team_add_user(event, admin_user, admin_team, client): resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'user': u.email }, follow=True) - assert 'Admin team' in resp.rendered_content - assert admin_user.email in resp.rendered_content - assert u.email in resp.rendered_content - assert u in admin_team.members.all() + assert 'Admin team' in resp.content.decode() + assert admin_user.email in resp.content.decode() + assert u.email in resp.content.decode() + with scopes_disabled(): + assert u in admin_team.members.all() @pytest.mark.django_db @@ -69,10 +71,11 @@ def test_team_create_invite(event, admin_user, admin_team, client): resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'user': 'foo@example.org' }, follow=True) - assert 'Admin team' in resp.rendered_content - assert admin_user.email in resp.rendered_content - assert 'foo@example.org' in resp.rendered_content - assert admin_team.invites.first().email == 'foo@example.org' + assert 'Admin team' in resp.content.decode() + assert admin_user.email in resp.content.decode() + assert 'foo@example.org' in resp.content.decode() + with scopes_disabled(): + assert admin_team.invites.first().email == 'foo@example.org' assert len(djmail.outbox) == 1 @@ -84,21 +87,23 @@ def test_team_create_token(event, admin_user, admin_team, client): resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'name': 'Test token' }, follow=True) - assert 'Test token' in resp.rendered_content - assert admin_team.tokens.first().name == 'Test token' - assert admin_team.tokens.first().token in resp.rendered_content + assert 'Test token' in resp.content.decode() + with scopes_disabled(): + assert admin_team.tokens.first().name == 'Test token' + assert admin_team.tokens.first().token in resp.content.decode() @pytest.mark.django_db def test_team_remove_token(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') - tk = admin_team.tokens.create(name='Test token') + with scopes_disabled(): + tk = admin_team.tokens.create(name='Test token') resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-token': str(tk.pk) }, follow=True) - assert tk.token not in resp.rendered_content - assert 'Test token' in resp.rendered_content + assert tk.token not in resp.content.decode() + assert 'Test token' in resp.content.decode() tk.refresh_from_db() assert not tk.active @@ -112,9 +117,9 @@ def test_team_resend_invite(event, admin_user, admin_team, client): resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'resend-invite': str(inv.pk) }, follow=True) - assert 'Admin team' in resp.rendered_content - assert admin_user.email in resp.rendered_content - assert 'foo@example.org' in resp.rendered_content + assert 'Admin team' in resp.content.decode() + assert admin_user.email in resp.content.decode() + assert 'foo@example.org' in resp.content.decode() assert len(djmail.outbox) == 1 @@ -122,13 +127,15 @@ def test_team_resend_invite(event, admin_user, admin_team, client): def test_team_revoke_invite(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') - inv = admin_team.invites.create(email='foo@example.org') + with scopes_disabled(): + inv = admin_team.invites.create(email='foo@example.org') resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-invite': str(inv.pk) }, follow=True) - assert 'Admin team' in resp.rendered_content - assert admin_user.email in resp.rendered_content - assert not admin_team.invites.exists() + assert 'Admin team' in resp.content.decode() + assert admin_user.email in resp.content.decode() + with scopes_disabled(): + assert not admin_team.invites.exists() @pytest.mark.django_db @@ -136,14 +143,16 @@ def test_team_remove_user(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') u = User.objects.create_user('dummy2@dummy.dummy', 'dummy') - admin_team.members.add(u) + with scopes_disabled(): + admin_team.members.add(u) resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-member': u.pk }, follow=True) - assert 'Admin team' in resp.rendered_content - assert admin_user.email in resp.rendered_content - assert u not in admin_team.members.all() + assert 'Admin team' in resp.content.decode() + assert admin_user.email in resp.content.decode() + with scopes_disabled(): + assert u not in admin_team.members.all() @pytest.mark.django_db @@ -153,30 +162,34 @@ def test_team_remove_last_admin(event, admin_user, admin_team, client): resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-member': admin_user.pk }, follow=True) - assert 'alert-danger' in resp.rendered_content - assert admin_user in admin_team.members.all() + assert 'alert-danger' in resp.content.decode() + with scopes_disabled(): + assert admin_user in admin_team.members.all() t2 = Team.objects.create(organizer=event.organizer, name='Admin team 2') resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-member': admin_user.pk }, follow=True) - assert 'alert-danger' in resp.rendered_content - assert admin_user in admin_team.members.all() + assert 'alert-danger' in resp.content.decode() + with scopes_disabled(): + assert admin_user in admin_team.members.all() t2.members.add(admin_user) resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-member': admin_user.pk }, follow=True) - assert 'alert-danger' in resp.rendered_content - assert admin_user in admin_team.members.all() + assert 'alert-danger' in resp.content.decode() + with scopes_disabled(): + assert admin_user in admin_team.members.all() t2.can_change_teams = True t2.save() resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'remove-member': admin_user.pk }, follow=True) - assert 'alert-danger' not in resp.rendered_content - assert admin_user not in admin_team.members.all() + assert 'alert-danger' not in resp.content.decode() + with scopes_disabled(): + assert admin_user not in admin_team.members.all() @pytest.mark.django_db @@ -188,12 +201,13 @@ def test_create_team(event, admin_user, admin_team, client): 'limit_events': str(event.pk), 'can_change_event_settings': 'on' }, follow=True) - t = Team.objects.last() - assert t.can_change_event_settings - assert t.can_create_events - assert not t.can_change_organizer_settings - assert list(t.limit_events.all()) == [event] - assert list(t.members.all()) == [admin_user] + with scopes_disabled(): + t = Team.objects.last() + assert t.can_change_event_settings + assert t.can_create_events + assert not t.can_change_organizer_settings + assert list(t.limit_events.all()) == [event] + assert list(t.members.all()) == [admin_user] @pytest.mark.django_db @@ -208,7 +222,8 @@ def test_update_team(event, admin_user, admin_team, client): admin_team.refresh_from_db() assert admin_team.can_change_event_settings assert not admin_team.can_change_organizer_settings - assert list(admin_team.limit_events.all()) == [event] + with scopes_disabled(): + assert list(admin_team.limit_events.all()) == [event] @pytest.mark.django_db @@ -218,17 +233,19 @@ def test_update_last_team_to_be_no_admin(event, admin_user, admin_team, client): 'name': 'Admin', 'can_change_event_settings': 'on' }, follow=True) - assert 'alert-danger' in resp.rendered_content + assert 'alert-danger' in resp.content.decode() @pytest.mark.django_db def test_remove_team(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') - t2 = Team.objects.create(organizer=event.organizer, name='Admin team 2') + with scopes_disabled(): + t2 = Team.objects.create(organizer=event.organizer, name='Admin team 2') resp = client.post('/control/organizer/dummy/team/{}/delete'.format(t2.pk), {}, follow=True) - assert Team.objects.count() == 1 - assert 'alert-success' in resp.rendered_content + with scopes_disabled(): + assert Team.objects.count() == 1 + assert 'alert-success' in resp.content.decode() @pytest.mark.django_db @@ -236,8 +253,9 @@ def test_remove_last_admin_team(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') resp = client.post('/control/organizer/dummy/team/{}/delete'.format(admin_team.pk), {}, follow=True) - assert Team.objects.count() == 1 - assert 'alert-danger' in resp.rendered_content + with scopes_disabled(): + assert Team.objects.count() == 1 + assert 'alert-danger' in resp.content.decode() @pytest.mark.django_db @@ -245,7 +263,8 @@ def test_resend_invalid_invite(event, admin_user, admin_team, client): client.login(email='dummy@dummy.dummy', password='dummy') djmail.outbox = [] - inv = admin_team.invites.create(email='foo@example.org') + with scopes_disabled(): + inv = admin_team.invites.create(email='foo@example.org') resp = client.post('/control/organizer/dummy/team/{}/'.format(admin_team.pk), { 'resend-invite': inv.pk + 1 }, follow=True) @@ -256,7 +275,8 @@ def test_resend_invalid_invite(event, admin_user, admin_team, client): @pytest.mark.django_db def test_invite_invalid_token(event, admin_team, client): - i = admin_team.invites.create(email='foo@bar.com') + with scopes_disabled(): + i = admin_team.invites.create(email='foo@bar.com') resp = client.get('/control/invite/foo{}bar'.format(i.token), follow=True) assert b'alert-danger' in resp.content assert b'invalid link' in resp.content @@ -265,9 +285,10 @@ def test_invite_invalid_token(event, admin_team, client): @pytest.mark.django_db def test_invite_existing_team_member(event, admin_team, client): u = User.objects.create_user('dummy2@dummy.dummy', 'dummy') - admin_team.members.add(u) - client.login(email='dummy2@dummy.dummy', password='dummy') - i = admin_team.invites.create(email='foo@bar.com') + with scopes_disabled(): + admin_team.members.add(u) + client.login(email='dummy2@dummy.dummy', password='dummy') + i = admin_team.invites.create(email='foo@bar.com') resp = client.get('/control/invite/{}'.format(i.token), follow=True) assert b'alert-danger' in resp.content assert b'already are part of' in resp.content @@ -277,16 +298,19 @@ def test_invite_existing_team_member(event, admin_team, client): def test_invite_authenticated(event, admin_team, client): u = User.objects.create_user('dummy2@dummy.dummy', 'dummy') client.login(email='dummy2@dummy.dummy', password='dummy') - i = admin_team.invites.create(email='foo@bar.com') + with scopes_disabled(): + i = admin_team.invites.create(email='foo@bar.com') resp = client.get('/control/invite/{}'.format(i.token), follow=True) assert b'alert-success' in resp.content - assert u in admin_team.members.all() - assert not admin_team.invites.exists() + with scopes_disabled(): + assert u in admin_team.members.all() + assert not admin_team.invites.exists() @pytest.mark.django_db def test_invite_new_user(event, admin_team, client): - i = admin_team.invites.create(email='foo@bar.com') + with scopes_disabled(): + i = admin_team.invites.create(email='foo@bar.com') resp = client.get('/control/invite/{}'.format(i.token), follow=True) assert b'