Add sub-events and relative date settings (#503)

* Data model

* little crud

* SubEventItemForm etc

* Drop SubEventItem.active, quota editor

* Fix failing tests

* First frontend stuff

* Addons form stuff

* Quota calculation

* net price display on EventIndex

* Add tests, solve some bugs

* Correct quota selection in more places, consolidate pricing logic

* Fix failing quota tests

* Fix TypeError

* Add tests for checkout

* Fixed a bug in QuotaForm

* Prevent immutable cart if a quota was removed from an item

* Add tests for pricing

* Handle waiting list

* Filter in check-in list

* Fixed import lost in rebase

* Fix waiting list widget

* Voucher management

* Voucher redemption

* Fix broken tests

* Add subevents to OrderChangeManager

* Create a subevent during event creation

* Fix bulk voucher creation

* Introduce subevent.active

* Copy from for subevents

* Show active in list

* ICal download for subevents

* Check start and end of presale

* Failing tests / show cart logic

* Test

* Rebase migrations

* REST API integration of sub-events

* Integrate quota calculation into the traditional quota form

* Make subevent argument to add_position optional

* Log-display foo

* pretixdroid and subevents

* Filter by subevent

* Add more tests

* Some mor tests

* Rebase fixes

* More tests

* Relative dates

* Restrict selection in relative datetime widgets

* Filter subevent list

* Re-label has_subevents

* Rebase fixes, subevents in calendar view

* Performance and caching issues

* Refactor calendar templates

* Permission tests

* Calendar fixes and month selection

* subevent selection

* Rename subevents to dates

* Add tests for calendar views
This commit is contained in:
Raphael Michel
2017-07-11 13:56:00 +02:00
committed by GitHub
parent 554800c06f
commit 8123effa65
141 changed files with 5920 additions and 1012 deletions

View File

@@ -2,7 +2,7 @@ import mimetypes
import os
from django.contrib import messages
from django.db.models import Count, Q
from django.db.models import Count, Prefetch, Q
from django.http import FileResponse, Http404, JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils import translation
@@ -11,7 +11,9 @@ from django.utils.translation import ugettext as _
from django.views.generic import TemplateView, View
from pretix.base.decimal import round_decimal
from pretix.base.models import CartPosition, QuestionAnswer, Quota, Voucher
from pretix.base.models import (
CartPosition, ItemVariation, QuestionAnswer, Quota, SubEvent, Voucher,
)
from pretix.base.services.cart import (
CartError, add_items_to_cart, clear_cart, remove_cart_position,
)
@@ -60,7 +62,8 @@ class CartActionMixin:
'variation': None,
'count': amount,
'price': price,
'voucher': voucher
'voucher': voucher,
'subevent': self.request.POST.get("subevent")
}
except ValueError:
raise CartError(_('Please enter numbers only.'))
@@ -71,7 +74,8 @@ class CartActionMixin:
'variation': int(parts[2]),
'count': amount,
'price': price,
'voucher': voucher
'voucher': voucher,
'subevent': self.request.POST.get("subevent")
}
except ValueError:
raise CartError(_('Please enter numbers only.'))
@@ -188,10 +192,29 @@ class RedeemView(EventViewMixin, TemplateView):
items = items.filter(vouchq).select_related(
'category', # for re-grouping
).prefetch_related(
'quotas', 'variations__quotas', 'quotas__event' # for .availability()
).annotate(quotac=Count('quotas')).filter(
Prefetch('quotas',
to_attr='_subevent_quotas',
queryset=self.request.event.quotas.filter(subevent=self.subevent)),
Prefetch('variations', to_attr='avail_variations',
queryset=ItemVariation.objects.filter(active=True, quotas__isnull=False).prefetch_related(
Prefetch('quotas',
to_attr='_subevent_quotas',
queryset=self.request.event.quotas.filter(subevent=self.subevent))
).distinct()),
).annotate(
quotac=Count('quotas'),
has_variations=Count('variations')
).filter(
quotac__gt=0
).distinct().order_by('category__position', 'category_id', 'position', 'name')
quota_cache = {}
if self.subevent:
item_price_override = self.subevent.item_price_overrides
var_price_override = self.subevent.var_price_overrides
else:
item_price_override = {}
var_price_override = {}
for item in items:
item.available_variations = list(item.variations.filter(active=True, quotas__isnull=False).distinct())
@@ -202,34 +225,49 @@ class RedeemView(EventViewMixin, TemplateView):
item.has_variations = item.variations.exists()
if not item.has_variations:
item._remove = not bool(item._subevent_quotas)
if self.voucher.allow_ignore_quota or self.voucher.block_quota:
item.cached_availability = (Quota.AVAILABILITY_OK, 1)
else:
item.cached_availability = item.check_quotas()
item.price = self.voucher.calculate_price(item.default_price)
item.cached_availability = item.check_quotas(subevent=self.subevent, _cache=quota_cache)
item.price = item_price_override.get(item.pk, item.default_price)
item.price = self.voucher.calculate_price(item.price)
if self.request.event.settings.display_net_prices:
item.price -= round_decimal(item.price * (1 - 100 / (100 + item.tax_rate)))
else:
for var in item.available_variations:
item._remove = False
for var in item.avail_variations:
if self.voucher.allow_ignore_quota or self.voucher.block_quota:
var.cached_availability = (Quota.AVAILABILITY_OK, 1)
else:
var.cached_availability = list(var.check_quotas())
var.display_price = self.voucher.calculate_price(var.price)
var.cached_availability = list(var.check_quotas(subevent=self.subevent, _cache=quota_cache))
var.display_price = var_price_override.get(var.pk, var.price)
var.display_price = self.voucher.calculate_price(var.display_price)
if self.request.event.settings.display_net_prices:
var.display_price -= round_decimal(var.display_price * (1 - 100 / (100 + item.tax_rate)))
item.available_variations = [
v for v in item.avail_variations if v._subevent_quotas
]
if self.voucher.variation_id:
item.available_variations = [v for v in item.available_variations
if v.pk == self.voucher.variation_id]
if len(item.available_variations) > 0:
item.min_price = min([v.display_price for v in item.available_variations])
item.max_price = max([v.display_price for v in item.available_variations])
item.min_price = min([v.display_price for v in item.avail_variations])
item.max_price = max([v.display_price for v in item.avail_variations])
items = [item for item in items if len(item.available_variations) > 0 or not item.has_variations]
items = [item for item in items
if (len(item.available_variations) > 0 or not item.has_variations) and not item._remove]
context['options'] = sum([(len(item.available_variations) if item.has_variations else 1)
for item in items])
# Regroup those by category
context['items_by_category'] = item_group_by_category(items)
context['subevent'] = self.subevent
return context
def dispatch(self, request, *args, **kwargs):
@@ -264,6 +302,17 @@ class RedeemView(EventViewMixin, TemplateView):
if request.event.presale_end and now() > request.event.presale_end:
err = error_messages['ended']
self.subevent = None
if request.event.has_subevents:
if 'subevent' in request.GET:
self.subevent = get_object_or_404(SubEvent, event=request.event, pk=request.GET.get('subevent'),
active=True)
if self.voucher.subevent:
self.subevent = self.voucher.subevent
else:
pass
if err:
messages.error(request, _(err))
return redirect(eventreverse(request.event, 'presale:event.index'))