Form UX: Use splitted date/time widgets

This commit is contained in:
Raphael Michel
2017-10-05 09:28:02 +02:00
parent a27f372785
commit 2f252f19c9
15 changed files with 223 additions and 85 deletions

View File

@@ -1,7 +1,9 @@
import os import os
from django import forms from django import forms
from django.utils.formats import get_format
from django.utils.html import conditional_escape from django.utils.html import conditional_escape
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from ...base.forms import I18nModelForm from ...base.forms import I18nModelForm
@@ -98,3 +100,34 @@ class SlugWidget(forms.TextInput):
ctx = super().get_context(name, value, attrs) ctx = super().get_context(name, value, attrs)
ctx['pre'] = self.prefix ctx['pre'] = self.prefix
return ctx return ctx
class SplitDateTimePickerWidget(forms.SplitDateTimeWidget):
def __init__(self, attrs=None, date_format=None, time_format=None):
attrs = attrs or {}
if 'placeholder' in attrs:
del attrs['placeholder']
date_attrs = dict(attrs)
time_attrs = dict(attrs)
date_attrs.setdefault('class', 'form-control splitdatetimepart')
time_attrs.setdefault('class', 'form-control splitdatetimepart')
date_attrs['class'] += ' datepickerfield'
time_attrs['class'] += ' timepickerfield'
time_attrs['class'] += ' timepickerfield'
df = date_format or get_format('DATE_INPUT_FORMATS')[0]
date_attrs['placeholder'] = now().replace(
year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0
).strftime(df)
tf = time_format or get_format('TIME_INPUT_FORMATS')[0]
time_attrs['placeholder'] = now().replace(
year=2000, month=1, day=1, hour=0, minute=0, second=0, microsecond=0
).strftime(tf)
widgets = (
forms.DateInput(attrs=date_attrs, format=date_format),
forms.TimeInput(attrs=time_attrs, format=time_format),
)
# Skip one hierarchy level
forms.MultiWidget.__init__(self, widgets, attrs)

View File

@@ -12,7 +12,9 @@ from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
from pretix.base.models import Event, Organizer, TaxRule from pretix.base.models import Event, Organizer, TaxRule
from pretix.base.models.event import EventMetaValue from pretix.base.models.event import EventMetaValue
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
from pretix.control.forms import ExtFileField, SlugWidget from pretix.control.forms import (
ExtFileField, SlugWidget, SplitDateTimePickerWidget,
)
from pretix.multidomain.urlreverse import build_absolute_uri from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.presale.style import get_fonts from pretix.presale.style import get_fonts
@@ -82,14 +84,18 @@ class EventWizardBasicsForm(I18nModelForm):
'presale_end', 'presale_end',
'location', 'location',
] ]
field_classes = {
'date_from': forms.SplitDateTimeField,
'date_to': forms.SplitDateTimeField,
'presale_start': forms.SplitDateTimeField,
'presale_end': forms.SplitDateTimeField,
}
widgets = { widgets = {
'date_from': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'date_from': SplitDateTimePickerWidget(),
'date_to': forms.DateTimeInput(attrs={'class': 'datetimepicker', 'date_to': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_basics-date_from_0'}),
'data-date-after': '#id_basics-date_from'}), 'presale_start': SplitDateTimePickerWidget(),
'presale_start': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'presale_end': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_basics-presale_start_0'}),
'presale_end': forms.DateTimeInput(attrs={'class': 'datetimepicker', 'slug': SlugWidget,
'data-date-after': '#id_basics-presale_start'}),
'slug': SlugWidget
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -206,14 +212,19 @@ class EventUpdateForm(I18nModelForm):
'presale_end', 'presale_end',
'location', 'location',
] ]
field_classes = {
'date_from': forms.SplitDateTimeField,
'date_to': forms.SplitDateTimeField,
'date_admission': forms.SplitDateTimeField,
'presale_start': forms.SplitDateTimeField,
'presale_end': forms.SplitDateTimeField,
}
widgets = { widgets = {
'date_from': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'date_from': SplitDateTimePickerWidget(),
'date_to': forms.DateTimeInput(attrs={'class': 'datetimepicker', 'data-date-after': '#id_date_from'}), 'date_to': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_date_from_0'}),
'date_admission': forms.DateTimeInput(attrs={'class': 'datetimepicker', 'date_admission': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_date_from_0'}),
'data-date-default': '#id_date_from'}), 'presale_start': SplitDateTimePickerWidget(),
'presale_start': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'presale_end': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_presale_start_0'}),
'presale_end': forms.DateTimeInput(attrs={'class': 'datetimepicker',
'data-date-after': '#id_presale_start'}),
} }

