mirror of
https://github.com/pretix/pretix.git
synced 2026-05-09 15:54:03 +00:00
@@ -11,9 +11,10 @@ from django.utils.translation import pgettext_lazy, ugettext as _
|
||||
|
||||
from pretix.base.i18n import LazyLocaleException, language
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, Item, ItemVariation, Voucher,
|
||||
CartPosition, Event, InvoiceAddress, Item, ItemVariation, Voucher,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.tax import TAXED_ZERO, TaxedPrice
|
||||
from pretix.base.services.async import ProfiledTask
|
||||
from pretix.base.services.locking import LockTimeoutException
|
||||
from pretix.base.services.pricing import get_price
|
||||
@@ -68,7 +69,7 @@ error_messages = {
|
||||
|
||||
class CartManager:
|
||||
AddOperation = namedtuple('AddOperation', ('count', 'item', 'variation', 'price', 'voucher', 'quotas',
|
||||
'addon_to', 'subevent'))
|
||||
'addon_to', 'subevent', 'includes_tax'))
|
||||
RemoveOperation = namedtuple('RemoveOperation', ('position',))
|
||||
ExtendOperation = namedtuple('ExtendOperation', ('position', 'count', 'item', 'variation', 'price', 'voucher',
|
||||
'quotas', 'subevent'))
|
||||
@@ -78,7 +79,7 @@ class CartManager:
|
||||
AddOperation: 30
|
||||
}
|
||||
|
||||
def __init__(self, event: Event, cart_id: str):
|
||||
def __init__(self, event: Event, cart_id: str, invoice_address: InvoiceAddress=None):
|
||||
self.event = event
|
||||
self.cart_id = cart_id
|
||||
self.now_dt = now()
|
||||
@@ -89,6 +90,7 @@ class CartManager:
|
||||
self._subevents_cache = {}
|
||||
self._variations_cache = {}
|
||||
self._expiry = None
|
||||
self.invoice_address = invoice_address
|
||||
|
||||
@property
|
||||
def positions(self):
|
||||
@@ -213,8 +215,12 @@ class CartManager:
|
||||
|
||||
def _get_price(self, item: Item, variation: Optional[ItemVariation],
|
||||
voucher: Optional[Voucher], custom_price: Optional[Decimal],
|
||||
subevent: Optional[SubEvent]):
|
||||
return get_price(item, variation, voucher, custom_price, subevent, self.event.settings.display_net_prices)
|
||||
subevent: Optional[SubEvent], cp_is_net: bool=None):
|
||||
return get_price(
|
||||
item, variation, voucher, custom_price, subevent,
|
||||
custom_price_is_net=cp_is_net if cp_is_net is not None else self.event.settings.display_net_prices,
|
||||
invoice_address=self.invoice_address
|
||||
)
|
||||
|
||||
def extend_expired_positions(self):
|
||||
expired = self.positions.filter(expires__lte=self.now_dt).select_related(
|
||||
@@ -222,7 +228,12 @@ class CartManager:
|
||||
).prefetch_related('item__quotas', 'variation__quotas')
|
||||
err = None
|
||||
for cp in expired:
|
||||
price = self._get_price(cp.item, cp.variation, cp.voucher, cp.price, cp.subevent)
|
||||
if not cp.includes_tax:
|
||||
price = self._get_price(cp.item, cp.variation, cp.voucher, cp.price, cp.subevent,
|
||||
cp_is_net=True)
|
||||
price = TaxedPrice(net=price.net, gross=price.net, rate=0, tax=0, name='')
|
||||
else:
|
||||
price = self._get_price(cp.item, cp.variation, cp.voucher, cp.price, cp.subevent)
|
||||
|
||||
quotas = list(cp.quotas)
|
||||
if not quotas:
|
||||
@@ -296,7 +307,7 @@ class CartManager:
|
||||
price = self._get_price(item, variation, voucher, i.get('price'), subevent)
|
||||
op = self.AddOperation(
|
||||
count=i['count'], item=item, variation=variation, price=price, voucher=voucher, quotas=quotas,
|
||||
addon_to=False, subevent=subevent
|
||||
addon_to=False, subevent=subevent, includes_tax=bool(price.rate)
|
||||
)
|
||||
self._check_item_constraints(op)
|
||||
operations.append(op)
|
||||
@@ -395,13 +406,13 @@ class CartManager:
|
||||
quota_diff[quota] += 1
|
||||
|
||||
if price_included[cp.pk].get(item.category_id):
|
||||
price = Decimal('0.00')
|
||||
price = TAXED_ZERO
|
||||
else:
|
||||
price = self._get_price(item, variation, None, None, cp.subevent)
|
||||
|
||||
op = self.AddOperation(
|
||||
count=1, item=item, variation=variation, price=price, voucher=None, quotas=quotas,
|
||||
addon_to=cp, subevent=cp.subevent
|
||||
addon_to=cp, subevent=cp.subevent, includes_tax=bool(price.rate)
|
||||
)
|
||||
self._check_item_constraints(op)
|
||||
operations.append(op)
|
||||
@@ -557,15 +568,14 @@ class CartManager:
|
||||
for k in range(available_count):
|
||||
new_cart_positions.append(CartPosition(
|
||||
event=self.event, item=op.item, variation=op.variation,
|
||||
price=op.price, expires=self._expiry,
|
||||
cart_id=self.cart_id, voucher=op.voucher,
|
||||
addon_to=op.addon_to if op.addon_to else None,
|
||||
subevent=op.subevent
|
||||
price=op.price.gross, expires=self._expiry, cart_id=self.cart_id,
|
||||
voucher=op.voucher, addon_to=op.addon_to if op.addon_to else None,
|
||||
subevent=op.subevent, includes_tax=op.includes_tax
|
||||
))
|
||||
elif isinstance(op, self.ExtendOperation):
|
||||
if available_count == 1:
|
||||
op.position.expires = self._expiry
|
||||
op.position.price = op.price
|
||||
op.position.price = op.price.gross
|
||||
op.position.save()
|
||||
elif available_count == 0:
|
||||
op.position.delete()
|
||||
@@ -591,8 +601,34 @@ class CartManager:
|
||||
raise CartError(err)
|
||||
|
||||
|
||||
def update_tax_rates(event: Event, cart_id: str, invoice_address: InvoiceAddress):
|
||||
positions = CartPosition.objects.filter(
|
||||
cart_id=cart_id, event=event
|
||||
).select_related('item', 'item__tax_rule')
|
||||
totaldiff = Decimal('0.00')
|
||||
for pos in positions:
|
||||
if not pos.item.tax_rule:
|
||||
continue
|
||||
charge_tax = pos.item.tax_rule.tax_applicable(invoice_address)
|
||||
if pos.includes_tax and not charge_tax:
|
||||
price = pos.item.tax(pos.price, base_price_is='gross').net
|
||||
totaldiff += price - pos.price
|
||||
pos.price = price
|
||||
pos.includes_tax = False
|
||||
pos.save(update_fields=['price', 'includes_tax'])
|
||||
elif charge_tax and not pos.includes_tax:
|
||||
price = pos.item.tax(pos.price, base_price_is='net').gross
|
||||
totaldiff += price - pos.price
|
||||
pos.price = price
|
||||
pos.includes_tax = True
|
||||
pos.save(update_fields=['price', 'includes_tax'])
|
||||
|
||||
return totaldiff
|
||||
|
||||
|
||||
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
|
||||
def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, locale='en') -> None:
|
||||
def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, locale='en',
|
||||
invoice_address: int=None) -> None:
|
||||
"""
|
||||
Adds a list of items to a user's cart.
|
||||
:param event: The event ID in question
|
||||
@@ -602,9 +638,17 @@ def add_items_to_cart(self, event: int, items: List[dict], cart_id: str=None, lo
|
||||
"""
|
||||
with language(locale):
|
||||
event = Event.objects.get(id=event)
|
||||
|
||||
ia = False
|
||||
if invoice_address:
|
||||
try:
|
||||
ia = InvoiceAddress.objects.get(pk=invoice_address)
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
pass
|
||||
|
||||
try:
|
||||
try:
|
||||
cm = CartManager(event=event, cart_id=cart_id)
|
||||
cm = CartManager(event=event, cart_id=cart_id, invoice_address=ia)
|
||||
cm.add_new_items(items)
|
||||
cm.commit()
|
||||
except LockTimeoutException:
|
||||
@@ -655,7 +699,8 @@ def clear_cart(self, event: int, cart_id: str=None, locale='en') -> None:
|
||||
|
||||
|
||||
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
|
||||
def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, locale='en') -> None:
|
||||
def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, locale='en',
|
||||
invoice_address: int=None) -> None:
|
||||
"""
|
||||
Removes a list of items from a user's cart.
|
||||
:param event: The event ID in question
|
||||
@@ -664,9 +709,16 @@ def set_cart_addons(self, event: int, addons: List[dict], cart_id: str=None, loc
|
||||
"""
|
||||
with language(locale):
|
||||
event = Event.objects.get(id=event)
|
||||
|
||||
ia = False
|
||||
if invoice_address:
|
||||
try:
|
||||
ia = InvoiceAddress.objects.get(pk=invoice_address)
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
pass
|
||||
try:
|
||||
try:
|
||||
cm = CartManager(event=event, cart_id=cart_id)
|
||||
cm = CartManager(event=event, cart_id=cart_id, invoice_address=ia)
|
||||
cm.set_addons(addons)
|
||||
cm.commit()
|
||||
except LockTimeoutException:
|
||||
|
||||
Reference in New Issue
Block a user