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

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