Add codification of tax rates (#4372)

* draft

* .

* Rebase migration

* Update src/pretix/base/models/tax.py

Co-authored-by: Mira <weller@rami.io>

* Test, isort, flake, migration rebase

* carry data & API

* Fix failing tests

* docs fixes

* Improve validation

* Tests

* More fixes

---------

Co-authored-by: Mira <weller@rami.io>
This commit is contained in:
Raphael Michel
2024-12-13 12:04:38 +01:00
committed by GitHub
parent a4385c8b6e
commit 53f129d5d3
36 changed files with 818 additions and 124 deletions

View File

@@ -192,13 +192,13 @@ def subevent2(event2, meta_prop):
@pytest.fixture
@scopes_disabled()
def taxrule(event):
return event.tax_rules.create(name="VAT", rate=19)
return event.tax_rules.create(name="VAT", rate=19, code="S/standard")
@pytest.fixture
@scopes_disabled()
def taxrule0(event):
return event.tax_rules.create(name="VAT", rate=0)
return event.tax_rules.create(name="VAT", rate=0, code="E")
@pytest.fixture

View File

@@ -151,6 +151,7 @@ def test_giftcard_detail_expand(token_client, organizer, event, giftcard):
"voucher_budget_use": None,
"tax_rate": "0.00",
"tax_value": "0.00",
"tax_code": None,
"secret": op.secret,
"addon_to": None,
"subevent": None,

View File

@@ -239,6 +239,7 @@ TEST_INVOICE_RES = {
"gross_value": "23.00",
"tax_value": "0.00",
"tax_name": "",
"tax_code": None,
"tax_rate": "0.00"
},
{
@@ -255,6 +256,7 @@ TEST_INVOICE_RES = {
'variation': None,
"gross_value": "0.25",
"tax_value": "0.05",
"tax_code": None,
"tax_name": "",
"tax_rate": "19.00"
}

View File

@@ -475,6 +475,7 @@ def test_order_create_invoice(token_client, organizer, event, order):
'gross_value': '23.00',
'tax_value': '0.00',
'tax_rate': '0.00',
'tax_code': None,
'tax_name': ''
},
{
@@ -492,6 +493,7 @@ def test_order_create_invoice(token_client, organizer, event, order):
'gross_value': '0.25',
'tax_value': '0.05',
'tax_rate': '19.00',
'tax_code': None,
'tax_name': ''
}
],

View File

