diff --git a/src/pretix/base/reldate.py b/src/pretix/base/reldate.py index 64bdb9170a..81578976a0 100644 --- a/src/pretix/base/reldate.py +++ b/src/pretix/base/reldate.py @@ -46,9 +46,8 @@ if TYPE_CHECKING: @dataclass(frozen=True) class BaseChoice: - base: Literal["event", "order", "order.subevents"] + base: Literal["event", "order"] attribute: str - modifier: str text: Promise supports_before: bool supports_after: bool @@ -56,8 +55,6 @@ class BaseChoice: @property def key(self) -> str: key = f"{self.base}__{self.attribute}" - if self.modifier: - key += f"__{self.modifier}" return key @staticmethod @@ -75,19 +72,13 @@ class BaseChoice: BASE_CHOICES: List[BaseChoice] = [ - BaseChoice('event', 'date_from', "", _('Event start'), True, True), - BaseChoice('event', 'date_to', "", _('Event end'), True, True), - BaseChoice('event', 'date_admission', "", _('Event admission'), True, True), - BaseChoice('event', 'presale_start', "", _('Presale start'), True, True), - BaseChoice('event', 'presale_end', "", _('Presale end'), True, True), - BaseChoice('order', 'datetime', "", _('Order creation'), False, True), - BaseChoice('order', 'expires', "", _('Order expiry'), True, True), - BaseChoice('order.subevents', 'date_from', "first", _('Subevent start (first subevent in order)'), True, True), - BaseChoice('order.subevents', 'date_from', "last", _('Subevent start (last subevent in order)'), True, True), - BaseChoice('order.subevents', 'date_to', "first", _('Subevent end (first subevent in order)'), True, True), - BaseChoice('order.subevents', 'date_to', "last", _('Subevent end (last subevent in order)'), True, True), - BaseChoice('order.subevents', 'date_admission', "first", _('Subevent admission (first subevent in order)'), True, True), - BaseChoice('order.subevents', 'date_admission', "last", _('Subevent admission (last subevent in order)'), True, True), + BaseChoice('event', 'date_from', _('Event start'), True, True), + BaseChoice('event', 'date_to', _('Event end'), True, True), + BaseChoice('event', 'date_admission', _('Event admission'), True, True), + BaseChoice('event', 'presale_start', _('Presale start'), True, True), + BaseChoice('event', 'presale_end', _('Presale end'), True, True), + BaseChoice('order', 'datetime', _('Order creation'), False, True), + BaseChoice('order', 'expires', _('Order expiry'), True, True), ] LIMIT_FALLBACKS = ['date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end'] @@ -100,10 +91,6 @@ ORDER_BASE_CHOICES = [ x for x in BASE_CHOICES if x.base == 'order' ] -SUBEVENT_BASE_CHOICES = [ - x for x in BASE_CHOICES if x.base == 'order.subevents' -] - @dataclass(frozen=True) class RelativeDate: @@ -157,23 +144,6 @@ class RelativeDate: if choice.base == "order" and isinstance(base, Order): event = base.event base_date = getattr(base, choice.attribute) - 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": - op = base.all_positions.order_by(f"subevent__{choice.attribute}").first() - if op is None: - raise ValueError("The order has no positions for subevents") - event = op.event - 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") - 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): event = base.event base_date = (getattr(base, choice.attribute) or @@ -470,13 +440,10 @@ class RelativeDateTimeField(forms.MultiValueField): ('relative_minutes', _('Relative time:')), ] self.relative_to_order = kwargs.pop('relative_to_order', False) - self.relative_to_subevent_positions = kwargs.pop('relative_to_subevent_positions', False) possible_choices = copy.deepcopy(EVENT_BASE_CHOICES) if self.relative_to_order: possible_choices.extend(ORDER_BASE_CHOICES) - if self.relative_to_subevent_positions: - possible_choices.extend(SUBEVENT_BASE_CHOICES) if kwargs.get('limit_choices'): limit = kwargs.pop('limit_choices') @@ -548,8 +515,6 @@ class RelativeDateTimeField(forms.MultiValueField): possible_choices = copy.deepcopy(EVENT_BASE_CHOICES) if self.relative_to_order: possible_choices.extend(ORDER_BASE_CHOICES) - if self.relative_to_subevent_positions and event.has_subevents: - possible_choices.extend(SUBEVENT_BASE_CHOICES) possible_choices = possible_choices choices = _get_choices(possible_choices) @@ -685,13 +650,10 @@ class RelativeDateField(RelativeDateTimeField): status_choices.insert(0, ('unset', _('Not set'))) self.relative_to_order = kwargs.pop('relative_to_order', False) - self.relative_to_subevent_positions = kwargs.pop('relative_to_subevent_positions', False) possible_choices = copy.deepcopy(EVENT_BASE_CHOICES) if self.relative_to_order: possible_choices.extend(ORDER_BASE_CHOICES) - if self.relative_to_subevent_positions: - possible_choices.extend(SUBEVENT_BASE_CHOICES) choices = _get_choices(possible_choices) @@ -728,8 +690,6 @@ class RelativeDateField(RelativeDateTimeField): ] if self.relative_to_order: choices += [(c.key, c.text) for c in ORDER_BASE_CHOICES] - if self.relative_to_subevent_positions and event.has_subevents: - choices += [(c.key, c.text) for c in SUBEVENT_BASE_CHOICES] self.widget.widgets[reldateparts.indizes.rel_days_relationto].choices = choices def compress(self, data_list): diff --git a/src/pretix/static/pretixbase/js/reldate.js b/src/pretix/static/pretixbase/js/reldate.js index 4f9bd34d75..057e46fe46 100644 --- a/src/pretix/static/pretixbase/js/reldate.js +++ b/src/pretix/static/pretixbase/js/reldate.js @@ -1,47 +1,45 @@ if (!window.__reldateInitialized) { - window.__reldateInitialized = true; - document.addEventListener('DOMContentLoaded', () => { + window.__reldateInitialized = true + document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('.reldatetime, .reldate').forEach(container => { + const groups = container.querySelectorAll('.radio') - document.querySelectorAll('.reldatetime, .reldate').forEach(container => { - const groups = container.querySelectorAll('.radio'); + groups.forEach(group => { + const referenceSelect = group.querySelector('select[data-relative-choice]') + const beforeAfterSelect = group.querySelector('select[data-relation-choice]') + if (!referenceSelect || !beforeAfterSelect) return - groups.forEach(group => { - const referenceSelect = group.querySelector('select[data-relative-choice]'); - const beforeAfterSelect = group.querySelector('select[data-relation-choice]'); - if (!referenceSelect || !beforeAfterSelect) return; + const beforeOption = beforeAfterSelect.querySelector('option[value="before"]') + const afterOption = beforeAfterSelect.querySelector('option[value="after"]') - const beforeOption = beforeAfterSelect.querySelector('option[value="before"]'); - const afterOption = beforeAfterSelect.querySelector('option[value="after"]'); + const updateBeforeOption = () => { + let supportsBefore = referenceSelect.selectedOptions[0].hasAttribute('data-supports-before') + if (beforeOption) { + beforeOption.disabled = !beforeOption.disabled && !supportsBefore + } - const updateBeforeOption = () => { - let supportsBefore = referenceSelect.selectedOptions[0].hasAttribute('data-supports-before') - if (beforeOption){ - beforeOption.disabled = !beforeOption.disabled && !supportsBefore; - } + let supportsAfter = referenceSelect.selectedOptions[0].hasAttribute('data-supports-after') + if (afterOption) { + afterOption.disabled = !afterOption.disabled && !supportsAfter + } - let supportsAfter = referenceSelect.selectedOptions[0].hasAttribute('data-supports-after') - if (afterOption){ - afterOption.disabled = !afterOption.disabled && !supportsAfter; - } + let dirty = false + if (beforeOption.disabled && beforeAfterSelect.value === 'before') { + beforeAfterSelect.value = 'after' + dirty = true + } + if (afterOption.disabled && beforeAfterSelect.value === 'after') { + beforeAfterSelect.value = 'before' + dirty = true + } - let dirty = false; - if (beforeOption.disabled && beforeAfterSelect.value === 'before') { - beforeAfterSelect.value = 'after'; - dirty = true; - } - if (afterOption.disabled && beforeAfterSelect.value === 'after'){ - beforeAfterSelect.value = 'before'; - dirty = true; - } - - if (dirty){ - beforeAfterSelect.dispatchEvent(new Event('change', { bubbles: true })); - } - - }; - referenceSelect.addEventListener('change', updateBeforeOption); - updateBeforeOption(); - }); - }); - }); + if (dirty) { + beforeAfterSelect.dispatchEvent(new Event('change', { bubbles: true })) + } + } + referenceSelect.addEventListener('change', updateBeforeOption) + updateBeforeOption() + }) + }) + }) } diff --git a/src/tests/base/test_reldate.py b/src/tests/base/test_reldate.py index 6394bfe19b..d8b30f8aed 100644 --- a/src/tests/base/test_reldate.py +++ b/src/tests/base/test_reldate.py @@ -206,73 +206,3 @@ 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'