forked from CGM_Public/pretix_original
1602 lines
70 KiB
Python
1602 lines
70 KiB
Python
#
|
|
# 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/>.
|
|
#
|
|
|
|
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
|
|
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
|
|
#
|
|
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
|
|
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
|
|
#
|
|
# This file contains Apache-licensed contributions copyrighted by: Flavia Bastos
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations under the License.
|
|
|
|
import datetime
|
|
from decimal import Decimal
|
|
|
|
from bs4 import BeautifulSoup
|
|
from django.test import TestCase
|
|
from django.utils.timezone import now
|
|
from django_scopes import scopes_disabled
|
|
from tests.base import extract_form_fields
|
|
|
|
from pretix.base.models import (
|
|
Event, Item, ItemAddOn, ItemCategory, ItemVariation, Order, OrderPosition,
|
|
Organizer, Question, Quota, SubEventItemVariation,
|
|
)
|
|
from pretix.base.models.orders import OrderPayment
|
|
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
|
|
|
|
|
class BaseOrdersTest(TestCase):
|
|
|
|
@scopes_disabled()
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.orga = Organizer.objects.create(name='CCC', slug='ccc')
|
|
self.event = Event.objects.create(
|
|
organizer=self.orga, name='30C3', slug='30c3',
|
|
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
|
presale_end=now() + datetime.timedelta(days=5),
|
|
plugins='pretix.plugins.stripe,pretix.plugins.banktransfer,tests.testdummy',
|
|
live=True
|
|
)
|
|
self.event.settings.set('payment_banktransfer__enabled', True)
|
|
self.event.settings.set('ticketoutput_testdummy__enabled', True)
|
|
|
|
self.tr = self.event.tax_rules.create(name="VAT", rate=10)
|
|
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
|
|
self.quota_shirts = Quota.objects.create(event=self.event, name='Shirts', size=2)
|
|
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', category=self.category, default_price=12)
|
|
self.quota_shirts.items.add(self.shirt)
|
|
self.shirt_red = ItemVariation.objects.create(item=self.shirt, default_price=14, value="Red")
|
|
self.shirt_blue = ItemVariation.objects.create(item=self.shirt, value="Blue")
|
|
self.quota_shirts.variations.add(self.shirt_red)
|
|
self.quota_shirts.variations.add(self.shirt_blue)
|
|
self.quota_tickets = Quota.objects.create(event=self.event, name='Tickets', size=5)
|
|
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket',
|
|
category=self.category, default_price=23,
|
|
admission=True)
|
|
self.quota_tickets.items.add(self.ticket)
|
|
self.event.settings.set('attendee_names_asked', True)
|
|
self.question = Question.objects.create(question='Foo', type=Question.TYPE_STRING, event=self.event,
|
|
required=False)
|
|
self.ticket.questions.add(self.question)
|
|
|
|
self.order = Order.objects.create(
|
|
status=Order.STATUS_PENDING,
|
|
event=self.event,
|
|
email='admin@localhost',
|
|
datetime=now() - datetime.timedelta(days=3),
|
|
expires=now() + datetime.timedelta(days=11),
|
|
total=Decimal("23"),
|
|
locale='en'
|
|
)
|
|
self.ticket_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.ticket,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.deleted_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.ticket,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={'full_name': "Lukas"},
|
|
canceled=True
|
|
)
|
|
|
|
|
|
class OrderChangeVariationTest(BaseOrdersTest):
|
|
def test_change_not_allowed(self):
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 302
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
|
)
|
|
assert response.status_code == 302
|
|
|
|
def test_change_variation_paid(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_red,
|
|
price=Decimal("14"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_blue.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
self.assertRedirects(response,
|
|
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
|
self.order.secret),
|
|
target_status_code=200)
|
|
shirt_pos.refresh_from_db()
|
|
assert shirt_pos.variation == self.shirt_blue
|
|
assert shirt_pos.price == Decimal('12.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.status == Order.STATUS_PENDING
|
|
assert self.order.total == Decimal('35.00')
|
|
|
|
# Attendee is not allowed
|
|
response = self.client.get(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (
|
|
self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
|
)
|
|
assert response.status_code == 302
|
|
|
|
def test_change_variation_require_higher_price(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'gt'
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_red,
|
|
price=Decimal("14"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_blue.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
shirt_pos.variation = self.shirt_blue
|
|
shirt_pos.price = Decimal('12.00')
|
|
shirt_pos.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
self.assertRedirects(response,
|
|
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
|
self.order.secret),
|
|
target_status_code=200)
|
|
shirt_pos.refresh_from_db()
|
|
assert shirt_pos.variation == self.shirt_red
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.status == Order.STATUS_PENDING
|
|
assert self.order.total == Decimal('37.00')
|
|
|
|
shirt_pos.variation = self.shirt_blue
|
|
shirt_pos.price = Decimal('14.00')
|
|
shirt_pos.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
},
|
|
follow=True
|
|
)
|
|
shirt_pos.refresh_from_db()
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert shirt_pos.variation == self.shirt_blue
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
|
|
def test_change_variation_require_higher_equal_price(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'gte'
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_red,
|
|
price=Decimal("14"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_blue.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
shirt_pos.variation = self.shirt_blue
|
|
shirt_pos.price = Decimal('12.00')
|
|
shirt_pos.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
self.assertRedirects(response,
|
|
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
|
self.order.secret),
|
|
target_status_code=200)
|
|
shirt_pos.refresh_from_db()
|
|
assert shirt_pos.variation == self.shirt_red
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.status == Order.STATUS_PENDING
|
|
assert self.order.total == Decimal('37.00')
|
|
|
|
shirt_pos.variation = self.shirt_blue
|
|
shirt_pos.price = Decimal('14.00')
|
|
shirt_pos.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
shirt_pos.refresh_from_db()
|
|
assert 'alert-success' in response.content.decode()
|
|
assert shirt_pos.variation == self.shirt_red
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
|
|
def test_change_variation_require_equal_price(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'eq'
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
price=Decimal("12"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
def test_change_variation_require_same_product(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
price=Decimal("12"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
def test_change_variation_hidden_variations(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
self.shirt_red.value = "RED SHIRT"
|
|
self.shirt_red.hide_without_voucher = True
|
|
self.shirt_red.save()
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
price=Decimal("12"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'RED SHIRT' not in response.content.decode()
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
def test_change_variation_hidden_variations_with_voucher(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
self.shirt_red.value = "RED SHIRT"
|
|
self.shirt_red.hide_without_voucher = True
|
|
self.shirt_red.save()
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
voucher=self.event.vouchers.create(code="ABCDE", item=self.shirt),
|
|
price=Decimal("12"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'RED SHIRT' in response.content.decode()
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
shirt_pos.refresh_from_db()
|
|
assert 'alert-success' in response.content.decode()
|
|
assert shirt_pos.variation == self.shirt_red
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
|
|
def test_change_variation_hidden_variations_with_useless_voucher(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
self.shirt_red.value = "RED SHIRT"
|
|
self.shirt_red.hide_without_voucher = True
|
|
self.shirt_red.save()
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
voucher=self.event.vouchers.create(code="ABCDE", item=self.shirt, show_hidden_items=False),
|
|
price=Decimal("12"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'RED SHIRT' not in response.content.decode()
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
def test_change_variation_require_quota(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
|
|
with scopes_disabled():
|
|
q = self.event.quotas.create(name="s2", size=0)
|
|
q.items.add(self.shirt)
|
|
q.variations.add(self.shirt_red)
|
|
|
|
with scopes_disabled():
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
price=Decimal("12"),
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
assert response.status_code == 200
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
q.variations.add(self.shirt_blue)
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
}, follow=True)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
self.assertRedirects(response,
|
|
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
|
self.order.secret),
|
|
target_status_code=200)
|
|
shirt_pos.refresh_from_db()
|
|
assert shirt_pos.variation == self.shirt_red
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
|
|
def test_change_paid_to_pending(self):
|
|
self.event.settings.change_allow_user_variation = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
self.order.status = Order.STATUS_PAID
|
|
self.order.save()
|
|
|
|
with scopes_disabled():
|
|
self.order.payments.create(provider="manual", amount=Decimal('35.00'), state=OrderPayment.PAYMENT_STATE_CONFIRMED)
|
|
shirt_pos = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.shirt,
|
|
variation=self.shirt_blue,
|
|
price=Decimal("12"),
|
|
)
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'op-{shirt_pos.pk}-itemvar': f'{self.shirt.pk}-{self.shirt_red.pk}',
|
|
f'op-{self.ticket_pos.pk}-itemvar': f'{self.ticket.pk}',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
self.assertRedirects(response,
|
|
'/%s/%s/order/%s/%s/pay/change' % (self.orga.slug, self.event.slug, self.order.code,
|
|
self.order.secret),
|
|
target_status_code=200)
|
|
assert 'The order has been changed. You can now proceed by paying the open amount of €2.00.' in response.content.decode()
|
|
shirt_pos.refresh_from_db()
|
|
assert shirt_pos.variation == self.shirt_red
|
|
assert shirt_pos.price == Decimal('14.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.status == Order.STATUS_PENDING
|
|
assert self.order.pending_sum == Decimal('2.00')
|
|
|
|
|
|
class OrderChangeAddonsTest(BaseOrdersTest):
|
|
|
|
@scopes_disabled()
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
self.workshopcat = ItemCategory.objects.create(name="Workshops", is_addon=True, event=self.event)
|
|
self.workshopquota = Quota.objects.create(event=self.event, name='Workshop 1', size=5)
|
|
self.workshop1 = Item.objects.create(event=self.event, name='Workshop 1',
|
|
category=self.workshopcat, default_price=Decimal('12.00'),
|
|
tax_rule=self.tr)
|
|
self.workshop2 = Item.objects.create(event=self.event, name='Workshop 2',
|
|
category=self.workshopcat, default_price=Decimal('12.00'),
|
|
tax_rule=self.tr)
|
|
self.workshop2a = ItemVariation.objects.create(item=self.workshop2, value='Workshop 2a')
|
|
self.workshop2b = ItemVariation.objects.create(item=self.workshop2, value='Workshop 2b')
|
|
self.workshopquota.items.add(self.workshop1)
|
|
self.workshopquota.items.add(self.workshop2)
|
|
self.workshopquota.variations.add(self.workshop2a)
|
|
self.workshopquota.variations.add(self.workshop2b)
|
|
self.iao = ItemAddOn.objects.create(
|
|
base_item=self.ticket, addon_category=self.workshopcat, max_count=1, min_count=0, multi_allowed=False
|
|
)
|
|
self.event.settings.change_allow_user_addons = True
|
|
self.event.settings.change_allow_user_price = 'any'
|
|
|
|
def test_disabled(self):
|
|
self.event.settings.change_allow_user_addons = False
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 302
|
|
|
|
def test_no_config(self):
|
|
self.iao.base_item = self.shirt
|
|
self.iao.save()
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 302
|
|
|
|
def test_no_change(self):
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-info' in response.content.decode()
|
|
|
|
def test_add_addon(self):
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
new_pos = self.ticket_pos.addons.get()
|
|
assert new_pos.item == self.workshop1
|
|
assert new_pos.price == Decimal('12.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('35.00')
|
|
|
|
def test_add_addon_free_price(self):
|
|
self.workshop1.free_price = True
|
|
self.workshop1.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}': '1',
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}_price': '50.00',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
new_pos = self.ticket_pos.addons.get()
|
|
assert new_pos.item == self.workshop1
|
|
assert new_pos.price == Decimal('50.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('73.00')
|
|
|
|
def test_add_addon_free_price_net(self):
|
|
self.event.settings.display_net_prices = True
|
|
self.workshop1.free_price = True
|
|
self.workshop1.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}': '1',
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}_price': '50.00',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
new_pos = self.ticket_pos.addons.get()
|
|
assert new_pos.item == self.workshop1
|
|
assert new_pos.price == Decimal('55.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('78.00')
|
|
|
|
def test_remove_addon(self):
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['checked']
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get()
|
|
assert a.canceled
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('23.00')
|
|
|
|
def test_increase_existing_addon_free_price_net(self):
|
|
self.event.settings.display_net_prices = True
|
|
self.iao.multi_allowed = True
|
|
self.iao.max_count = 2
|
|
self.iao.save()
|
|
self.workshop1.free_price = True
|
|
self.workshop1.save()
|
|
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("55"),
|
|
tax_rule=self.tr,
|
|
tax_rate=Decimal("10"),
|
|
tax_value=Decimal("5"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("55")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['value'] == '1'
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}_price]')[0].attrs['value'] == '50.00'
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}': '2',
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}_price': '100.00',
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
# only the price of the new addon is changed!
|
|
assert self.ticket_pos.addons.count() == 2
|
|
a = self.ticket_pos.addons.first()
|
|
assert a.item == self.workshop1
|
|
assert a.price == Decimal('55.00')
|
|
a = self.ticket_pos.addons.last()
|
|
assert a.item == self.workshop1
|
|
assert a.price == Decimal('110.00')
|
|
|
|
def test_change_addon(self):
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['checked']
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
# todo: should this keep questions?
|
|
a = self.ticket_pos.addons.get(canceled=False)
|
|
assert a.item == self.workshop2
|
|
assert a.variation == self.workshop2a
|
|
|
|
def test_paid_to_pending_expiry_date(self):
|
|
self.order.status = Order.STATUS_PAID
|
|
self.order.expires = now() - datetime.timedelta(days=12)
|
|
self.order.save()
|
|
with scopes_disabled():
|
|
self.order.payments.create(
|
|
provider="manual",
|
|
amount=self.order.total,
|
|
state=OrderPayment.PAYMENT_STATE_CONFIRMED,
|
|
)
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
new_pos = self.ticket_pos.addons.get()
|
|
assert new_pos.item == self.workshop1
|
|
assert new_pos.price == Decimal('12.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('35.00')
|
|
assert self.order.pending_sum == Decimal('12.00')
|
|
assert self.order.expires > now()
|
|
|
|
def test_quota_sold_out(self):
|
|
self.workshopquota.size = 0
|
|
self.workshopquota.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert not doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
assert self.ticket_pos.addons.count() == 0
|
|
|
|
def test_quota_hide_sold_out_do_not_hide_initial(self):
|
|
self.event.settings.hide_sold_out = True
|
|
self.workshopquota.size = 1
|
|
self.workshopquota.save()
|
|
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
assert 'Workshop 2' not in response.content.decode()
|
|
|
|
def test_quota_sold_out_replace(self):
|
|
self.workshopquota.size = 1
|
|
self.workshopquota.save()
|
|
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['checked']
|
|
# TODO: Technically, it is allowed to do this change, although the frontend currently does not allow it
|
|
# We test for the backend behaviour anyways
|
|
assert not doc.select(f'input[name=cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get(canceled=False)
|
|
assert a.item == self.workshop2
|
|
assert a.variation == self.workshop2a
|
|
|
|
def _assert_ws2a_not_allowed(self):
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 2a' not in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert not doc.select(f'input[name=cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}]')
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode() or 'alert-info' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
assert self.ticket_pos.addons.count() == 0
|
|
|
|
def test_voucher_required(self):
|
|
self.workshop2.require_voucher = True
|
|
self.workshop2.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_require_bundling(self):
|
|
self.workshop2.require_bundling = True
|
|
self.workshop2.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_sales_channel(self):
|
|
self.workshop2.sales_channels = ['pretixpos']
|
|
self.workshop2.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_var_sales_channel(self):
|
|
self.workshop2a.sales_channels = ['pretixpos']
|
|
self.workshop2a.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_inactive(self):
|
|
self.workshop2.active = False
|
|
self.workshop2.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_var_inactive(self):
|
|
self.workshop2a.active = False
|
|
self.workshop2a.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_over(self):
|
|
self.workshop2.available_until = now() - datetime.timedelta(days=3)
|
|
self.workshop2.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_var_over(self):
|
|
self.workshop2a.available_until = now() - datetime.timedelta(days=3)
|
|
self.workshop2a.save()
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_forbidden_membership(self):
|
|
self.workshop2a.require_membership = True
|
|
self.workshop2a.save()
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
@scopes_disabled()
|
|
def _subevent_setup(self):
|
|
self.event.has_subevents = True
|
|
self.event.save()
|
|
se = self.event.subevents.create(name="Date", date_from=now())
|
|
self.ticket_pos.subevent = se
|
|
self.ticket_pos.save()
|
|
self.workshopquota.subevent = se
|
|
self.workshopquota.save()
|
|
return se
|
|
|
|
def test_forbidden_disabled_for_subevent(self):
|
|
se = self._subevent_setup()
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 2' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}]')
|
|
|
|
SubEventItemVariation.objects.create(subevent=se, variation=self.workshop2a, disabled=True)
|
|
|
|
self._assert_ws2a_not_allowed()
|
|
|
|
def test_presale_has_ended(self):
|
|
self.event.presale_end = now() - datetime.timedelta(days=1)
|
|
self.event.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 2a' in response.content.decode()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'has ended' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
assert self.ticket_pos.addons.count() == 0
|
|
|
|
def test_presale_last_payment_term_only_relevant_if_additional_charge(self):
|
|
self.order.status = Order.STATUS_PAID
|
|
self.order.save()
|
|
self._subevent_setup()
|
|
self.event.settings.set('payment_term_last', RelativeDateWrapper(
|
|
RelativeDate(days_before=2, time=None, base_date_name='date_from', minutes_before=None)
|
|
))
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 2a' in response.content.decode()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'no longer being accepted' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
assert self.ticket_pos.addons.count() == 0
|
|
|
|
self.workshop2a.default_price = Decimal('0.00')
|
|
self.workshop2a.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
new_pos = self.ticket_pos.addons.get()
|
|
assert new_pos.item == self.workshop2
|
|
assert new_pos.price == Decimal('0.00')
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('23.00')
|
|
|
|
def test_multi_allowed_and_max_count_enforced(self):
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '2'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
self.iao.max_count = 2
|
|
self.iao.multi_allowed = True
|
|
self.iao.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '2'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' not in response.content.decode()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '3'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
def test_min_count_enforced(self):
|
|
self.iao.min_count = 1
|
|
self.iao.save()
|
|
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['checked']
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
|
|
def test_allow_user_price_gte(self):
|
|
self.event.settings.change_allow_user_price = 'gte'
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'reduces' in response.content.decode()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
'confirm': 'true'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'reduces' in response.content.decode()
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('35.00')
|
|
|
|
def test_allow_user_price_eq(self):
|
|
self.event.settings.change_allow_user_price = 'eq'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'changes' in response.content.decode()
|
|
|
|
self.workshop2a.default_price = Decimal('0.00')
|
|
self.workshop2a.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' not in response.content.decode()
|
|
|
|
def test_allow_user_price_gt(self):
|
|
self.event.settings.change_allow_user_price = 'gt'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' not in response.content.decode()
|
|
|
|
self.workshop2a.default_price = Decimal('0.00')
|
|
self.workshop2a.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'increases' in response.content.decode()
|
|
|
|
def test_ignore_bundled_positions(self):
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop2,
|
|
variation=self.workshop2a,
|
|
is_bundled=True,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
|
)
|
|
assert response.status_code == 200
|
|
assert 'Workshop 1' in response.content.decode()
|
|
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
assert doc.select(f'input[name=cp_{self.ticket_pos.pk}_item_{self.workshop1.pk}]')[0].attrs['checked']
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
|
{
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get(item=self.workshop1)
|
|
assert a.canceled
|
|
a = self.ticket_pos.addons.get(item=self.workshop2)
|
|
assert not a.canceled
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('35.00')
|
|
|
|
def test_refund_auto(self):
|
|
self.event.settings.cancel_allow_user_paid_refund_as_giftcard = 'off'
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.status = Order.STATUS_PAID
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED)
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get()
|
|
assert a.canceled
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('23.00')
|
|
assert self.order.refunds.exists()
|
|
|
|
def test_refund_manually(self):
|
|
self.event.settings.cancel_allow_user_paid_refund_as_giftcard = 'manually'
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.status = Order.STATUS_PAID
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED)
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get()
|
|
assert a.canceled
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('23.00')
|
|
assert not self.order.refunds.exists()
|
|
|
|
def test_refund_giftcard(self):
|
|
self.event.settings.cancel_allow_user_paid_refund_as_giftcard = 'force'
|
|
with scopes_disabled():
|
|
OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("12"),
|
|
addon_to=self.ticket_pos,
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.order.status = Order.STATUS_PAID
|
|
self.order.total += Decimal("12")
|
|
self.order.save()
|
|
self.order.payments.create(provider='testdummy_partialrefund', amount=self.order.total, state=OrderPayment.PAYMENT_STATE_CONFIRMED)
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), {}, follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get()
|
|
assert a.canceled
|
|
self.order.refresh_from_db()
|
|
assert self.order.total == Decimal('23.00')
|
|
r = self.order.refunds.get()
|
|
assert r.provider == 'giftcard'
|
|
|
|
def test_attendee(self):
|
|
self.workshop2a.default_price = Decimal('0.00')
|
|
self.workshop2a.save()
|
|
self.event.settings.change_allow_attendee = True
|
|
response = self.client.post(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
self.client.post(
|
|
'/%s/%s/order/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret), form_data, follow=True
|
|
)
|
|
|
|
with scopes_disabled():
|
|
a = self.ticket_pos.addons.get()
|
|
assert a.variation == self.workshop2a
|
|
|
|
def test_attendee_limited_to_own_ticket(self):
|
|
with scopes_disabled():
|
|
ticket_pos2 = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.ticket,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
self.event.settings.change_allow_attendee = True
|
|
response = self.client.post(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
{
|
|
f'cp_{ticket_pos2.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'did not make any changes' in response.content.decode()
|
|
|
|
def test_attendee_needs_to_keep_price(self):
|
|
self.event.settings.change_allow_user_price = 'any' # ignored, for attendees its always "eq"
|
|
self.event.settings.change_allow_attendee = True
|
|
response = self.client.post(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' in response.content.decode()
|
|
assert 'changes' in response.content.decode()
|
|
|
|
self.workshop2a.default_price = Decimal('0.00')
|
|
self.workshop2a.save()
|
|
|
|
response = self.client.post(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
{
|
|
f'cp_{self.ticket_pos.pk}_variation_{self.workshop2.pk}_{self.workshop2a.pk}': '1'
|
|
},
|
|
follow=True
|
|
)
|
|
assert 'alert-danger' not in response.content.decode()
|
|
|
|
def test_attendee_price_hidden(self):
|
|
self.event.settings.change_allow_attendee = True
|
|
response = self.client.get(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
follow=True
|
|
)
|
|
assert '€' not in response.content.decode()
|
|
self.event.settings.hide_prices_from_attendees = False
|
|
response = self.client.get(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
follow=True
|
|
)
|
|
assert '€' in response.content.decode()
|
|
|
|
def test_attendee_change_of_addons_does_not_affect_other_positions(self):
|
|
with scopes_disabled():
|
|
ticket_pos2 = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.ticket,
|
|
variation=None,
|
|
price=Decimal("23"),
|
|
attendee_name_parts={'full_name': "Peter"}
|
|
)
|
|
a1 = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("0"),
|
|
addon_to=self.ticket_pos,
|
|
)
|
|
a2 = OrderPosition.objects.create(
|
|
order=self.order,
|
|
item=self.workshop1,
|
|
variation=None,
|
|
price=Decimal("0"),
|
|
addon_to=ticket_pos2,
|
|
)
|
|
|
|
self.event.settings.change_allow_attendee = True
|
|
|
|
response = self.client.get(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
)
|
|
doc = BeautifulSoup(response.content.decode(), "lxml")
|
|
form_data = extract_form_fields(doc.select('.main-box form')[0])
|
|
form_data['confirm'] = 'true'
|
|
response = self.client.post(
|
|
'/%s/%s/ticket/%s/%s/%s/change' % (self.orga.slug, self.event.slug, self.order.code, self.ticket_pos.positionid, self.ticket_pos.web_secret),
|
|
form_data, follow=True
|
|
)
|
|
assert 'alert-success' in response.content.decode()
|
|
|
|
a1.refresh_from_db()
|
|
a2.refresh_from_db()
|
|
assert not a1.canceled
|
|
assert not a2.canceled
|