@@ -42,8 +42,13 @@ from pretix.base.models.orders import CartPosition, OrderFee, QuestionAnswer
@pytest.fixture
def item(event):
return event.items.create(name="Budget Ticket", default_price=23)
def taxrule(event):
return event.tax_rules.create(rate=Decimal('19.00'), code="S/standard")
@pytest.fixture
def item(event, taxrule):
return event.items.create(name="Budget Ticket", default_price=23, tax_rule=taxrule)
@pytest.fixture
@@ -51,11 +56,6 @@ def item2(event2):
return event2.items.create(name="Budget Ticket", default_price=23)
@pytest.fixture
def taxrule(event):
return event.tax_rules.create(rate=Decimal('19.00'))
@pytest.fixture
def medium(organizer):
return organizer.reusable_media.create(
@@ -414,6 +414,7 @@ def test_order_create_simulate(token_client, organizer, event, item, quota, ques
'internal_type': '',
'tax_rate': '0.00',
'tax_value': '0.00',
'tax_code': None,
'tax_rule': None,
'canceled': False
}
@@ -450,8 +451,9 @@ def test_order_create_simulate(token_client, organizer, event, item, quota, ques
'attendee_email': None,
'voucher': voucher.pk,
'voucher_budget_use': '1.50',
'tax_rate': '0.00',
'tax_value': '0.00',
'tax_rate': '19.00',
'tax_value': '3.43',
'tax_code': 'S/standard',
'addon_to': None,
'subevent': None,
'discount': None,
@@ -466,7 +468,7 @@ def test_order_create_simulate(token_client, organizer, event, item, quota, ques
'options': [opt.pk],
'option_identifiers': [opt.identifier]}
],
'tax_rule': None,
'tax_rule': item.tax_rule_id,
'pseudonymization_id': 'PREVIEW',
'seat': None,
'company': "FOOCORP",
@@ -529,14 +531,14 @@ def test_order_create_positionids_addons_simulated(token_client, organizer, even
{'id': 0, 'order': '', 'positionid': 1, 'item': item.pk, 'variation': None, 'price': '23.00',
'attendee_name': 'Peter', 'attendee_name_parts': {'full_name': 'Peter', '_scheme': 'full'}, 'company': None,
'street': None, 'zipcode': None, 'city': None, 'country': None, 'state': None, 'attendee_email': None,
'voucher': None, 'tax_rate': '0.00', 'tax_value': '0.00', 'discount': None, 'voucher_budget_use': None,
'addon_to': None, 'subevent': None, 'checkins': [], 'print_logs': [], 'downloads': [], 'answers': [], 'tax_rule': None,
'voucher': None, 'tax_rate': '19.00', 'tax_code': 'S/standard', 'tax_value': '3.67', 'discount': None, 'voucher_budget_use': None,
'addon_to': None, 'subevent': None, 'checkins': [], 'print_logs': [], 'downloads': [], 'answers': [], 'tax_rule': item.tax_rule_id,
'pseudonymization_id': 'PREVIEW', 'seat': None, 'canceled': False, 'valid_from': None, 'valid_until': None, 'blocked': None},
{'id': 0, 'order': '', 'positionid': 2, 'item': item.pk, 'variation': None, 'price': '23.00',
'attendee_name': 'Peter', 'attendee_name_parts': {'full_name': 'Peter', '_scheme': 'full'}, 'company': None,
'street': None, 'zipcode': None, 'city': None, 'country': None, 'state': None, 'attendee_email': None,
'voucher': None, 'tax_rate': '0.00', 'tax_value': '0.00', 'discount': None, 'voucher_budget_use': None,
'addon_to': 1, 'subevent': None, 'checkins': [], 'print_logs': [], 'downloads': [], 'answers': [], 'tax_rule': None,
'voucher': None, 'tax_rate': '19.00', 'tax_code': 'S/standard', 'tax_value': '3.67', 'discount': None, 'voucher_budget_use': None,
'addon_to': 1, 'subevent': None, 'checkins': [], 'print_logs': [], 'downloads': [], 'answers': [], 'tax_rule': item.tax_rule_id,
'pseudonymization_id': 'PREVIEW', 'seat': None, 'canceled': False, 'valid_from': None, 'valid_until': None, 'blocked': None}
]

View File

@@ -50,7 +50,7 @@ def item2(event2):
@pytest.fixture
def taxrule(event):
return event.tax_rules.create(rate=Decimal('19.00'))
return event.tax_rules.create(rate=Decimal('19.00'), code="S/standard")
@pytest.fixture
@@ -111,9 +111,9 @@ def order(event, item, device, taxrule, question):
amount=Decimal('23.00'),
)
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
tax_value=Decimal('0.05'), tax_rule=taxrule)
tax_value=Decimal('0.05'), tax_rule=taxrule, tax_code=taxrule.code)
o.fees.create(fee_type=OrderFee.FEE_TYPE_PAYMENT, value=Decimal('0.25'), tax_rate=Decimal('19.00'),
tax_value=Decimal('0.05'), tax_rule=taxrule, canceled=True)
tax_value=Decimal('0.05'), tax_rule=taxrule, tax_code=taxrule.code, canceled=True)
InvoiceAddress.objects.create(order=o, company="Sample company", country=Country('NZ'),
vat_id="DE123", vat_id_validated=True, custom_field="Custom info")
op = OrderPosition.objects.create(
@@ -196,6 +196,7 @@ TEST_ORDERPOSITION_RES = {
"tax_rate": "0.00",
"tax_value": "0.00",
"tax_rule": None,
"tax_code": None,
"secret": "z3fsn8jyufm5kpk768q69gkbyr5f4h6w",
"addon_to": None,
"pseudonymization_id": "ABCDEFGHKL",
@@ -297,6 +298,7 @@ TEST_ORDER_RES = {
"description": "",
"internal_type": "",
"tax_rate": "19.00",
"tax_code": "S/standard",
"tax_value": "0.05"
}
],

View File

@@ -188,6 +188,7 @@ def test_medium_detail(token_client, organizer, event, medium, giftcard, custome
"voucher_budget_use": None,
"tax_rate": "0.00",
"tax_value": "0.00",
"tax_code": None,
"secret": op.secret,
"addon_to": None,
"subevent": None,

View File

@@ -31,6 +31,7 @@ TEST_TAXRULE_RES = {
'keep_gross_if_rate_changes': False,
'name': {'en': 'VAT'},
'rate': '19.00',
'code': 'S/standard',
'price_includes_tax': True,
'eu_reverse_charge': False,
'home_country': '',

View File

@@ -234,6 +234,7 @@ def test_reverse_charge_note(env):
assert inv.foreign_currency_rate == Decimal("4.2408")
assert inv.foreign_currency_rate_date == date.today()
assert inv.foreign_currency_source == 'eu:ecb:eurofxref-daily'
assert inv.lines.first().tax_code == "AE"
@pytest.mark.django_db
@@ -249,6 +250,7 @@ def test_custom_tax_note(env):
'address_type': '',
'action': 'vat',
'rate': '20',
'code': 'S/reduced',
'invoice_text': {
'de': 'Polnische Steuer anwendbar',
'en': 'Polish tax applies'
@@ -268,6 +270,7 @@ def test_custom_tax_note(env):
inv = generate_invoice(order)
assert "Polish tax applies" in inv.additional_text
assert inv.lines.first().tax_code == "S/reduced"
@pytest.mark.django_db

View File

@@ -1992,6 +1992,7 @@ class OrderChangeManagerTests(TestCase):
assert nop.tax_value == Decimal('0.00')
assert self.order.total == self.op1.price + self.op2.price + nop.price
assert nop.positionid == 3
assert self.order.transactions.filter(item=self.shirt).last().tax_code == "AE"
@classscope(attr='o')
def test_add_item_custom_price(self):
@@ -2216,7 +2217,7 @@ class OrderChangeManagerTests(TestCase):
self._enable_reverse_charge()
self.tr7.custom_rules = json.dumps([
{'country': 'AT', 'address_type': '', 'action': 'vat', 'rate': '100.00'}
{'country': 'AT', 'address_type': '', 'action': 'vat', 'rate': '100.00', 'code': 'S/reduced'}
])
self.tr7.save()
@@ -2230,6 +2231,7 @@ class OrderChangeManagerTests(TestCase):
assert self.order.total == Decimal('86.00') + fee.value
assert self.order.transactions.count() == 7
assert self.order.transactions.filter(item=op.item).last().tax_code == "S/reduced"
@classscope(attr='o')
def test_recalculate_country_rate_keep_gross(self):
@@ -3270,6 +3272,7 @@ class OrderChangeManagerTests(TestCase):
nop = self.order.positions.first()
nop.tax_value = Decimal('0.00')
nop.tax_rate = Decimal('0.00')
nop.tax_code = None
nop.save()
InvoiceAddress.objects.create(
order=self.order, is_business=True, vat_id='ATU1234567', vat_id_validated=True,

View File

@@ -46,63 +46,82 @@ def event():
def test_from_gross_price(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=True
rate=Decimal('10.00'),
code='S/standard',
price_includes_tax=True
)
tp = tr.tax(Decimal('100.00'))
assert tp.gross == Decimal('100')
assert tp.net == Decimal('90.91')
assert tp.tax == Decimal('100.00') - Decimal('90.91')
assert tp.rate == Decimal('10.00')
assert tp.code == 'S/standard'
@pytest.mark.django_db
def test_from_net_price(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False
rate=Decimal('10.00'),
code=None,
price_includes_tax=False,
)
tp = tr.tax(Decimal('100.00'))
assert tp.gross == Decimal('110.00')
assert tp.net == Decimal('100.00')
assert tp.tax == Decimal('10.00')
assert tp.rate == Decimal('10.00')
assert tp.code is None
@pytest.mark.django_db
def test_reverse_charge_no_address(event):
tr = TaxRule(
event=event, eu_reverse_charge=True,
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
)
assert not tr.is_reverse_charge(None)
assert tr._tax_applicable(None)
assert tr.tax_code_for(None) == "S/standard"
@pytest.mark.django_db
def test_reverse_charge_no_country(event):
tr = TaxRule(
event=event, eu_reverse_charge=True,
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
rate=Decimal('10.00'),
price_includes_tax=False,
code="S/standard",
)
ia = InvoiceAddress(
)
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_reverse_charge_individual_same_country(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
)
ia = InvoiceAddress(
is_business=False,
@@ -111,20 +130,26 @@ def test_reverse_charge_individual_same_country(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_reverse_charge_individual_eu(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=False,
@@ -133,20 +158,26 @@ def test_reverse_charge_individual_eu(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_reverse_charge_individual_3rdc(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=False,
@@ -155,20 +186,26 @@ def test_reverse_charge_individual_3rdc(event):
assert not tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "O"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code='O',
)
@pytest.mark.django_db
def test_reverse_charge_business_same_country(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -177,20 +214,26 @@ def test_reverse_charge_business_same_country(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_reverse_charge_business_eu(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -199,20 +242,26 @@ def test_reverse_charge_business_eu(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_reverse_charge_business_3rdc(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -221,20 +270,26 @@ def test_reverse_charge_business_3rdc(event):
assert not tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "O"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code='O',
)
@pytest.mark.django_db
def test_reverse_charge_valid_vat_id_business_same_country(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -245,20 +300,26 @@ def test_reverse_charge_valid_vat_id_business_same_country(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_reverse_charge_valid_vat_id_business_eu(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -269,20 +330,26 @@ def test_reverse_charge_valid_vat_id_business_eu(event):
assert tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "AE"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code='AE',
)
@pytest.mark.django_db
def test_reverse_charge_valid_vat_id_business_3rdc(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -293,20 +360,26 @@ def test_reverse_charge_valid_vat_id_business_3rdc(event):
assert not tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "O"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code='O',
)
@pytest.mark.django_db
def test_reverse_charge_disabled(event):
tr = TaxRule(
event=event, eu_reverse_charge=False, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False
event=event,
eu_reverse_charge=False,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False
)
ia = InvoiceAddress(
is_business=True,
@@ -317,20 +390,26 @@ def test_reverse_charge_disabled(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@pytest.mark.django_db
def test_custom_rules_override(event):
tr = TaxRule(
event=event, eu_reverse_charge=True, home_country=Country('DE'),
rate=Decimal('10.00'), price_includes_tax=False,
event=event,
eu_reverse_charge=True,
home_country=Country('DE'),
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'ZZ', 'address_type': '', 'action': 'vat'}
])
@@ -344,12 +423,14 @@ def test_custom_rules_override(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@@ -357,9 +438,11 @@ def test_custom_rules_override(event):
def test_custom_rules_in_order(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'ZZ', 'address_type': '', 'action': 'vat'},
{'country': 'ZZ', 'address_type': '', 'action': 'vat', 'code': 'S/reduced'},
{'country': 'ZZ', 'address_type': '', 'action': 'reverse'}
])
)
@@ -372,12 +455,14 @@ def test_custom_rules_in_order(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/reduced"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/reduced",
)
@@ -385,9 +470,11 @@ def test_custom_rules_in_order(event):
def test_custom_rules_any_country(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'ZZ', 'address_type': '', 'action': 'no'},
{'country': 'ZZ', 'address_type': '', 'action': 'no', 'code': 'O'},
])
)
ia = InvoiceAddress(
@@ -397,12 +484,14 @@ def test_custom_rules_any_country(event):
assert not tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "O"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code="O",
)
@@ -410,9 +499,11 @@ def test_custom_rules_any_country(event):
def test_custom_rules_eu_country(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'EU', 'address_type': '', 'action': 'no'},
{'country': 'EU', 'address_type': '', 'action': 'no', 'code': 'Z'},
])
)
ia = InvoiceAddress(
@@ -422,18 +513,21 @@ def test_custom_rules_eu_country(event):
assert not tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "Z"
ia = InvoiceAddress(
is_business=True,
country=Country('US')
)
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@@ -441,9 +535,11 @@ def test_custom_rules_eu_country(event):
def test_custom_rules_specific_country(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
code="S/standard",
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'AT', 'address_type': '', 'action': 'no'},
{'country': 'AT', 'address_type': '', 'action': 'no', 'code': 'Z'},
])
)
ia = InvoiceAddress(
@@ -453,12 +549,14 @@ def test_custom_rules_specific_country(event):
assert not tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "Z"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code="Z",
)
ia = InvoiceAddress(
@@ -474,6 +572,7 @@ def test_custom_rules_specific_country(event):
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
@@ -481,7 +580,8 @@ def test_custom_rules_specific_country(event):
def test_custom_rules_specific_state(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'US-NY', 'address_type': '', 'action': 'vat', 'rate': '20.00'},
{'country': 'US-DE', 'address_type': '', 'action': 'no'},
@@ -501,6 +601,7 @@ def test_custom_rules_specific_state(event):
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code=None,
)
ia = InvoiceAddress(
@@ -517,6 +618,7 @@ def test_custom_rules_specific_state(event):
tax=Decimal('30.00'),
rate=Decimal('30.00'),
name='',
code=None,
)
ia = InvoiceAddress(
@@ -533,6 +635,7 @@ def test_custom_rules_specific_state(event):
tax=Decimal('20.00'),
rate=Decimal('20.00'),
name='',
code=None,
)
ia = InvoiceAddress(
@@ -549,6 +652,7 @@ def test_custom_rules_specific_state(event):
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code=None,
)
@@ -556,7 +660,8 @@ def test_custom_rules_specific_state(event):
def test_custom_rules_individual(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'ZZ', 'address_type': 'individual', 'action': 'no'},
])
@@ -574,6 +679,7 @@ def test_custom_rules_individual(event):
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code=None,
)
ia = InvoiceAddress(
@@ -589,6 +695,7 @@ def test_custom_rules_individual(event):
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code=None,
)
@@ -596,7 +703,8 @@ def test_custom_rules_individual(event):
def test_custom_rules_business(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'ZZ', 'address_type': 'business', 'action': 'no'},
])
@@ -614,6 +722,7 @@ def test_custom_rules_business(event):
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code=None,
)
ia = InvoiceAddress(
@@ -629,6 +738,7 @@ def test_custom_rules_business(event):
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code=None,
)
@@ -636,7 +746,9 @@ def test_custom_rules_business(event):
def test_custom_rules_vat_id(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
code="S/standard",
custom_rules=json.dumps([
{'country': 'EU', 'address_type': 'business_vat_id', 'action': 'reverse'},
])
@@ -648,12 +760,14 @@ def test_custom_rules_vat_id(event):
assert not tr.is_reverse_charge(ia)
assert tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('10.00')
assert tr.tax_code_for(ia) == "S/standard"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('110.00'),
net=Decimal('100.00'),
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code="S/standard",
)
ia = InvoiceAddress(
@@ -665,12 +779,14 @@ def test_custom_rules_vat_id(event):
assert tr.is_reverse_charge(ia)
assert not tr._tax_applicable(ia)
assert tr.tax_rate_for(ia) == Decimal('0.00')
assert tr.tax_code_for(ia) == "AE"
assert tr.tax(Decimal('100.00'), invoice_address=ia) == TaxedPrice(
gross=Decimal('100.00'),
net=Decimal('100.00'),
tax=Decimal('0.00'),
rate=Decimal('0.00'),
name='',
code='AE',
)
@@ -678,7 +794,8 @@ def test_custom_rules_vat_id(event):
def test_custom_rules_country_rate(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'EU', 'address_type': 'business_vat_id', 'action': 'vat', 'rate': '100.00'},
])
@@ -696,6 +813,7 @@ def test_custom_rules_country_rate(event):
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code=None,
)
ia = InvoiceAddress(
is_business=True,
@@ -712,6 +830,7 @@ def test_custom_rules_country_rate(event):
tax=Decimal('100.00'),
rate=Decimal('100.00'),
name='',
code=None,
)
@@ -719,7 +838,8 @@ def test_custom_rules_country_rate(event):
def test_custom_rules_country_rate_keep_gross_if_rate_changes(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
keep_gross_if_rate_changes=True,
custom_rules=json.dumps([
{'country': 'EU', 'address_type': 'business_vat_id', 'action': 'vat', 'rate': '100.00'},
@@ -738,6 +858,7 @@ def test_custom_rules_country_rate_keep_gross_if_rate_changes(event):
tax=Decimal('10.00'),
rate=Decimal('10.00'),
name='',
code=None,
)
ia = InvoiceAddress(
is_business=True,
@@ -754,6 +875,7 @@ def test_custom_rules_country_rate_keep_gross_if_rate_changes(event):
tax=Decimal('55.00'),
rate=Decimal('100.00'),
name='',
code=None,
)
@@ -761,7 +883,8 @@ def test_custom_rules_country_rate_keep_gross_if_rate_changes(event):
def test_custom_rules_country_rate_subtract_from_gross(event):
tr = TaxRule(
event=event,
rate=Decimal('10.00'), price_includes_tax=False,
rate=Decimal('10.00'),
price_includes_tax=False,
custom_rules=json.dumps([
{'country': 'EU', 'address_type': 'business_vat_id', 'action': 'vat', 'rate': '100.00'},
])
@@ -781,6 +904,7 @@ def test_custom_rules_country_rate_subtract_from_gross(event):
tax=Decimal('81.82'),
rate=Decimal('100.00'),
name='',
code=None,
)