Tax rules and reverse charge (#559)

Tax rules and reverse charge
This commit is contained in:
Raphael Michel
2017-08-23 13:13:16 +03:00
committed by GitHub
parent b9ec5ea83c
commit 56338be13e
82 changed files with 2934 additions and 428 deletions

View File

@@ -53,3 +53,8 @@ def subevent(event):
event.save()
return event.subevents.create(name="Foobar",
date_from=datetime(2017, 12, 27, 10, 0, 0, tzinfo=UTC))
@pytest.fixture
def taxrule(event):
return event.tax_rules.create(name="VAT", rate=19)

View File

@@ -63,6 +63,7 @@ TEST_ITEM_RES = {
"description": None,
"free_price": False,
"tax_rate": "0.00",
"tax_rule": None,
"admission": False,
"position": 0,
"picture": None,

View File

@@ -54,6 +54,7 @@ TEST_ORDERPOSITION_RES = {
"voucher": None,
"tax_rate": "0.00",
"tax_value": "0.00",
"tax_rule": None,
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
"addon_to": None,
"checkins": [],
@@ -74,17 +75,20 @@ TEST_ORDER_RES = {
"payment_fee": "0.00",
"payment_fee_tax_rate": "0.00",
"payment_fee_tax_value": "0.00",
"payment_fee_tax_rule": None,
"total": "23.00",
"comment": "",
"invoice_address": {
"last_modified": "2017-12-01T10:00:00Z",
"is_business": False,
"company": "Sample company",
"name": "",
"street": "",
"zipcode": "",
"city": "",
"country": "NZ",
"vat_id": ""
"vat_id": "",
"vat_id_validated": False
},
"positions": [TEST_ORDERPOSITION_RES],
"downloads": []
@@ -268,11 +272,15 @@ TEST_INVOICE_RES = {
"additional_text": "",
"payment_provider_text": "",
"footer_text": "",
"foreign_currency_display": None,
"foreign_currency_rate": None,
"foreign_currency_rate_date": None,
"lines": [
{
"description": "Budget Ticket",
"gross_value": "23.00",
"tax_value": "0.00",
"tax_name": "",
"tax_rate": "0.00"
}
]

View File

@@ -0,0 +1,28 @@
import pytest
TEST_TAXRULE_RES = {
'name': {'en': 'VAT'},
'rate': '19.00',
'price_includes_tax': True,
'eu_reverse_charge': False,
'home_country': ''
}
@pytest.mark.django_db
def test_rule_list(token_client, organizer, event, taxrule):
res = dict(TEST_TAXRULE_RES)
res["id"] = taxrule.pk
resp = token_client.get('/api/v1/organizers/{}/events/{}/taxrules/'.format(organizer.slug, event.slug))
assert resp.status_code == 200
assert [res] == resp.data['results']
@pytest.mark.django_db
def test_rule_detail(token_client, organizer, event, taxrule):
res = dict(TEST_TAXRULE_RES)
res["id"] = taxrule.pk
resp = token_client.get('/api/v1/organizers/{}/events/{}/taxrules/{}/'.format(organizer.slug, event.slug,
taxrule.pk))
assert resp.status_code == 200
assert res == resp.data

View File

@@ -1,8 +1,10 @@
from datetime import timedelta
import json
from datetime import date, timedelta
from decimal import Decimal
import pytest
from django.db import DatabaseError
from django.core.serializers.json import DjangoJSONEncoder
from django.db import DatabaseError, transaction
from django.utils.timezone import now
from django_countries.fields import Country
@@ -14,6 +16,8 @@ from pretix.base.services.invoices import (
build_preview_invoice_pdf, generate_cancellation, generate_invoice,
invoice_pdf_task, regenerate_invoice,
)
from pretix.base.services.orders import OrderChangeManager
from pretix.base.settings import GlobalSettingsObject
@pytest.fixture
@@ -23,19 +27,20 @@ def env():
organizer=o, name='Dummy', slug='dummy',
date_from=now(), plugins='pretix.plugins.banktransfer'
)
tr = event.tax_rules.create(rate=Decimal('19.00'))
o = Order.objects.create(
code='FOO', event=event, email='dummy@dummy.test',
status=Order.STATUS_PENDING,
datetime=now(), expires=now() + timedelta(days=10),
total=0, payment_provider='banktransfer',
payment_fee=Decimal('0.25'), payment_fee_tax_rate=0,
payment_fee_tax_value=0, locale='en'
payment_fee=Decimal('0.25'), payment_fee_tax_rate=Decimal('19.00'),
payment_fee_tax_value=Decimal('0.04'), locale='en', payment_fee_tax_rule=tr
)
ticket = Item.objects.create(event=event, name='Early-bird ticket',
category=None, default_price=23,
category=None, default_price=23, tax_rule=tr,
admission=True)
t_shirt = Item.objects.create(event=event, name='T-Shirt',
category=None, default_price=42,
category=None, default_price=42, tax_rule=tr,
admission=True)
variation = ItemVariation.objects.create(value='M', item=t_shirt)
OrderPosition.objects.create(
@@ -52,6 +57,22 @@ def env():
price=Decimal("42.00"),
positionid=2,
)
gs = GlobalSettingsObject()
gs.settings.ecb_rates_date = date.today()
gs.settings.ecb_rates_dict = json.dumps({
"USD": "1.1648",
"RON": "4.5638",
"CZK": "26.024",
"BGN": "1.9558",
"HRK": "7.4098",
"EUR": "1.0000",
"NOK": "9.3525",
"HUF": "305.15",
"DKK": "7.4361",
"PLN": "4.2408",
"GBP": "0.89350",
"SEK": "9.5883"
}, cls=DjangoJSONEncoder)
return event, o
@@ -116,6 +137,59 @@ def test_positions_skip_free(env):
assert inv.lines.count() == 2
@pytest.mark.django_db
def test_reverse_charge_note(env):
event, order = env
tr = event.tax_rules.first()
tr.eu_reverse_charge = True
tr.home_country = Country('DE')
tr.save()
event.settings.set('invoice_language', 'en')
InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street', zipcode='12345', city='Warsaw',
country=Country('PL'), vat_id='PL123456780', vat_id_validated=True, order=order,
is_business=True)
ocm = OrderChangeManager(order, None)
ocm.recalculate_taxes()
ocm.commit()
assert not order.positions.filter(tax_value__gt=0).exists()
inv = generate_invoice(order)
assert "reverse charge" in inv.additional_text.lower()
assert inv.foreign_currency_display == "PLN"
assert inv.foreign_currency_rate == Decimal("4.2408")
assert inv.foreign_currency_rate_date == date.today()
@pytest.mark.django_db
def test_reverse_charge_foreign_currency_data_too_old(env):
event, order = env
gs = GlobalSettingsObject()
gs.settings.ecb_rates_date = date.today() - timedelta(days=14)
tr = event.tax_rules.first()
tr.eu_reverse_charge = True
tr.home_country = Country('DE')
tr.save()
event.settings.set('invoice_language', 'en')
InvoiceAddress.objects.create(company='Acme Company', street='221B Baker Street', zipcode='12345', city='Warsaw',
country=Country('PL'), vat_id='PL123456780', vat_id_validated=True, order=order,
is_business=True)
ocm = OrderChangeManager(order, None)
ocm.recalculate_taxes()
ocm.commit()
assert not order.positions.filter(tax_value__gt=0).exists()
inv = generate_invoice(order)
assert "reverse charge" in inv.additional_text.lower()
assert inv.foreign_currency_rate is None
assert inv.foreign_currency_rate_date is None
@pytest.mark.django_db
def test_positions(env):
event, order = env
@@ -279,11 +353,12 @@ def test_invoice_number_prefixes(env):
# Test database uniqueness check
with pytest.raises(DatabaseError):
Invoice.objects.create(
order=order,
event=order.event,
organizer=order.event.organizer,
date=now().date(),
locale='en',
invoice_no='00001',
)
with transaction.atomic():
Invoice.objects.create(
order=order,
event=order.event,
organizer=order.event.organizer,
date=now().date(),
locale='en',
invoice_no='00001',
)

View File

@@ -935,6 +935,56 @@ class EventTest(TestCase):
self.assertIn('slug', str(context.exception))
def test_copy(self):
event1 = Event.objects.create(
organizer=self.organizer, name='Download', slug='ab1234',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
is_public=True,
)
tr7 = event1.tax_rules.create(rate=Decimal('7.00'))
c1 = event1.categories.create(name='Tickets')
c2 = event1.categories.create(name='Workshops')
i1 = event1.items.create(name='Foo', default_price=Decimal('13.00'), tax_rule=tr7,
category=c1)
v1 = i1.variations.create(value='Bar')
i1.addons.create(addon_category=c2)
q1 = event1.quotas.create(name='Quota 1', size=50)
q1.items.add(i1)
q1.variations.add(v1)
que1 = event1.questions.create(question="Age", type="N")
que1.items.add(i1)
event1.settings.foo_setting = 23
event1.settings.tax_rate_default = tr7
event2 = Event.objects.create(
organizer=self.organizer, name='Download', slug='ab1234',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc)
)
event2.copy_data_from(event1)
for a in (tr7, c1, c2, i1, q1, que1):
a.refresh_from_db()
assert a.event == event1
trnew = event2.tax_rules.first()
assert trnew.rate == tr7.rate
c1new = event2.categories.get(name='Tickets')
c2new = event2.categories.get(name='Workshops')
i1new = event2.items.first()
assert i1new.name == i1.name
assert i1new.category == c1new
assert i1new.tax_rule == trnew
assert i1new.variations.count() == 1
assert i1new.addons.get(addon_category=c2new)
q1new = event2.quotas.first()
assert q1new.size == q1.size
assert q1new.items.get(pk=i1new.pk)
que1new = event2.questions.first()
assert que1new.type == que1.type
assert que1new.items.get(pk=i1new.pk)
assert event2.settings.foo_setting == '23'
assert event2.settings.tax_rate_default == trnew
class SubEventTest(TestCase):
@classmethod

View File

@@ -6,10 +6,11 @@ import pytz
from django.core import mail as djmail
from django.test import TestCase
from django.utils.timezone import make_aware, now
from django_countries.fields import Country
from pretix.base.decimal import round_decimal
from pretix.base.models import (
CartPosition, Event, Item, Order, OrderPosition, Organizer,
CartPosition, Event, InvoiceAddress, Item, Order, OrderPosition, Organizer,
)
from pretix.base.models.items import SubEventItem
from pretix.base.payment import FreeOrderProvider
@@ -102,7 +103,8 @@ def test_expiry_last_relative_subevents(event):
event.date_from = now() + timedelta(days=5)
event.has_subevents = True
event.save()
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
tr7 = event.tax_rules.create(rate=Decimal('17.00'))
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rule=tr7,
default_price=Decimal('23.00'), admission=True)
se1 = event.subevents.create(name="SE1", date_from=now() + timedelta(days=10))
@@ -196,7 +198,7 @@ class DownloadReminderTests(TestCase):
expires=now() + timedelta(days=10),
total=Decimal('46.00'), payment_provider='banktransfer'
)
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket',
default_price=Decimal('23.00'), admission=True)
self.op1 = OrderPosition.objects.create(
order=self.order, item=self.ticket, variation=None,
@@ -233,18 +235,21 @@ class OrderChangeManagerTests(TestCase):
def setUp(self):
super().setUp()
o = Organizer.objects.create(name='Dummy', slug='dummy')
self.event = Event.objects.create(organizer=o, name='Dummy', slug='dummy', date_from=now(), plugins='pretix.plugins.banktransfer')
self.event = Event.objects.create(organizer=o, name='Dummy', slug='dummy', date_from=now(),
plugins='pretix.plugins.banktransfer')
self.order = Order.objects.create(
code='FOO', event=self.event, email='dummy@dummy.test',
status=Order.STATUS_PENDING, locale='en',
datetime=now(), expires=now() + timedelta(days=10),
total=Decimal('46.00'), payment_provider='banktransfer'
)
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00'))
self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00'))
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7,
default_price=Decimal('23.00'), admission=True)
self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rate=Decimal('7.00'),
self.ticket2 = Item.objects.create(event=self.event, name='Other ticket', tax_rule=self.tr7,
default_price=Decimal('23.00'), admission=True)
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rate=Decimal('19.00'),
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rule=self.tr19,
default_price=Decimal('12.00'))
self.op1 = OrderPosition.objects.create(
order=self.order, item=self.ticket, variation=None,
@@ -260,6 +265,18 @@ class OrderChangeManagerTests(TestCase):
self.quota.items.add(self.ticket2)
self.quota.items.add(self.shirt)
def _enable_reverse_charge(self):
self.tr7.eu_reverse_charge = True
self.tr7.home_country = Country('DE')
self.tr7.save()
self.tr19.eu_reverse_charge = True
self.tr19.home_country = Country('DE')
self.tr19.save()
return InvoiceAddress.objects.create(
order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True,
country=Country('AT')
)
def test_change_subevent_quota_required(self):
self.event.has_subevents = True
self.event.save()
@@ -291,6 +308,48 @@ class OrderChangeManagerTests(TestCase):
assert self.op1.price == 12
assert self.order.total == self.op1.price + self.op2.price
def test_change_subevent_reverse_charge(self):
self._enable_reverse_charge()
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(name="Foo", date_from=now())
se2 = self.event.subevents.create(name="Bar", date_from=now())
SubEventItem.objects.create(subevent=se2, item=self.ticket, price=10.7)
self.op1.subevent = se1
self.op1.save()
self.quota.subevent = se2
self.quota.save()
self.ocm.change_subevent(self.op1, se2)
self.ocm.commit()
self.op1.refresh_from_db()
self.order.refresh_from_db()
assert self.op1.subevent == se2
assert self.op1.price == Decimal('10.00')
assert self.op1.tax_value == Decimal('0.00')
assert self.order.total == self.op1.price + self.op2.price
def test_change_subevent_net_price(self):
self.event.has_subevents = True
self.event.save()
se1 = self.event.subevents.create(name="Foo", date_from=now())
se2 = self.event.subevents.create(name="Bar", date_from=now())
self.tr7.price_includes_tax = False
self.tr7.save()
SubEventItem.objects.create(subevent=se2, item=self.ticket, price=10)
self.op1.subevent = se1
self.op1.save()
self.quota.subevent = se2
self.quota.save()
self.ocm.change_subevent(self.op1, se2)
self.ocm.commit()
self.op1.refresh_from_db()
self.order.refresh_from_db()
assert self.op1.subevent == se2
assert self.op1.price == Decimal('10.70')
assert self.order.total == self.op1.price + self.op2.price
def test_change_subevent_sold_out(self):
self.event.has_subevents = True
self.event.save()
@@ -320,10 +379,35 @@ class OrderChangeManagerTests(TestCase):
self.order.refresh_from_db()
assert self.op1.item == self.shirt
assert self.op1.price == self.shirt.default_price
assert self.op1.tax_rate == self.shirt.tax_rate
assert self.op1.tax_rate == self.shirt.tax_rule.rate
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price
def test_change_item_net_price_success(self):
self.tr19.price_includes_tax = False
self.tr19.save()
self.ocm.change_item(self.op1, self.shirt, None)
self.ocm.commit()
self.op1.refresh_from_db()
self.order.refresh_from_db()
assert self.op1.item == self.shirt
assert self.op1.price == Decimal('14.28')
assert self.op1.tax_rate == self.shirt.tax_rule.rate
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price
def test_change_item_reverse_charge(self):
self._enable_reverse_charge()
self.ocm.change_item(self.op1, self.shirt, None)
self.ocm.commit()
self.op1.refresh_from_db()
self.order.refresh_from_db()
assert self.op1.item == self.shirt
assert self.op1.price == Decimal('10.08')
assert self.op1.tax_rate == Decimal('0.00')
assert self.op1.tax_value == Decimal('0.00')
assert self.order.total == self.op1.price + self.op2.price
def test_change_price_success(self):
self.ocm.change_price(self.op1, Decimal('24.00'))
self.ocm.commit()
@@ -334,6 +418,18 @@ class OrderChangeManagerTests(TestCase):
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price
def test_change_price_net_success(self):
self.tr7.price_includes_tax = False
self.tr7.save()
self.ocm.change_price(self.op1, Decimal('10.00'))
self.ocm.commit()
self.op1.refresh_from_db()
self.order.refresh_from_db()
assert self.op1.item == self.ticket
assert self.op1.price == Decimal('10.70')
assert round_decimal(self.op1.price * (1 - 100 / (100 + self.op1.tax_rate))) == self.op1.tax_value
assert self.order.total == self.op1.price + self.op2.price
def test_cancel_success(self):
self.ocm.cancel(self.op1)
self.ocm.commit()
@@ -436,7 +532,7 @@ class OrderChangeManagerTests(TestCase):
assert self.op2.item == self.ticket
def test_payment_fee_calculation(self):
self.event.settings.set('tax_rate_default', Decimal('19.00'))
self.event.settings.set('tax_rate_default', self.tr19.pk)
prov = self.ocm._get_payment_provider()
prov.settings.set('_fee_abs', Decimal('0.30'))
self.ocm.change_price(self.op1, Decimal('24.00'))
@@ -445,7 +541,8 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == Decimal('47.30')
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
assert self.order.payment_fee_tax_rate == Decimal('19.00')
assert round_decimal(self.order.payment_fee * (1 - 100 / (100 + self.order.payment_fee_tax_rate))) == self.order.payment_fee_tax_value
assert round_decimal(self.order.payment_fee * (
1 - 100 / (100 + self.order.payment_fee_tax_rate))) == self.order.payment_fee_tax_value
def test_require_pending(self):
self.order.status = Order.STATUS_PAID
@@ -497,8 +594,37 @@ class OrderChangeManagerTests(TestCase):
nop = self.order.positions.last()
assert nop.item == self.shirt
assert nop.price == self.shirt.default_price
assert nop.tax_rate == self.shirt.tax_rate
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rate))) == nop.tax_value
assert nop.tax_rate == self.shirt.tax_rule.rate
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3
def test_add_item_net_price_success(self):
self.tr19.price_includes_tax = False
self.tr19.save()
self.ocm.add_position(self.shirt, None, None, None)
self.ocm.commit()
self.order.refresh_from_db()
assert self.order.positions.count() == 3
nop = self.order.positions.last()
assert nop.item == self.shirt
assert nop.price == Decimal('14.28')
assert nop.tax_rate == self.shirt.tax_rule.rate
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3
def test_add_item_reverse_charge(self):
self._enable_reverse_charge()
self.ocm.add_position(self.shirt, None, None, None)
self.ocm.commit()
self.order.refresh_from_db()
assert self.order.positions.count() == 3
nop = self.order.positions.last()
assert nop.item == self.shirt
assert nop.price == Decimal('10.08')
assert nop.tax_rate == Decimal('0.00')
assert nop.tax_value == Decimal('0.00')
assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3
@@ -510,8 +636,22 @@ class OrderChangeManagerTests(TestCase):
nop = self.order.positions.last()
assert nop.item == self.shirt
assert nop.price == Decimal('13.00')
assert nop.tax_rate == self.shirt.tax_rate
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rate))) == nop.tax_value
assert nop.tax_rate == self.shirt.tax_rule.rate
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
assert self.order.total == self.op1.price + self.op2.price + nop.price
def test_add_item_custom_price_tax_always_included(self):
self.tr19.price_includes_tax = False
self.tr19.save()
self.ocm.add_position(self.shirt, None, Decimal('11.90'), None)
self.ocm.commit()
self.order.refresh_from_db()
assert self.order.positions.count() == 3
nop = self.order.positions.last()
assert nop.item == self.shirt
assert nop.price == Decimal('11.90')
assert nop.tax_rate == self.shirt.tax_rule.rate
assert round_decimal(nop.price * (1 - 100 / (100 + self.shirt.tax_rule.rate))) == nop.tax_value
assert self.order.total == self.op1.price + self.op2.price + nop.price
def test_add_item_quota_full(self):
@@ -577,3 +717,44 @@ class OrderChangeManagerTests(TestCase):
self.ocm.add_position(self.ticket, None, Decimal('0.00'))
self.ocm.commit()
assert self.order.invoices.count() == 1
def test_recalculate_reverse_charge(self):
self.event.settings.set('tax_rate_default', self.tr19.pk)
prov = self.ocm._get_payment_provider()
prov.settings.set('_fee_abs', Decimal('0.30'))
self.ocm._recalculate_total_and_payment_fee()
assert self.order.total == Decimal('46.30')
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
assert self.order.payment_fee_tax_rate == Decimal('19.00')
assert self.order.payment_fee_tax_value == Decimal('0.05')
ia = self._enable_reverse_charge()
self.ocm.recalculate_taxes()
self.ocm.commit()
ops = list(self.order.positions.all())
for op in ops:
assert op.price == Decimal('21.50')
assert op.tax_value == Decimal('0.00')
assert op.tax_rate == Decimal('0.00')
assert self.order.total == Decimal('43.30')
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
assert self.order.payment_fee_tax_rate == Decimal('0.00')
assert self.order.payment_fee_tax_value == Decimal('0.00')
ia.vat_id_validated = False
ia.save()
self.ocm.recalculate_taxes()
self.ocm.commit()
ops = list(self.order.positions.all())
for op in ops:
assert op.price == Decimal('23.01') # sic. we can't really avoid it.
assert op.tax_value == Decimal('1.51')
assert op.tax_rate == Decimal('7.00')
assert self.order.total == Decimal('46.32')
assert self.order.payment_fee == prov.calculate_fee(self.order.total)
assert self.order.payment_fee_tax_rate == Decimal('19.00')
assert self.order.payment_fee_tax_value == Decimal('0.05')

