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

@@ -1086,6 +1086,11 @@ class TaxRuleLineForm(forms.Form):
('no', _('No VAT')),
],
)
rate = forms.DecimalField(
label=_('Deviating tax rate'),
max_digits=10, decimal_places=2,
required=False
)
TaxRuleLineFormSet = formset_factory(

View File

@@ -183,14 +183,15 @@ class CommentForm(I18nModelForm):
class OtherOperationsForm(forms.Form):
recalculate_taxes = forms.BooleanField(
recalculate_taxes = forms.ChoiceField(
label=_('Re-calculate taxes'),
required=False,
help_text=_(
'This operation re-checks if taxes should be paid to the items due to e.g. configured reverse charge rules '
'and changes the prices and tax values accordingly. This is useful e.g. after an invoice address change. '
'Use with care and only if you need to. Note that rounding differences might occur in this procedure.'
)
choices=(
('', _('Do not re-calculate taxes')),
('gross', _('Re-calculate taxes based on address and product settings, keep gross amount the same.')),
('net', _('Re-calculate taxes based on address and product settings, keep net amount the same.')),
),
widget=forms.RadioSelect
)
reissue_invoice = forms.BooleanField(
label=_('Issue a new invoice if required'),

View File

@@ -59,7 +59,7 @@
{{ form.id }}
{% bootstrap_field form.DELETE form_group_class="" layout="inline" %}
</div>
<div class="col-sm-4">
<div class="col-sm-3">
{% bootstrap_field form.country layout='inline' form_group_class="" %}
</div>
<div class="col-sm-3">
@@ -68,8 +68,11 @@
<div class="col-sm-3">
{% bootstrap_field form.action layout='inline' form_group_class="" %}
</div>
<div class="col-sm-2 text-right flip">
<button type="button" class="btn btn-danger" data-formset-delete-button>
<div class="col-sm-2">
{% bootstrap_field form.rate layout='inline' form_group_class="" %}
</div>
<div class="col-sm-1 text-right flip">
<button type="button" class="btn btn-block btn-danger" data-formset-delete-button>
<i class="fa fa-trash"></i></button>
</div>
</div>
@@ -82,7 +85,7 @@
{{ form.id }}
{% bootstrap_field formset.empty_form.DELETE form_group_class="" layout="inline" %}
</div>
<div class="col-sm-4">
<div class="col-sm-3">
{% bootstrap_field formset.empty_form.country layout='inline' form_group_class="" %}
</div>
<div class="col-sm-3">
@@ -91,8 +94,11 @@
<div class="col-sm-3">
{% bootstrap_field formset.empty_form.action layout='inline' form_group_class="" %}
</div>
<div class="col-sm-2 text-right flip">
<button type="button" class="btn btn-danger" data-formset-delete-button>
<div class="col-sm-2">
{% bootstrap_field formset.empty_form.rate layout='inline' form_group_class="" %}
</div>
<div class="col-sm-1 text-right flip">
<button type="button" class="btn btn-block btn-danger" data-formset-delete-button>
<i class="fa fa-trash"></i></button>
</div>
</div>

View File

@@ -9,6 +9,7 @@ from django.conf import settings
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.core.files import File
from django.core.serializers.json import DjangoJSONEncoder
from django.db import transaction
from django.db.models import ProtectedError
from django.forms import inlineformset_factory
@@ -1135,7 +1136,7 @@ class TaxUpdate(EventSettingsViewMixin, EventPermissionRequiredMixin, UpdateView
messages.success(self.request, _('Your changes have been saved.'))
form.instance.custom_rules = json.dumps([
f.cleaned_data for f in self.formset if f not in self.formset.deleted_forms
])
], cls=DjangoJSONEncoder)
if form.has_changed():
self.object.log_action(
'pretix.event.taxrule.changed', user=self.request.user, data={

View File

@@ -1397,11 +1397,6 @@ class OrderChange(OrderView):
for f in fees:
f.form = OrderFeeChangeForm(prefix='of-{}'.format(f.pk), instance=f,
data=self.request.POST if self.request.method == "POST" else None)
try:
ia = self.order.invoice_address
except InvoiceAddress.DoesNotExist:
ia = None
f.apply_tax = self.request.event.settings.tax_rate_default and self.request.event.settings.tax_rate_default.tax_applicable(invoice_address=ia)
return fees
@cached_property
@@ -1411,11 +1406,6 @@ class OrderChange(OrderView):
p.form = OrderPositionChangeForm(prefix='op-{}'.format(p.pk), instance=p, items=self.items,
initial={'seat': p.seat.seat_guid if p.seat else None},
data=self.request.POST if self.request.method == "POST" else None)
try:
ia = self.order.invoice_address
except InvoiceAddress.DoesNotExist:
ia = None
p.apply_tax = p.item.tax_rule and p.item.tax_rule.tax_applicable(invoice_address=ia)
return positions
def get_context_data(self, **kwargs):
@@ -1431,7 +1421,9 @@ class OrderChange(OrderView):
return False
else:
if self.other_form.cleaned_data['recalculate_taxes']:
ocm.recalculate_taxes()
ocm.recalculate_taxes(
keep=self.other_form.cleaned_data['recalculate_taxes']
)
return True
def _process_add(self, ocm):
@@ -1523,7 +1515,7 @@ class OrderChange(OrderView):
if p.seat and p.form.cleaned_data['seat'] and p.form.cleaned_data['seat'] != p.seat.seat_guid:
ocm.change_seat(p, p.form.cleaned_data['seat'])
if p.form.cleaned_data['price'] != p.price:
if p.form.cleaned_data['price'] is not None and p.form.cleaned_data['price'] != p.price:
ocm.change_price(p, p.form.cleaned_data['price'])
if p.form.cleaned_data['tax_rule'] and p.form.cleaned_data['tax_rule'] != p.tax_rule: