Allow country specific tax rules (#1714)

This commit is contained in:
Raphael Michel
2020-07-08 15:00:13 +02:00
committed by GitHub
parent 1c9a1b5e02
commit 6e9d921af6
20 changed files with 716 additions and 161 deletions

View File

@@ -1,3 +1,4 @@
import json
from datetime import datetime, timedelta
from decimal import Decimal
@@ -1442,6 +1443,68 @@ class OrderChangeManagerTests(TestCase):
self.ocm.commit()
assert self.order.invoices.count() == 1
@classscope(attr='o')
def test_recalculate_country_rate(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')
fee = self.order.fees.get(fee_type=OrderFee.FEE_TYPE_PAYMENT)
assert fee.value == prov.calculate_fee(self.order.total)
assert fee.tax_rate == Decimal('19.00')
assert fee.tax_value == Decimal('0.05')
self.ocm = OrderChangeManager(self.order, None)
self._enable_reverse_charge()
self.tr7.custom_rules = json.dumps([
{'country': 'AT', 'address_type': '', 'action': 'vat', 'rate': '100.00'}
])
self.tr7.save()
self.ocm.recalculate_taxes(keep='net')
self.ocm.commit()
ops = list(self.order.positions.all())
for op in ops:
assert op.price == Decimal('43.00')
assert op.tax_value == Decimal('21.50')
assert op.tax_rate == Decimal('100.00')
assert self.order.total == Decimal('86.00') + fee.value
@classscope(attr='o')
def test_recalculate_country_rate_keep_gross(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')
fee = self.order.fees.get(fee_type=OrderFee.FEE_TYPE_PAYMENT)
assert fee.value == prov.calculate_fee(self.order.total)
assert fee.tax_rate == Decimal('19.00')
assert fee.tax_value == Decimal('0.05')
self.ocm = OrderChangeManager(self.order, None)
self._enable_reverse_charge()
self.tr7.custom_rules = json.dumps([
{'country': 'AT', 'address_type': '', 'action': 'vat', 'rate': '100.00'}
])
self.tr7.save()
self.ocm.recalculate_taxes(keep='gross')
self.ocm.commit()
ops = list(self.order.positions.all())
for op in ops:
assert op.price == Decimal('23.00')
assert op.tax_value == Decimal('11.50')
assert op.tax_rate == Decimal('100.00')
assert self.order.total == Decimal('46.00') + fee.value
@classscope(attr='o')
def test_recalculate_reverse_charge(self):
self.event.settings.set('tax_rate_default', self.tr19.pk)
@@ -2305,6 +2368,27 @@ class OrderChangeManagerTests(TestCase):
assert nop.tax_rate == Decimal('0.00')
assert nop.tax_value == Decimal('0.00')
@classscope(attr='o')
def test_change_taxrate_to_country_specific(self):
self.tr19.eu_reverse_charge = True
self.tr19.custom_rules = json.dumps([
{'country': 'AT', 'address_type': '', 'action': 'vat', 'rate': '100.00'}
])
self.tr19.save()
InvoiceAddress.objects.create(
order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True,
country=Country('AT')
)
self.ocm.change_tax_rule(self.op1, self.tr19)
self.ocm.commit()
self.order.refresh_from_db()
nop = self.order.positions.first()
assert nop.price == Decimal('23.00')
assert nop.tax_rule == self.tr19
assert nop.tax_rate == Decimal('100.00')
assert nop.tax_value == Decimal('19.33')
@classscope(attr='o')
def test_change_taxrate_from_reverse_charge(self):
self.tr7.eu_reverse_charge = True

View File

@@ -1,3 +1,4 @@
import json
from decimal import Decimal
import pytest
@@ -325,3 +326,35 @@ def test_tax_reverse_charge_invalid_vat_id(item):
)
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_country_specific_rule_net_based(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'BE', 'address_type': '', 'action': 'vat', 'rate': '100.00'}
])
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=True,
country=Country('BE')
)
assert get_price(item, invoice_address=ia).gross == Decimal('200.00')
@pytest.mark.django_db
def test_country_specific_rule_gross_based(item):
item.default_price = Decimal('100.00')
item.tax_rule = item.event.tax_rules.create(
rate=Decimal('19.00'), price_includes_tax=True,
custom_rules=json.dumps([
{'country': 'BE', 'address_type': '', 'action': 'vat', 'rate': '100.00'}
])
)
ia = InvoiceAddress(
is_business=True, vat_id="EU1234", vat_id_validated=True,
country=Country('BE')
)
assert get_price(item, invoice_address=ia).gross == Decimal('168.06')

