diff --git a/src/pretix/base/reldate.py b/src/pretix/base/reldate.py index 0aff8479db..c49d02a10c 100644 --- a/src/pretix/base/reldate.py +++ b/src/pretix/base/reldate.py @@ -157,7 +157,7 @@ class RelativeDate: if choice.base == "order" and isinstance(base, Order): event = base.event base_date = getattr(base, choice.attribute) - elif choice.base == "order.subevent" and isinstance(base, Order): + elif choice.base == "order.subevents" and isinstance(base, Order): if not base.event.has_subevents: raise ValueError("The order is for an event without subevents") if choice.modifier == "first": @@ -165,12 +165,13 @@ class RelativeDate: if op is None: raise ValueError("The order has no positions for subevents") event = op.event - base_date = getattr(base, choice.attribute) + base_date = getattr(op.subevent, choice.attribute) elif choice.modifier == "last": op = base.all_positions.order_by(f"subevent__{choice.attribute}").last() if op is None: raise ValueError("The order has no positions for subevents") - base_date = getattr(base, choice.attribute) + event = op.event + base_date = getattr(op.subevent, choice.attribute) else: raise ValueError("The selected modifier does not exist") elif choice.base == "event" and isinstance(base, SubEvent): diff --git a/src/tests/base/test_reldate.py b/src/tests/base/test_reldate.py index 7bc68d505f..6394bfe19b 100644 --- a/src/tests/base/test_reldate.py +++ b/src/tests/base/test_reldate.py @@ -20,12 +20,13 @@ # . # from datetime import datetime, time, timedelta +from decimal import Decimal from zoneinfo import ZoneInfo import pytest -from django_scopes import scope +from django_scopes import scope, scopes_disabled -from pretix.base.models import Event, Order, Organizer +from pretix.base.models import Event, Order, OrderPosition, Organizer from pretix.base.reldate import RelativeDate, RelativeDateWrapper TOKYO = ZoneInfo('Asia/Tokyo') @@ -40,7 +41,6 @@ def event(): date_from=datetime(2017, 12, 27, 5, 0, 0, tzinfo=TOKYO), presale_start=datetime(2017, 12, 1, 5, 0, 0, tzinfo=TOKYO), plugins='pretix.plugins.banktransfer' - ) event.settings.timezone = "Asia/Tokyo" return event @@ -206,3 +206,73 @@ def test_relative_to_order(event): rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='order__datetime', minutes=None, is_after=True)) assert rdw.datetime(order).astimezone(TOKYO) == datetime(2020, 3, 30, 18, 0, 0, tzinfo=TOKYO) assert rdw.to_string() == 'RELDATE/1/-/order__datetime/after' + + +@pytest.mark.django_db +@scopes_disabled() +def test_relative_to_subevent(event): + event.has_subevents = True + event.save() + se1 = event.subevents.create( + name="Foobar", + date_from=datetime(2023, 6, 27, 5, 0, 0, tzinfo=TOKYO), + date_to=datetime(2023, 7, 27, 5, 0, 0, tzinfo=TOKYO), + date_admission=datetime(2023, 6, 27, 6, 0, 0, tzinfo=TOKYO), + ) + se2 = event.subevents.create( + name="Foobar1", + date_from=datetime(2024, 6, 27, 5, 0, 0, tzinfo=TOKYO), + date_to=datetime(2024, 7, 27, 5, 0, 0, tzinfo=TOKYO), + date_admission=datetime(2024, 6, 27, 6, 0, 0, tzinfo=TOKYO), + ) + + order_moment = datetime(2020, 3, 29, 18, 0, 0, tzinfo=TOKYO) + + order = Order.objects.create( + code='FOO', event=event, email='dummy@dummy.test', + status=Order.STATUS_PENDING, secret="k24fiuwvu8kxz3y1", + datetime=order_moment, + expires=order_moment + timedelta(days=10), + sales_channel=event.organizer.sales_channels.get(identifier="web"), + total=23, locale='en' + ) + item = event.items.create(name="Budget Ticket", default_price=23) + OrderPosition.objects.create( + order=order, + subevent=se1, + item=item, + tax_value=Decimal("3"), + price=Decimal("23"), + attendee_name_parts={'full_name': "Peter"}, + secret="z3fsn8jyufm5kpk768q69gkbyr5f4h6w" + ) + OrderPosition.objects.create( + order=order, + subevent=se2, + item=item, + tax_value=Decimal("3"), + price=Decimal("23"), + attendee_name_parts={'full_name': "Peter"}, + secret="z3fsn8jyufm5kpk768q69gkbyr5f4h6w" + ) + + rdw = RelativeDate(days=1, time=None, base_date_name='order.subevents__date_from__first', minutes=None, is_after=True) + assert rdw.datetime(order).astimezone(TOKYO) == datetime(2023, 6, 28, 5, 0, 0, tzinfo=TOKYO) + assert rdw.to_string() == 'RELDATE/1/-/order.subevents__date_from__first/after' + rdw = RelativeDate(days=1, time=None, base_date_name='order.subevents__date_from__last', minutes=None, is_after=True) + assert rdw.datetime(order).astimezone(TOKYO) == datetime(2024, 6, 28, 5, 0, 0, tzinfo=TOKYO) + assert rdw.to_string() == 'RELDATE/1/-/order.subevents__date_from__last/after' + + rdw = RelativeDate(days=1, time=None, base_date_name='order.subevents__date_to__first', minutes=None, is_after=True) + assert rdw.datetime(order).astimezone(TOKYO) == datetime(2023, 7, 28, 5, 0, 0, tzinfo=TOKYO) + assert rdw.to_string() == 'RELDATE/1/-/order.subevents__date_to__first/after' + rdw = RelativeDate(days=1, time=None, base_date_name='order.subevents__date_to__last', minutes=None, is_after=True) + assert rdw.datetime(order).astimezone(TOKYO) == datetime(2024, 7, 28, 5, 0, 0, tzinfo=TOKYO) + assert rdw.to_string() == 'RELDATE/1/-/order.subevents__date_to__last/after' + + rdw = RelativeDate(days=1, time=None, base_date_name='order.subevents__date_admission__first', minutes=None, is_after=True) + assert rdw.datetime(order).astimezone(TOKYO) == datetime(2023, 6, 28, 6, 0, 0, tzinfo=TOKYO) + assert rdw.to_string() == 'RELDATE/1/-/order.subevents__date_admission__first/after' + rdw = RelativeDate(days=1, time=None, base_date_name='order.subevents__date_admission__last', minutes=None, is_after=True) + assert rdw.datetime(order).astimezone(TOKYO) == datetime(2024, 6, 28, 6, 0, 0, tzinfo=TOKYO) + assert rdw.to_string() == 'RELDATE/1/-/order.subevents__date_admission__last/after'