mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
Allow country specific tax rules (#1714)
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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={
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user