View File

@@ -53,7 +53,7 @@ def test_reverse_charge_no_address(event):
rate=Decimal('10.00'), price_includes_tax=False
)
assert not tr.is_reverse_charge(None)
assert tr.tax_applicable(None)
assert tr._tax_applicable(None)
@pytest.mark.django_db
@@ -65,7 +65,8 @@ def test_reverse_charge_no_country(event):
ia = InvoiceAddress(
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -79,7 +80,8 @@ def test_reverse_charge_individual_same_country(event):
country=Country('DE')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -93,7 +95,8 @@ def test_reverse_charge_individual_eu(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -107,7 +110,8 @@ def test_reverse_charge_individual_3rdc(event):
country=Country('US')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
@pytest.mark.django_db
@@ -121,7 +125,8 @@ def test_reverse_charge_business_same_country(event):
country=Country('DE')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -135,7 +140,8 @@ def test_reverse_charge_business_eu(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -149,7 +155,8 @@ def test_reverse_charge_business_3rdc(event):
country=Country('US')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
@pytest.mark.django_db
@@ -165,7 +172,8 @@ def test_reverse_charge_valid_vat_id_business_same_country(event):
vat_id_validated=True
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -181,7 +189,8 @@ def test_reverse_charge_valid_vat_id_business_eu(event):
country=Country('AT')
)
assert tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
@pytest.mark.django_db
@@ -197,7 +206,8 @@ def test_reverse_charge_valid_vat_id_business_3rdc(event):
vat_id_validated=True
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
@pytest.mark.django_db
@@ -213,7 +223,8 @@ def test_reverse_charge_disabled(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -232,7 +243,8 @@ def test_custom_rules_override(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -252,7 +264,8 @@ def test_custom_rules_in_order(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -269,7 +282,8 @@ def test_custom_rules_any_country(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
@pytest.mark.django_db
@@ -286,13 +300,14 @@ def test_custom_rules_eu_country(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
ia = InvoiceAddress(
is_business=True,
country=Country('US')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
@pytest.mark.django_db
@@ -309,13 +324,15 @@ def test_custom_rules_specific_country(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
ia = InvoiceAddress(
is_business=True,
country=Country('DE')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -332,13 +349,15 @@ def test_custom_rules_individual(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
ia = InvoiceAddress(
is_business=True,
country=Country('DE')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -355,13 +374,15 @@ def test_custom_rules_business(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
ia = InvoiceAddress(
is_business=False,
country=Country('DE')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
@pytest.mark.django_db
@@ -378,7 +399,8 @@ def test_custom_rules_vat_id(event):
country=Country('AT')
)
assert not tr.is_reverse_charge(ia)
assert tr.tax_applicable(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
ia = InvoiceAddress(
is_business=True,
country=Country('DE'),
@@ -386,4 +408,32 @@ def test_custom_rules_vat_id(event):
vat_id_validated=True
)
assert tr.is_reverse_charge(ia)
assert not tr.tax_applicable(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
@pytest.mark.django_db
def test_custom_rules_country_rate(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'EU', 'address_type': 'business_vat_id', 'action': 'vat', 'rate': '100.00'},
])
)
ia = InvoiceAddress(
is_business=True,
country=Country('DE')
)
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
ia = InvoiceAddress(
is_business=True,
country=Country('DE'),
vat_id='DE1234',
vat_id_validated=True
)
assert tr.tax_rate_for(ia) == Decimal('100.00')
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)