View File

@@ -12,6 +12,7 @@ from pretix.base.models import (
Item, ItemCategory, ItemVariation, Question, QuestionOption, Quota, Item, ItemCategory, ItemVariation, Question, QuestionOption, Quota,
) )
from pretix.base.models.items import ItemAddOn from pretix.base.models.items import ItemAddOn
from pretix.control.forms import SplitDateTimePickerWidget
class CategoryForm(I18nModelForm): class CategoryForm(I18nModelForm):
@@ -286,9 +287,13 @@ class ItemUpdateForm(I18nModelForm):
'min_per_order', 'min_per_order',
'checkin_attention' 'checkin_attention'
] ]
field_classes = {
'available_from': forms.SplitDateTimeField,
'available_until': forms.SplitDateTimeField,
}
widgets = { widgets = {
'available_from': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'available_from': SplitDateTimePickerWidget(),
'available_until': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'available_until': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_available_from_0'}),
} }

View File

@@ -5,6 +5,7 @@ from i18nfield.forms import I18nInlineFormSet
from pretix.base.forms import I18nModelForm from pretix.base.forms import I18nModelForm
from pretix.base.models.event import SubEvent, SubEventMetaValue from pretix.base.models.event import SubEvent, SubEventMetaValue
from pretix.base.models.items import SubEventItem from pretix.base.models.items import SubEventItem
from pretix.control.forms import SplitDateTimePickerWidget
class SubEventForm(I18nModelForm): class SubEventForm(I18nModelForm):
@@ -27,13 +28,19 @@ class SubEventForm(I18nModelForm):
'location', 'location',
'frontpage_text' 'frontpage_text'
] ]
field_classes = {
'date_from': forms.SplitDateTimeField,
'date_to': forms.SplitDateTimeField,
'date_admission': forms.SplitDateTimeField,
'presale_start': forms.SplitDateTimeField,
'presale_end': forms.SplitDateTimeField,
}
widgets = { widgets = {
'date_from': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'date_from': SplitDateTimePickerWidget(),
'date_to': forms.DateTimeInput(attrs={'class': 'datetimepicker', 'data-date-after': '#id_date_from'}), 'date_to': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_date_from_0'}),
'date_admission': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'date_admission': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_date_from_0'}),
'presale_start': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'presale_start': SplitDateTimePickerWidget(),
'presale_end': forms.DateTimeInput(attrs={'class': 'datetimepicker', 'presale_end': SplitDateTimePickerWidget(attrs={'data-date-after': '#id_presale_start_0'}),
'data-date-after': '#id_presale_start'}),
} }

View File

