mirror of
https://github.com/pretix/pretix.git
synced 2026-08-16 11:46:27 +00:00
Discounts (#2510)
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import pytest
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.models import Discount
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def discount(event):
|
||||
return event.discounts.create(
|
||||
internal_name="3 for 2",
|
||||
condition_min_count=3,
|
||||
benefit_discount_matching_percent=100,
|
||||
benefit_only_apply_to_cheapest_n_matches=1,
|
||||
position=1,
|
||||
)
|
||||
|
||||
|
||||
TEST_DISCOUNT_RES = {
|
||||
"active": True,
|
||||
"internal_name": "3 for 2",
|
||||
"position": 1,
|
||||
"sales_channels": ["web"],
|
||||
"available_from": None,
|
||||
"available_until": None,
|
||||
"subevent_mode": "mixed",
|
||||
"condition_all_products": True,
|
||||
"condition_limit_products": [],
|
||||
"condition_apply_to_addons": True,
|
||||
"condition_ignore_voucher_discounted": False,
|
||||
"condition_min_count": 3,
|
||||
"condition_min_value": "0.00",
|
||||
"benefit_discount_matching_percent": "100.00",
|
||||
"benefit_only_apply_to_cheapest_n_matches": 1
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_discount_list(token_client, organizer, event, team, discount):
|
||||
res = dict(TEST_DISCOUNT_RES)
|
||||
res["id"] = discount.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/discounts/'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/discounts/?active=true'.format(
|
||||
organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/discounts/?active=false'.format(
|
||||
organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [] == resp.data['results']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_discount_detail(token_client, organizer, event, team, discount):
|
||||
res = dict(TEST_DISCOUNT_RES)
|
||||
res["id"] = discount.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/discounts/{}/'.format(organizer.slug, event.slug,
|
||||
discount.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res == resp.data
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_discount_create(token_client, organizer, event, team):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"active": True,
|
||||
"internal_name": "3 for 2",
|
||||
"position": 2,
|
||||
"sales_channels": ["web"],
|
||||
"available_from": None,
|
||||
"available_until": None,
|
||||
"subevent_mode": "mixed",
|
||||
"condition_all_products": True,
|
||||
"condition_limit_products": [],
|
||||
"condition_apply_to_addons": True,
|
||||
"condition_ignore_voucher_discounted": False,
|
||||
"condition_min_count": 3,
|
||||
"condition_min_value": "0.00",
|
||||
"benefit_discount_matching_percent": "100.00",
|
||||
"benefit_only_apply_to_cheapest_n_matches": 1
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
with scopes_disabled():
|
||||
d = Discount.objects.get(pk=resp.data['id'])
|
||||
assert d.event == event
|
||||
assert d.internal_name == "3 for 2"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_discount_update(token_client, organizer, event, team, discount):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/{}/'.format(organizer.slug, event.slug, discount.pk),
|
||||
{
|
||||
"internal_name": "Foo"
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
with scopes_disabled():
|
||||
d = Discount.objects.get(pk=resp.data['id'])
|
||||
assert d.event == event
|
||||
assert d.internal_name == "Foo"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_discount_delete(token_client, organizer, event, discount):
|
||||
resp = token_client.delete(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/{}/'.format(organizer.slug, event.slug, discount.pk))
|
||||
assert resp.status_code == 204
|
||||
with scopes_disabled():
|
||||
assert not event.discounts.filter(pk=discount.id).exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_validate_errors(token_client, organizer, event, team):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"internal_name": "3 for 2",
|
||||
"subevent_mode": "mixed",
|
||||
"condition_min_count": 3,
|
||||
"condition_min_value": "2.00",
|
||||
"benefit_discount_matching_percent": "100.00",
|
||||
"benefit_only_apply_to_cheapest_n_matches": 1
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"internal_name": "3 for 2",
|
||||
"subevent_mode": "mixed",
|
||||
"condition_min_count": 0,
|
||||
"condition_min_value": "0.00",
|
||||
"benefit_discount_matching_percent": "100.00",
|
||||
"benefit_only_apply_to_cheapest_n_matches": 1
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"internal_name": "3 for 2",
|
||||
"subevent_mode": "mixed",
|
||||
"condition_min_count": 0,
|
||||
"condition_min_value": "2.00",
|
||||
"benefit_discount_matching_percent": "100.00",
|
||||
"benefit_only_apply_to_cheapest_n_matches": 1
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/discounts/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"internal_name": "3 for 2",
|
||||
"subevent_mode": "distinct",
|
||||
"condition_min_count": 0,
|
||||
"condition_min_value": "2.00",
|
||||
"benefit_discount_matching_percent": "100.00",
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
@@ -81,6 +81,7 @@ event_permission_sub_urls = [
|
||||
('get', None, 'items/', 200),
|
||||
('get', None, 'questions/', 200),
|
||||
('get', None, 'quotas/', 200),
|
||||
('get', None, 'discounts/', 200),
|
||||
('post', 'can_change_items', 'items/', 400),
|
||||
('get', None, 'items/1/', 404),
|
||||
('put', 'can_change_items', 'items/1/', 404),
|
||||
@@ -91,6 +92,11 @@ event_permission_sub_urls = [
|
||||
('put', 'can_change_items', 'categories/1/', 404),
|
||||
('patch', 'can_change_items', 'categories/1/', 404),
|
||||
('delete', 'can_change_items', 'categories/1/', 404),
|
||||
('post', 'can_change_items', 'discounts/', 400),
|
||||
('get', None, 'discounts/1/', 404),
|
||||
('put', 'can_change_items', 'discounts/1/', 404),
|
||||
('patch', 'can_change_items', 'discounts/1/', 404),
|
||||
('delete', 'can_change_items', 'discounts/1/', 404),
|
||||
('post', 'can_change_items', 'items/1/variations/', 404),
|
||||
('get', None, 'items/1/variations/', 404),
|
||||
('get', None, 'items/1/variations/1/', 404),
|
||||
|
||||
@@ -924,7 +924,7 @@ class VoucherTestCase(BaseQuotaTestCase):
|
||||
datetime=now() - timedelta(days=5), expires=now() + timedelta(days=5), total=46,
|
||||
)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, voucher=v, price=Decimal('20.00'),
|
||||
price_before_voucher=Decimal('23.00'))
|
||||
voucher_budget_use=Decimal('3.00'))
|
||||
assert v.budget_used() == Decimal('3.00')
|
||||
|
||||
order = Order.objects.create(
|
||||
@@ -932,7 +932,7 @@ class VoucherTestCase(BaseQuotaTestCase):
|
||||
datetime=now() - timedelta(days=5), expires=now() + timedelta(days=5), total=46,
|
||||
)
|
||||
OrderPosition.objects.create(order=order, item=self.item1, voucher=v, price=Decimal('20.00'),
|
||||
price_before_voucher=Decimal('23.00'))
|
||||
voucher_budget_use=Decimal('3.00'))
|
||||
assert v.budget_used() == Decimal('6.00')
|
||||
|
||||
|
||||
|
||||
@@ -1070,10 +1070,10 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert self.order.transactions.count() == 4
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_change_item_change_price_before_voucher(self):
|
||||
def test_change_item_change_voucher_budget_use(self):
|
||||
self.op1.voucher = self.event.vouchers.create(item=self.shirt, redeemed=1, price_mode='set', value='5.00')
|
||||
self.op1.price = Decimal('5.00')
|
||||
self.op1.price_before_voucher = Decimal('23.00')
|
||||
self.op1.voucher_budget_use = Decimal('18.00')
|
||||
self.op1.save()
|
||||
p = self.op1.price
|
||||
self.ocm.change_item(self.op1, self.shirt, None)
|
||||
@@ -1082,13 +1082,13 @@ class OrderChangeManagerTests(TestCase):
|
||||
self.order.refresh_from_db()
|
||||
assert self.op1.item == self.shirt
|
||||
assert self.op1.price == p
|
||||
assert self.op1.price_before_voucher == Decimal('12.00')
|
||||
assert self.op1.voucher_budget_use == Decimal('7.00')
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_change_item_change_price_before_voucher_minimum_value(self):
|
||||
def test_change_item_change_voucher_budget_use_minimum_value(self):
|
||||
self.op1.voucher = self.event.vouchers.create(item=self.shirt, redeemed=1, price_mode='set', value='20.00')
|
||||
self.op1.price = Decimal('20.00')
|
||||
self.op1.price_before_voucher = Decimal('23.00')
|
||||
self.op1.voucher_budget_use = Decimal('3.00')
|
||||
self.op1.save()
|
||||
p = self.op1.price
|
||||
self.ocm.change_item(self.op1, self.shirt, None)
|
||||
@@ -1097,7 +1097,7 @@ class OrderChangeManagerTests(TestCase):
|
||||
self.order.refresh_from_db()
|
||||
assert self.op1.item == self.shirt
|
||||
assert self.op1.price == p
|
||||
assert self.op1.price_before_voucher == Decimal('20.00')
|
||||
assert self.op1.voucher_budget_use == Decimal('0.00')
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_change_item_success(self):
|
||||
@@ -3133,7 +3133,7 @@ class OrderReactivateTest(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_reactivate_voucher_budget(self):
|
||||
self.op1.voucher = self.event.vouchers.create(code="FOO", item=self.ticket, budget=Decimal('0.00'))
|
||||
self.op1.price_before_voucher = self.op1.price * 2
|
||||
self.op1.voucher_budget_use = self.op1.price
|
||||
self.op1.save()
|
||||
with pytest.raises(OrderError):
|
||||
reactivate_order(self.order)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,8 +40,8 @@ from django_scopes import scopes_disabled
|
||||
from tests.base import SoupTest, extract_form_fields
|
||||
|
||||
from pretix.base.models import (
|
||||
Event, Item, ItemCategory, ItemVariation, Order, OrderPosition, Organizer,
|
||||
Question, Quota, Team, User,
|
||||
Discount, Event, Item, ItemCategory, ItemVariation, Order, OrderPosition,
|
||||
Organizer, Question, Quota, Team, User,
|
||||
)
|
||||
|
||||
|
||||
@@ -695,3 +695,64 @@ class ItemsTest(ItemFormTest):
|
||||
i = Item.objects.get(name__icontains='New Item')
|
||||
q = Quota.objects.get(name__icontains='New Quota')
|
||||
assert q.items.filter(pk=i.pk).exists()
|
||||
|
||||
|
||||
class DiscountTest(ItemFormTest):
|
||||
|
||||
def test_create(self):
|
||||
doc = self.get_doc('/control/event/%s/%s/discounts/add' % (self.orga1.slug, self.event1.slug))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
form_data['internal_name'] = 'Group discount'
|
||||
form_data['condition_min_count'] = '2'
|
||||
form_data['benefit_discount_matching_percent'] = '20'
|
||||
doc = self.post_doc('/control/event/%s/%s/discounts/add' % (self.orga1.slug, self.event1.slug), form_data)
|
||||
assert doc.select(".alert-success")
|
||||
self.assertIn("Group discount", doc.select("#page-wrapper table")[0].text)
|
||||
|
||||
def test_update(self):
|
||||
c = Discount.objects.create(event=self.event1, internal_name="2 for 1")
|
||||
doc = self.get_doc('/control/event/%s/%s/discounts/%s/' % (self.orga1.slug, self.event1.slug, c.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
form_data['internal_name'] = 'Group discount'
|
||||
form_data['condition_min_count'] = '2'
|
||||
form_data['benefit_discount_matching_percent'] = '20'
|
||||
doc = self.post_doc('/control/event/%s/%s/discounts/%s/' % (self.orga1.slug, self.event1.slug, c.id),
|
||||
form_data)
|
||||
assert doc.select(".alert-success")
|
||||
self.assertIn("Group discount", doc.select("#page-wrapper table")[0].text)
|
||||
self.assertNotIn("2 for 1", doc.select("#page-wrapper table")[0].text)
|
||||
with scopes_disabled():
|
||||
assert str(Discount.objects.get(id=c.id).benefit_discount_matching_percent) == '20.00'
|
||||
|
||||
def test_sort(self):
|
||||
with scopes_disabled():
|
||||
c1 = Discount.objects.create(event=self.event1, internal_name="Group discount", condition_min_value=2,
|
||||
benefit_discount_matching_percent=20)
|
||||
Discount.objects.create(event=self.event1, internal_name="Big group", condition_min_value=5,
|
||||
benefit_discount_matching_percent=40)
|
||||
doc = self.get_doc('/control/event/%s/%s/discounts/' % (self.orga1.slug, self.event1.slug))
|
||||
self.assertIn("Group discount", doc.select("table > tbody > tr")[0].text)
|
||||
self.assertIn("Big group", doc.select("table > tbody > tr")[1].text)
|
||||
|
||||
self.client.post('/control/event/%s/%s/discounts/%s/down' % (self.orga1.slug, self.event1.slug, c1.id))
|
||||
doc = self.get_doc('/control/event/%s/%s/discounts/' % (self.orga1.slug, self.event1.slug))
|
||||
self.assertIn("Group discount", doc.select("table > tbody > tr")[1].text)
|
||||
self.assertIn("Big group", doc.select("table > tbody > tr")[0].text)
|
||||
|
||||
self.client.post('/control/event/%s/%s/discounts/%s/up' % (self.orga1.slug, self.event1.slug, c1.id))
|
||||
doc = self.get_doc('/control/event/%s/%s/discounts/' % (self.orga1.slug, self.event1.slug))
|
||||
self.assertIn("Group discount", doc.select("table > tbody > tr")[0].text)
|
||||
self.assertIn("Big group", doc.select("table > tbody > tr")[1].text)
|
||||
|
||||
def test_delete(self):
|
||||
with scopes_disabled():
|
||||
c = Discount.objects.create(event=self.event1, internal_name="Group discount", condition_min_value=2,
|
||||
benefit_discount_matching_percent=20)
|
||||
doc = self.get_doc('/control/event/%s/%s/discounts/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
|
||||
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
|
||||
doc = self.post_doc('/control/event/%s/%s/discounts/%s/delete' % (self.orga1.slug, self.event1.slug, c.id),
|
||||
form_data)
|
||||
assert doc.select(".alert-success")
|
||||
self.assertNotIn("Group discount", doc.select("#page-wrapper")[0].text)
|
||||
with scopes_disabled():
|
||||
assert not Discount.objects.filter(id=c.id).exists()
|
||||
|
||||
@@ -938,7 +938,7 @@ def test_order_extend_expired_voucher_budget_ok(client, env):
|
||||
)
|
||||
p = o.positions.first()
|
||||
p.voucher = v
|
||||
p.price_before_voucher = p.price
|
||||
p.voucher_budget_use = Decimal('1.50')
|
||||
p.price -= Decimal('1.50')
|
||||
p.save()
|
||||
|
||||
@@ -969,7 +969,7 @@ def test_order_extend_expired_voucher_budget_fail(client, env):
|
||||
)
|
||||
p = o.positions.first()
|
||||
p.voucher = v
|
||||
p.price_before_voucher = p.price
|
||||
p.voucher_budget_use = Decimal('1.50')
|
||||
p.price -= Decimal('1.50')
|
||||
p.save()
|
||||
|
||||
|
||||
@@ -113,6 +113,12 @@ event_urls = [
|
||||
"categories/2/up",
|
||||
"categories/2/down",
|
||||
"categories/2/delete",
|
||||
"discounts/",
|
||||
"discounts/add",
|
||||
"discounts/2/",
|
||||
"discounts/2/up",
|
||||
"discounts/2/down",
|
||||
"discounts/2/delete",
|
||||
"questions/",
|
||||
"questions/2/delete",
|
||||
"questions/2/",
|
||||
@@ -325,6 +331,16 @@ event_permission_urls = [
|
||||
("can_change_items", "quotas/2/change", 404, HTTP_GET),
|
||||
("can_change_items", "quotas/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "quotas/add", 200, HTTP_GET),
|
||||
# ("can_change_items", "discounts/", 200),
|
||||
# We don't have to create categories and similar objects
|
||||
# for testing this, it is enough to test that a 404 error
|
||||
# is returned instead of a 403 one.
|
||||
("can_change_items", "discounts/2/", 404, HTTP_GET),
|
||||
("can_change_items", "discounts/2/delete", 404, HTTP_GET),
|
||||
("can_change_items", "discounts/2/up", 404, HTTP_POST),
|
||||
("can_change_items", "discounts/2/down", 404, HTTP_POST),
|
||||
("can_change_items", "discounts/reorder", 400, HTTP_POST),
|
||||
("can_change_items", "discounts/add", 200, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/", 200, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/2/", 404, HTTP_GET),
|
||||
("can_change_event_settings", "subevents/2/delete", 404, HTTP_GET),
|
||||
|
||||
+115
-60
@@ -46,15 +46,14 @@ from tests.testdummy.signals import FoobarSalesChannel
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, InvoiceAddress, Item, ItemCategory, ItemVariation,
|
||||
Organizer, Question, QuestionAnswer, Quota, SeatingPlan, Voucher,
|
||||
CartPosition, Discount, Event, InvoiceAddress, Item, ItemCategory,
|
||||
ItemVariation, Organizer, Question, QuestionAnswer, Quota, SeatingPlan,
|
||||
Voucher,
|
||||
)
|
||||
from pretix.base.models.items import (
|
||||
ItemAddOn, ItemBundle, SubEventItem, SubEventItemVariation,
|
||||
)
|
||||
from pretix.base.services.cart import (
|
||||
CartError, CartManager, error_messages, update_tax_rates,
|
||||
)
|
||||
from pretix.base.services.cart import CartError, CartManager, error_messages
|
||||
from pretix.testutils.scope import classscope
|
||||
from pretix.testutils.sessions import get_cart_session_key
|
||||
|
||||
@@ -1557,7 +1556,8 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, Decimal('21.00'))
|
||||
self.assertEqual(objs[0].price_before_voucher, Decimal('23.00'))
|
||||
self.assertEqual(objs[0].listed_price, Decimal('23.00'))
|
||||
self.assertEqual(objs[0].price_after_voucher, Decimal('20.70'))
|
||||
|
||||
def test_voucher_free_price_before_voucher_cap(self):
|
||||
with scopes_disabled():
|
||||
@@ -1582,7 +1582,8 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, Decimal('41.00'))
|
||||
self.assertEqual(objs[0].price_before_voucher, Decimal('41.00'))
|
||||
self.assertEqual(objs[0].listed_price, Decimal('23.00'))
|
||||
self.assertEqual(objs[0].price_after_voucher, Decimal('20.70'))
|
||||
|
||||
def test_voucher_free_price_lower_bound(self):
|
||||
with scopes_disabled():
|
||||
@@ -1607,7 +1608,8 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, Decimal('20.70'))
|
||||
self.assertEqual(objs[0].price_before_voucher, Decimal('23.00'))
|
||||
self.assertEqual(objs[0].listed_price, Decimal('23.00'))
|
||||
self.assertEqual(objs[0].price_after_voucher, Decimal('20.70'))
|
||||
|
||||
def test_voucher_redemed(self):
|
||||
with scopes_disabled():
|
||||
@@ -1977,11 +1979,11 @@ class CartTest(CartTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||
price=15, expires=now() + timedelta(minutes=10)
|
||||
price=15, listed_price=15, price_after_voucher=15, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, item=self.ticket, price_mode='set', value=Decimal('4.00')
|
||||
@@ -2001,11 +2003,11 @@ class CartTest(CartTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||
price=150, expires=now() + timedelta(minutes=10)
|
||||
price=150, listed_price=150, price_after_voucher=150, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', value=Decimal('4.00'), max_usages=100, redeemed=99
|
||||
@@ -2026,11 +2028,11 @@ class CartTest(CartTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||
price=150, expires=now() + timedelta(minutes=10)
|
||||
price=150, listed_price=150, price_after_voucher=150, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('4.00'), max_usages=100
|
||||
@@ -2051,14 +2053,14 @@ class CartTest(CartTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
v2 = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('4.00'), max_usages=100
|
||||
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('8.00'), max_usages=100
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||
price=150, expires=now() + timedelta(minutes=10), voucher=v2
|
||||
price=8, expires=now() + timedelta(minutes=10), voucher=v2
|
||||
)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', quota=self.quota_all, value=Decimal('4.00'), max_usages=100
|
||||
@@ -2073,7 +2075,7 @@ class CartTest(CartTestMixin, TestCase):
|
||||
assert cp1.voucher == v
|
||||
assert cp1.price == Decimal('4.00')
|
||||
assert cp2.voucher == v2
|
||||
assert cp2.price == Decimal('150.00')
|
||||
assert cp2.price == Decimal('8.00')
|
||||
|
||||
"""
|
||||
def test_voucher_apply_only_positive(self):
|
||||
@@ -2104,11 +2106,11 @@ class CartTest(CartTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||
price=15, expires=now() + timedelta(minutes=10)
|
||||
price=15, listed_price=15, price_after_voucher=15, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', value=Decimal('40.00'), max_usages=100,
|
||||
@@ -2128,11 +2130,11 @@ class CartTest(CartTestMixin, TestCase):
|
||||
with scopes_disabled():
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||
price=15, expires=now() + timedelta(minutes=10)
|
||||
price=15, listed_price=15, price_after_voucher=15, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', value=Decimal('40.00'), max_usages=100, redeemed=100
|
||||
@@ -2147,6 +2149,79 @@ class CartTest(CartTestMixin, TestCase):
|
||||
assert cp1.voucher is None
|
||||
assert cp2.voucher is None
|
||||
|
||||
def test_discount(self):
|
||||
with scopes_disabled():
|
||||
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=20,
|
||||
benefit_only_apply_to_cheapest_n_matches=1)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 2)
|
||||
self.assertEqual({objs[0].price, objs[1].price}, {Decimal('23.00'), Decimal('18.40')})
|
||||
|
||||
def test_discount_and_voucher_mixed(self):
|
||||
with scopes_disabled():
|
||||
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=50,
|
||||
benefit_only_apply_to_cheapest_n_matches=1)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', value=Decimal('4.00'), max_usages=100
|
||||
)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 4)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 2)
|
||||
self.assertEqual({objs[0].price, objs[1].price}, {Decimal('4.00'), Decimal('2.00')})
|
||||
|
||||
def test_discount_and_voucher_mix_forbidden(self):
|
||||
with scopes_disabled():
|
||||
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=50,
|
||||
benefit_only_apply_to_cheapest_n_matches=1, condition_ignore_voucher_discounted=True)
|
||||
v = Voucher.objects.create(
|
||||
event=self.event, price_mode='set', value=Decimal('4.00'), max_usages=100
|
||||
)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].item, self.ticket)
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 4)
|
||||
self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'_voucher_code': v.code,
|
||||
}, follow=True)
|
||||
with scopes_disabled():
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 2)
|
||||
self.assertEqual({objs[0].price, objs[1].price}, {Decimal('4.00'), Decimal('4.00')})
|
||||
|
||||
|
||||
class CartAddonTest(CartTestMixin, TestCase):
|
||||
@scopes_disabled()
|
||||
@@ -2836,7 +2911,9 @@ class CartAddonTest(CartTestMixin, TestCase):
|
||||
self.cm.commit()
|
||||
cp1.refresh_from_db()
|
||||
assert cp1.expires > now()
|
||||
assert cp1.price_before_voucher == Decimal('23.00')
|
||||
assert cp1.listed_price == Decimal('23.00')
|
||||
assert cp1.price_after_voucher == Decimal('20.00')
|
||||
assert cp1.price == Decimal('20.00')
|
||||
|
||||
|
||||
class CartBundleTest(CartTestMixin, TestCase):
|
||||
@@ -2911,7 +2988,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
assert cp.price == 23 - 1.5
|
||||
assert cp.addons.count() == 1
|
||||
assert cp.voucher == v
|
||||
assert cp.price_before_voucher == 23 - 1.5
|
||||
assert cp.listed_price == 23
|
||||
assert cp.price_after_voucher == 23
|
||||
a = cp.addons.get()
|
||||
assert a.item == self.trans
|
||||
assert a.price == 1.5
|
||||
@@ -2934,7 +3012,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
assert cp.price == 23 - 1.5 - 1.5
|
||||
assert cp.addons.count() == 1
|
||||
assert cp.voucher == v
|
||||
assert cp.price_before_voucher == 23 - 1.5
|
||||
assert cp.listed_price == 23
|
||||
assert cp.price_after_voucher == 23 - 1.5
|
||||
a = cp.addons.get()
|
||||
assert a.item == self.trans
|
||||
assert a.price == 1.5
|
||||
@@ -3221,13 +3300,11 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.tax_value == Decimal('3.43')
|
||||
assert cp.addons.count() == 1
|
||||
assert cp.includes_tax
|
||||
a = cp.addons.first()
|
||||
assert a.item == self.trans
|
||||
assert a.price == 1.5
|
||||
assert a.tax_rate == Decimal('7.00')
|
||||
assert a.tax_value == Decimal('0.10')
|
||||
assert a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_one_bundled_one_addon(self):
|
||||
@@ -3421,15 +3498,14 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
|
||||
price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
|
||||
)
|
||||
update_tax_rates(self.event, self.session_key, ia)
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.recompute_final_prices_and_taxes()
|
||||
cp.refresh_from_db()
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.40')
|
||||
assert a.tax_rate == Decimal('0.00')
|
||||
assert not a.includes_tax
|
||||
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.commit()
|
||||
@@ -3438,10 +3514,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.40')
|
||||
assert a.tax_rate == 0
|
||||
assert not a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_expired_reverse_charge_all(self):
|
||||
@@ -3464,15 +3538,14 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
|
||||
price=1.5, expires=now() - timedelta(minutes=10), is_bundled=True
|
||||
)
|
||||
update_tax_rates(self.event, self.session_key, ia)
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.recompute_final_prices_and_taxes()
|
||||
cp.refresh_from_db()
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('18.07')
|
||||
assert cp.tax_rate == Decimal('0.00')
|
||||
assert not cp.includes_tax
|
||||
assert a.price == Decimal('1.40')
|
||||
assert a.tax_rate == Decimal('0.00')
|
||||
assert not a.includes_tax
|
||||
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.commit()
|
||||
@@ -3481,10 +3554,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('18.07')
|
||||
assert cp.tax_rate == Decimal('0.00')
|
||||
assert not cp.includes_tax
|
||||
assert a.price == Decimal('1.40')
|
||||
assert a.tax_rate == Decimal('0.00')
|
||||
assert not a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_reverse_charge_all_add(self):
|
||||
@@ -3513,10 +3584,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a = CartPosition.objects.filter(addon_to__isnull=False).get()
|
||||
assert cp.price == Decimal('18.07')
|
||||
assert cp.tax_rate == Decimal('0.00')
|
||||
assert not cp.includes_tax
|
||||
assert a.price == Decimal('1.40')
|
||||
assert a.tax_rate == Decimal('0.00')
|
||||
assert not a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_reverse_charge_bundled_add_keep_gross_price(self):
|
||||
@@ -3546,10 +3615,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a = CartPosition.objects.filter(addon_to__isnull=False).get()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.50')
|
||||
assert a.tax_rate == Decimal('0.00')
|
||||
assert not a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_reverse_charge_bundled_add(self):
|
||||
@@ -3578,10 +3645,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a = CartPosition.objects.filter(addon_to__isnull=False).get()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.40')
|
||||
assert a.tax_rate == Decimal('0.00')
|
||||
assert not a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_expired_country_taxing_only_bundled(self):
|
||||
@@ -3606,17 +3671,16 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
)
|
||||
a = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
|
||||
price=1.47, expires=now() - timedelta(minutes=10), is_bundled=True, override_tax_rate=Decimal('5.00')
|
||||
price=1.47, expires=now() - timedelta(minutes=10), is_bundled=True, tax_rate=Decimal('5.00')
|
||||
)
|
||||
update_tax_rates(self.event, self.session_key, ia)
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.recompute_final_prices_and_taxes()
|
||||
cp.refresh_from_db()
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.47')
|
||||
assert a.tax_rate == Decimal('5.00')
|
||||
assert a.includes_tax
|
||||
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.commit()
|
||||
@@ -3625,10 +3689,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.47')
|
||||
assert a.tax_rate == Decimal('5.00')
|
||||
assert a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_expired_country_tax_all(self):
|
||||
@@ -3654,21 +3716,20 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
|
||||
cp = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=21.68, expires=now() - timedelta(minutes=10), override_tax_rate=Decimal('20.00')
|
||||
price=21.68, expires=now() - timedelta(minutes=10), tax_rate=Decimal('20.00')
|
||||
)
|
||||
a = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=cp,
|
||||
price=1.47, expires=now() - timedelta(minutes=10), is_bundled=True, override_tax_rate=Decimal('5.00')
|
||||
price=1.47, expires=now() - timedelta(minutes=10), is_bundled=True, tax_rate=Decimal('5.00')
|
||||
)
|
||||
update_tax_rates(self.event, self.session_key, ia)
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.recompute_final_prices_and_taxes()
|
||||
cp.refresh_from_db()
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('21.68')
|
||||
assert cp.tax_rate == Decimal('20.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.47')
|
||||
assert a.tax_rate == Decimal('5.00')
|
||||
assert a.includes_tax
|
||||
|
||||
self.cm.invoice_address = ia
|
||||
self.cm.commit()
|
||||
@@ -3677,10 +3738,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a.refresh_from_db()
|
||||
assert cp.price == Decimal('21.68')
|
||||
assert cp.tax_rate == Decimal('20.0')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.47')
|
||||
assert a.tax_rate == Decimal('5.00')
|
||||
assert a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_country_tax_all_add(self):
|
||||
@@ -3718,10 +3777,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a = CartPosition.objects.filter(addon_to__isnull=False).get()
|
||||
assert cp.price == Decimal('21.68')
|
||||
assert cp.tax_rate == Decimal('20.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.47')
|
||||
assert a.tax_rate == Decimal('5.00')
|
||||
assert a.includes_tax
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_country_tax_bundled_add(self):
|
||||
@@ -3754,10 +3811,8 @@ class CartBundleTest(CartTestMixin, TestCase):
|
||||
a = CartPosition.objects.filter(addon_to__isnull=False).get()
|
||||
assert cp.price == Decimal('21.50')
|
||||
assert cp.tax_rate == Decimal('19.00')
|
||||
assert cp.includes_tax
|
||||
assert a.price == Decimal('1.47')
|
||||
assert a.tax_rate == Decimal('5.00')
|
||||
assert a.includes_tax
|
||||
|
||||
|
||||
class CartSeatingTest(CartTestMixin, TestCase):
|
||||
|
||||
@@ -39,9 +39,9 @@ from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, Invoice, InvoiceAddress, Item, ItemCategory, Order,
|
||||
OrderPayment, OrderPosition, Organizer, Question, QuestionAnswer, Quota,
|
||||
SeatingPlan, Voucher,
|
||||
CartPosition, Discount, Event, Invoice, InvoiceAddress, Item, ItemCategory,
|
||||
Order, OrderPayment, OrderPosition, Organizer, Question, QuestionAnswer,
|
||||
Quota, SeatingPlan, Voucher,
|
||||
)
|
||||
from pretix.base.models.items import (
|
||||
ItemAddOn, ItemBundle, ItemVariation, SubEventItem, SubEventItemVariation,
|
||||
@@ -539,7 +539,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == Decimal('23.20')
|
||||
assert cr1.override_tax_rate == Decimal('20.00')
|
||||
assert cr1.tax_rate == Decimal('20.00')
|
||||
assert cr1.tax_value == Decimal('3.87')
|
||||
return cr1
|
||||
|
||||
@@ -572,7 +572,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10),
|
||||
price=23, listed_price=23, price_after_voucher=23, custom_price_input=23, custom_price_input_is_net=False,
|
||||
expires=now() + timedelta(minutes=10),
|
||||
voucher=self.event.vouchers.create()
|
||||
)
|
||||
|
||||
@@ -621,21 +622,80 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
cr = CartPosition.objects.get(cart_id=self.session_key)
|
||||
assert cr.price == Decimal('21.26')
|
||||
|
||||
def test_free_price_net_price_reverse_charge_keep_gross(self):
|
||||
def test_free_price_net_price_reverse_charge_keep_gross_but_enforce_min(self):
|
||||
# This is an end-to-end test of a very confusing case in which the event is set to
|
||||
# "show net prices" but the tax rate is set to "keep gross if rate changes" in
|
||||
# combination of free prices.
|
||||
# This means the user will be greeted with a display price of "23 EUR + VAT". If they
|
||||
# then adjust the price to pay more, e.g. "24 EUR", it will be interpreted as a net
|
||||
# value (since the event is set to shown net values). The cart position is therefore
|
||||
# created with a gross price of 28.56 EUR. Then, the user enters their invoice address, which
|
||||
# triggers reverse charge. The tax is now removed, and the price would be reverted to "24.00 + 0%",
|
||||
# however that is now lower than the minimum price of "27.37 incl VAT", so the price is raised to 27.37.
|
||||
self.event.settings.display_net_prices = True
|
||||
self.ticket.free_price = True
|
||||
self.ticket.save()
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.keep_gross_if_rate_changes = True
|
||||
self.tr19.price_includes_tax = False
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1',
|
||||
'price_%d' % self.ticket.id: '24.00',
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/?require_cookie=true' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.get()
|
||||
assert cr1.listed_price == Decimal('23.00')
|
||||
assert cr1.custom_price_input == Decimal('24.00')
|
||||
assert cr1.custom_price_input_is_net
|
||||
assert cr1.price == Decimal('28.56')
|
||||
assert cr1.tax_rate == Decimal('19.00')
|
||||
|
||||
with mock.patch('vat_moss.id.validate') as mock_validate:
|
||||
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
|
||||
self.client.post('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), {
|
||||
'is_business': 'business',
|
||||
'company': 'Foo',
|
||||
'name': 'Bar',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == Decimal('27.37')
|
||||
assert cr1.tax_rate == Decimal('0.00')
|
||||
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
with scopes_disabled():
|
||||
op = OrderPosition.objects.get()
|
||||
self.assertEqual(op.price, Decimal('27.37'))
|
||||
self.assertEqual(op.tax_value, Decimal('0.00'))
|
||||
self.assertEqual(op.tax_rate, Decimal('0.00'))
|
||||
|
||||
def test_free_price_net_price_reverse_charge_keep_gross(self):
|
||||
# This is the slightly happier case of the previous test in which the event is set to
|
||||
# "show net prices" but the tax rate is set to "keep gross if rate changes" in
|
||||
# combination of free prices.
|
||||
# This means the user will be greeted with a display price of "23 EUR + VAT". If they
|
||||
# then adjust the price to pay more, e.g. "40 EUR", it will be interpreted as a net
|
||||
# value (since the event is set to shown net values). The cart position is therefore
|
||||
# created with a gross price of 47.60 EUR. Then, the user enters their invoice address, which
|
||||
# triggers reverse charge. The tax is now removed, but since the tax rule is set to
|
||||
# keep the gross price the same, the user will still need to pay 47.60 EUR (incl 0% VAT),
|
||||
# instead of the 40 EUR the maybe wanted in the first place.
|
||||
# While confusing, this behaviour is technically correct and the correct answer to anyone
|
||||
# complaining about this is "do not turn display_net_prices and keep_gross_if_rate_changes
|
||||
# on at the same time" (display_net_prices only makes sense if you're targeting a B2B
|
||||
# audience in which case keep_gross_if_rate_changes is useless or even harmful).
|
||||
# triggers reverse charge. The tax is now removed, and the price is reverted to "40.00 + 0%"
|
||||
# since that was the user's original intent.
|
||||
self.event.settings.display_net_prices = True
|
||||
self.ticket.free_price = True
|
||||
self.ticket.save()
|
||||
@@ -655,6 +715,9 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.get()
|
||||
assert cr1.listed_price == Decimal('23.00')
|
||||
assert cr1.custom_price_input == Decimal('40.00')
|
||||
assert cr1.custom_price_input_is_net
|
||||
assert cr1.price == Decimal('47.60')
|
||||
assert cr1.tax_rate == Decimal('19.00')
|
||||
|
||||
@@ -673,7 +736,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == Decimal('47.60')
|
||||
assert cr1.price == Decimal('40.00')
|
||||
assert cr1.tax_rate == Decimal('0.00')
|
||||
|
||||
self._set_session('payment', 'banktransfer')
|
||||
@@ -683,7 +746,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
with scopes_disabled():
|
||||
op = OrderPosition.objects.get()
|
||||
self.assertEqual(op.price, Decimal('47.60'))
|
||||
self.assertEqual(op.price, Decimal('40.00'))
|
||||
self.assertEqual(op.tax_value, Decimal('0.00'))
|
||||
self.assertEqual(op.tax_rate, Decimal('0.00'))
|
||||
|
||||
@@ -1662,7 +1725,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=42, expires=now() + timedelta(minutes=10)
|
||||
price=42, listed_price=42, price_after_voucher=42, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -1682,7 +1745,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=0, expires=now() + timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -1701,7 +1764,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
price_included=True)
|
||||
cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=0, expires=now() - timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() - timedelta(minutes=10)
|
||||
)
|
||||
self.ticket.default_price = 0
|
||||
self.ticket.save()
|
||||
@@ -1712,7 +1775,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.workshop1,
|
||||
price=0, expires=now() - timedelta(minutes=10),
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() - timedelta(minutes=10),
|
||||
addon_to=cp1
|
||||
)
|
||||
self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -1734,7 +1797,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=42, expires=now() + timedelta(minutes=10)
|
||||
price=42, listed_price=42, price_after_voucher=42, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
@@ -1751,7 +1814,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=0, expires=now() + timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self._set_session('payment', 'free')
|
||||
|
||||
@@ -1771,7 +1834,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=0, expires=now() + timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self._set_session('payment', 'free')
|
||||
|
||||
@@ -2043,7 +2106,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() - timedelta(minutes=10)
|
||||
listed_price=23, price_after_voucher=23, custom_price_input=23, price=23,
|
||||
expires=now() - timedelta(minutes=10)
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
@@ -2276,12 +2340,14 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select(".alert-danger")), 1)
|
||||
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
|
||||
with scopes_disabled():
|
||||
self.assertEqual(CartPosition.objects.filter(cart_id=self.session_key).count(), 1)
|
||||
self.assertEqual(CartPosition.objects.filter(cart_id=self.session_key).count(), 0)
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=12, expires=now() - timedelta(minutes=10), voucher=v
|
||||
)
|
||||
|
||||
cr1.voucher = v
|
||||
cr1.save()
|
||||
self.client.get('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
@@ -2342,6 +2408,48 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 1)
|
||||
|
||||
def test_discount_success(self):
|
||||
with scopes_disabled():
|
||||
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=20)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
listed_price=23, price_after_voucher=23, price=18.4, expires=now() - timedelta(minutes=10),
|
||||
)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
listed_price=23, price_after_voucher=23, price=18.4, expires=now() - timedelta(minutes=10),
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
with scopes_disabled():
|
||||
self.assertFalse(CartPosition.objects.filter(cart_id=self.session_key).exists())
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
self.assertEqual(Order.objects.count(), 1)
|
||||
self.assertEqual(OrderPosition.objects.count(), 2)
|
||||
self.assertEqual(OrderPosition.objects.filter(price=18.4).count(), 2)
|
||||
|
||||
def test_discount_changed(self):
|
||||
with scopes_disabled():
|
||||
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=20)
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
listed_price=23, price_after_voucher=23, price=23, expires=now() - timedelta(minutes=10),
|
||||
)
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
listed_price=23, price_after_voucher=23, price=23, expires=now() - timedelta(minutes=10),
|
||||
)
|
||||
self._set_session('payment', 'banktransfer')
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
self.assertEqual(len(doc.select(".alert-danger")), 1)
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.get(id=cr1.id)
|
||||
self.assertEqual(cr1.price, Decimal('18.40'))
|
||||
|
||||
def test_max_per_item_failed(self):
|
||||
self.quota_tickets.size = 3
|
||||
self.quota_tickets.save()
|
||||
@@ -2964,7 +3072,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=0, expires=now() + timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -2977,7 +3085,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.workshop2, variation=self.workshop2a,
|
||||
price=0, expires=now() + timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -2997,7 +3105,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TestCase):
|
||||
with scopes_disabled():
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.workshop2, variation=self.workshop2a,
|
||||
price=0, expires=now() + timedelta(minutes=10)
|
||||
price=0, listed_price=0, price_after_voucher=0, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
@@ -3109,7 +3217,7 @@ class QuestionsTestCase(BaseCheckoutTestCase, TestCase):
|
||||
)
|
||||
cr2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=20, expires=now() + timedelta(minutes=10)
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
@@ -3352,11 +3460,11 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
)
|
||||
self.cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=21.5, expires=now() + timedelta(minutes=10)
|
||||
price=21.5, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
self.bundled1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.trans, addon_to=self.cp1,
|
||||
price=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
|
||||
price=1.5, listed_price=1.5, price_after_voucher=1.5, expires=now() + timedelta(minutes=10), is_bundled=True
|
||||
)
|
||||
|
||||
@classscope(attr='orga')
|
||||
@@ -3417,6 +3525,10 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
self.ticket.free_price = True
|
||||
self.ticket.default_price = 1
|
||||
self.ticket.save()
|
||||
self.cp1.custom_price_input = 20
|
||||
self.cp1.listed_price = 1
|
||||
self.cp1.price_after_voucher = 1
|
||||
self.cp1.line_price = 20 - 1.5
|
||||
self.cp1.price = 20 - 1.5
|
||||
self.cp1.save()
|
||||
|
||||
@@ -3434,6 +3546,10 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
self.ticket.free_price = True
|
||||
self.ticket.default_price = 1
|
||||
self.ticket.save()
|
||||
self.cp1.custom_price_input = 1
|
||||
self.cp1.listed_price = 1
|
||||
self.cp1.price_after_voucher = 1
|
||||
self.cp1.line_price = 0
|
||||
self.cp1.price = 0
|
||||
self.cp1.save()
|
||||
|
||||
@@ -3514,12 +3630,12 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
self.cp1.save()
|
||||
self.bundled1.expires = now() - timedelta(minutes=10)
|
||||
self.bundled1.save()
|
||||
with self.assertRaises(OrderError):
|
||||
_perform_order(self.event, 'manual', [self.cp1.pk, self.bundled1.pk], 'admin@example.org', 'en', None, {}, 'web')
|
||||
self.cp1.refresh_from_db()
|
||||
self.bundled1.refresh_from_db()
|
||||
assert self.cp1.price == 21
|
||||
assert self.bundled1.price == 2
|
||||
oid = _perform_order(self.event, 'manual', [self.cp1.pk, self.bundled1.pk], 'admin@example.org', 'en', None, {}, 'web')
|
||||
o = Order.objects.get(pk=oid)
|
||||
cp = o.positions.get(addon_to__isnull=True)
|
||||
b = cp.addons.first()
|
||||
assert cp.price == 21
|
||||
assert b.price == 2
|
||||
|
||||
@classscope(attr='orga')
|
||||
def test_expired_designated_price_changed_beyond_base_price(self):
|
||||
@@ -3558,10 +3674,8 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
price=2.5, expires=now() - timedelta(minutes=10), is_bundled=False
|
||||
)
|
||||
self.cp1.expires = now() - timedelta(minutes=10)
|
||||
self.cp1.includes_tax = False
|
||||
self.cp1.save()
|
||||
self.bundled1.expires = now() - timedelta(minutes=10)
|
||||
self.bundled1.includes_tax = False
|
||||
self.bundled1.save()
|
||||
|
||||
oid = _perform_order(self.event, 'manual', [self.cp1.pk, self.bundled1.pk, a.pk], 'admin@example.org', 'en', None, {}, 'web')
|
||||
@@ -3632,7 +3746,6 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
self.cp1.save()
|
||||
self.bundled1.expires = now() - timedelta(minutes=10)
|
||||
self.bundled1.price = Decimal('1.40')
|
||||
self.bundled1.includes_tax = False
|
||||
self.bundled1.save()
|
||||
|
||||
oid = _perform_order(self.event, 'manual', [self.cp1.pk, self.bundled1.pk], 'admin@example.org', 'en', ia.pk, {}, 'web')
|
||||
@@ -3663,11 +3776,9 @@ class CheckoutBundleTest(BaseCheckoutTestCase, TestCase):
|
||||
self.trans.save()
|
||||
self.cp1.expires = now() - timedelta(minutes=10)
|
||||
self.cp1.price = Decimal('18.07')
|
||||
self.cp1.includes_tax = False
|
||||
self.cp1.save()
|
||||
self.bundled1.expires = now() - timedelta(minutes=10)
|
||||
self.bundled1.price = Decimal('1.40')
|
||||
self.bundled1.includes_tax = False
|
||||
self.bundled1.save()
|
||||
|
||||
oid = _perform_order(self.event, 'manual', [self.cp1.pk, self.bundled1.pk], 'admin@example.org', 'en', ia.pk, {}, 'web')
|
||||
@@ -3717,7 +3828,7 @@ class CheckoutSeatingTest(BaseCheckoutTestCase, TestCase):
|
||||
self.seat_a3 = self.event.seats.create(seat_number="A3", product=self.ticket, seat_guid="A3")
|
||||
self.cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=21.5, expires=now() + timedelta(minutes=10), seat=self.seat_a1
|
||||
price=21.5, listed_price=21.5, price_after_voucher=21.5, expires=now() + timedelta(minutes=10), seat=self.seat_a1
|
||||
)
|
||||
|
||||
@scopes_disabled()
|
||||
@@ -3800,11 +3911,11 @@ class CheckoutVoucherBudgetTest(BaseCheckoutTestCase, TestCase):
|
||||
valid_until=now() + timedelta(days=2), max_usages=999, redeemed=0)
|
||||
self.cp1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price_before_voucher=23, price=21.5, expires=now() + timedelta(minutes=10), voucher=self.v
|
||||
price_after_voucher=21.5, listed_price=23, price=21.5, expires=now() + timedelta(minutes=10), voucher=self.v
|
||||
)
|
||||
self.cp2 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price_before_voucher=23, price=21.5, expires=now() + timedelta(minutes=10), voucher=self.v
|
||||
price_after_voucher=21.5, listed_price=23, price=21.5, expires=now() + timedelta(minutes=10), voucher=self.v
|
||||
)
|
||||
|
||||
@scopes_disabled()
|
||||
@@ -3814,7 +3925,7 @@ class CheckoutVoucherBudgetTest(BaseCheckoutTestCase, TestCase):
|
||||
o = Order.objects.get(pk=oid)
|
||||
op = o.positions.first()
|
||||
assert op.item == self.ticket
|
||||
assert op.price_before_voucher == Decimal('23.00')
|
||||
assert op.voucher_budget_use == Decimal('1.50')
|
||||
|
||||
@scopes_disabled()
|
||||
def test_budget_exceeded_for_second_order(self):
|
||||
|
||||
Reference in New Issue
Block a user