Relative dates: Add UI to specify dates after reference date (#3707)

* Relative dates: Add UI to specify dates after reference date

* Do not use form fields twice

* Update src/pretix/base/reldate.py

Co-authored-by: Richard Schreiber <schreiber@rami.io>

* Update src/pretix/base/reldate.py

Co-authored-by: Richard Schreiber <schreiber@rami.io>

* Update src/pretix/base/reldate.py

Co-authored-by: Richard Schreiber <schreiber@rami.io>

---------

Co-authored-by: Richard Schreiber <schreiber@rami.io>
This commit is contained in:
Raphael Michel
2023-11-10 12:13:33 +01:00
committed by GitHub
co-authored by Richard Schreiber
parent d7aa94d6ae
commit 27e042baf7
10 changed files with 139 additions and 81 deletions
+82 -36
View File
@@ -39,7 +39,7 @@ BASE_CHOICES = (
('presale_end', _('Presale end')), ('presale_end', _('Presale end')),
) )
RelativeDate = namedtuple('RelativeDate', ['days_before', 'minutes_before', 'time', 'base_date_name']) RelativeDate = namedtuple('RelativeDate', ['days', 'minutes', 'time', 'is_after', 'base_date_name'], defaults=(0, None, None, False, 'date_from'))
class RelativeDateWrapper: class RelativeDateWrapper:
@@ -64,7 +64,7 @@ class RelativeDateWrapper:
elif isinstance(self.data, datetime.date): elif isinstance(self.data, datetime.date):
return self.data return self.data
else: else:
if self.data.minutes_before is not None: if self.data.minutes is not None:
raise ValueError('A minute-based relative datetime can not be used as a date') raise ValueError('A minute-based relative datetime can not be used as a date')
tz = ZoneInfo(event.settings.timezone) tz = ZoneInfo(event.settings.timezone)
@@ -77,7 +77,10 @@ class RelativeDateWrapper:
else: else:
base_date = getattr(event, self.data.base_date_name) or event.date_from base_date = getattr(event, self.data.base_date_name) or event.date_from
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.data.days_before) if self.data.is_after:
new_date = base_date.astimezone(tz) + datetime.timedelta(days=self.data.days)
else:
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.data.days)
return new_date.date() return new_date.date()
def datetime(self, event) -> datetime.datetime: def datetime(self, event) -> datetime.datetime:
@@ -96,10 +99,16 @@ class RelativeDateWrapper:
else: else:
base_date = getattr(event, self.data.base_date_name) or event.date_from base_date = getattr(event, self.data.base_date_name) or event.date_from
if self.data.minutes_before is not None: if self.data.minutes is not None:
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.data.minutes_before) if self.data.is_after:
return base_date.astimezone(tz) + datetime.timedelta(minutes=self.data.minutes)
else:
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.data.minutes)
else: else:
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.data.days_before)).astimezone(tz) if self.data.is_after:
new_date = (base_date.astimezone(tz) + datetime.timedelta(days=self.data.days)).astimezone(tz)
else:
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.data.days)).astimezone(tz)
if self.data.time: if self.data.time:
new_date = new_date.replace( new_date = new_date.replace(
hour=self.data.time.hour, hour=self.data.time.hour,
@@ -113,15 +122,17 @@ class RelativeDateWrapper:
if isinstance(self.data, (datetime.datetime, datetime.date)): if isinstance(self.data, (datetime.datetime, datetime.date)):
return self.data.isoformat() return self.data.isoformat()
else: else:
if self.data.minutes_before is not None: if self.data.minutes is not None:
return 'RELDATE/minutes/{}/{}/'.format( # return 'RELDATE/minutes/{}/{}/{}'.format( #
self.data.minutes_before, self.data.minutes,
self.data.base_date_name self.data.base_date_name,
'after' if self.data.is_after else '',
) )
return 'RELDATE/{}/{}/{}/'.format( # return 'RELDATE/{}/{}/{}/{}'.format( #
self.data.days_before, self.data.days,
self.data.time.strftime('%H:%M:%S') if self.data.time else '-', self.data.time.strftime('%H:%M:%S') if self.data.time else '-',
self.data.base_date_name self.data.base_date_name,
'after' if self.data.is_after else '',
) )
@classmethod @classmethod
@@ -130,10 +141,11 @@ class RelativeDateWrapper:
parts = input.split('/') parts = input.split('/')
if parts[1] == 'minutes': if parts[1] == 'minutes':
data = RelativeDate( data = RelativeDate(
days_before=0, days=0,
minutes_before=int(parts[2]), minutes=int(parts[2]),
base_date_name=parts[3], base_date_name=parts[3],
time=None time=None,
is_after=len(parts) > 4 and parts[4] == "after",
) )
else: else:
if parts[2] == '-': if parts[2] == '-':
@@ -143,17 +155,19 @@ class RelativeDateWrapper:
time = datetime.time(hour=int(timeparts[0]), minute=int(timeparts[1]), second=int(timeparts[2])) time = datetime.time(hour=int(timeparts[0]), minute=int(timeparts[1]), second=int(timeparts[2]))
try: try:
data = RelativeDate( data = RelativeDate(
days_before=int(parts[1] or 0), days=int(parts[1] or 0),
base_date_name=parts[3], base_date_name=parts[3],
time=time, time=time,
minutes_before=None minutes=None,
is_after=len(parts) > 4 and parts[4] == "after",
) )
except ValueError: except ValueError:
data = RelativeDate( data = RelativeDate(
days_before=0, days=0,
base_date_name=parts[3], base_date_name=parts[3],
time=time, time=time,
minutes_before=None minutes=None,
is_after=len(parts) > 4 and parts[4] == "after",
) )
if data.base_date_name not in [k[0] for k in BASE_CHOICES]: if data.base_date_name not in [k[0] for k in BASE_CHOICES]:
raise ValueError('{} is not a valid base date'.format(data.base_date_name)) raise ValueError('{} is not a valid base date'.format(data.base_date_name))
@@ -165,20 +179,30 @@ class RelativeDateWrapper:
return len(self.to_string()) return len(self.to_string())
BEFORE_AFTER_CHOICE = (
('before', _('before')),
('after', _('after')),
)
class RelativeDateTimeWidget(forms.MultiWidget): class RelativeDateTimeWidget(forms.MultiWidget):
template_name = 'pretixbase/forms/widgets/reldatetime.html' template_name = 'pretixbase/forms/widgets/reldatetime.html'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.status_choices = kwargs.pop('status_choices') self.status_choices = kwargs.pop('status_choices')
base_choices = kwargs.pop('base_choices')
widgets = ( widgets = (
forms.RadioSelect(choices=self.status_choices), forms.RadioSelect(choices=self.status_choices),
forms.DateTimeInput( forms.DateTimeInput(
attrs={'class': 'datetimepicker'} attrs={'class': 'datetimepicker'}
), ),
forms.NumberInput(), forms.NumberInput(),
forms.Select(choices=kwargs.pop('base_choices')), forms.Select(choices=base_choices),
forms.TimeInput(attrs={'placeholder': _('Time'), 'class': 'timepickerfield'}), forms.TimeInput(attrs={'placeholder': _('Time'), 'class': 'timepickerfield'}),
forms.NumberInput(), forms.NumberInput(),
forms.Select(choices=base_choices),
forms.Select(choices=BEFORE_AFTER_CHOICE),
forms.Select(choices=BEFORE_AFTER_CHOICE),
) )
super().__init__(widgets=widgets, *args, **kwargs) super().__init__(widgets=widgets, *args, **kwargs)
@@ -186,12 +210,14 @@ class RelativeDateTimeWidget(forms.MultiWidget):
if isinstance(value, str): if isinstance(value, str):
value = RelativeDateWrapper.from_string(value) value = RelativeDateWrapper.from_string(value)
if not value: if not value:
return ['unset', None, 1, 'date_from', None, 0] return ['unset', None, 1, 'date_from', None, 0, "date_from", "before", "before"]
elif isinstance(value.data, (datetime.datetime, datetime.date)): elif isinstance(value.data, (datetime.datetime, datetime.date)):
return ['absolute', value.data, 1, 'date_from', None, 0] return ['absolute', value.data, 1, 'date_from', None, 0, "date_from", "before", "before"]
elif value.data.minutes_before is not None: elif value.data.minutes is not None:
return ['relative_minutes', None, None, value.data.base_date_name, None, value.data.minutes_before] return ['relative_minutes', None, None, value.data.base_date_name, None, value.data.minutes, value.data.base_date_name,
return ['relative', None, value.data.days_before, value.data.base_date_name, value.data.time, 0] "after" if value.data.is_after else "before", "after" if value.data.is_after else "before"]
return ['relative', None, value.data.days, value.data.base_date_name, value.data.time, 0, value.data.base_date_name,
"after" if value.data.is_after else "before", "after" if value.data.is_after else "before"]
def get_context(self, name, value, attrs): def get_context(self, name, value, attrs):
ctx = super().get_context(name, value, attrs) ctx = super().get_context(name, value, attrs)
@@ -234,6 +260,18 @@ class RelativeDateTimeField(forms.MultiValueField):
forms.IntegerField( forms.IntegerField(
required=False required=False
), ),
forms.ChoiceField(
choices=choices,
required=False
),
forms.ChoiceField(
choices=BEFORE_AFTER_CHOICE,
required=False
),
forms.ChoiceField(
choices=BEFORE_AFTER_CHOICE,
required=False
),
) )
if 'widget' not in kwargs: if 'widget' not in kwargs:
kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=choices) kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=choices)
@@ -257,17 +295,19 @@ class RelativeDateTimeField(forms.MultiValueField):
return None return None
elif data_list[0] == 'relative_minutes': elif data_list[0] == 'relative_minutes':
return RelativeDateWrapper(RelativeDate( return RelativeDateWrapper(RelativeDate(
days_before=0, days=0,
base_date_name=data_list[3], base_date_name=data_list[3],
time=None, time=None,
minutes_before=data_list[5] minutes=data_list[5],
is_after=data_list[7] == "after",
)) ))
else: else:
return RelativeDateWrapper(RelativeDate( return RelativeDateWrapper(RelativeDate(
days_before=data_list[2], days=data_list[2],
base_date_name=data_list[3], base_date_name=data_list[6],
time=data_list[4], time=data_list[4],
minutes_before=None minutes=None,
is_after=data_list[8] == "after",
)) ))
def has_changed(self, initial, data): def has_changed(self, initial, data):
@@ -298,6 +338,7 @@ class RelativeDateWidget(RelativeDateTimeWidget):
), ),
forms.NumberInput(), forms.NumberInput(),
forms.Select(choices=kwargs.pop('base_choices')), forms.Select(choices=kwargs.pop('base_choices')),
forms.Select(choices=BEFORE_AFTER_CHOICE),
) )
forms.MultiWidget.__init__(self, widgets=widgets, *args, **kwargs) forms.MultiWidget.__init__(self, widgets=widgets, *args, **kwargs)
@@ -305,10 +346,10 @@ class RelativeDateWidget(RelativeDateTimeWidget):
if isinstance(value, str): if isinstance(value, str):
value = RelativeDateWrapper.from_string(value) value = RelativeDateWrapper.from_string(value)
if not value: if not value:
return ['unset', None, 1, 'date_from'] return ['unset', None, 1, 'date_from', 'before']
elif isinstance(value.data, (datetime.datetime, datetime.date)): elif isinstance(value.data, (datetime.datetime, datetime.date)):
return ['absolute', value.data, 1, 'date_from'] return ['absolute', value.data, 1, 'date_from', 'before']
return ['relative', None, value.data.days_before, value.data.base_date_name] return ['relative', None, value.data.days, value.data.base_date_name, "after" if value.data.is_after else "before"]
class RelativeDateField(RelativeDateTimeField): class RelativeDateField(RelativeDateTimeField):
@@ -335,6 +376,10 @@ class RelativeDateField(RelativeDateTimeField):
choices=BASE_CHOICES, choices=BASE_CHOICES,
required=False required=False
), ),
forms.ChoiceField(
choices=BEFORE_AFTER_CHOICE,
required=False
),
) )
if 'widget' not in kwargs: if 'widget' not in kwargs:
kwargs['widget'] = RelativeDateWidget(status_choices=status_choices, base_choices=BASE_CHOICES) kwargs['widget'] = RelativeDateWidget(status_choices=status_choices, base_choices=BASE_CHOICES)
@@ -351,9 +396,10 @@ class RelativeDateField(RelativeDateTimeField):
return None return None
else: else:
return RelativeDateWrapper(RelativeDate( return RelativeDateWrapper(RelativeDate(
days_before=data_list[2], days=data_list[2],
base_date_name=data_list[3], base_date_name=data_list[3],
time=None, minutes_before=None time=None, minutes=None,
is_after=data_list[4] == "after"
)) ))
def clean(self, value): def clean(self, value):
@@ -12,7 +12,8 @@
{% include widget.subwidgets.1.template_name with widget=widget.subwidgets.1 %} {% include widget.subwidgets.1.template_name with widget=widget.subwidgets.1 %}
{% elif selopt.value == "relative" %} {% elif selopt.value == "relative" %}
{% include widget.subwidgets.2.template_name with widget=widget.subwidgets.2 %} {% include widget.subwidgets.2.template_name with widget=widget.subwidgets.2 %}
{% trans "days before" %} {% trans "days" %}
{% include widget.subwidgets.4.template_name with widget=widget.subwidgets.4 %}
{% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %} {% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %}
{% endif %} {% endif %}
</div> </div>
@@ -12,12 +12,14 @@
{% include widget.subwidgets.1.template_name with widget=widget.subwidgets.1 %} {% include widget.subwidgets.1.template_name with widget=widget.subwidgets.1 %}
{% elif selopt.value == "relative_minutes" %} {% elif selopt.value == "relative_minutes" %}
{% include widget.subwidgets.5.template_name with widget=widget.subwidgets.5 %} {% include widget.subwidgets.5.template_name with widget=widget.subwidgets.5 %}
{% trans "minutes before" %} {% trans "minutes" %}
{% include widget.subwidgets.7.template_name with widget=widget.subwidgets.7 %}
{% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %} {% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %}
{% elif selopt.value == "relative" %} {% elif selopt.value == "relative" %}
{% include widget.subwidgets.2.template_name with widget=widget.subwidgets.2 %} {% include widget.subwidgets.2.template_name with widget=widget.subwidgets.2 %}
{% trans "days before" %} {% trans "days" %}
{% include widget.subwidgets.3.template_name with widget=widget.subwidgets.3 %} {% include widget.subwidgets.8.template_name with widget=widget.subwidgets.8 %}
{% include widget.subwidgets.6.template_name with widget=widget.subwidgets.6 %}
{% trans "at" %} {% trans "at" %}
{% include widget.subwidgets.4.template_name with widget=widget.subwidgets.4 %} {% include widget.subwidgets.4.template_name with widget=widget.subwidgets.4 %}
{% endif %} {% endif %}
+4 -4
View File
@@ -758,16 +758,16 @@ class SubEventBulkCreate(SubEventEditorMixin, EventPermissionRequiredMixin, Asyn
initial['time_to'] = i.date_to.astimezone(tz).time() if i.date_to else None initial['time_to'] = i.date_to.astimezone(tz).time() if i.date_to else None
initial['time_admission'] = i.date_admission.astimezone(tz).time() if i.date_admission else None initial['time_admission'] = i.date_admission.astimezone(tz).time() if i.date_admission else None
initial['rel_presale_start'] = RelativeDateWrapper(RelativeDate( initial['rel_presale_start'] = RelativeDateWrapper(RelativeDate(
days_before=(i.date_from.astimezone(tz).date() - i.presale_start.astimezone(tz).date()).days, days=(i.date_from.astimezone(tz).date() - i.presale_start.astimezone(tz).date()).days,
base_date_name='date_from', base_date_name='date_from',
time=i.presale_start.astimezone(tz).time(), time=i.presale_start.astimezone(tz).time(),
minutes_before=None minutes=None
)) if i.presale_start else None )) if i.presale_start else None
initial['rel_presale_end'] = RelativeDateWrapper(RelativeDate( initial['rel_presale_end'] = RelativeDateWrapper(RelativeDate(
days_before=(i.date_from.astimezone(tz).date() - i.presale_end.astimezone(tz).date()).days, days=(i.date_from.astimezone(tz).date() - i.presale_end.astimezone(tz).date()).days,
base_date_name='date_from', base_date_name='date_from',
time=i.presale_end.astimezone(tz).time(), time=i.presale_end.astimezone(tz).time(),
minutes_before=None minutes=None
)) if i.presale_end else None )) if i.presale_end else None
else: else:
kwargs['instance'] = SubEvent(event=self.request.event) kwargs['instance'] = SubEvent(event=self.request.event)
+12 -12
View File
@@ -1108,7 +1108,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.op2.subevent = se2 self.op2.subevent = se2
self.op2.save() self.op2.save()
self.event.settings.set('payment_term_last', RelativeDateWrapper( self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
self.order.status = Order.STATUS_EXPIRED self.order.status = Order.STATUS_EXPIRED
@@ -1251,7 +1251,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.op2.subevent = se2 self.op2.subevent = se2
self.op2.save() self.op2.save()
self.event.settings.set('last_order_modification_date', RelativeDateWrapper( self.event.settings.set('last_order_modification_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
assert self.order.can_modify_answers assert self.order.can_modify_answers
self.op2.subevent = se3 self.op2.subevent = se3
@@ -1267,7 +1267,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=datetime.timezone.utc) self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=datetime.timezone.utc)
self.event.save() self.event.save()
self.event.settings.set('payment_term_last', RelativeDateWrapper( self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
assert self.order.payment_term_last == datetime.datetime(2017, 5, 1, 23, 59, 59, tzinfo=datetime.timezone.utc) assert self.order.payment_term_last == datetime.datetime(2017, 5, 1, 23, 59, 59, tzinfo=datetime.timezone.utc)
@@ -1283,7 +1283,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.op2.subevent = se2 self.op2.subevent = se2
self.op2.save() self.op2.save()
self.event.settings.set('payment_term_last', RelativeDateWrapper( self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
assert self.order.payment_term_last > now() assert self.order.payment_term_last > now()
self.op2.subevent = se3 self.op2.subevent = se3
@@ -1299,7 +1299,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=datetime.timezone.utc) self.event.date_from = datetime.datetime(2017, 5, 3, 12, 0, 0, tzinfo=datetime.timezone.utc)
self.event.save() self.event.save()
self.event.settings.set('ticket_download_date', RelativeDateWrapper( self.event.settings.set('ticket_download_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
assert self.order.ticket_download_date == datetime.datetime(2017, 5, 1, 12, 0, 0, tzinfo=datetime.timezone.utc) assert self.order.ticket_download_date == datetime.datetime(2017, 5, 1, 12, 0, 0, tzinfo=datetime.timezone.utc)
@@ -1315,7 +1315,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.op2.subevent = se2 self.op2.subevent = se2
self.op2.save() self.op2.save()
self.event.settings.set('ticket_download_date', RelativeDateWrapper( self.event.settings.set('ticket_download_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
assert self.order.ticket_download_date > now() assert self.order.ticket_download_date > now()
self.op2.subevent = se3 self.op2.subevent = se3
@@ -1486,13 +1486,13 @@ class OrderTestCase(BaseQuotaTestCase):
assert self.order.user_cancel_deadline is None assert self.order.user_cancel_deadline is None
self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper( self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper(
RelativeDate(days_before=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes=None)
)) ))
self.order = Order.objects.get(pk=self.order.pk) self.order = Order.objects.get(pk=self.order.pk)
assert self.order.user_cancel_deadline > now() assert self.order.user_cancel_deadline > now()
assert self.order.user_cancel_allowed assert self.order.user_cancel_allowed
self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper( self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper(
RelativeDate(days_before=4, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=4, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes=None)
)) ))
self.order = Order.objects.get(pk=self.order.pk) self.order = Order.objects.get(pk=self.order.pk)
assert self.order.user_cancel_deadline < now() assert self.order.user_cancel_deadline < now()
@@ -1511,7 +1511,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.op2.save() self.op2.save()
self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper( self.event.settings.set('cancel_allow_user_until', RelativeDateWrapper(
RelativeDate(days_before=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes=None)
)) ))
self.order = Order.objects.get(pk=self.order.pk) self.order = Order.objects.get(pk=self.order.pk)
assert self.order.user_cancel_deadline < now() assert self.order.user_cancel_deadline < now()
@@ -1922,13 +1922,13 @@ class OrderTestCase(BaseQuotaTestCase):
assert self.order.user_change_deadline is None assert self.order.user_change_deadline is None
self.event.settings.set('change_allow_user_until', RelativeDateWrapper( self.event.settings.set('change_allow_user_until', RelativeDateWrapper(
RelativeDate(days_before=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes=None)
)) ))
self.order = Order.objects.get(pk=self.order.pk) self.order = Order.objects.get(pk=self.order.pk)
assert self.order.user_change_deadline > now() assert self.order.user_change_deadline > now()
assert self.order.user_change_allowed assert self.order.user_change_allowed
self.event.settings.set('change_allow_user_until', RelativeDateWrapper( self.event.settings.set('change_allow_user_until', RelativeDateWrapper(
RelativeDate(days_before=4, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=4, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes=None)
)) ))
self.order = Order.objects.get(pk=self.order.pk) self.order = Order.objects.get(pk=self.order.pk)
assert self.order.user_change_deadline < now() assert self.order.user_change_deadline < now()
@@ -1950,7 +1950,7 @@ class OrderTestCase(BaseQuotaTestCase):
self.op2.save() self.op2.save()
self.event.settings.set('change_allow_user_until', RelativeDateWrapper( self.event.settings.set('change_allow_user_until', RelativeDateWrapper(
RelativeDate(days_before=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=datetime.time(14, 0, 0), base_date_name='date_from', minutes=None)
)) ))
self.order = Order.objects.get(pk=self.order.pk) self.order = Order.objects.get(pk=self.order.pk)
assert self.order.user_change_deadline < now() assert self.order.user_change_deadline < now()
+2 -2
View File
@@ -198,7 +198,7 @@ def test_expiry_last_relative(event):
event.date_from = now() + timedelta(days=5) event.date_from = now() + timedelta(days=5)
event.save() event.save()
event.settings.set('payment_term_last', RelativeDateWrapper( event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
order = _create_order(event, email='dummy@example.org', positions=[], order = _create_order(event, email='dummy@example.org', positions=[],
now_dt=today, now_dt=today,
@@ -238,7 +238,7 @@ def test_expiry_last_relative_subevents(event):
) )
event.settings.set('payment_term_last', RelativeDateWrapper( event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
order = _create_order(event, email='dummy@example.org', positions=[cp1, cp2], order = _create_order(event, email='dummy@example.org', positions=[cp1, cp2],
now_dt=today, now_dt=today,
+6 -6
View File
@@ -133,7 +133,7 @@ def test_availability_date_relative(event):
event.save() event.save()
prov = DummyPaymentProvider(event) prov = DummyPaymentProvider(event)
prov.settings.set('_availability_date', RelativeDateWrapper( prov.settings.set('_availability_date', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
utc = datetime.timezone.utc utc = datetime.timezone.utc
@@ -150,7 +150,7 @@ def test_availability_start_relative(event):
event.save() event.save()
prov = DummyPaymentProvider(event) prov = DummyPaymentProvider(event)
prov.settings.set('_availability_start', RelativeDateWrapper( prov.settings.set('_availability_start', RelativeDateWrapper(
RelativeDate(days_before=2, time=datetime.time(12, 0), base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=datetime.time(12, 0), base_date_name='date_from', minutes=None)
)) ))
utc = datetime.timezone.utc utc = datetime.timezone.utc
@@ -193,12 +193,12 @@ def test_availability_date_cart_relative_subevents(event):
prov = DummyPaymentProvider(event) prov = DummyPaymentProvider(event)
prov.settings.set('_availability_date', RelativeDateWrapper( prov.settings.set('_availability_date', RelativeDateWrapper(
RelativeDate(days_before=3, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=3, time=None, base_date_name='date_from', minutes=None)
)) ))
assert prov._is_available_by_time(cart_id="123") assert prov._is_available_by_time(cart_id="123")
prov.settings.set('_availability_date', RelativeDateWrapper( prov.settings.set('_availability_date', RelativeDateWrapper(
RelativeDate(days_before=4, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=4, time=None, base_date_name='date_from', minutes=None)
)) ))
assert not prov._is_available_by_time(cart_id="123") assert not prov._is_available_by_time(cart_id="123")
@@ -232,11 +232,11 @@ def test_availability_date_order_relative_subevents(event):
prov = DummyPaymentProvider(event) prov = DummyPaymentProvider(event)
prov.settings.set('_availability_date', RelativeDateWrapper( prov.settings.set('_availability_date', RelativeDateWrapper(
RelativeDate(days_before=3, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=3, time=None, base_date_name='date_from', minutes=None)
)) ))
assert prov._is_available_by_time(order=order) assert prov._is_available_by_time(order=order)
prov.settings.set('_availability_date', RelativeDateWrapper( prov.settings.set('_availability_date', RelativeDateWrapper(
RelativeDate(days_before=4, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=4, time=None, base_date_name='date_from', minutes=None)
)) ))
assert not prov._is_available_by_time(order=order) assert not prov._is_available_by_time(order=order)
+24 -15
View File
@@ -56,49 +56,58 @@ def test_absolute_date(event):
@pytest.mark.django_db @pytest.mark.django_db
def test_relative_date_without_time(event): def test_relative_date_without_time(event):
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='date_from', minutes=None))
assert rdw.datetime(event).astimezone(TOKYO) == datetime(2017, 12, 26, 5, 0, 0, tzinfo=TOKYO) assert rdw.datetime(event).astimezone(TOKYO) == datetime(2017, 12, 26, 5, 0, 0, tzinfo=TOKYO)
assert rdw.to_string() == 'RELDATE/1/-/date_from/' assert rdw.to_string() == 'RELDATE/1/-/date_from/'
rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='date_from', minutes=None, is_after=True))
assert rdw.datetime(event).astimezone(TOKYO) == datetime(2017, 12, 28, 5, 0, 0, tzinfo=TOKYO)
assert rdw.to_string() == 'RELDATE/1/-/date_from/after'
@pytest.mark.django_db @pytest.mark.django_db
def test_relative_date_other_base_point(event): def test_relative_date_other_base_point(event):
with scope(organizer=event.organizer): with scope(organizer=event.organizer):
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='presale_start', minutes=None))
assert rdw.datetime(event) == datetime(2017, 11, 30, 5, 0, 0, tzinfo=TOKYO) assert rdw.datetime(event) == datetime(2017, 11, 30, 5, 0, 0, tzinfo=TOKYO)
assert rdw.to_string() == 'RELDATE/1/-/presale_start/' assert rdw.to_string() == 'RELDATE/1/-/presale_start/'
# presale_end is unset, defaults to date_from # presale_end is unset, defaults to date_from
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_end', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='presale_end', minutes=None))
assert rdw.datetime(event) == datetime(2017, 12, 26, 5, 0, 0, tzinfo=TOKYO) assert rdw.datetime(event) == datetime(2017, 12, 26, 5, 0, 0, tzinfo=TOKYO)
assert rdw.to_string() == 'RELDATE/1/-/presale_end/' assert rdw.to_string() == 'RELDATE/1/-/presale_end/'
# subevent base # subevent base
se = event.subevents.create(name="SE1", date_from=datetime(2017, 11, 27, 5, 0, 0, tzinfo=TOKYO)) se = event.subevents.create(name="SE1", date_from=datetime(2017, 11, 27, 5, 0, 0, tzinfo=TOKYO))
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='date_from', minutes=None))
assert rdw.datetime(se) == datetime(2017, 11, 26, 5, 0, 0, tzinfo=TOKYO) assert rdw.datetime(se) == datetime(2017, 11, 26, 5, 0, 0, tzinfo=TOKYO)
# presale_start is unset on subevent, default to event # presale_start is unset on subevent, default to event
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=None, base_date_name='presale_start', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='presale_start', minutes=None))
assert rdw.datetime(se) == datetime(2017, 11, 30, 5, 0, 0, tzinfo=TOKYO) assert rdw.datetime(se) == datetime(2017, 11, 30, 5, 0, 0, tzinfo=TOKYO)
# presale_end is unset on all, default to date_from of subevent # 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', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=None, base_date_name='presale_end', minutes=None))
assert rdw.datetime(se) == datetime(2017, 11, 26, 5, 0, 0, tzinfo=TOKYO) assert rdw.datetime(se) == datetime(2017, 11, 26, 5, 0, 0, tzinfo=TOKYO)
@pytest.mark.django_db @pytest.mark.django_db
def test_relative_date_in_minutes(event): def test_relative_date_in_minutes(event):
rdw = RelativeDateWrapper(RelativeDate(days_before=0, time=None, base_date_name='date_from', minutes_before=60)) rdw = RelativeDateWrapper(RelativeDate(days=0, time=None, base_date_name='date_from', minutes=60))
assert rdw.to_string() == 'RELDATE/minutes/60/date_from/' assert rdw.to_string() == 'RELDATE/minutes/60/date_from/'
assert rdw.datetime(event) == datetime(2017, 12, 27, 4, 0, 0, tzinfo=TOKYO) assert rdw.datetime(event) == datetime(2017, 12, 27, 4, 0, 0, tzinfo=TOKYO)
rdw = RelativeDateWrapper(RelativeDate(days=0, time=None, base_date_name='date_from', minutes=60, is_after=True))
assert rdw.to_string() == 'RELDATE/minutes/60/date_from/after'
assert rdw.datetime(event) == datetime(2017, 12, 27, 6, 0, 0, tzinfo=TOKYO)
@pytest.mark.django_db @pytest.mark.django_db
def test_relative_date_with_time(event): def test_relative_date_with_time(event):
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=time(8, 5, 13), base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=time(8, 5, 13), base_date_name='date_from', minutes=None))
assert rdw.to_string() == 'RELDATE/1/08:05:13/date_from/' assert rdw.to_string() == 'RELDATE/1/08:05:13/date_from/'
assert rdw.datetime(event) == datetime(2017, 12, 26, 8, 5, 13, tzinfo=TOKYO) assert rdw.datetime(event) == datetime(2017, 12, 26, 8, 5, 13, tzinfo=TOKYO)
rdw = RelativeDateWrapper(RelativeDate(days=1, time=time(8, 5, 13), base_date_name='date_from', minutes=None, is_after=True))
assert rdw.to_string() == 'RELDATE/1/08:05:13/date_from/after'
assert rdw.datetime(event) == datetime(2017, 12, 28, 8, 5, 13, tzinfo=TOKYO)
@pytest.mark.django_db @pytest.mark.django_db
@@ -106,21 +115,21 @@ def test_relative_date_with_time_around_dst(event):
event.settings.timezone = "Europe/Berlin" event.settings.timezone = "Europe/Berlin"
event.date_from = datetime(2020, 3, 29, 18, 0, 0, tzinfo=BERLIN) event.date_from = datetime(2020, 3, 29, 18, 0, 0, tzinfo=BERLIN)
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=time(18, 0, 0), base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=time(18, 0, 0), base_date_name='date_from', minutes=None))
assert rdw.to_string() == 'RELDATE/1/18:00:00/date_from/' assert rdw.to_string() == 'RELDATE/1/18:00:00/date_from/'
assert rdw.datetime(event) == datetime(2020, 3, 28, 18, 0, 0, tzinfo=BERLIN) assert rdw.datetime(event) == datetime(2020, 3, 28, 18, 0, 0, tzinfo=BERLIN)
rdw = RelativeDateWrapper(RelativeDate(days_before=0, time=time(2, 30, 0), base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=0, time=time(2, 30, 0), base_date_name='date_from', minutes=None))
assert rdw.to_string() == 'RELDATE/0/02:30:00/date_from/' assert rdw.to_string() == 'RELDATE/0/02:30:00/date_from/'
assert rdw.datetime(event) == datetime(2020, 3, 29, 2, 30, 0, tzinfo=BERLIN) assert rdw.datetime(event) == datetime(2020, 3, 29, 2, 30, 0, tzinfo=BERLIN)
event.date_from = datetime(2020, 10, 25, 18, 0, 0, tzinfo=BERLIN) event.date_from = datetime(2020, 10, 25, 18, 0, 0, tzinfo=BERLIN)
rdw = RelativeDateWrapper(RelativeDate(days_before=1, time=time(18, 0, 0), base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=1, time=time(18, 0, 0), base_date_name='date_from', minutes=None))
assert rdw.to_string() == 'RELDATE/1/18:00:00/date_from/' assert rdw.to_string() == 'RELDATE/1/18:00:00/date_from/'
assert rdw.datetime(event) == datetime(2020, 10, 24, 18, 0, 0, tzinfo=BERLIN) assert rdw.datetime(event) == datetime(2020, 10, 24, 18, 0, 0, tzinfo=BERLIN)
rdw = RelativeDateWrapper(RelativeDate(days_before=0, time=time(2, 30, 0), base_date_name='date_from', minutes_before=None)) rdw = RelativeDateWrapper(RelativeDate(days=0, time=time(2, 30, 0), base_date_name='date_from', minutes=None))
assert rdw.to_string() == 'RELDATE/0/02:30:00/date_from/' assert rdw.to_string() == 'RELDATE/0/02:30:00/date_from/'
assert rdw.datetime(event) == datetime(2020, 10, 25, 2, 30, 0, tzinfo=BERLIN) assert rdw.datetime(event) == datetime(2020, 10, 25, 2, 30, 0, tzinfo=BERLIN)
@@ -131,10 +140,10 @@ def test_unserialize():
assert rdw.data == d assert rdw.data == d
rdw = RelativeDateWrapper.from_string('RELDATE/1/-/date_from/') rdw = RelativeDateWrapper.from_string('RELDATE/1/-/date_from/')
assert rdw.data == RelativeDate(days_before=1, time=None, base_date_name='date_from', minutes_before=None) assert rdw.data == RelativeDate(days=1, time=None, base_date_name='date_from', minutes=None)
rdw = RelativeDateWrapper.from_string('RELDATE/1/18:05:13/date_from/') rdw = RelativeDateWrapper.from_string('RELDATE/1/18:05:13/date_from/')
assert rdw.data == RelativeDate(days_before=1, time=time(18, 5, 13), base_date_name='date_from', minutes_before=None) assert rdw.data == RelativeDate(days=1, time=time(18, 5, 13), base_date_name='date_from', minutes=None)
rdw = RelativeDateWrapper.from_string('RELDATE/minutes/60/date_from/') rdw = RelativeDateWrapper.from_string('RELDATE/minutes/60/date_from/')
assert rdw.data == RelativeDate(days_before=0, time=None, base_date_name='date_from', minutes_before=60) assert rdw.data == RelativeDate(days=0, time=None, base_date_name='date_from', minutes=60)
+1 -1
View File
@@ -1218,7 +1218,7 @@ class OrderChangeAddonsTest(BaseOrdersTest):
self.order.save() self.order.save()
self._subevent_setup() self._subevent_setup()
self.event.settings.set('payment_term_last', RelativeDateWrapper( self.event.settings.set('payment_term_last', RelativeDateWrapper(
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None) RelativeDate(days=2, time=None, base_date_name='date_from', minutes=None)
)) ))
response = self.client.get( response = self.client.get(
+1 -1
View File
@@ -944,7 +944,7 @@ class OrdersTest(BaseOrdersTest):
self.event.date_from = now() + datetime.timedelta(days=3) self.event.date_from = now() + datetime.timedelta(days=3)
self.event.save() self.event.save()
self.event.settings.set('ticket_download_date', RelativeDateWrapper(RelativeDate( self.event.settings.set('ticket_download_date', RelativeDateWrapper(RelativeDate(
base_date_name='date_from', days_before=2, time=None, minutes_before=None base_date_name='date_from', days=2, time=None, minutes=None
))) )))
response = self.client.post( response = self.client.post(
'/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code, '/%s/%s/order/%s/%s/download/%d/testdummy' % (self.orga.slug, self.event.slug, self.order.code,