@@ -8,6 +8,7 @@ from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from pretix.base.forms import I18nModelForm from pretix.base.forms import I18nModelForm
from pretix.base.models import Item, ItemVariation, Quota, Voucher from pretix.base.models import Item, ItemVariation, Quota, Voucher
from pretix.control.forms import SplitDateTimePickerWidget
from pretix.control.signals import voucher_form_validation from pretix.control.signals import voucher_form_validation
@@ -27,8 +28,11 @@ class VoucherForm(I18nModelForm):
'code', 'valid_until', 'block_quota', 'allow_ignore_quota', 'value', 'tag', 'code', 'valid_until', 'block_quota', 'allow_ignore_quota', 'value', 'tag',
'comment', 'max_usages', 'price_mode', 'subevent' 'comment', 'max_usages', 'price_mode', 'subevent'
] ]
field_classes = {
'valid_until': forms.SplitDateTimeField,
}
widgets = { widgets = {
'valid_until': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'valid_until': SplitDateTimePickerWidget(),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -218,8 +222,11 @@ class VoucherBulkForm(VoucherForm):
'valid_until', 'block_quota', 'allow_ignore_quota', 'value', 'tag', 'comment', 'valid_until', 'block_quota', 'allow_ignore_quota', 'value', 'tag', 'comment',
'max_usages', 'price_mode', 'subevent' 'max_usages', 'price_mode', 'subevent'
] ]
field_classes = {
'valid_until': forms.SplitDateTimeField,
}
widgets = { widgets = {
'valid_until': forms.DateTimeInput(attrs={'class': 'datetimepicker'}), 'valid_until': SplitDateTimePickerWidget(),
} }
labels = { labels = {
'max_usages': _('Maximum usages per voucher') 'max_usages': _('Maximum usages per voucher')

View File

@@ -9,10 +9,10 @@
<legend>{% trans "General information" %}</legend> <legend>{% trans "General information" %}</legend>
{% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.slug layout="horizontal" %} {% bootstrap_field form.slug layout="horizontal" %}
{% bootstrap_field form.date_from layout="horizontal" %} {% bootstrap_field form.date_from layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.date_to layout="horizontal" %} {% bootstrap_field form.date_to layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.location layout="horizontal" %} {% bootstrap_field form.location layout="horizontal" %}
{% bootstrap_field form.date_admission layout="horizontal" %} {% bootstrap_field form.date_admission layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.currency layout="horizontal" %} {% bootstrap_field form.currency layout="horizontal" %}
{% bootstrap_field form.is_public layout="horizontal" %} {% bootstrap_field form.is_public layout="horizontal" %}
@@ -51,9 +51,9 @@
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "Timeline" %}</legend> <legend>{% trans "Timeline" %}</legend>
{% bootstrap_field form.presale_start layout="horizontal" %} {% bootstrap_field form.presale_start layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field sform.presale_start_show_date layout="horizontal" %} {% bootstrap_field sform.presale_start_show_date layout="horizontal" %}
{% bootstrap_field form.presale_end layout="horizontal" %} {% bootstrap_field form.presale_end layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field sform.show_items_outside_presale_period layout="horizontal" %} {% bootstrap_field sform.show_items_outside_presale_period layout="horizontal" %}
{% bootstrap_field sform.last_order_modification_date layout="horizontal" %} {% bootstrap_field sform.last_order_modification_date layout="horizontal" %}
</fieldset> </fieldset>

View File

@@ -29,8 +29,8 @@
</div> </div>
</div> </div>
</div> </div>
{% bootstrap_field form.date_from layout="horizontal" %} {% bootstrap_field form.date_from layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.date_to layout="horizontal" %} {% bootstrap_field form.date_to layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.location layout="horizontal" %} {% bootstrap_field form.location layout="horizontal" %}
{% bootstrap_field form.currency layout="horizontal" %} {% bootstrap_field form.currency layout="horizontal" %}
{% bootstrap_field form.tax_rate layout="horizontal" %} {% bootstrap_field form.tax_rate layout="horizontal" %}
@@ -43,8 +43,8 @@
{% if form.presale_start %} {% if form.presale_start %}
<fieldset> <fieldset>
<legend>{% trans "Timeline" %}</legend> <legend>{% trans "Timeline" %}</legend>
{% bootstrap_field form.presale_start layout="horizontal" %} {% bootstrap_field form.presale_start layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.presale_end layout="horizontal" %} {% bootstrap_field form.presale_end layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
</fieldset> </fieldset>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@@ -23,8 +23,8 @@
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "Availability" %}</legend> <legend>{% trans "Availability" %}</legend>
{% bootstrap_field form.available_from layout="horizontal" %} {% bootstrap_field form.available_from layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.available_until layout="horizontal" %} {% bootstrap_field form.available_until layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.max_per_order layout="horizontal" %} {% bootstrap_field form.max_per_order layout="horizontal" %}
{% bootstrap_field form.min_per_order layout="horizontal" %} {% bootstrap_field form.min_per_order layout="horizontal" %}
{% bootstrap_field form.require_voucher layout="horizontal" %} {% bootstrap_field form.require_voucher layout="horizontal" %}

View File

@@ -22,10 +22,10 @@
<legend>{% trans "General information" %}</legend> <legend>{% trans "General information" %}</legend>
{% bootstrap_field form.name layout="horizontal" %} {% bootstrap_field form.name layout="horizontal" %}
{% bootstrap_field form.active layout="horizontal" %} {% bootstrap_field form.active layout="horizontal" %}
{% bootstrap_field form.date_from layout="horizontal" %} {% bootstrap_field form.date_from layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.date_to layout="horizontal" %} {% bootstrap_field form.date_to layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.location layout="horizontal" %} {% bootstrap_field form.location layout="horizontal" %}
{% bootstrap_field form.date_admission layout="horizontal" %} {% bootstrap_field form.date_admission layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.frontpage_text layout="horizontal" %} {% bootstrap_field form.frontpage_text layout="horizontal" %}
{% if meta_forms %} {% if meta_forms %}
<div class="form-group metadata-group"> <div class="form-group metadata-group">
@@ -49,8 +49,8 @@
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "Timeline" %}</legend> <legend>{% trans "Timeline" %}</legend>
{% bootstrap_field form.presale_start layout="horizontal" %} {% bootstrap_field form.presale_start layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.presale_end layout="horizontal" %} {% bootstrap_field form.presale_end layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "Quotas" %}</legend> <legend>{% trans "Quotas" %}</legend>

