add option to split taxes

This commit is contained in:
Richard Schreiber 2022-09-19 17:33:27 +02:00
parent 1ad356307e
commit 17c2b40d1f
3 changed files with 53 additions and 1 deletions

View file

@ -1,3 +1,4 @@
from collections import defaultdict
from decimal import Decimal
from django.urls import resolve, reverse
@ -5,7 +6,7 @@ from django.dispatch import receiver
from django.http import HttpRequest
from django.utils.translation import gettext_lazy as _, gettext, get_language
from pretix.base.decimal import round_decimal
from pretix.base.models import Event, Order, TaxRule
from pretix.base.models import CartPosition, Event, Order, TaxRule
from pretix.base.models.orders import OrderFee
from pretix.base.settings import settings_hierarkey
from pretix.base.signals import order_fee_calculation
@ -76,7 +77,52 @@ def get_fees(event, total, invoice_address, mod='', request=None, positions=[],
summed += fval
if (fee_per_ticket or fee_abs or fee_percent) and total != Decimal('0.00'):
tax_rule_zero = TaxRule.zero()
fee = round_decimal(fee_abs + total * (fee_percent / 100) + len(positions) * fee_per_ticket, event.currency)
split_taxes = event.settings.get('service_fee_split_taxes', as_type=bool)
if split_taxes:
# split taxes based on products ordered
d = defaultdict(lambda: Decimal('0.00'))
for p in positions:
if isinstance(p, CartPosition):
tr = p.item.tax_rule
else:
tr = p.tax_rule
d[tr] += p.price - p.tax_value
base_values = sorted([tuple(t) for t in d.items()], key=lambda t: t[0].rate)
sum_base = sum(t[1] for t in base_values)
if sum_base:
fee_values = [(t[0], round_decimal(fee * t[1] / sum_base, event.currency))
for t in base_values]
sum_fee = sum(t[1] for t in fee_values)
# If there are rounding differences, we fix them up, but always leaning to the benefit of the tax
# authorities
if sum_fee > fee:
fee_values[0] = (fee_values[0][0], fee_values[0][1] + (fee - sum_fee))
elif sum_fee < fee:
fee_values[-1] = (fee_values[-1][0], fee_values[-1][1] + (fee - sum_fee))
else:
fee_values = [(event.settings.tax_rate_default or tax_rule_zero, fee)]
else:
fee_values = [(event.settings.tax_rate_default or tax_rule_zero, fee)]
fees = []
for tax_rule, price in fee_values:
tax_rule = tax_rule or tax_rule_zero
tax = tax_rule.tax(price, invoice_address=invoice_address, base_price_is='gross')
fees.append(OrderFee(
fee_type=OrderFee.FEE_TYPE_SERVICE,
internal_type='',
value=price,
tax_rate=tax.rate,
tax_value=tax.tax,
tax_rule=tax_rule
))
return fees
tax_rule = event.settings.tax_rate_default or TaxRule.zero()
tax = tax_rule.tax(fee, invoice_address=invoice_address, base_price_is='gross')
return [OrderFee(

View file

@ -14,6 +14,7 @@
{% bootstrap_field form.service_fee_skip_free layout="control" %}
{% bootstrap_field form.service_fee_abs addon_after=request.event.currency layout="control" %}
{% bootstrap_field form.service_fee_percent addon_after="%" layout="control" %}
{% bootstrap_field form.service_fee_split_taxes layout="control" %}
{% bootstrap_field form.service_fee_skip_if_gift_card layout="control" %}
</fieldset>
<fieldset>

View file

@ -46,6 +46,11 @@ class ServiceFeeSettingsForm(SettingsForm):
help_text=_('Note that regardless of this setting, a per-ticket fee will not be charged if the entire order is free.'),
required=False
)
service_fee_split_taxes = forms.BooleanField(
label=_('Split taxes proportionate to the tax rates and net values of the ordered products.'),
help_text=_('If not split based on ordered products, the tax rate falls back to the events base tax rate or no tax, if none is given.'),
required=False
)
service_fee_abs_resellers = forms.DecimalField(
label=_('Fixed fee per order'),