mirror of
https://github.com/pretix/pretix.git
synced 2026-05-10 16:04:02 +00:00
AddOnsStep: Use post data as initial data if exists (Z#23232311)
This commit is contained in:
@@ -37,6 +37,7 @@ import uuid
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.cache import caches
|
from django.core.cache import caches
|
||||||
@@ -69,6 +70,7 @@ from pretix.base.services.cart import (
|
|||||||
from pretix.base.services.cross_selling import CrossSellingService
|
from pretix.base.services.cross_selling import CrossSellingService
|
||||||
from pretix.base.services.memberships import validate_memberships_in_order
|
from pretix.base.services.memberships import validate_memberships_in_order
|
||||||
from pretix.base.services.orders import perform_order
|
from pretix.base.services.orders import perform_order
|
||||||
|
from pretix.base.services.pricing import get_price
|
||||||
from pretix.base.services.tasks import EventTask
|
from pretix.base.services.tasks import EventTask
|
||||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||||
from pretix.base.signals import validate_cart_addons
|
from pretix.base.signals import validate_cart_addons
|
||||||
@@ -529,6 +531,48 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
|||||||
self._completed = True
|
self._completed = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _get_initial_val_price(self, current_addon_products, cartpos, item, variation):
|
||||||
|
val = None
|
||||||
|
price = None
|
||||||
|
|
||||||
|
if self.request.POST:
|
||||||
|
if variation:
|
||||||
|
field = f'cp_{cartpos.pk}_variation_{item.pk}_{variation.pk}'
|
||||||
|
else:
|
||||||
|
field = f'cp_{cartpos.pk}_item_{item.pk}'
|
||||||
|
|
||||||
|
try:
|
||||||
|
val = int(self.request.POST.get(field) or '0')
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if val and item.free_price:
|
||||||
|
custom_price = forms.DecimalField(localize=True).to_python(self.request.POST.get(f'{field}_price') or '0')
|
||||||
|
price = get_price(
|
||||||
|
item, variation, voucher=cartpos.voucher, custom_price=custom_price, subevent=cartpos.subevent,
|
||||||
|
custom_price_is_net=self.event.settings.display_net_prices,
|
||||||
|
invoice_address=self.invoice_address,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
price = variation.suggested_price if variation else item.suggested_price
|
||||||
|
|
||||||
|
else:
|
||||||
|
current_products = current_addon_products[item.pk, variation.pk if variation else None]
|
||||||
|
val = len(current_products)
|
||||||
|
if current_products and item.free_price:
|
||||||
|
a = current_products[0]
|
||||||
|
price = TaxedPrice(
|
||||||
|
net=a.price - a.tax_value,
|
||||||
|
gross=a.price,
|
||||||
|
tax=a.tax_value,
|
||||||
|
name=a.item.tax_rule.name if a.item.tax_rule else "",
|
||||||
|
rate=a.tax_rate,
|
||||||
|
code=a.item.tax_rule.code if a.item.tax_rule else None,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
price = variation.suggested_price if variation else item.suggested_price
|
||||||
|
|
||||||
|
return val, price
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def forms(self):
|
def forms(self):
|
||||||
"""
|
"""
|
||||||
@@ -587,34 +631,10 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
|||||||
|
|
||||||
if i.has_variations:
|
if i.has_variations:
|
||||||
for v in i.available_variations:
|
for v in i.available_variations:
|
||||||
v.initial = len(current_addon_products[i.pk, v.pk])
|
v.initial, v.initial_price = self._get_initial_val_price(current_addon_products, cartpos, i, v)
|
||||||
if v.initial and i.free_price:
|
|
||||||
a = current_addon_products[i.pk, v.pk][0]
|
|
||||||
v.initial_price = TaxedPrice(
|
|
||||||
net=a.price - a.tax_value,
|
|
||||||
gross=a.price,
|
|
||||||
tax=a.tax_value,
|
|
||||||
name=a.item.tax_rule.name if a.item.tax_rule else "",
|
|
||||||
rate=a.tax_rate,
|
|
||||||
code=a.item.tax_rule.code if a.item.tax_rule else None,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
v.initial_price = v.suggested_price
|
|
||||||
i.expand = any(v.initial for v in i.available_variations)
|
i.expand = any(v.initial for v in i.available_variations)
|
||||||
else:
|
else:
|
||||||
i.initial = len(current_addon_products[i.pk, None])
|
i.initial, i.initial_price = self._get_initial_val_price(current_addon_products, cartpos, i, None)
|
||||||
if i.initial and i.free_price:
|
|
||||||
a = current_addon_products[i.pk, None][0]
|
|
||||||
i.initial_price = TaxedPrice(
|
|
||||||
net=a.price - a.tax_value,
|
|
||||||
gross=a.price,
|
|
||||||
tax=a.tax_value,
|
|
||||||
name=a.item.tax_rule.name if a.item.tax_rule else "",
|
|
||||||
rate=a.tax_rate,
|
|
||||||
code=a.item.tax_rule.code if a.item.tax_rule else None,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
i.initial_price = i.suggested_price
|
|
||||||
|
|
||||||
if items:
|
if items:
|
||||||
formsetentry['categories'].append({
|
formsetentry['categories'].append({
|
||||||
|
|||||||
@@ -99,6 +99,15 @@ class BaseCheckoutTestCase:
|
|||||||
self.workshopquota.variations.add(self.workshop2a)
|
self.workshopquota.variations.add(self.workshop2a)
|
||||||
self.workshopquota.variations.add(self.workshop2b)
|
self.workshopquota.variations.add(self.workshop2b)
|
||||||
|
|
||||||
|
self.parkingcat = ItemCategory.objects.create(name="Parking", is_addon=True, event=self.event)
|
||||||
|
self.parkingquota = Quota.objects.create(event=self.event, name='Parking', size=5)
|
||||||
|
self.parking1 = Item.objects.create(event=self.event, name='Premium Parking',
|
||||||
|
category=self.parkingcat, default_price=Decimal('15.00'))
|
||||||
|
self.parking2 = Item.objects.create(event=self.event, name='Standard Parking',
|
||||||
|
category=self.parkingcat, default_price=Decimal('5.00'))
|
||||||
|
self.parkingquota.items.add(self.parking1)
|
||||||
|
self.parkingquota.items.add(self.parking2)
|
||||||
|
|
||||||
def _set_session(self, key, value):
|
def _set_session(self, key, value):
|
||||||
session = self.client.session
|
session = self.client.session
|
||||||
session['carts'][get_cart_session_key(self.client, self.event)][key] = value
|
session['carts'][get_cart_session_key(self.client, self.event)][key] = value
|
||||||
@@ -4202,6 +4211,58 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
|
|||||||
assert '35.29' in response.content.decode()
|
assert '35.29' in response.content.decode()
|
||||||
assert '10.08' in response.content.decode()
|
assert '10.08' in response.content.decode()
|
||||||
|
|
||||||
|
def test_set_addons_invalid_initial(self):
|
||||||
|
self.event.settings.locales = ['de', 'en']
|
||||||
|
self.event.settings.locale = 'de'
|
||||||
|
with scopes_disabled():
|
||||||
|
ItemAddOn.objects.create(base_item=self.ticket, addon_category=self.workshopcat, min_count=1)
|
||||||
|
ItemAddOn.objects.create(base_item=self.ticket, addon_category=self.parkingcat, min_count=1)
|
||||||
|
cp1 = CartPosition.objects.create(
|
||||||
|
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||||
|
price=23, expires=now() - timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
self.workshop1.free_price = True
|
||||||
|
self.workshop1.save()
|
||||||
|
self.workshop2.free_price = True
|
||||||
|
self.workshop2.save()
|
||||||
|
|
||||||
|
ws1_val = 'cp_{}_item_{}'.format(cp1.pk, self.workshop1.pk)
|
||||||
|
ws1_price = 'cp_{}_item_{}_price'.format(cp1.pk, self.workshop1.pk)
|
||||||
|
ws2a_val = 'cp_{}_variation_{}_{}'.format(cp1.pk, self.workshop2.pk, self.workshop2a.pk)
|
||||||
|
ws2a_price = 'cp_{}_variation_{}_{}_price'.format(cp1.pk, self.workshop2.pk, self.workshop2a.pk)
|
||||||
|
p1_val = 'cp_{}_item_{}'.format(cp1.pk, self.parking1.pk)
|
||||||
|
p2_val = 'cp_{}_item_{}'.format(cp1.pk, self.parking2.pk)
|
||||||
|
|
||||||
|
response = self.client.post('/%s/%s/checkout/addons/' % (self.orga.slug, self.event.slug), {
|
||||||
|
ws1_val: '1',
|
||||||
|
ws2a_val: '1',
|
||||||
|
})
|
||||||
|
assert response.status_code == 200
|
||||||
|
with scopes_disabled():
|
||||||
|
assert cp1.addons.count() == 0
|
||||||
|
doc = BeautifulSoup(response.text, 'lxml')
|
||||||
|
assert doc.find('input', {'name': ws1_val}).attrs.get('checked')
|
||||||
|
assert doc.find('input', {'name': ws2a_val}).attrs.get('checked')
|
||||||
|
assert not doc.find('input', {'name': p1_val}).attrs.get('checked')
|
||||||
|
assert not doc.find('input', {'name': p2_val}).attrs.get('checked')
|
||||||
|
|
||||||
|
response = self.client.post('/%s/%s/checkout/addons/' % (self.orga.slug, self.event.slug), {
|
||||||
|
ws1_val: '1',
|
||||||
|
ws1_price: '222,22',
|
||||||
|
ws2a_val: '1',
|
||||||
|
ws2a_price: '333.33',
|
||||||
|
})
|
||||||
|
assert response.status_code == 200
|
||||||
|
with scopes_disabled():
|
||||||
|
assert cp1.addons.count() == 0
|
||||||
|
doc = BeautifulSoup(response.text, 'lxml')
|
||||||
|
assert doc.find('input', {'name': ws1_val}).attrs.get('checked')
|
||||||
|
assert doc.find('input', {'name': ws1_price}).attrs.get('value') in ['222.22', '222,22']
|
||||||
|
assert doc.find('input', {'name': ws2a_val}).attrs.get('checked')
|
||||||
|
assert doc.find('input', {'name': ws2a_price}).attrs.get('value') in ['333.33', '333,33']
|
||||||
|
assert not doc.find('input', {'name': p1_val}).attrs.get('checked')
|
||||||
|
assert not doc.find('input', {'name': p2_val}).attrs.get('checked')
|
||||||
|
|
||||||
def test_confirm_subevent_presale_not_yet(self):
|
def test_confirm_subevent_presale_not_yet(self):
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
self.event.has_subevents = True
|
self.event.has_subevents = True
|
||||||
|
|||||||
Reference in New Issue
Block a user