diff --git a/src/pretix/api/serializers/event.py b/src/pretix/api/serializers/event.py index ba71833a88..da98d68a4c 100644 --- a/src/pretix/api/serializers/event.py +++ b/src/pretix/api/serializers/event.py @@ -554,7 +554,7 @@ class SubEventSerializer(I18nAwareModelSerializer): class TaxRuleSerializer(CountryFieldMixin, I18nAwareModelSerializer): class Meta: model = TaxRule - fields = ('id', 'name', 'rate', 'price_includes_tax', 'eu_reverse_charge', 'home_country') + fields = ('id', 'name', 'rate', 'price_includes_tax') class EventSettingsSerializer(serializers.Serializer): diff --git a/src/pretix/base/migrations/0170_auto_20201030_2109.py b/src/pretix/base/migrations/0170_auto_20201030_2109.py new file mode 100644 index 0000000000..5cc696eaa2 --- /dev/null +++ b/src/pretix/base/migrations/0170_auto_20201030_2109.py @@ -0,0 +1,49 @@ +# Generated by Django 3.0.10 on 2020-10-30 21:09 +import json + +from django.db import migrations + + +def migrate_tax_rules(apps, schema_editor): + TaxRule = apps.get_model('pretixbase', 'TaxRule') + for tr in TaxRule.objects.filter(eu_reverse_charge=True): + if tr.custom_rules and tr.custom_rules != '[]': + # Custom rules take precedence + continue + r = [{ + 'country': str(tr.home_country), + 'address_type': '', + 'action': 'vat' + }, { + 'country': 'EU', + 'address_type': 'business_vat_id', + 'action': 'reverse' + }, { + 'country': 'EU', + 'address_type': '', + 'action': 'vat' + }, { + 'country': 'ZZ', + 'address_type': '', + 'action': 'no' + }] + tr.custom_rules = json.dumps(r) + tr.save() + + +class Migration(migrations.Migration): + dependencies = [ + ('pretixbase', '0169_checkinlist_gates'), + ] + + operations = [ + migrations.RunPython(migrate_tax_rules, migrations.RunPython.noop), + migrations.RemoveField( + model_name='taxrule', + name='eu_reverse_charge', + ), + migrations.RemoveField( + model_name='taxrule', + name='home_country', + ), + ] diff --git a/src/pretix/base/models/tax.py b/src/pretix/base/models/tax.py index 4eedfb5aef..974167b7e8 100644 --- a/src/pretix/base/models/tax.py +++ b/src/pretix/base/models/tax.py @@ -1,7 +1,6 @@ import json from decimal import Decimal -from django.core.exceptions import ValidationError from django.db import models from django.utils.formats import localize from django.utils.translation import gettext_lazy as _ @@ -10,7 +9,6 @@ from i18nfield.fields import I18nCharField from pretix.base.decimal import round_decimal from pretix.base.models.base import LoggedModel from pretix.base.templatetags.money import money_filter -from pretix.helpers.countries import FastCountryField class TaxedPrice: @@ -107,21 +105,6 @@ class TaxRule(LoggedModel): verbose_name=_("The configured product prices include the tax amount"), default=True, ) - eu_reverse_charge = models.BooleanField( - verbose_name=_("Use EU reverse charge taxation rules"), - default=False, - help_text=_("Not recommended. Most events will NOT be qualified for reverse charge since the place of " - "taxation is the location of the event. This option disables charging VAT for all customers " - "outside the EU and for business customers in different EU countries who entered a valid EU VAT " - "ID. Only enable this option after consulting a tax counsel. No warranty given for correct tax " - "calculation. USE AT YOUR OWN RISK.") - ) - home_country = FastCountryField( - verbose_name=_('Merchant country'), - blank=True, - help_text=_('Your country of residence. This is the country the EU reverse charge rule will not apply in, ' - 'if configured above.'), - ) custom_rules = models.TextField(blank=True, null=True) class Meta: @@ -147,17 +130,13 @@ class TaxRule(LoggedModel): eu_reverse_charge=False ) - def clean(self): - if self.eu_reverse_charge and not self.home_country: - raise ValidationError(_('You need to set your home country to use the reverse charge feature.')) - def __str__(self): if self.price_includes_tax: s = _('incl. {rate}% {name}').format(rate=self.rate, name=self.name) else: s = _('plus {rate}% {name}').format(rate=self.rate, name=self.name) - if self.eu_reverse_charge: - s += ' ({})'.format(_('reverse charge enabled')) + if self.has_custom_rules: + s += ' ({})'.format(_('with custom rules')) return str(s) @property @@ -258,50 +237,12 @@ class TaxRule(LoggedModel): if self._custom_rules: rule = self.get_matching_rule(invoice_address) return rule['action'] == 'reverse' - - if not self.eu_reverse_charge: - return False - - if not invoice_address or not invoice_address.country: - return False - - if str(invoice_address.country) not in EU_COUNTRIES: - return False - - if invoice_address.country == self.home_country: - return False - - if invoice_address.is_business and invoice_address.vat_id and invoice_address.vat_id_validated: - return True - return False def _tax_applicable(self, invoice_address): if self._custom_rules: rule = self.get_matching_rule(invoice_address) return rule.get('action', 'vat') == 'vat' - - if not self.eu_reverse_charge: - # No reverse charge rules? Always apply VAT! - return True - - if not invoice_address or not invoice_address.country: - # No country specified? Always apply VAT! - return True - - if str(invoice_address.country) not in EU_COUNTRIES: - # Non-EU country? Never apply VAT! - return False - - if invoice_address.country == self.home_country: - # Within same EU country? Always apply VAT! - return True - - if invoice_address.is_business and invoice_address.vat_id and invoice_address.vat_id_validated: - # Reverse charge case - return False - - # Consumer in different EU country / invalid VAT return True def delete(self, *args, **kwargs): diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index 56caa71d78..131f2909fb 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -1164,7 +1164,7 @@ TaxRuleLineFormSet = formset_factory( class TaxRuleForm(I18nModelForm): class Meta: model = TaxRule - fields = ['name', 'rate', 'price_includes_tax', 'eu_reverse_charge', 'home_country'] + fields = ['name', 'rate', 'price_includes_tax'] class WidgetCodeForm(forms.Form): diff --git a/src/pretix/control/templates/pretixcontrol/event/tax_edit.html b/src/pretix/control/templates/pretixcontrol/event/tax_edit.html index 2d06661fcc..c542f5822f 100644 --- a/src/pretix/control/templates/pretixcontrol/event/tax_edit.html +++ b/src/pretix/control/templates/pretixcontrol/event/tax_edit.html @@ -34,15 +34,9 @@ for more information. Note that we are not responsible for the correct handling of taxes in your ticket shop. If in doubt, please contact a lawyer or tax consultant. {% endblocktrans %} - - {% bootstrap_field form.eu_reverse_charge layout="control" %} - {% bootstrap_field form.home_country layout="control" %} -

{% trans "Custom taxation rules" %}

-
+
{% blocktrans trimmed %} - These settings are intended for professional users with very specific taxation situations. - If you create any rule here, the reverse charge settings above will be ignored. The rules will be - checked in order and once the first rule matches the order, it will be used and all further rules will + The rules will be checked in order and once the first rule matches the order, it will be used and all further rules will be ignored. If no rule matches, tax will be charged. {% endblocktrans %} {% trans "All of these rules will only apply if an invoice address is set." %}