View File

@@ -108,7 +108,8 @@ def test_availability_date_cart_relative_subevents(event):
event.date_from = now() + datetime.timedelta(days=5)
event.has_subevents = True
event.save()
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
tr7 = event.tax_rules.create(rate=Decimal('7.00'))
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rule=tr7,
default_price=Decimal('23.00'), admission=True)
se1 = event.subevents.create(name="SE1", date_from=now() + datetime.timedelta(days=10))
@@ -138,7 +139,8 @@ def test_availability_date_order_relative_subevents(event):
event.date_from = now() + datetime.timedelta(days=5)
event.has_subevents = True
event.save()
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
tr7 = event.tax_rules.create(rate=Decimal('7.00'))
ticket = Item.objects.create(event=event, name='Early-bird ticket', tax_rule=tr7,
default_price=Decimal('23.00'), admission=True)
se1 = event.subevents.create(name="SE1", date_from=now() + datetime.timedelta(days=10))

View File

@@ -2,8 +2,9 @@ from decimal import Decimal
import pytest
from django.utils.timezone import now
from django_countries.fields import Country
from pretix.base.models import Event, Organizer
from pretix.base.models import Event, InvoiceAddress, Organizer
from pretix.base.models.items import SubEventItem, SubEventItemVariation
from pretix.base.services.pricing import get_price
@@ -42,143 +43,143 @@ def subevent(event):
@pytest.mark.django_db
def test_base_item_default(item):
assert get_price(item) == Decimal('23.00')
assert get_price(item).gross == Decimal('23.00')
@pytest.mark.django_db
def test_base_item_subevent_no_entry(item, subevent):
assert get_price(item, subevent=subevent) == Decimal('23.00')
assert get_price(item, subevent=subevent).gross == Decimal('23.00')
@pytest.mark.django_db
def test_base_item_subevent_no_override(item, subevent):
SubEventItem.objects.create(item=item, subevent=subevent, price=None)
assert get_price(item, subevent=subevent) == Decimal('23.00')
assert get_price(item, subevent=subevent).gross == Decimal('23.00')
@pytest.mark.django_db
def test_base_item_subevent_override(item, subevent):
SubEventItem.objects.create(item=item, subevent=subevent, price=Decimal('24.00'))
assert get_price(item, subevent=subevent) == Decimal('24.00')
assert get_price(item, subevent=subevent).gross == Decimal('24.00')
@pytest.mark.django_db
def test_variation_with_default_item_price(item, variation):
assert get_price(item, variation=variation) == Decimal('23.00')
assert get_price(item, variation=variation).gross == Decimal('23.00')
@pytest.mark.django_db
def test_variation_with_specific_price(item, variation):
variation.default_price = Decimal('24.00')
assert get_price(item, variation=variation) == Decimal('24.00')
assert get_price(item, variation=variation).gross == Decimal('24.00')
@pytest.mark.django_db
def test_variation_with_default_subevent_and_default_price(item, subevent, variation):
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=None)
assert get_price(item, variation=variation, subevent=subevent) == Decimal('23.00')
assert get_price(item, variation=variation, subevent=subevent).gross == Decimal('23.00')
@pytest.mark.django_db
def test_variation_with_subevent_and_default_price(item, subevent, variation):
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=Decimal('24.00'))
assert get_price(item, variation=variation, subevent=subevent) == Decimal('24.00')
assert get_price(item, variation=variation, subevent=subevent).gross == Decimal('24.00')
@pytest.mark.django_db
def test_variation_with_no_subevent_and_specific_price(item, subevent, variation):
variation.default_price = Decimal('24.00')
assert get_price(item, variation=variation, subevent=subevent) == Decimal('24.00')
assert get_price(item, variation=variation, subevent=subevent).gross == Decimal('24.00')
@pytest.mark.django_db
def test_variation_with_default_subevent_and_specific_price(item, subevent, variation):
variation.default_price = Decimal('24.00')
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=None)
assert get_price(item, variation=variation, subevent=subevent) == Decimal('24.00')
assert get_price(item, variation=variation, subevent=subevent).gross == Decimal('24.00')
@pytest.mark.django_db
def test_variation_with_subevent_and_specific_price(item, subevent, variation):
variation.default_price = Decimal('24.00')
SubEventItemVariation.objects.create(variation=variation, subevent=subevent, price=Decimal('26.00'))
assert get_price(item, variation=variation, subevent=subevent) == Decimal('26.00')
assert get_price(item, variation=variation, subevent=subevent).gross == Decimal('26.00')
@pytest.mark.django_db
def test_voucher_no_override(item, subevent, voucher):
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('23.00')
assert get_price(item, subevent=subevent, voucher=voucher).gross == Decimal('23.00')
@pytest.mark.django_db
def test_voucher_set_price(item, subevent, voucher):
voucher.price_mode = 'set'
voucher.value = Decimal('12.00')
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('12.00')
assert get_price(item, subevent=subevent, voucher=voucher).gross == Decimal('12.00')
@pytest.mark.django_db
def test_voucher_subtract(item, subevent, voucher):
voucher.price_mode = 'subtract'
voucher.value = Decimal('12.00')
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('11.00')
assert get_price(item, subevent=subevent, voucher=voucher).gross == Decimal('11.00')
@pytest.mark.django_db
def test_voucher_percent(item, subevent, voucher):
voucher.price_mode = 'percent'
voucher.value = Decimal('10.00')
assert get_price(item, subevent=subevent, voucher=voucher) == Decimal('20.70')
assert get_price(item, subevent=subevent, voucher=voucher).gross == Decimal('20.70')
@pytest.mark.django_db
def test_free_price_ignored_if_disabled(item):
assert get_price(item, custom_price=Decimal('42.00')) == Decimal('23.00')
assert get_price(item, custom_price=Decimal('42.00')).gross == Decimal('23.00')
@pytest.mark.django_db
def test_free_price_ignored_if_lower(item):
item.free_price = True
assert get_price(item, custom_price=Decimal('12.00')) == Decimal('23.00')
assert get_price(item, custom_price=Decimal('12.00')).gross == Decimal('23.00')
@pytest.mark.django_db
def test_free_price_ignored_if_lower_than_voucher(item, voucher):
voucher.price_mode = 'set'
voucher.value = Decimal('50.00')
assert get_price(item, voucher=voucher, custom_price=Decimal('40.00')) == Decimal('50.00')
assert get_price(item, voucher=voucher, custom_price=Decimal('40.00')).gross == Decimal('50.00')
@pytest.mark.django_db
def test_free_price_ignored_if_lower_than_subevent(item, subevent):
item.free_price = True
SubEventItem.objects.create(item=item, subevent=subevent, price=Decimal('50.00'))
assert get_price(item, subevent=subevent, custom_price=Decimal('40.00')) == Decimal('50.00')
assert get_price(item, subevent=subevent, custom_price=Decimal('40.00')).gross == Decimal('50.00')
@pytest.mark.django_db
def test_free_price_ignored_if_lower_than_variation(item, variation):
variation.default_price = Decimal('50.00')
item.free_price = True
assert get_price(item, variation=variation, custom_price=Decimal('40.00')) == Decimal('50.00')
assert get_price(item, variation=variation, custom_price=Decimal('40.00')).gross == Decimal('50.00')
@pytest.mark.django_db
def test_free_price_accepted(item):
item.free_price = True
assert get_price(item, custom_price=Decimal('42.00')) == Decimal('42.00')
assert get_price(item, custom_price=Decimal('42.00')).gross == Decimal('42.00')
@pytest.mark.django_db
def test_free_price_string(item):
item.free_price = True
assert get_price(item, custom_price='42,00') == Decimal('42.00')
assert get_price(item, custom_price='42,00').gross == Decimal('42.00')
@pytest.mark.django_db
def test_free_price_float(item):
item.free_price = True
assert get_price(item, custom_price=42.00) == Decimal('42.00')
assert get_price(item, custom_price=42.00).gross == Decimal('42.00')
@pytest.mark.django_db
@@ -191,5 +192,136 @@ def test_free_price_limit(item):
@pytest.mark.django_db
def test_free_price_net(item):
item.free_price = True
item.tax_rate = 19
assert get_price(item, custom_price=Decimal('100.00'), custom_price_is_net=True) == Decimal('119.00')
item.tax_rule = item.event.tax_rules.create(rate=Decimal('19.00'))
assert get_price(item, custom_price=Decimal('100.00'), custom_price_is_net=True).gross == Decimal('119.00')
@pytest.mark.django_db
def test_tax_included(item):
item.default_price = Decimal('119.00')
item.tax_rule = item.event.tax_rules.create(rate=Decimal('19.00'), price_includes_tax=True)
assert get_price(item).gross == Decimal('119.00')
assert get_price(item).net == Decimal('100.00')
assert get_price(item).tax == Decimal('19.00')
assert get_price(item).rate == Decimal('19.00')
@pytest.mark.django_db
def test_tax_none(item):
item.default_price = Decimal('100.00')
assert get_price(item).gross == Decimal('100.00')
assert get_price(item).net == Decimal('100.00')
assert get_price(item).tax == Decimal('0.00')
assert get_price(item).rate == Decimal('0.00')
@pytest.mark.django_db
def test_tax_added(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(rate=Decimal('19.00'), price_includes_tax=False)
assert get_price(item).gross == Decimal('119.00')
assert get_price(item).net == Decimal('100.00')
assert get_price(item).tax == Decimal('19.00')
assert get_price(item).rate == Decimal('19.00')
@pytest.mark.django_db
def test_tax_reverse_charge_valid(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=True, home_country=Country('DE')
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=True,
country=Country('BE')
)
assert item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('100.00')
@pytest.mark.django_db
def test_tax_reverse_charge_disabled(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=False, home_country=Country('DE')
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=True,
country=Country('BE')
)
assert not item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('119.00')
@pytest.mark.django_db
def test_tax_reverse_charge_no_country(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=True, home_country=Country('DE')
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=True,
)
assert not item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('119.00')
@pytest.mark.django_db
def test_tax_reverse_charge_non_eu_country(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=True, home_country=Country('DE')
)
ia = InvoiceAddress(
country=Country('US')
)
assert not item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('100.00')
@pytest.mark.django_db
def test_tax_reverse_charge_same_country(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=True, home_country=Country('DE')
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=True,
country=Country('DE')
)
assert not item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('119.00')
@pytest.mark.django_db
def test_tax_reverse_charge_consumer(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=True, home_country=Country('DE')
)
ia = InvoiceAddress(
is_business=False, country=Country('BE')
)
assert not item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('119.00')
@pytest.mark.django_db
def test_tax_reverse_charge_invalid_vat_id(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
eu_reverse_charge=True, home_country=Country('DE')
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=False,
country=Country('BE')
)
assert not item.tax_rule.is_reverse_charge(ia)
assert get_price(item, invoice_address=ia).gross == Decimal('119.00')

View File

@@ -132,35 +132,39 @@ class EventsTest(SoupTest):
assert len(doc.select(".btn-primary")) == 0
def test_payment_settings(self):
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
self.get_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug))
self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
'payment_banktransfer__enabled': 'true',
'payment_banktransfer__fee_abs': '12.23',
'payment_banktransfer_bank_details_0': 'Test',
'settings-payment_term_days': '2',
'settings-tax_rate_default': '19.00',
'settings-tax_rate_default': tr19.pk,
})
self.event1.settings.flush()
assert self.event1.settings.get('payment_banktransfer__enabled', as_type=bool)
assert self.event1.settings.get('payment_banktransfer__fee_abs', as_type=Decimal) == Decimal('12.23')
def test_payment_settings_dont_require_fields_of_inactive_providers(self):
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
'settings-tax_rate_default': '19.00',
'settings-tax_rate_default': tr19.pk,
'settings-payment_term_days': '2'
}, follow=True)
assert doc.select('.alert-success')
def test_payment_settings_require_fields_of_active_providers(self):
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
'payment_banktransfer__enabled': 'true',
'payment_banktransfer__fee_abs': '12.23',
'settings-payment_term_days': '2',
'settings-tax_rate_default': '19.00',
'settings-tax_rate_default': tr19.pk,
})
assert doc.select('.alert-danger')
def test_payment_settings_last_date_payment_after_presale_end(self):
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
self.event1.presale_end = datetime.datetime.now()
self.event1.save(update_fields=['presale_end'])
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
@@ -172,13 +176,14 @@ class EventsTest(SoupTest):
'settings-payment_term_last_1': (self.event1.presale_end - datetime.timedelta(1)).strftime('%Y-%m-%d'),
'settings-payment_term_last_2': '0',
'settings-payment_term_last_3': 'date_from',
'settings-tax_rate_default': '19.00',
'settings-tax_rate_default': tr19.pk,
})
assert doc.select('.alert-danger')
self.event1.presale_end = None
self.event1.save(update_fields=['presale_end'])
def test_payment_settings_relative_date_payment_after_presale_end(self):
tr19 = self.event1.tax_rules.create(rate=Decimal('19.00'))
self.event1.presale_end = self.event1.date_from - datetime.timedelta(days=5)
self.event1.save(update_fields=['presale_end'])
doc = self.post_doc('/control/event/%s/%s/settings/payment' % (self.orga1.slug, self.event1.slug), {
@@ -190,7 +195,7 @@ class EventsTest(SoupTest):
'settings-payment_term_last_1': '',
'settings-payment_term_last_2': '10',
'settings-payment_term_last_3': 'date_from',
'settings-tax_rate_default': '19.00',
'settings-tax_rate_default': tr19.pk,
})
assert doc.select('.alert-danger')
self.event1.presale_end = None
@@ -268,6 +273,7 @@ class EventsTest(SoupTest):
'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg',
'basics-currency': 'EUR',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00',
@@ -292,6 +298,7 @@ class EventsTest(SoupTest):
'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg',
'basics-currency': 'EUR',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00',
@@ -323,6 +330,7 @@ class EventsTest(SoupTest):
'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg',
'basics-currency': 'EUR',
'basics-tax_rate': '19.00',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00',
@@ -352,6 +360,8 @@ class EventsTest(SoupTest):
assert ev.presale_start == berlin_tz.localize(datetime.datetime(2016, 11, 1, 10, 0, 0)).astimezone(pytz.utc)
assert ev.presale_end == berlin_tz.localize(datetime.datetime(2016, 11, 30, 18, 0, 0)).astimezone(pytz.utc)
assert ev.tax_rules.filter(rate=Decimal('19.00')).exists()
def test_create_event_with_subevents_success(self):
doc = self.get_doc('/control/events/add')
tabletext = doc.select("form")[0].text
@@ -374,6 +384,7 @@ class EventsTest(SoupTest):
'basics-location_0': 'Hamburg',
'basics-location_1': 'Hamburg',
'basics-currency': 'EUR',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00',
@@ -402,6 +413,7 @@ class EventsTest(SoupTest):
'basics-date_to': '',
'basics-location_0': 'Hamburg',
'basics-currency': 'EUR',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'UTC',
'basics-presale_start': '',
@@ -441,6 +453,7 @@ class EventsTest(SoupTest):
'basics-date_to': '2016-12-30 19:00:00',
'basics-location_0': 'Hamburg',
'basics-currency': 'EUR',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-20 11:00:00',
@@ -463,6 +476,7 @@ class EventsTest(SoupTest):
'basics-date_to': '2016-12-30 19:00:00',
'basics-location_0': 'Hamburg',
'basics-currency': '$',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00',
@@ -485,6 +499,7 @@ class EventsTest(SoupTest):
'basics-date_to': '2016-12-30 19:00:00',
'basics-location_0': 'Hamburg',
'basics-currency': 'ASD',
'basics-tax_rate': '',
'basics-locale': 'en',
'basics-timezone': 'Europe/Berlin',
'basics-presale_start': '2016-11-01 10:00:00',

