Files
pretix_cgo/src/pretix/presale/views/__init__.py
2017-04-17 14:54:15 +02:00

165 lines
5.9 KiB
Python

from datetime import timedelta
from decimal import Decimal
from itertools import groupby
from django.db.models import Sum
from django.utils.functional import cached_property
from django.utils.timezone import now
from pretix.base.decimal import round_decimal
from pretix.base.models import CartPosition, OrderPosition
from pretix.base.signals import register_payment_providers
class CartMixin:
@cached_property
def positions(self):
"""
A list of this users cart position
"""
return list(get_cart(self.request))
def get_cart(self, answers=False, queryset=None, payment_fee=None, payment_fee_tax_rate=None, downloads=False):
if queryset:
prefetch = []
if answers:
prefetch.append('item__questions')
prefetch.append('answers')
cartpos = queryset.order_by(
'item', 'variation'
).select_related(
'item', 'variation', 'addon_to'
).prefetch_related(
*prefetch
)
else:
cartpos = self.positions
lcp = list(cartpos)
has_addons = {cp.addon_to.pk for cp in lcp if cp.addon_to}
# Group items of the same variation
# We do this by list manipulations instead of a GROUP BY query, as
# Django is unable to join related models in a .values() query
def keyfunc(pos):
if isinstance(pos, OrderPosition):
if pos.addon_to:
i = pos.addon_to.positionid
else:
i = pos.positionid
else:
if pos.addon_to:
i = pos.addon_to.pk
else:
i = pos.pk
has_attendee_data = pos.item.admission and (
self.request.event.settings.attendee_names_asked
or self.request.event.settings.attendee_emails_asked
)
addon_penalty = 1 if pos.addon_to else 0
if downloads or pos.pk in has_addons or pos.addon_to:
return i, addon_penalty, pos.pk, 0, 0, 0, 0,
if answers and (has_attendee_data or pos.item.questions.all()):
return i, addon_penalty, pos.pk, 0, 0, 0, 0,
return 0, addon_penalty, 0, pos.item_id, pos.variation_id, pos.price, (pos.voucher_id or 0)
positions = []
for k, g in groupby(sorted(lcp, key=keyfunc), key=keyfunc):
g = list(g)
group = g[0]
group.count = len(g)
group.total = group.count * group.price
group.net_total = group.count * group.net_price
group.has_questions = answers and k[0] != ""
if answers:
group.cache_answers()
positions.append(group)
total = sum(p.total for p in positions)
net_total = sum(p.net_total for p in positions)
tax_total = sum(p.total - p.net_total for p in positions)
payment_fee = payment_fee if payment_fee is not None else self.get_payment_fee(total)
payment_fee_tax_rate = round_decimal(payment_fee_tax_rate
if payment_fee_tax_rate is not None
else self.request.event.settings.tax_rate_default)
payment_fee_tax_value = round_decimal(payment_fee * (1 - 100 / (100 + payment_fee_tax_rate)))
payment_fee_net = payment_fee - payment_fee_tax_value
tax_total += payment_fee_tax_value
net_total += payment_fee_net
try:
first_expiry = min(p.expires for p in positions) if positions else now()
minutes_left = max(first_expiry - now(), timedelta()).seconds // 60
except AttributeError:
first_expiry = None
minutes_left = None
return {
'positions': positions,
'raw': cartpos,
'total': total + payment_fee,
'net_total': net_total,
'tax_total': tax_total,
'payment_fee': payment_fee,
'payment_fee_net': payment_fee_net,
'payment_fee_tax_rate': payment_fee_tax_rate,
'answers': answers,
'minutes_left': minutes_left,
'first_expiry': first_expiry
}
def get_payment_fee(self, total):
if total == 0:
return Decimal('0.00')
payment_fee = 0
if 'payment' in self.request.session:
responses = register_payment_providers.send(self.request.event)
for receiver, response in responses:
provider = response(self.request.event)
if provider.identifier == self.request.session['payment']:
payment_fee = provider.calculate_fee(total)
return payment_fee
def get_cart(request):
if not hasattr(request, '_cart_cache'):
request._cart_cache = CartPosition.objects.filter(
cart_id=request.session.session_key, event=request.event
).order_by(
'item', 'variation'
).select_related(
'item', 'variation'
).prefetch_related(
'item__questions', 'answers'
)
return request._cart_cache
def get_cart_total(request):
if not hasattr(request, '_cart_total_cache'):
if hasattr(request, '_cart_cache'):
request._cart_total_cache = sum(i.price for i in request._cart_cache)
else:
request._cart_total_cache = CartPosition.objects.filter(
cart_id=request.session.session_key, event=request.event
).aggregate(sum=Sum('price'))['sum']
return request._cart_total_cache
class EventViewMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['event'] = self.request.event
return context
class OrganizerViewMixin:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['organizer'] = self.request.organizer
return context