Enforce start and end time of presale (#15)

This commit is contained in:
Raphael Michel
2015-04-16 17:40:08 +02:00
parent 1532b3f1ee
commit 14c582d11e
9 changed files with 209 additions and 90 deletions

View File

@@ -482,6 +482,20 @@ class Event(Versionable):
"""
return SettingsProxy(self, type=EventSetting, parent=self.organizer)
@property
def presale_has_ended(self):
if self.presale_end and now() > self.presale_end:
return True
return False
@property
def presale_is_running(self):
if self.presale_start and now() < self.presale_start:
return False
if self.presale_end and now() > self.presale_end:
return False
return True
class EventPermission(Versionable):
"""

View File

@@ -41,6 +41,14 @@ DEFAULTS = {
'default': 'True',
'type': bool
},
'presale_start_show_date': {
'default': 'True',
'type': bool
},
'show_items_outside_presale_period': {
'default': 'True',
'type': bool
},
'timezone': {
'default': settings.TIME_ZONE,
'type': str

View File

@@ -28,7 +28,9 @@
<fieldset>
<legend>{% trans "Timeline" %}</legend>
{% bootstrap_field form.presale_start layout="horizontal" %}
{% bootstrap_field sform.presale_start_show_date layout="horizontal" %}
{% bootstrap_field form.presale_end layout="horizontal" %}
{% bootstrap_field sform.show_items_outside_presale_period layout="horizontal" %}
{% bootstrap_field sform.payment_term_days layout="horizontal" %}
{% bootstrap_field sform.payment_term_last layout="horizontal" %}
{% bootstrap_field sform.payment_term_accept_late layout="horizontal" %}

View File

@@ -55,6 +55,16 @@ class EventSettingsForm(SettingsForm):
label='Payment term in days',
help_text=_("The number of days after placing an order the user has to pay to preserve his reservation."),
)
show_items_outside_presale_period = forms.BooleanField(
label=_("Show items outside presale period"),
help_text=_("Show item details before presale has started and after presale has ended"),
required=False
)
presale_start_show_date = forms.BooleanField(
label=_("Show start date"),
help_text=_("Show the presale start date before presale has started"),
required=False
)
payment_term_last = forms.DateTimeField(
label='Last date of payments',
help_text=_("The last date any payments are accepted. This has precedence over the number of "

View File

@@ -30,97 +30,118 @@
</div>
</div>
{% endif %}
<form method="post"
action="{% url "presale:event.cart.add" organizer=request.event.organizer.slug event=request.event.slug %}?next={{ request.path_info|urlencode }}">
{% csrf_token %}
{% for tup in items_by_category %}
<section>
{% if tup.0 %}<h3>{{ tup.0.name }}</h3>{% endif %}
{% for item in tup.1 %}
{% if item.has_variations %}
<div class="item-with-variations">
<div class="row-fluid product-row headline">
{% if not event.presale_is_running %}
<div class="alert alert-info">
{% if event.presale_has_ended %}
{% blocktrans trimmed %}
The presale period for this event is over.
{% endblocktrans %}
{% elif event.settings.presale_start_show_date %}
{% blocktrans trimmed with date=event.presale_start|date time=event.presale_start|time %}
The presale for this event will start on {{ date }} at {{ time }}.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed %}
The presale for this event has not yet started.
{% endblocktrans %}
{% endif %}
</div>
{% endif %}
{% if event.presale_is_running or event.settings.show_items_outside_presale_period %}
<form method="post"
action="{% url "presale:event.cart.add" organizer=request.event.organizer.slug event=request.event.slug %}?next={{ request.path_info|urlencode }}">
{% csrf_token %}
{% for tup in items_by_category %}
<section>
{% if tup.0 %}<h3>{{ tup.0.name }}</h3>{% endif %}
{% for item in tup.1 %}
{% if item.has_variations %}
<div class="item-with-variations">
<div class="row-fluid product-row headline">
<div class="col-md-8 col-xs-12">
<a href="javascript:void();" data-toggle="variations">
<strong>{{ item.name }}</strong>
</a>
{% if item.short_description %}<p>{{ item.short_description }}</p>{% endif %}
</div>
<div class="col-md-2 col-xs-6 price">
{% blocktrans trimmed with minprice=item.min_price|floatformat:2 currency=event.currency %}
from {{ currency }} {{ minprice }}
{% endblocktrans %}
</div>
<div class="col-md-2 col-xs-6 availability-box">
<a href="javascript:void();" data-toggle="variations" class="js-only">
{% trans "Show variants" %}
</a>
</div>
<div class="clearfix"></div>
</div>
<div class="variations">
{% for var in item.available_variations %}
<div class="row-fluid product-row variation">
<div class="col-md-8 col-xs-12">
{{ var }}
</div>
<div class="col-md-2 col-xs-6 price">
{{ event.currency }} {{ var.price|floatformat:2 }}
{% if item.tax_rate %}
<br /><small>{% blocktrans trimmed with rate=item.tax_rate %}
incl. {{ rate }}% taxes
{% endblocktrans %}</small>
{% endif %}
</div>
{% if var.cached_availability.0 == 100 %}
<div class="col-md-2 col-xs-6 availability-box available">
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
max="{{ var.cached_availability.1 }}"
name="variation_{{ item.identity }}_{{ var.variation.identity }}">
</div>
{% else %}
{% include "pretixpresale/event/fragment_availability.html" with avail=var.cached_availability.0 %}
{% endif %}
<div class="clearfix"></div>
</div>
{% endfor %}
</div>
</div>
{% else %}
<div class="row-fluid product-row simple">
<div class="col-md-8 col-xs-12">
<a href="javascript:void();" data-toggle="variations">
<strong>{{ item.name }}</strong>
</a>
<strong>{{ item.name }}</strong>
{% if item.short_description %}<p>{{ item.short_description }}</p>{% endif %}
</div>
<div class="col-md-2 col-xs-6 price">
{% blocktrans trimmed with minprice=item.min_price|floatformat:2 currency=event.currency %}
from {{ currency }} {{ minprice }}
{% endblocktrans %}
</div>
<div class="col-md-2 col-xs-6 availability-box">
<a href="javascript:void();" data-toggle="variations" class="js-only">
{% trans "Show variants" %}
</a>
{{ event.currency }} {{ item.price }}
{% if item.tax_rate %}
<br /><small>{% blocktrans trimmed with rate=item.tax_rate %}
incl. {{ rate }}% taxes
{% endblocktrans %}</small>
{% endif %}
</div>
{% if item.cached_availability.0 == 100 %}
<div class="col-md-2 col-xs-6 availability-box available">
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
max="{{ item.cached_availability.1 }}" name="item_{{ item.identity }}">
</div>
{% else %}
{% include "pretixpresale/event/fragment_availability.html" with avail=item.cached_availability.0 %}
{% endif %}
<div class="clearfix"></div>
</div>
<div class="variations">
{% for var in item.available_variations %}
<div class="row-fluid product-row variation">
<div class="col-md-8 col-xs-12">
{{ var }}
</div>
<div class="col-md-2 col-xs-6 price">
{{ event.currency }} {{ var.price|floatformat:2 }}
{% if item.tax_rate %}
<br /><small>{% blocktrans trimmed with rate=item.tax_rate %}
incl. {{ rate }}% taxes
{% endblocktrans %}</small>
{% endif %}
</div>
{% if var.cached_availability.0 == 100 %}
<div class="col-md-2 col-xs-6 availability-box available">
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
max="{{ var.cached_availability.1 }}"
name="variation_{{ item.identity }}_{{ var.variation.identity }}">
</div>
{% else %}
{% include "pretixpresale/event/fragment_availability.html" with avail=var.cached_availability.0 %}
{% endif %}
<div class="clearfix"></div>
</div>
{% endfor %}
</div>
</div>
{% else %}
<div class="row-fluid product-row simple">
<div class="col-md-8 col-xs-12">
<strong>{{ item.name }}</strong>
{% if item.short_description %}<p>{{ item.short_description }}</p>{% endif %}
</div>
<div class="col-md-2 col-xs-6 price">
{{ event.currency }} {{ item.price }}
{% if item.tax_rate %}
<br /><small>{% blocktrans trimmed with rate=item.tax_rate %}
incl. {{ rate }}% taxes
{% endblocktrans %}</small>
{% endif %}
</div>
{% if item.cached_availability.0 == 100 %}
<div class="col-md-2 col-xs-6 availability-box available">
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
max="{{ item.cached_availability.1 }}" name="item_{{ item.identity }}">
</div>
{% else %}
{% include "pretixpresale/event/fragment_availability.html" with avail=item.cached_availability.0 %}
{% endif %}
<div class="clearfix"></div>
</div>
{% endif %}
{% endfor %}
</section>
{% endfor %}
<div class="row-fluid checkout-button-row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-block btn-primary btn-lg" type="submit">
<i class="fa fa-shopping-cart"></i> {% trans "Add to cart" %}
</button>
</div>
<div class="clearfix"></div>
</div>
</form>
{% endif %}
{% endfor %}
</section>
{% endfor %}
{% if event.presale_is_running %}
<div class="row-fluid checkout-button-row">
<div class="col-md-4 col-md-offset-8">
<button class="btn btn-block btn-primary btn-lg" type="submit">
<i class="fa fa-shopping-cart"></i> {% trans "Add to cart" %}
</button>
</div>
<div class="clearfix"></div>
</div>
{% endif %}
</form>
{% endif %}
{% endblock %}

View File

@@ -4,8 +4,10 @@ from django.contrib.auth.views import redirect_to_login
from django.core.urlresolvers import reverse
from django.db.models import Q
from django.http import HttpResponseBadRequest, HttpResponseForbidden
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from pretix.base.models import CartPosition
from pretix.base.signals import register_payment_providers

View File

@@ -99,6 +99,13 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
self.msg_some_unavailable = False
def post(self, request, *args, **kwargs):
if request.event.presale_start and now() < request.event.presale_start:
messages.error(request, _('The presale period not yet started.'))
return redirect(self.get_failure_url())
if request.event.presale_end and now() > request.event.presale_end:
messages.error(request, _('The presale period has ended.'))
return redirect(self.get_failure_url())
self.items = self._items_from_post_data()
# We do not use EventLoginRequiredMixin here, as we want to store stuff into the

View File

@@ -355,10 +355,11 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch
quota_ok = False
break
if quota_ok:
cp = cp.clone()
cartpos[i] = cp
cp.expires = now() + timedelta(minutes=self.request.event.settings.get('reservation_time', as_type=int))
cp.save()
if not self.request.event.presale_end or now() < self.request.event.presale_end:
cp = cp.clone()
cartpos[i] = cp
cp.expires = now() + timedelta(minutes=self.request.event.settings.get('reservation_time', as_type=int))
cp.save()
else:
cp.delete() # Sorry!
if not self.msg_some_unavailable: # Everything went well