View File

@@ -1,9 +1,11 @@
from datetime import timedelta
from decimal import Decimal
from unittest import mock
import pytest
from django.core import mail
from django.utils.timezone import now
from django_countries.fields import Country
from tests.base import SoupTest
from pretix.base.models import (
@@ -558,9 +560,11 @@ class OrderChangeTests(SoupTest):
datetime=now(), expires=now() + timedelta(days=10),
total=Decimal('46.00'), payment_provider='banktransfer'
)
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rate=Decimal('7.00'),
self.tr7 = self.event.tax_rules.create(rate=Decimal('7.00'))
self.tr19 = self.event.tax_rules.create(rate=Decimal('19.00'))
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket', tax_rule=self.tr7,
default_price=Decimal('23.00'), admission=True)
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rate=Decimal('19.00'),
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', tax_rule=self.tr19,
default_price=Decimal('12.00'))
self.op1 = OrderPosition.objects.create(
order=self.order, item=self.ticket, variation=None,
@@ -593,7 +597,7 @@ class OrderChangeTests(SoupTest):
self.order.refresh_from_db()
assert self.op1.item == self.shirt
assert self.op1.price == self.shirt.default_price
assert self.op1.tax_rate == self.shirt.tax_rate
assert self.op1.tax_rate == self.shirt.tax_rule.rate
assert self.order.total == self.op1.price + self.op2.price
def test_change_subevent_success(self):
@@ -678,3 +682,135 @@ class OrderChangeTests(SoupTest):
assert self.order.positions.count() == 3
assert self.order.positions.last().item == self.shirt
assert self.order.positions.last().price == 14
def test_recalculate_reverse_charge(self):
self.tr7.eu_reverse_charge = True
self.tr7.home_country = Country('DE')
self.tr7.save()
self.tr19.eu_reverse_charge = True
self.tr19.home_country = Country('DE')
self.tr19.save()
InvoiceAddress.objects.create(
order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True,
country=Country('AT')
)
self.client.post('/control/event/{}/{}/orders/{}/change'.format(
self.event.organizer.slug, self.event.slug, self.order.code
), {
'other-recalculate_taxes': 'on',
'add-itemvar'.format(self.op2.pk): str(self.ticket.pk),
'op-{}-operation'.format(self.op1.pk): '',
'op-{}-operation'.format(self.op2.pk): '',
'op-{}-itemvar'.format(self.op2.pk): str(self.ticket.pk),
'op-{}-price'.format(self.op2.pk): str(self.op2.price),
'op-{}-itemvar'.format(self.op1.pk): str(self.ticket.pk),
'op-{}-price'.format(self.op1.pk): str(self.op1.price),
})
ops = list(self.order.positions.all())
for op in ops:
assert op.price == Decimal('21.50')
assert op.tax_value == Decimal('0.00')
assert op.tax_rate == Decimal('0.00')
@pytest.mark.django_db
def test_check_vatid(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT'))
with mock.patch('vat_moss.id.validate') as mock_validate:
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-success' in response.rendered_content
ia.refresh_from_db()
assert ia.vat_id_validated
@pytest.mark.django_db
def test_check_vatid_no_entered(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, country=Country('AT'))
with mock.patch('vat_moss.id.validate') as mock_validate:
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
ia.refresh_from_db()
assert not ia.vat_id_validated
@pytest.mark.django_db
def test_check_vatid_invalid_country(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('FR'))
with mock.patch('vat_moss.id.validate') as mock_validate:
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
ia.refresh_from_db()
assert not ia.vat_id_validated
@pytest.mark.django_db
def test_check_vatid_noneu_country(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='CHU1234567', country=Country('CH'))
with mock.patch('vat_moss.id.validate') as mock_validate:
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
ia.refresh_from_db()
assert not ia.vat_id_validated
@pytest.mark.django_db
def test_check_vatid_no_country(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567')
with mock.patch('vat_moss.id.validate') as mock_validate:
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
ia.refresh_from_db()
assert not ia.vat_id_validated
@pytest.mark.django_db
def test_check_vatid_no_invoiceaddress(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
with mock.patch('vat_moss.id.validate') as mock_validate:
mock_validate.return_value = ('AT', 'AT123456', 'Foo')
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
@pytest.mark.django_db
def test_check_vatid_invalid(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT'))
with mock.patch('vat_moss.id.validate') as mock_validate:
def raiser(*args, **kwargs):
import vat_moss.errors
raise vat_moss.errors.InvalidError('Fail')
mock_validate.side_effect = raiser
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
ia.refresh_from_db()
assert not ia.vat_id_validated
@pytest.mark.django_db
def test_check_vatid_unavailable(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
ia = InvoiceAddress.objects.create(order=env[2], is_business=True, vat_id='ATU1234567', country=Country('AT'))
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
response = client.post('/control/event/dummy/dummy/orders/FOO/checkvatid', {}, follow=True)
assert 'alert-danger' in response.rendered_content
ia.refresh_from_db()
assert not ia.vat_id_validated

View File

@@ -41,6 +41,10 @@ event_urls = [
"settings/invoice",
"settings/invoice/preview",
"settings/display",
"settings/tax/",
"settings/tax/add",
"settings/tax/1/",
"settings/tax/1/delete",
"items/",
"items/add",
"items/1/",
@@ -81,6 +85,7 @@ event_urls = [
"orders/ABC/contact",
"orders/ABC/comment",
"orders/ABC/locale",
"orders/ABC/checkvatid",
"orders/ABC/",
"orders/",
"waitinglist/",
@@ -162,6 +167,10 @@ event_permission_urls = [
("can_change_event_settings", "settings/display", 200),
("can_change_event_settings", "settings/invoice", 200),
("can_change_event_settings", "settings/invoice/preview", 200),
("can_change_event_settings", "settings/tax/", 200),
("can_change_event_settings", "settings/tax/1/", 404),
("can_change_event_settings", "settings/tax/add", 200),
("can_change_event_settings", "settings/tax/1/delete", 404),
("can_change_event_settings", "comment/", 405),
# Lists are currently not access-controlled
# ("can_change_items", "items/", 200),
@@ -197,6 +206,7 @@ event_permission_urls = [
("can_change_orders", "orders/FOO/extend", 200),
("can_change_orders", "orders/FOO/contact", 200),
("can_change_orders", "orders/FOO/transition", 405),
("can_change_orders", "orders/FOO/checkvatid", 405),
("can_change_orders", "orders/FOO/resend", 405),
("can_change_orders", "orders/FOO/invoice", 405),
("can_change_orders", "orders/FOO/change", 200),

View File

@@ -0,0 +1,115 @@
import datetime
from decimal import Decimal
from django.utils.timezone import now
from tests.base import SoupTest, extract_form_fields
from pretix.base.models import Event, Order, Organizer, Team, User
class TaxRateFormTest(SoupTest):
def setUp(self):
super().setUp()
self.user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
self.orga1 = Organizer.objects.create(name='CCC', slug='ccc')
self.orga2 = Organizer.objects.create(name='MRM', slug='mrm')
self.event1 = Event.objects.create(
organizer=self.orga1, name='30C3', slug='30c3',
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
)
t = Team.objects.create(organizer=self.orga1, can_change_event_settings=True, can_change_items=True)
t.members.add(self.user)
t.limit_events.add(self.event1)
self.client.login(email='dummy@dummy.dummy', password='dummy')
def test_create(self):
doc = self.get_doc('/control/event/%s/%s/settings/tax/add' % (self.orga1.slug, self.event1.slug))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['name_0'] = 'VAT'
form_data['rate'] = '19.00'
form_data['price_includes_tax'] = 'on'
doc = self.post_doc('/control/event/%s/%s/settings/tax/add' % (self.orga1.slug, self.event1.slug), form_data)
assert doc.select(".alert-success")
self.assertIn("VAT", doc.select("#page-wrapper table")[0].text)
assert self.event1.tax_rules.get(
rate=19, price_includes_tax=True, eu_reverse_charge=False
)
def test_update(self):
tr = self.event1.tax_rules.create(rate=19, name="VAT")
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/' % (self.orga1.slug, self.event1.slug, tr.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['rate'] = '20.00'
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/' % (self.orga1.slug, self.event1.slug, tr.id),
form_data)
assert doc.select(".alert-success")
tr.refresh_from_db()
assert tr.rate == Decimal('20.00')
def test_delete(self):
tr = self.event1.tax_rules.create(rate=19, name="VAT")
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
form_data)
assert doc.select(".alert-success")
self.assertNotIn("VAT", doc.select("#page-wrapper")[0].text)
assert not self.event1.tax_rules.exists()
def test_delete_item_existing(self):
tr = self.event1.tax_rules.create(rate=19, name="VAT")
self.event1.items.create(name="foo", default_price=12, tax_rule=tr)
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
form_data)
self.assertIn("VAT", doc.select("#page-wrapper")[0].text)
assert self.event1.tax_rules.exists()
def test_delete_default_rule(self):
tr = self.event1.tax_rules.create(rate=19, name="VAT")
self.event1.settings.tax_rate_default = tr
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
form_data)
self.assertIn("VAT", doc.select("#page-wrapper")[0].text)
assert self.event1.tax_rules.exists()
def test_delete_order_existing(self):
tr = self.event1.tax_rules.create(rate=19, name="VAT")
self.event1.orders.create(
code='FOO', event=self.event1, email='dummy@dummy.test',
status=Order.STATUS_PENDING,
datetime=now(), expires=now() + datetime.timedelta(days=10),
total=14, payment_provider='banktransfer', locale='en',
payment_fee=0.3,
payment_fee_tax_rate=19,
payment_fee_tax_value=0.05,
payment_fee_tax_rule=tr
)
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
form_data)
self.assertIn("VAT", doc.select("#page-wrapper")[0].text)
assert self.event1.tax_rules.exists()
def test_delete_orderpos_existing(self):
tr = self.event1.tax_rules.create(rate=19, name="VAT")
i = self.event1.items.create(name="foo", default_price=12)
o = self.event1.orders.create(
code='FOO', event=self.event1, email='dummy@dummy.test',
status=Order.STATUS_PENDING,
datetime=now(), expires=now() + datetime.timedelta(days=10),
total=12, payment_provider='banktransfer', locale='en'
)
o.positions.create(
item=i, price=12, tax_rule=tr, tax_rate=19, tax_value=12 - 12 / 1.19
)
doc = self.get_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/settings/tax/%s/delete' % (self.orga1.slug, self.event1.slug, tr.id),
form_data)
self.assertIn("VAT", doc.select("#page-wrapper")[0].text)
assert self.event1.tax_rules.exists()

View File

@@ -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()

View File

@@ -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

View File

@@ -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)