forked from CGM_Public/pretix_original
@@ -7,8 +7,8 @@ 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.models import CartPosition, InvoiceAddress, OrderPosition
|
||||
from pretix.base.models.tax import TaxRule
|
||||
from pretix.presale.signals import question_form_fields
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class CartMixin:
|
||||
"""
|
||||
return list(get_cart(self.request))
|
||||
|
||||
def get_cart(self, answers=False, queryset=None, payment_fee=None, payment_fee_tax_rate=None, downloads=False):
|
||||
def get_cart(self, answers=False, queryset=None, order=None, downloads=False):
|
||||
if queryset:
|
||||
prefetch = []
|
||||
if answers:
|
||||
@@ -90,6 +90,7 @@ class CartMixin:
|
||||
group.total = group.count * group.price
|
||||
group.net_total = group.count * group.net_price
|
||||
group.has_questions = answers and k[0] != ""
|
||||
group.tax_rule = group.item.tax_rule
|
||||
if answers:
|
||||
group.cache_answers()
|
||||
group.additional_answers = pos_additional_fields.get(group.pk)
|
||||
@@ -99,14 +100,35 @@ class CartMixin:
|
||||
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
|
||||
if order:
|
||||
payment_fee = order.payment_fee
|
||||
tax_total += order.payment_fee_tax_value
|
||||
payment_fee_net = order.payment_fee - order.payment_fee_tax_value
|
||||
net_total += payment_fee_net
|
||||
payment_fee_tax_rule = order.payment_fee_tax_rule
|
||||
payment_fee_tax_rate = order.payment_fee_tax_rate
|
||||
else:
|
||||
payment_fee = self.get_payment_fee(total)
|
||||
payment_fee_tax_rule = self.request.event.settings.tax_rate_default or TaxRule.zero()
|
||||
|
||||
iapk = self.request.session.get('invoice_address_{}'.format(self.request.event.pk))
|
||||
ia = None
|
||||
if payment_fee_tax_rule.eu_reverse_charge and iapk:
|
||||
try:
|
||||
ia = InvoiceAddress.objects.get(pk=iapk, order__isnull=True)
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
pass
|
||||
|
||||
if payment_fee_tax_rule.tax_applicable(ia):
|
||||
payment_fee_tax = payment_fee_tax_rule.tax(payment_fee, base_price_is='gross')
|
||||
tax_total += payment_fee_tax.tax
|
||||
net_total += payment_fee_tax.net
|
||||
payment_fee_net = payment_fee_tax.net
|
||||
payment_fee_tax_rate = payment_fee_tax.rate
|
||||
else:
|
||||
net_total += payment_fee
|
||||
payment_fee_net = payment_fee
|
||||
payment_fee_tax_rate = Decimal('0.00')
|
||||
|
||||
try:
|
||||
first_expiry = min(p.expires for p in positions) if positions else now()
|
||||
@@ -124,6 +146,7 @@ class CartMixin:
|
||||
'payment_fee': payment_fee,
|
||||
'payment_fee_net': payment_fee_net,
|
||||
'payment_fee_tax_rate': payment_fee_tax_rate,
|
||||
'payment_fee_tax_rule': payment_fee_tax_rule,
|
||||
'answers': answers,
|
||||
'minutes_left': minutes_left,
|
||||
'first_expiry': first_expiry,
|
||||
@@ -147,7 +170,8 @@ def get_cart(request):
|
||||
).order_by(
|
||||
'item', 'variation'
|
||||
).select_related(
|
||||
'item', 'variation', 'subevent', 'subevent__event', 'subevent__event__organizer'
|
||||
'item', 'variation', 'subevent', 'subevent__event', 'subevent__event__organizer',
|
||||
'item__tax_rule'
|
||||
).prefetch_related(
|
||||
'item__questions', 'answers'
|
||||
)
|
||||
|
||||
@@ -6,13 +6,14 @@ 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
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
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, ItemVariation, QuestionAnswer, Quota, SubEvent, Voucher,
|
||||
CartPosition, InvoiceAddress, ItemVariation, QuestionAnswer, Quota,
|
||||
SubEvent, Voucher,
|
||||
)
|
||||
from pretix.base.services.cart import (
|
||||
CartError, add_items_to_cart, clear_cart, remove_cart_position,
|
||||
@@ -37,6 +38,17 @@ class CartActionMixin:
|
||||
def get_error_url(self):
|
||||
return self.get_next_url()
|
||||
|
||||
@cached_property
|
||||
def invoice_address(self):
|
||||
iapk = self.request.session.get('invoice_address_{}'.format(self.request.event.pk))
|
||||
if not iapk:
|
||||
return InvoiceAddress()
|
||||
|
||||
try:
|
||||
return InvoiceAddress.objects.get(pk=iapk, order__isnull=True)
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
return InvoiceAddress()
|
||||
|
||||
def _item_from_post_value(self, key, value, voucher=None):
|
||||
if value.strip() == '' or '_' not in key:
|
||||
return
|
||||
@@ -154,7 +166,8 @@ class CartAdd(EventViewMixin, CartActionMixin, AsyncAction, View):
|
||||
def post(self, request, *args, **kwargs):
|
||||
items = self._items_from_post_data()
|
||||
if items:
|
||||
return self.do(self.request.event.id, items, self.request.session.session_key, translation.get_language())
|
||||
return self.do(self.request.event.id, items, self.request.session.session_key, translation.get_language(),
|
||||
self.invoice_address.pk)
|
||||
else:
|
||||
if 'ajax' in self.request.GET or 'ajax' in self.request.POST:
|
||||
return JsonResponse({
|
||||
@@ -190,12 +203,12 @@ class RedeemView(EventViewMixin, TemplateView):
|
||||
items = items.filter(quotas__in=[self.voucher.quota_id])
|
||||
|
||||
items = items.filter(vouchq).select_related(
|
||||
'category', # for re-grouping
|
||||
'category', 'tax_rule', # for re-grouping
|
||||
).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=self.request.event.quotas.filter(subevent=self.subevent)),
|
||||
Prefetch('variations', to_attr='avail_variations',
|
||||
Prefetch('variations', to_attr='available_variations',
|
||||
queryset=ItemVariation.objects.filter(active=True, quotas__isnull=False).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
@@ -217,13 +230,11 @@ class RedeemView(EventViewMixin, TemplateView):
|
||||
var_price_override = {}
|
||||
|
||||
for item in items:
|
||||
item.available_variations = list(item.variations.filter(active=True, quotas__isnull=False).distinct())
|
||||
if self.voucher.item_id and self.voucher.variation_id:
|
||||
item.available_variations = [v for v in item.available_variations if v.pk == self.voucher.variation_id]
|
||||
|
||||
item.order_max = item.max_per_order or int(self.request.event.settings.max_items_per_order)
|
||||
|
||||
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:
|
||||
@@ -231,32 +242,32 @@ class RedeemView(EventViewMixin, TemplateView):
|
||||
else:
|
||||
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)))
|
||||
price = item_price_override.get(item.pk, item.default_price)
|
||||
price = self.voucher.calculate_price(price)
|
||||
item.display_price = item.tax(price)
|
||||
else:
|
||||
item._remove = False
|
||||
for var in item.avail_variations:
|
||||
for var in item.available_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(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)))
|
||||
price = var_price_override.get(var.pk, var.price)
|
||||
price = self.voucher.calculate_price(price)
|
||||
var.display_price = item.tax(price)
|
||||
|
||||
item.available_variations = [
|
||||
v for v in item.avail_variations if v._subevent_quotas
|
||||
v for v in item.available_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.avail_variations])
|
||||
item.max_price = max([v.display_price for v in item.avail_variations])
|
||||
item.min_price = min([v.display_price.net if self.request.event.settings.display_net_prices else
|
||||
v.display_price.gross for v in item.available_variations])
|
||||
item.max_price = max([v.display_price.net if self.request.event.settings.display_net_prices else
|
||||
v.display_price.gross for v in item.available_variations])
|
||||
|
||||
items = [item for item in items
|
||||
if (len(item.available_variations) > 0 or not item.has_variations) and not item._remove]
|
||||
|
||||
@@ -17,7 +17,6 @@ from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import ItemVariation
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
@@ -53,7 +52,7 @@ def get_grouped_items(event, subevent=None):
|
||||
& Q(hide_without_voucher=False)
|
||||
& ~Q(category__is_addon=True)
|
||||
).select_related(
|
||||
'category', # for re-grouping
|
||||
'category', 'tax_rule', # for re-grouping
|
||||
).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
@@ -88,17 +87,9 @@ def get_grouped_items(event, subevent=None):
|
||||
item.order_max = min(item.cached_availability[1]
|
||||
if item.cached_availability[1] is not None else sys.maxsize,
|
||||
max_per_order)
|
||||
item.price = item.default_price
|
||||
price = item.default_price
|
||||
item.display_price = item.tax(item_price_override.get(item.pk, price))
|
||||
|
||||
if event.settings.display_net_prices:
|
||||
if item_price_override.get(item.pk):
|
||||
_p = item_price_override.get(item.pk)
|
||||
tax_value = round_decimal(_p * (1 - 100 / (100 + item.tax_rate)))
|
||||
item.display_price = _p - tax_value
|
||||
else:
|
||||
item.display_price = item.default_price_net
|
||||
else:
|
||||
item.display_price = item_price_override.get(item.pk, item.price)
|
||||
display_add_to_cart = display_add_to_cart or item.order_max > 0
|
||||
else:
|
||||
for var in item.available_variations:
|
||||
@@ -107,15 +98,7 @@ def get_grouped_items(event, subevent=None):
|
||||
if var.cached_availability[1] is not None else sys.maxsize,
|
||||
max_per_order)
|
||||
|
||||
if event.settings.display_net_prices:
|
||||
if var_price_override.get(var.pk):
|
||||
_p = var_price_override.get(var.pk)
|
||||
tax_value = round_decimal(_p * (1 - 100 / (100 + item.tax_rate)))
|
||||
var.display_price = _p - tax_value
|
||||
else:
|
||||
var.display_price = var.net_price
|
||||
else:
|
||||
var.display_price = var_price_override.get(var.pk, var.price)
|
||||
var.display_price = var.tax(var_price_override.get(var.pk, var.price))
|
||||
|
||||
display_add_to_cart = display_add_to_cart or var.order_max > 0
|
||||
|
||||
@@ -123,8 +106,10 @@ def get_grouped_items(event, subevent=None):
|
||||
v for v in item.available_variations if v._subevent_quotas
|
||||
]
|
||||
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.net if event.settings.display_net_prices else
|
||||
v.display_price.gross for v in item.available_variations])
|
||||
item.max_price = max([v.display_price.net if event.settings.display_net_prices else
|
||||
v.display_price.gross for v in item.available_variations])
|
||||
item._remove = not bool(item.available_variations)
|
||||
|
||||
items = [item for item in items
|
||||
|
||||
@@ -97,8 +97,8 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TemplateView):
|
||||
ctx['download_buttons'] = self.download_buttons
|
||||
ctx['cart'] = self.get_cart(
|
||||
answers=True, downloads=ctx['can_download'],
|
||||
queryset=self.order.positions.all(),
|
||||
payment_fee=self.order.payment_fee, payment_fee_tax_rate=self.order.payment_fee_tax_rate
|
||||
queryset=self.order.positions.select_related('tax_rule'),
|
||||
order=self.order
|
||||
)
|
||||
ctx['can_download_multi'] = any([b['multi'] for b in self.download_buttons]) and (
|
||||
self.request.event.settings.ticket_download_nonadm or
|
||||
@@ -412,7 +412,7 @@ class OrderModify(EventViewMixin, OrderDetailMixin, QuestionsViewMixin, Template
|
||||
def invoice_form(self):
|
||||
return InvoiceAddressForm(data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
instance=self.invoice_address)
|
||||
instance=self.invoice_address, validate_vat_id=False)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
failed = not self.save() or not self.invoice_form.is_valid()
|
||||
|
||||
Reference in New Issue
Block a user