forked from CGM_Public/pretix_original
@@ -6,10 +6,12 @@ from bs4 import BeautifulSoup
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.utils.timezone import now
|
||||
from django_countries.fields import Country
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, Item, ItemCategory, ItemVariation, Organizer,
|
||||
Question, QuestionAnswer, Quota, Voucher,
|
||||
CartPosition, Event, InvoiceAddress, Item, ItemCategory, ItemVariation,
|
||||
Organizer, Question, QuestionAnswer, Quota, Voucher,
|
||||
)
|
||||
from pretix.base.models.items import (
|
||||
ItemAddOn, SubEventItem, SubEventItemVariation,
|
||||
@@ -26,9 +28,11 @@ class CartTestMixin:
|
||||
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
|
||||
live=True
|
||||
)
|
||||
self.tr19 = self.event.tax_rules.create(rate=19)
|
||||
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.shirt = Item.objects.create(event=self.event, name='T-Shirt', category=self.category, default_price=12,
|
||||
tax_rule=self.tr19)
|
||||
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')
|
||||
@@ -36,7 +40,8 @@ class CartTestMixin:
|
||||
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)
|
||||
category=self.category, default_price=23,
|
||||
tax_rule=self.tr19)
|
||||
self.quota_tickets.items.add(self.ticket)
|
||||
|
||||
self.quota_all = Quota.objects.create(event=self.event, name='All', size=None)
|
||||
@@ -90,6 +95,35 @@ class CartTest(CartTestMixin, TestCase):
|
||||
self.assertIsNone(objs[0].variation)
|
||||
self.assertEqual(objs[0].price, 23)
|
||||
|
||||
def _set_session(self, key, value):
|
||||
session = self.client.session
|
||||
session[key] = value
|
||||
session.save()
|
||||
|
||||
def _enable_reverse_charge(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
ia = InvoiceAddress.objects.create(
|
||||
is_business=True, vat_id='ATU1234567', vat_id_validated=True,
|
||||
country=Country('AT')
|
||||
)
|
||||
self._set_session('invoice_address_{}'.format(self.event.pk), ia.pk)
|
||||
return ia
|
||||
|
||||
def test_reverse_charge(self):
|
||||
self._enable_reverse_charge()
|
||||
response = self.client.post('/%s/%s/cart/add' % (self.orga.slug, self.event.slug), {
|
||||
'item_%d' % self.ticket.id: '1'
|
||||
}, follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
doc = BeautifulSoup(response.rendered_content, "lxml")
|
||||
self.assertIn('Early-bird', doc.select('.cart .cart-row')[0].select('strong')[0].text)
|
||||
objs = list(CartPosition.objects.filter(cart_id=self.session_key, event=self.event))
|
||||
self.assertEqual(len(objs), 1)
|
||||
self.assertEqual(objs[0].price, round_decimal(Decimal('23.00') / Decimal('1.19')))
|
||||
|
||||
def test_subevent_missing(self):
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
|
||||
@@ -2,16 +2,19 @@ import datetime
|
||||
import os
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from unittest import mock
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from django.conf import settings
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.test import TestCase
|
||||
from django.utils.timezone import now
|
||||
from django_countries.fields import Country
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import (
|
||||
CartPosition, Event, Item, ItemCategory, Order, OrderPosition, Organizer,
|
||||
Question, Quota, Voucher,
|
||||
CartPosition, Event, InvoiceAddress, Item, ItemCategory, Order,
|
||||
OrderPosition, Organizer, Question, Quota, Voucher,
|
||||
)
|
||||
from pretix.base.models.items import ItemAddOn, ItemVariation, SubEventItem
|
||||
|
||||
@@ -26,10 +29,12 @@ class CheckoutTestCase(TestCase):
|
||||
plugins='pretix.plugins.stripe,pretix.plugins.banktransfer',
|
||||
live=True
|
||||
)
|
||||
self.tr19 = self.event.tax_rules.create(rate=19)
|
||||
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
|
||||
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)
|
||||
category=self.category, default_price=23, admission=True,
|
||||
tax_rule=self.tr19)
|
||||
self.quota_tickets.items.add(self.ticket)
|
||||
self.event.settings.set('attendee_names_asked', False)
|
||||
self.event.settings.set('payment_banktransfer__enabled', True)
|
||||
@@ -51,6 +56,17 @@ class CheckoutTestCase(TestCase):
|
||||
self.workshopquota.variations.add(self.workshop2a)
|
||||
self.workshopquota.variations.add(self.workshop2b)
|
||||
|
||||
def _enable_reverse_charge(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
ia = InvoiceAddress.objects.create(
|
||||
is_business=True, vat_id='ATU1234567', vat_id_validated=True,
|
||||
country=Country('AT')
|
||||
)
|
||||
self._set_session('invoice_address_{}'.format(self.event.pk), ia.pk)
|
||||
return ia
|
||||
|
||||
def test_empty_cart(self):
|
||||
response = self.client.get('/%s/%s/checkout/start' % (self.orga.slug, self.event.slug), follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/' % (self.orga.slug, self.event.slug),
|
||||
@@ -112,6 +128,218 @@ class CheckoutTestCase(TestCase):
|
||||
self.assertEqual(cr1.answers.filter(question=q2).count(), 1)
|
||||
self.assertFalse(cr2.answers.filter(question=q2).exists())
|
||||
|
||||
def test_reverse_charge(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
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 == round_decimal(Decimal('23.00') / Decimal('1.19'))
|
||||
|
||||
ia = InvoiceAddress.objects.get(pk=self.client.session.get('invoice_address_{}'.format(self.event.pk)))
|
||||
assert ia.vat_id_validated
|
||||
|
||||
def test_reverse_charge_enable_then_disable(self):
|
||||
self.test_reverse_charge()
|
||||
|
||||
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': 'individual',
|
||||
'name': 'Bar',
|
||||
'street': 'Baz',
|
||||
'zipcode': '12345',
|
||||
'city': 'Here',
|
||||
'country': 'AT',
|
||||
'vat_id': '',
|
||||
'email': 'admin@localhost'
|
||||
}, follow=True)
|
||||
|
||||
cr = CartPosition.objects.get(cart_id=self.session_key)
|
||||
assert cr.price == Decimal('23.00')
|
||||
|
||||
ia = InvoiceAddress.objects.get(pk=self.client.session.get('invoice_address_{}'.format(self.event.pk)))
|
||||
assert not ia.vat_id_validated
|
||||
|
||||
def test_reverse_charge_invalid_vatid(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
with mock.patch('vat_moss.id.validate') as mock_validate:
|
||||
def raiser(*args, **kwargs):
|
||||
import vat_moss.errors
|
||||
raise vat_moss.errors.InvalidError()
|
||||
|
||||
mock_validate.side_effect = raiser
|
||||
resp = 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)
|
||||
assert 'alert-danger' in resp.rendered_content
|
||||
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == Decimal('23.00')
|
||||
|
||||
def test_reverse_charge_vatid_non_eu(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('NO')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
with mock.patch('vat_moss.id.validate') as mock_validate:
|
||||
mock_validate.return_value = ('AU', 'AU123456', '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': 'AU',
|
||||
'vat_id': 'AU123456',
|
||||
'email': 'admin@localhost'
|
||||
}, follow=True)
|
||||
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == round_decimal(Decimal('23.00') / Decimal('1.19'))
|
||||
|
||||
ia = InvoiceAddress.objects.get(pk=self.client.session.get('invoice_address_{}'.format(self.event.pk)))
|
||||
assert not ia.vat_id_validated
|
||||
|
||||
def test_reverse_charge_vatid_same_country(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('AT')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
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('23.00')
|
||||
|
||||
ia = InvoiceAddress.objects.get(pk=self.client.session.get('invoice_address_{}'.format(self.event.pk)))
|
||||
assert ia.vat_id_validated
|
||||
|
||||
def test_reverse_charge_vatid_check_invalid_country(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
with mock.patch('vat_moss.id.validate') as mock_validate:
|
||||
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
|
||||
resp = 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': 'FR',
|
||||
'vat_id': 'AT123456',
|
||||
'email': 'admin@localhost'
|
||||
}, follow=True)
|
||||
assert 'alert-danger' in resp.rendered_content
|
||||
|
||||
cr1.refresh_from_db()
|
||||
assert cr1.price == Decimal('23.00')
|
||||
|
||||
def test_reverse_charge_vatid_check_unavailable(self):
|
||||
self.tr19.eu_reverse_charge = True
|
||||
self.tr19.home_country = Country('DE')
|
||||
self.tr19.save()
|
||||
self.event.settings.invoice_address_vatid = True
|
||||
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
price=23, expires=now() + timedelta(minutes=10)
|
||||
)
|
||||
|
||||
with mock.patch('vat_moss.id.validate') as mock_validate:
|
||||
def raiser(*args, **kwargs):
|
||||
import vat_moss.errors
|
||||
raise vat_moss.errors.WebServiceUnavailableError('Fail')
|
||||
|
||||
mock_validate.side_effect = raiser
|
||||
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('23.00')
|
||||
|
||||
ia = InvoiceAddress.objects.get(pk=self.client.session.get('invoice_address_{}'.format(self.event.pk)))
|
||||
assert not ia.vat_id_validated
|
||||
|
||||
def test_question_file_upload(self):
|
||||
q1 = Question.objects.create(
|
||||
event=self.event, question='Student ID', type=Question.TYPE_FILE,
|
||||
@@ -426,6 +654,22 @@ class CheckoutTestCase(TestCase):
|
||||
self.assertEqual(len(doc.select(".thank-you")), 1)
|
||||
self.assertEqual(OrderPosition.objects.filter(item=self.workshop1).last().price, 0)
|
||||
|
||||
def test_confirm_price_changed_reverse_charge(self):
|
||||
self._enable_reverse_charge()
|
||||
self.ticket.default_price = 24
|
||||
self.ticket.save()
|
||||
cr1 = CartPosition.objects.create(
|
||||
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||
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.rendered_content, "lxml")
|
||||
self.assertEqual(len(doc.select(".alert-danger")), 1)
|
||||
cr1 = CartPosition.objects.get(id=cr1.id)
|
||||
self.assertEqual(cr1.price, round_decimal(Decimal('24.00') / Decimal('1.19')))
|
||||
|
||||
def test_confirm_price_changed(self):
|
||||
self.ticket.default_price = 24
|
||||
self.ticket.save()
|
||||
@@ -1018,9 +1262,9 @@ class CheckoutTestCase(TestCase):
|
||||
self.workshopquota.size = 1
|
||||
self.workshopquota.subevent = se
|
||||
self.workshopquota.save()
|
||||
self.workshop1.tax_rate = 19
|
||||
self.workshop1.tax_rule = self.event.tax_rules.get_or_create(rate=Decimal('19.00'), name="VAT")[0]
|
||||
self.workshop1.save()
|
||||
self.workshop2.tax_rate = 19
|
||||
self.workshop2.tax_rule = self.event.tax_rules.get_or_create(rate=Decimal('19.00'), name="VAT")[0]
|
||||
self.workshop2.save()
|
||||
SubEventItem.objects.create(subevent=se, item=self.workshop1, price=42)
|
||||
|
||||
@@ -1033,8 +1277,8 @@ class CheckoutTestCase(TestCase):
|
||||
response = self.client.get('/%s/%s/checkout/questions/' % (self.orga.slug, self.event.slug), follow=True)
|
||||
self.assertRedirects(response, '/%s/%s/checkout/addons/' % (self.orga.slug, self.event.slug),
|
||||
target_status_code=200)
|
||||
assert 'Workshop 1 (+ EUR 35.29 plus 19.00% taxes)' in response.rendered_content
|
||||
assert 'A (+ EUR 10.08 plus 19.00% taxes)' in response.rendered_content
|
||||
assert 'Workshop 1 (+ EUR 35.29 plus 19.00% VAT)' in response.rendered_content
|
||||
assert 'A (+ EUR 10.08 plus 19.00% VAT)' in response.rendered_content
|
||||
|
||||
def test_confirm_subevent_presale_not_yet(self):
|
||||
self.event.has_subevents = True
|
||||
|
||||
@@ -215,8 +215,9 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
|
||||
self.event.settings.display_net_prices = True
|
||||
se1 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
|
||||
tr = self.event.tax_rules.get_or_create(rate=Decimal('19.00'))[0]
|
||||
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=15,
|
||||
tax_rate=19)
|
||||
tax_rule=tr)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
q.items.add(item)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se2)
|
||||
@@ -463,7 +464,7 @@ class VoucherRedeemItemDisplayTest(EventTestMixin, SoupTest):
|
||||
self.event.settings.display_net_prices = True
|
||||
self.event.has_subevents = True
|
||||
self.event.save()
|
||||
self.item.tax_rate = 19
|
||||
self.item.tax_rule = self.event.tax_rules.get_or_create(rate=Decimal('19.00'))[0]
|
||||
self.item.save()
|
||||
se1 = self.event.subevents.create(name='SE1', date_from=now(), active=True)
|
||||
q = Quota.objects.create(event=self.event, name='Quota', size=2, subevent=se1)
|
||||
|
||||
Reference in New Issue
Block a user