forked from CGM_Public/pretix_original
* Data model + Editor * Cart and order management * Rebase migrations * Fix typos, add tests on cart handling * Add tests for checkout and quotas * Add API endpoints * Validation of settings * Front page tax display * Voucher handling * Widget foo * Show correct net pricing * Front page tests * reverse charge foo * Allow to require bundling * Fix test failure on postgres
This commit is contained in:
@@ -8,8 +8,8 @@ from django_countries.fields import Country
|
||||
from pytz import UTC
|
||||
|
||||
from pretix.base.models import (
|
||||
CartPosition, InvoiceAddress, Item, ItemAddOn, ItemCategory, ItemVariation,
|
||||
Order, OrderPosition, Question, QuestionOption, Quota,
|
||||
CartPosition, InvoiceAddress, Item, ItemAddOn, ItemBundle, ItemCategory,
|
||||
ItemVariation, Order, OrderPosition, Question, QuestionOption, Quota,
|
||||
)
|
||||
from pretix.base.models.orders import OrderFee
|
||||
|
||||
@@ -225,6 +225,7 @@ TEST_ITEM_RES = {
|
||||
"picture": None,
|
||||
"available_from": None,
|
||||
"available_until": None,
|
||||
"require_bundling": False,
|
||||
"require_voucher": False,
|
||||
"hide_without_voucher": False,
|
||||
"allow_cancel": True,
|
||||
@@ -235,6 +236,7 @@ TEST_ITEM_RES = {
|
||||
"require_approval": False,
|
||||
"variations": [],
|
||||
"addons": [],
|
||||
"bundles": [],
|
||||
"original_price": None
|
||||
}
|
||||
|
||||
@@ -344,6 +346,25 @@ def test_item_detail_addons(token_client, organizer, event, team, item, category
|
||||
assert res == resp.data
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_item_detail_bundles(token_client, organizer, event, team, item, category):
|
||||
i = event.items.create(name="Included thing", default_price=2)
|
||||
item.bundles.create(bundled_item=i, count=1, designated_price=2)
|
||||
res = dict(TEST_ITEM_RES)
|
||||
|
||||
res["id"] = item.pk
|
||||
res["bundles"] = [{
|
||||
"bundled_item": i.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 1,
|
||||
"designated_price": '2.00',
|
||||
}]
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug,
|
||||
item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res == resp.data
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_item_create(token_client, organizer, event, item, category, taxrule):
|
||||
resp = token_client.post(
|
||||
@@ -601,7 +622,134 @@ def test_item_create_with_addon(token_client, organizer, event, item, category,
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_item_update(token_client, organizer, event, item, category, category2, taxrule2):
|
||||
def test_item_create_with_bundle(token_client, organizer, event, item, category, item2, taxrule):
|
||||
i = event.items.create(name="Included thing", default_price=2)
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"category": category.pk,
|
||||
"name": {
|
||||
"en": "Ticket"
|
||||
},
|
||||
"active": True,
|
||||
"description": None,
|
||||
"default_price": "23.00",
|
||||
"free_price": False,
|
||||
"tax_rate": "19.00",
|
||||
"tax_rule": taxrule.pk,
|
||||
"admission": True,
|
||||
"position": 0,
|
||||
"picture": None,
|
||||
"available_from": None,
|
||||
"available_until": None,
|
||||
"require_voucher": False,
|
||||
"hide_without_voucher": False,
|
||||
"allow_cancel": True,
|
||||
"min_per_order": None,
|
||||
"max_per_order": None,
|
||||
"checkin_attention": False,
|
||||
"has_variations": True,
|
||||
"bundles": [
|
||||
{
|
||||
"bundled_item": i.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 2,
|
||||
"designated_price": "3.00",
|
||||
}
|
||||
]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
item = Item.objects.get(pk=resp.data['id'])
|
||||
b = item.bundles.first()
|
||||
assert b.bundled_item == i
|
||||
assert b.bundled_variation is None
|
||||
assert b.count == 2
|
||||
assert b.designated_price == 3
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"category": category.pk,
|
||||
"name": {
|
||||
"en": "Ticket"
|
||||
},
|
||||
"active": True,
|
||||
"description": None,
|
||||
"default_price": "23.00",
|
||||
"free_price": False,
|
||||
"tax_rate": "19.00",
|
||||
"tax_rule": taxrule.pk,
|
||||
"admission": True,
|
||||
"position": 0,
|
||||
"picture": None,
|
||||
"available_from": None,
|
||||
"available_until": None,
|
||||
"require_voucher": False,
|
||||
"hide_without_voucher": False,
|
||||
"allow_cancel": True,
|
||||
"min_per_order": None,
|
||||
"max_per_order": None,
|
||||
"checkin_attention": False,
|
||||
"has_variations": True,
|
||||
"bundles": [
|
||||
{
|
||||
"bundled_item": item2.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 2,
|
||||
"designated_price": "3.00",
|
||||
}
|
||||
]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"bundles":["The bundled item must belong to the same event as the item."]}'
|
||||
|
||||
v = item2.variations.create(value="foo")
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/'.format(organizer.slug, event.slug),
|
||||
{
|
||||
"category": category.pk,
|
||||
"name": {
|
||||
"en": "Ticket"
|
||||
},
|
||||
"active": True,
|
||||
"description": None,
|
||||
"default_price": "23.00",
|
||||
"free_price": False,
|
||||
"tax_rate": "19.00",
|
||||
"tax_rule": taxrule.pk,
|
||||
"admission": True,
|
||||
"position": 0,
|
||||
"picture": None,
|
||||
"available_from": None,
|
||||
"available_until": None,
|
||||
"require_voucher": False,
|
||||
"hide_without_voucher": False,
|
||||
"allow_cancel": True,
|
||||
"min_per_order": None,
|
||||
"max_per_order": None,
|
||||
"checkin_attention": False,
|
||||
"has_variations": True,
|
||||
"bundles": [
|
||||
{
|
||||
"bundled_item": item.pk,
|
||||
"bundled_variation": v.pk,
|
||||
"count": 2,
|
||||
"designated_price": "3.00",
|
||||
}
|
||||
]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"bundles":["The chosen variation does not belong to this item."]}'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_item_update(token_client, organizer, event, item, category, item2, category2, taxrule2):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk),
|
||||
{
|
||||
@@ -673,7 +821,25 @@ def test_item_update(token_client, organizer, event, item, category, category2,
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons or variations via PATCH/PUT is not supported. Please use ' \
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons, bundles, or variations via PATCH/PUT is not supported. Please use ' \
|
||||
'the dedicated nested endpoint."]}'
|
||||
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/'.format(organizer.slug, event.slug, item.pk),
|
||||
{
|
||||
"bundles": [
|
||||
{
|
||||
"bundled_item": item2.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 2,
|
||||
"designated_price": "3.00",
|
||||
}
|
||||
]
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons, bundles, or variations via PATCH/PUT is not supported. Please use ' \
|
||||
'the dedicated nested endpoint."]}'
|
||||
|
||||
|
||||
@@ -699,7 +865,7 @@ def test_item_update_with_variation(token_client, organizer, event, item):
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons or variations via PATCH/PUT is not supported. Please use ' \
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons, bundles, or variations via PATCH/PUT is not supported. Please use ' \
|
||||
'the dedicated nested endpoint."]}'
|
||||
|
||||
|
||||
@@ -721,7 +887,7 @@ def test_item_update_with_addon(token_client, organizer, event, item, category):
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons or variations via PATCH/PUT is not supported. Please use ' \
|
||||
assert resp.content.decode() == '{"non_field_errors":["Updating add-ons, bundles, or variations via PATCH/PUT is not supported. Please use ' \
|
||||
'the dedicated nested endpoint."]}'
|
||||
|
||||
|
||||
@@ -922,6 +1088,123 @@ def test_only_variation_not_delete(token_client, organizer, event, item, variati
|
||||
assert item.variations.filter(pk=variation.id).exists()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def bundle(item, item3, category):
|
||||
return item.bundles.create(bundled_item=item3, count=1, designated_price=2)
|
||||
|
||||
|
||||
TEST_BUNDLE_RES = {
|
||||
"bundled_item": 0,
|
||||
"bundled_variation": None,
|
||||
"count": 1,
|
||||
"designated_price": "2.00"
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_bundles_list(token_client, organizer, event, item, bundle, item3):
|
||||
res = dict(TEST_BUNDLE_RES)
|
||||
res["id"] = bundle.pk
|
||||
res["bundled_item"] = item3.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug,
|
||||
item.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res == resp.data['results'][0]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_bundles_detail(token_client, organizer, event, item, bundle, item3):
|
||||
res = dict(TEST_BUNDLE_RES)
|
||||
res["id"] = bundle.pk
|
||||
res["bundled_item"] = item3.pk
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/bundles/{}/'.format(organizer.slug, event.slug,
|
||||
item.pk, bundle.pk))
|
||||
assert resp.status_code == 200
|
||||
assert res == resp.data
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_bundles_create(token_client, organizer, event, item, item2, item3):
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk),
|
||||
{
|
||||
"bundled_item": item3.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 1,
|
||||
"designated_price": "1.50",
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 201
|
||||
b = ItemBundle.objects.get(pk=resp.data['id'])
|
||||
assert b.bundled_item == item3
|
||||
assert b.bundled_variation is None
|
||||
assert b.designated_price == 1.5
|
||||
assert b.count == 1
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk),
|
||||
{
|
||||
"bundled_item": item2.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 1,
|
||||
"designated_price": "1.50",
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["The bundled item must belong to the same event as the item."]}'
|
||||
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk),
|
||||
{
|
||||
"bundled_item": item.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 1,
|
||||
"designated_price": "1.50",
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["The bundled item must not be the same item as the bundling one."]}'
|
||||
|
||||
item3.bundles.create(bundled_item=item, count=1, designated_price=3)
|
||||
resp = token_client.post(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/bundles/'.format(organizer.slug, event.slug, item.pk),
|
||||
{
|
||||
"bundled_item": item3.pk,
|
||||
"bundled_variation": None,
|
||||
"count": 1,
|
||||
"designated_price": "1.50",
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
assert resp.content.decode() == '{"non_field_errors":["The bundled item must not have bundles on its own."]}'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_bundles_update(token_client, organizer, event, item, bundle):
|
||||
resp = token_client.patch(
|
||||
'/api/v1/organizers/{}/events/{}/items/{}/bundles/{}/'.format(organizer.slug, event.slug, item.pk, bundle.pk),
|
||||
{
|
||||
"count": 3,
|
||||
},
|
||||
format='json'
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
a = ItemBundle.objects.get(pk=bundle.pk)
|
||||
assert a.count == 3
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_bundles_delete(token_client, organizer, event, item, bundle):
|
||||
resp = token_client.delete('/api/v1/organizers/{}/events/{}/items/{}/bundles/{}/'.format(organizer.slug, event.slug,
|
||||
item.pk, bundle.pk))
|
||||
assert resp.status_code == 204
|
||||
assert not item.bundles.filter(pk=bundle.id).exists()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def addon(item, category):
|
||||
return item.addons.create(addon_category=category, min_count=0, max_count=10, position=1)
|
||||
|
||||
Reference in New Issue
Block a user