Cart expiry handling, checkout link

This commit is contained in:
Raphael Michel
2015-02-14 23:53:39 +01:00
parent 93aeda0bdb
commit 38e313c886
5 changed files with 77 additions and 8 deletions

View File

@@ -9,6 +9,24 @@
</div>
<div class="panel-body">
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event editable=True %}
<div class="row-fluid">
<div class="col-md-6 col-xs-12">
{% if cart.minutes_left > 0 %}
<em>{% blocktrans trimmed with minutes=cart.minutes_left %}
The items in your cart are reserved for you for {{ minutes }} minutes.
{% endblocktrans %}</em>
{% else %}
<em>{% trans "The items in your cart are no longer reserved for you." %}</em>
{% endif %}
</div>
<div class="col-md-4 col-md-offset-2 col-xs-12">
<a class="btn btn-block btn-primary btn-lg"
href="{% url "presale:event.checkout.start" organizer=request.event.organizer.slug event=request.event.slug %}">
<i class="fa fa-shopping-cart"></i> {% trans "Proceed with checkout" %}
</a>
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
{% endif %}

View File

@@ -2,6 +2,8 @@ from django.conf.urls import patterns, url, include
import pretix.presale.views.event
import pretix.presale.views.cart
import pretix.presale.views.checkout
urlpatterns = patterns(
'',
@@ -11,6 +13,7 @@ urlpatterns = patterns(
url(r'^$', pretix.presale.views.event.EventIndex.as_view(), name='event.index'),
url(r'^cart/add$', pretix.presale.views.cart.CartAdd.as_view(), name='event.cart.add'),
url(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'),
url(r'^checkout$', pretix.presale.views.checkout.CheckoutStart.as_view(), name='event.checkout.start'),
)
)),
)

View File

@@ -1,7 +1,9 @@
import uuid
from itertools import groupby
from datetime import timedelta
from django.db.models import Q
from django.utils.timezone import now
from pretix.base.models import CartPosition
@@ -49,6 +51,10 @@ class CartDisplayMixin(CartMixin):
return {
'positions': positions,
'total': sum(p.total for p in positions),
'minutes_left': (
max(min(p.expires for p in positions) - now(), timedelta()).seconds // 60
if positions else 0
),
}

View File

@@ -57,6 +57,14 @@ class CartActionMixin(CartMixin):
return False
return items
def _re_add_position(self, items, position):
for i, tup in enumerate(items):
if tup[0] == position.item_id and tup[1] == position.variation_id:
items[i] = (tup[0], tup[1], tup[2] + 1)
return items
items.append((position.item_id, position.variation_id, 1))
return items
class CartRemove(EventViewMixin, CartActionMixin, View):
@@ -94,6 +102,25 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
_("You cannot select more than %d items per order") % self.event.max_items_per_order)
return redirect(self.get_failure_url())
# Extend this user's cart session to 30 minutes from now to ensure all items in the
# cart expire at the same time
qw = Q(session=self.get_session_key())
if self.request.user.is_authenticated():
qw |= Q(user=self.request.user)
# We can extend the reservation of items which are not yet expired without
# risk
CartPosition.objects.current.filter(
qw & Q(event=self.request.event) & Q(expires__gt=now())
).update(expires=now() + timedelta(minutes=30))
# For items that are already expired, we have to delete and re-add them, as they might
# be no longer available. Sorry!
for cp in CartPosition.objects.current.filter(
qw & Q(event=self.request.event) & Q(expires__lte=now())):
items = self._re_add_position(items, cp)
cp.delete()
# Fetch items from the database
items_cache = {
i.identity: i for i
@@ -110,14 +137,6 @@ class CartAdd(EventViewMixin, CartActionMixin, View):
).select_related("item", "item__event").prefetch_related("quotas", "values", "values__prop")
}
# Extend this user's cart session to 30 minutes from now to ensure all items in the
# cart expire at the same time
qw = Q(session=self.get_session_key())
if self.request.user.is_authenticated():
qw |= Q(user=self.request.user)
CartPosition.objects.current.filter(
qw & Q(event=self.request.event)).update(expires=now() + timedelta(minutes=30))
# Process the request itself
msg_some_unavailable = False
for i in items:

View File

@@ -0,0 +1,23 @@
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.shortcuts import redirect
from django.views.generic import View
from django.utils.translation import ugettext_lazy as _
from pretix.presale.views import EventViewMixin, CartDisplayMixin
class CheckoutStart(EventViewMixin, CartDisplayMixin, View):
def get_failure_url(self):
return reverse('presale:event.index', kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
})
def get(self, *args, **kwargs):
cart = self.get_cart()
if not cart['positions']:
messages.error(self.request,
_("Your cart is empty") % self.event.max_items_per_order)
return redirect(self.get_failure_url())