View File

@@ -38,7 +38,7 @@
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{% trans "Voucher details" %}</legend> <legend>{% trans "Voucher details" %}</legend>
{% bootstrap_field form.valid_until layout="horizontal" %} {% bootstrap_field form.valid_until layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.block_quota layout="horizontal" %} {% bootstrap_field form.block_quota layout="horizontal" %}
{% bootstrap_field form.allow_ignore_quota layout="horizontal" %} {% bootstrap_field form.allow_ignore_quota layout="horizontal" %}
<div class="form-group"> <div class="form-group">

View File

@@ -26,7 +26,7 @@
<legend>{% trans "Voucher details" %}</legend> <legend>{% trans "Voucher details" %}</legend>
{% bootstrap_field form.code layout="horizontal" %} {% bootstrap_field form.code layout="horizontal" %}
{% bootstrap_field form.max_usages layout="horizontal" %} {% bootstrap_field form.max_usages layout="horizontal" %}
{% bootstrap_field form.valid_until layout="horizontal" %} {% bootstrap_field form.valid_until layout="horizontal" horizontal_field_class="col-md-9 splitdatetimerow" %}
{% bootstrap_field form.block_quota layout="horizontal" %} {% bootstrap_field form.block_quota layout="horizontal" %}
{% bootstrap_field form.allow_ignore_quota layout="horizontal" %} {% bootstrap_field form.allow_ignore_quota layout="horizontal" %}
<div class="form-group"> <div class="form-group">

View File

