Add tax splitting

This commit is contained in:
Richard Schreiber 2022-09-20 09:28:10 +02:00 committed by GitHub
commit 8343230a96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 17 deletions

View file

@ -1,17 +1,19 @@
from collections import defaultdict
from decimal import Decimal
from django.urls import resolve, reverse
from django.dispatch import receiver
from django.http import HttpRequest
from django.utils.translation import gettext_lazy as _, gettext, get_language
from django.urls import resolve, reverse
from django.utils.translation import get_language, gettext, gettext_lazy as _
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
from pretix.base.templatetags.money import money_filter
from pretix.control.signals import nav_event_settings
from pretix.presale.signals import fee_calculation_for_cart, front_page_top, order_meta_from_request
from pretix.presale.signals import (
fee_calculation_for_cart, front_page_top, order_meta_from_request,
)
from pretix.presale.views import get_cart
from pretix.presale.views.cart import cart_session
@ -76,17 +78,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)
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(
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=fee,
value=price,
tax_rate=tax.rate,
tax_value=tax.tax,
tax_rule=tax_rule
)]
))
return fees
return []
@ -94,7 +131,9 @@ def get_fees(event, total, invoice_address, mod='', request=None, positions=[],
def cart_fee(sender: Event, request: HttpRequest, invoice_address, total, **kwargs):
mod = ''
try:
from pretix_resellers.utils import ResellerException, get_reseller_and_user
from pretix_resellers.utils import (
ResellerException, get_reseller_and_user,
)
except ImportError:
pass
else:
@ -153,7 +192,9 @@ def front_page_top_recv(sender: Event, **kwargs):
def order_meta_signal(sender: Event, request: HttpRequest, **kwargs):
meta = {}
try:
from pretix_resellers.utils import ResellerException, get_reseller_and_user
from pretix_resellers.utils import (
ResellerException, get_reseller_and_user,
)
except ImportError:
pass
else:

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'),