@@ -179,11 +179,22 @@ $(function () {
today: 'fa fa-screenshot', today: 'fa fa-screenshot',
clear: 'fa fa-trash', clear: 'fa fa-trash',
close: 'fa fa-remove' close: 'fa fa-remove'
} },
}; };
if ($(this).is('[data-is-payment-date]')) if ($(this).is('[data-is-payment-date]'))
opts["daysOfWeekDisabled"] = JSON.parse($("body").attr("data-payment-weekdays-disabled")); opts["daysOfWeekDisabled"] = JSON.parse($("body").attr("data-payment-weekdays-disabled"));
$(this).datetimepicker(opts); $(this).datetimepicker(opts);
if ($(this).parent().is('.splitdatetimerow')) {
$(this).on("dp.change", function (ev) {
var $timepicker = $(this).closest(".splitdatetimerow").find(".timepickerfield");
var date = $(this).data('DateTimePicker').date();
if (date === null) {
return;
}
date.set({'hour': 0, 'minute': 0, 'second': 0});
$timepicker.data('DateTimePicker').date(date);
});
}
}); });
$(".timepickerfield").each(function() { $(".timepickerfield").each(function() {

View File

@@ -190,3 +190,26 @@ pre.mail-preview {
margin-right: 10px; margin-right: 10px;
} }
} }
.splitdatetimerow {
display: flex;
flex-direction: row;
flex-wrap: wrap;
.help-block {
width: 100%;
}
}
.splitdatetimepart {
width: 50%;
display: inline-block;
&.datepickerfield {
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
&.timepickerfield {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
border-left: 0;
}
}

View File

@@ -50,18 +50,21 @@ class EventsTest(SoupTest):
def test_settings(self): def test_settings(self):
doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug))
doc.select("[name=date_to]")[0]['value'] = "2013-12-30 17:00:00" doc.select("[name=date_to_0]")[0]['value'] = "2013-12-30"
doc.select("[name=date_to_1]")[0]['value'] = "17:00:00"
doc.select("[name=settings-max_items_per_order]")[0]['value'] = "12" doc.select("[name=settings-max_items_per_order]")[0]['value'] = "12"
doc = self.post_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug), doc = self.post_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug),
extract_form_fields(doc.select('.container-fluid form')[0])) extract_form_fields(doc.select('.container-fluid form')[0]))
assert len(doc.select(".alert-success")) > 0 assert len(doc.select(".alert-success")) > 0
assert doc.select("[name=date_to]")[0]['value'] == "2013-12-30 17:00:00" assert doc.select("[name=date_to_0]")[0]['value'] == "2013-12-30"
assert doc.select("[name=date_to_1]")[0]['value'] == "17:00:00"
assert doc.select("[name=settings-max_items_per_order]")[0]['value'] == "12" assert doc.select("[name=settings-max_items_per_order]")[0]['value'] == "12"
def test_settings_timezone(self): def test_settings_timezone(self):
doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/settings/' % (self.orga1.slug, self.event1.slug))
doc.select("[name=date_to]")[0]['value'] = "2013-12-30 17:00:00" doc.select("[name=date_to_0]")[0]['value'] = "2013-12-30"
doc.select("[name=date_to_1]")[0]['value'] = "17:00:00"
doc.select("[name=settings-max_items_per_order]")[0]['value'] = "12" doc.select("[name=settings-max_items_per_order]")[0]['value'] = "12"
doc.select("[name=settings-timezone]")[0]['value'] = "Asia/Tokyo" doc.select("[name=settings-timezone]")[0]['value'] = "Asia/Tokyo"
doc.find('option', {"value": "Asia/Tokyo"})['selected'] = 'selected' doc.find('option', {"value": "Asia/Tokyo"})['selected'] = 'selected'
@@ -71,7 +74,8 @@ class EventsTest(SoupTest):
extract_form_fields(doc.select('.container-fluid form')[0])) extract_form_fields(doc.select('.container-fluid form')[0]))
assert len(doc.select(".alert-success")) > 0 assert len(doc.select(".alert-success")) > 0
# date_to should not be changed even though the timezone is changed # date_to should not be changed even though the timezone is changed
assert doc.select("[name=date_to]")[0]['value'] == "2013-12-30 17:00:00" assert doc.select("[name=date_to_0]")[0]['value'] == "2013-12-30"
assert doc.select("[name=date_to_1]")[0]['value'] == "17:00:00"
assert 'selected' in doc.find('option', {"value": "Asia/Tokyo"}).attrs assert 'selected' in doc.find('option', {"value": "Asia/Tokyo"}).attrs
assert doc.select("[name=settings-max_items_per_order]")[0]['value'] == "12" assert doc.select("[name=settings-max_items_per_order]")[0]['value'] == "12"
@@ -293,16 +297,20 @@ class EventsTest(SoupTest):
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-name_1': '33C3', 'basics-name_1': '33C3',
'basics-slug': '31c3', 'basics-slug': '31c3',
'basics-date_from': '2016-12-27 10:00:00', 'basics-date_from_0': '2016-12-27',
'basics-date_to': '2016-12-30 19:00:00', 'basics-date_from_1': '10:00:00',
'basics-date_to_0': '2016-12-30',
'basics-date_to_1': '19:00:00',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg', 'basics-location_1': 'Hamburg',
'basics-currency': 'EUR', 'basics-currency': 'EUR',
'basics-tax_rate': '', 'basics-tax_rate': '',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin', 'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00', 'basics-presale_start_0': '2016-11-01',
'basics-presale_end': '2016-11-30 18:00:00', 'basics-presale_start_1': '10:00:00',
'basics-presale_end_0': '2016-11-30',
'basics-presale_end_1': '18:00:00',
}) })
assert doc.select(".alert-danger") assert doc.select(".alert-danger")
@@ -325,16 +333,20 @@ class EventsTest(SoupTest):
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-name_1': '33C3', 'basics-name_1': '33C3',
'basics-slug': '33c3', 'basics-slug': '33c3',
'basics-date_from': '2016-12-27 10:00:00', 'basics-date_from_0': '2016-12-27',
'basics-date_to': '2016-12-30 19:00:00', 'basics-date_from_1': '10:00:00',
'basics-date_to_0': '2016-12-30',
'basics-date_to_1': '19:00:00',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg', 'basics-location_1': 'Hamburg',
'basics-currency': 'EUR', 'basics-currency': 'EUR',
'basics-tax_rate': '19.00', 'basics-tax_rate': '19.00',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin', 'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00', 'basics-presale_start_0': '2016-11-01',
'basics-presale_end': '2016-11-30 18:00:00', 'basics-presale_start_1': '10:00:00',
'basics-presale_end_0': '2016-11-30',
'basics-presale_end_1': '18:00:00',
}) })
assert doc.select("#id_copy-copy_from_event_1") assert doc.select("#id_copy-copy_from_event_1")
@@ -379,16 +391,20 @@ class EventsTest(SoupTest):
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-name_1': '33C3', 'basics-name_1': '33C3',
'basics-slug': '33c3', 'basics-slug': '33c3',
'basics-date_from': '2016-12-27 10:00:00', 'basics-date_from_0': '2016-12-27',
'basics-date_to': '2016-12-30 19:00:00', 'basics-date_from_1': '10:00:00',
'basics-date_to_0': '2016-12-30',
'basics-date_to_1': '19:00:00',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg', 'basics-location_1': 'Hamburg',
'basics-currency': 'EUR', 'basics-currency': 'EUR',
'basics-tax_rate': '', 'basics-tax_rate': '',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin', 'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00', 'basics-presale_start_0': '2016-11-01',
'basics-presale_end': '2016-11-30 18:00:00', 'basics-presale_start_1': '10:00:00',
'basics-presale_end_0': '2016-11-30',
'basics-presale_end_1': '18:00:00',
}) })
self.post_doc('/control/events/add', { self.post_doc('/control/events/add', {
'event_wizard-current_step': 'copy', 'event_wizard-current_step': 'copy',
@@ -409,15 +425,19 @@ class EventsTest(SoupTest):
'event_wizard-current_step': 'basics', 'event_wizard-current_step': 'basics',
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-slug': '33c3', 'basics-slug': '33c3',
'basics-date_from': '2016-12-27 10:00:00', 'basics-date_from_0': '2016-12-27',
'basics-date_to': '', 'basics-date_from_1': '10:00:00',
'basics-date_to_0': '',
'basics-date_to_1': '',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-currency': 'EUR', 'basics-currency': 'EUR',
'basics-tax_rate': '', 'basics-tax_rate': '',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'UTC', 'basics-timezone': 'UTC',
'basics-presale_start': '', 'basics-presale_start_0': '',
'basics-presale_end': '', 'basics-presale_start_1': '',
'basics-presale_end_0': '',
'basics-presale_end_1': '',
}) })
self.post_doc('/control/events/add', { self.post_doc('/control/events/add', {
'event_wizard-current_step': 'copy', 'event_wizard-current_step': 'copy',
@@ -449,15 +469,19 @@ class EventsTest(SoupTest):
'event_wizard-current_step': 'basics', 'event_wizard-current_step': 'basics',
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-slug': '33c3', 'basics-slug': '33c3',
'basics-date_from': '', 'basics-date_from_0': '',
'basics-date_to': '2016-12-30 19:00:00', 'basics-date_from_1': '',
'basics-date_to_0': '2016-12-30',
'basics-date_to_1': '19:00:00',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-currency': 'EUR', 'basics-currency': 'EUR',
'basics-tax_rate': '', 'basics-tax_rate': '',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin', 'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-20 11:00:00', 'basics-presale_start_0': '2016-11-01',
'basics-presale_end': '2016-11-24 18:00:00', 'basics-presale_start_1': '10:00:00',
'basics-presale_end_0': '2016-11-30',
'basics-presale_end_1': '18:00:00',
}) })
assert doc.select(".alert-danger") assert doc.select(".alert-danger")
@@ -472,15 +496,19 @@ class EventsTest(SoupTest):
'event_wizard-current_step': 'basics', 'event_wizard-current_step': 'basics',
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-slug': '31c4', 'basics-slug': '31c4',
'basics-date_from': '2016-12-27 10:00:00', 'basics-date_from_0': '2016-12-27',
'basics-date_to': '2016-12-30 19:00:00', 'basics-date_from_1': '10:00:00',
'basics-date_to_0': '2016-12-30',
'basics-date_to_1': '19:00:00',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-currency': '$', 'basics-currency': '$',
'basics-tax_rate': '', 'basics-tax_rate': '',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin', 'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00', 'basics-presale_start_0': '2016-11-01',
'basics-presale_end': '2016-11-30 18:00:00', 'basics-presale_start_1': '10:00:00',
'basics-presale_end_0': '2016-11-30',
'basics-presale_end_1': '18:00:00',
}) })
assert doc.select(".alert-danger") assert doc.select(".alert-danger")
@@ -495,15 +523,19 @@ class EventsTest(SoupTest):
'event_wizard-current_step': 'basics', 'event_wizard-current_step': 'basics',
'basics-name_0': '33C3', 'basics-name_0': '33C3',
'basics-slug': '31c5', 'basics-slug': '31c5',
'basics-date_from': '2016-12-27 10:00:00', 'basics-date_from_0': '2016-12-27',
'basics-date_to': '2016-12-30 19:00:00', 'basics-date_from_1': '10:00:00',
'basics-date_to_0': '2016-12-30',
'basics-date_to_1': '19:00:00',
'basics-location_0': 'Hamburg', 'basics-location_0': 'Hamburg',
'basics-currency': 'ASD', 'basics-currency': 'ASD',
'basics-tax_rate': '', 'basics-tax_rate': '',
'basics-locale': 'en', 'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin', 'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00', 'basics-presale_start_0': '2016-11-01',
'basics-presale_end': '2016-11-30 18:00:00', 'basics-presale_start_1': '10:00:00',
'basics-presale_end_0': '2016-11-30',
'basics-presale_end_1': '18:00:00',
}) })
assert doc.select(".alert-danger") assert doc.select(".alert-danger")
@@ -543,10 +575,13 @@ class SubEventsTest(SoupTest):
doc = self.post_doc('/control/event/ccc/30c3/subevents/add', { doc = self.post_doc('/control/event/ccc/30c3/subevents/add', {
'name_0': 'SE2', 'name_0': 'SE2',
'active': 'on', 'active': 'on',
'date_from': '2017-07-01 10:00:00', 'date_from_0': '2017-07-01',
'date_to': '2017-07-01 12:00:00', 'date_from_1': '10:00:00',
'date_to_0': '2017-07-01',
'date_to_1': '12:00:00',
'location_0': 'Hamburg', 'location_0': 'Hamburg',
'presale_start': '2017-06-20 10:00:00', 'presale_start_0': '2017-06-20',
'presale_start_1': '10:00:00',
'quotas-TOTAL_FORMS': '1', 'quotas-TOTAL_FORMS': '1',
'quotas-INITIAL_FORMS': '0', 'quotas-INITIAL_FORMS': '0',
'quotas-MIN_NUM_FORMS': '0', 'quotas-MIN_NUM_FORMS': '0',
@@ -579,10 +614,13 @@ class SubEventsTest(SoupTest):
doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk, { doc = self.post_doc('/control/event/ccc/30c3/subevents/%d/' % self.subevent1.pk, {
'name_0': 'SE2', 'name_0': 'SE2',
'active': 'on', 'active': 'on',
'date_from': '2017-07-01 10:00:00', 'date_from_0': '2017-07-01',
'date_to': '2017-07-01 12:00:00', 'date_from_1': '10:00:00',
'date_to_0': '2017-07-01',
'date_to_1': '12:00:00',
'location_0': 'Hamburg', 'location_0': 'Hamburg',
'presale_start': '2017-06-20 10:00:00', 'presale_start_0': '2017-06-20',
'presale_start_1': '10:00:00',
'quotas-TOTAL_FORMS': '1', 'quotas-TOTAL_FORMS': '1',
'quotas-INITIAL_FORMS': '0', 'quotas-INITIAL_FORMS': '0',
'quotas-MIN_NUM_FORMS': '0', 'quotas-MIN_NUM_FORMS': '0',

View File

@@ -194,7 +194,8 @@ class VoucherFormTest(SoupTest):
self._create_voucher({ self._create_voucher({
'itemvar': '%d-%d' % (self.shirt.pk, self.shirt_red.pk), 'itemvar': '%d-%d' % (self.shirt.pk, self.shirt_red.pk),
'block_quota': 'on', 'block_quota': 'on',
'valid_until': (now() - datetime.timedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S') 'valid_until_0': (now() - datetime.timedelta(days=3)).strftime('%Y-%m-%d'),
'valid_until_1': (now() - datetime.timedelta(days=3)).strftime('%H:%M:%S')
}) })
def test_create_blocking_variation_voucher_quota_free(self): def test_create_blocking_variation_voucher_quota_free(self):
@@ -276,7 +277,8 @@ class VoucherFormTest(SoupTest):
v = self.event.vouchers.create(item=self.ticket, valid_until=now() - datetime.timedelta(days=3), v = self.event.vouchers.create(item=self.ticket, valid_until=now() - datetime.timedelta(days=3),
block_quota=True) block_quota=True)
self._change_voucher(v, { self._change_voucher(v, {
'valid_until': (now() + datetime.timedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S') 'valid_until_0': (now() + datetime.timedelta(days=3)).strftime('%Y-%m-%d'),
'valid_until_1': (now() + datetime.timedelta(days=3)).strftime('%H:%M:%S')
}, expected_failure=True) }, expected_failure=True)
v.refresh_from_db() v.refresh_from_db()
assert v.valid_until < now() assert v.valid_until < now()
@@ -285,7 +287,8 @@ class VoucherFormTest(SoupTest):
v = self.event.vouchers.create(item=self.ticket, valid_until=now() - datetime.timedelta(days=3), v = self.event.vouchers.create(item=self.ticket, valid_until=now() - datetime.timedelta(days=3),
block_quota=True) block_quota=True)
self._change_voucher(v, { self._change_voucher(v, {
'valid_until': (now() + datetime.timedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S') 'valid_until_0': (now() + datetime.timedelta(days=3)).strftime('%Y-%m-%d'),
'valid_until_1': (now() + datetime.timedelta(days=3)).strftime('%H:%M:%S')
}) })
v.refresh_from_db() v.refresh_from_db()
assert v.valid_until > now() assert v.valid_until > now()