Allow more decimal places for tax rates

This commit is contained in:
Raphael Michel
2026-04-15 23:28:18 +02:00
committed by Raphael Michel
parent bda27d72e7
commit 476a88d4fd
18 changed files with 173 additions and 56 deletions

View File

@@ -20,6 +20,7 @@
# <https://www.gnu.org/licenses/>. # <https://www.gnu.org/licenses/>.
# #
import json import json
import re
from django.db.models import prefetch_related_objects from django.db.models import prefetch_related_objects
from rest_framework import serializers from rest_framework import serializers
@@ -135,3 +136,30 @@ class SalesChannelMigrationMixin:
else: else:
value["sales_channels"] = value["limit_sales_channels"] value["sales_channels"] = value["limit_sales_channels"]
return value return value
class CompatDecimalField(serializers.DecimalField):
"""
Historically, pretix recorded tax rates as decimals with two places. Today, pretix supports tax rates with up to
four places. Since our API outputs decimals with the stored precision, this would have changed the API output from
"19.00" to "19.0000" without warning. While this is semantically the same thing, we need to assume some pretix API
users might run into trouble, either because they treat the value as a string and then map something
(e.g. ``if tax_rate == "19.00"``) or process it with a language where this is a significant difference. For example,
while in Python ``Decimal("19.00") == Decimal("19.0000")`` is true, in Java
``(new BigDecimal("19.00")).equals(new BigDecimal("19.0000"))`` is false and only
``(new BigDecimal("19.00")).compareTo(new BigDecimal("19.0000")) == 0`` is true.
Therefore, we stay backwards compatible by outputting two decimal places *as long as the trailing digits are zero-valued.
"""
regex = re.compile(r"^([0-9]+\.[0-9]{2})0+$")
def to_representation(self, value):
if self.localize:
raise ValueError("localization not supported")
value = super().to_representation(value)
if value and "." not in value:
return f"{value}.00"
if m := self.regex.match(value):
return m.group(1)
return value

View File

@@ -48,7 +48,7 @@ from rest_framework.fields import ChoiceField, Field
from rest_framework.relations import SlugRelatedField from rest_framework.relations import SlugRelatedField
from pretix.api.serializers import ( from pretix.api.serializers import (
CompatibleJSONField, SalesChannelMigrationMixin, CompatDecimalField, CompatibleJSONField, SalesChannelMigrationMixin,
) )
from pretix.api.serializers.fields import PluginsField from pretix.api.serializers.fields import PluginsField
from pretix.api.serializers.i18n import I18nAwareModelSerializer from pretix.api.serializers.i18n import I18nAwareModelSerializer
@@ -681,6 +681,7 @@ class TaxRuleSerializer(CountryFieldMixin, I18nAwareModelSerializer):
required=False, required=False,
allow_null=True, allow_null=True,
) )
rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta: class Meta:
model = TaxRule model = TaxRule

View File

@@ -42,7 +42,9 @@ from django.utils.functional import cached_property, lazy
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from pretix.api.serializers import SalesChannelMigrationMixin from pretix.api.serializers import (
CompatDecimalField, SalesChannelMigrationMixin,
)
from pretix.api.serializers.event import MetaDataField from pretix.api.serializers.event import MetaDataField
from pretix.api.serializers.fields import UploadedFileField from pretix.api.serializers.fields import UploadedFileField
from pretix.api.serializers.i18n import I18nAwareModelSerializer from pretix.api.serializers.i18n import I18nAwareModelSerializer
@@ -276,10 +278,10 @@ class ItemAddOnSerializer(serializers.ModelSerializer):
return value return value
class ItemTaxRateField(serializers.Field): class ItemTaxRateField(CompatDecimalField):
def to_representation(self, i): def to_representation(self, i):
if i.tax_rule: if i.tax_rule:
return str(Decimal(i.tax_rule.rate)) return super().to_representation(Decimal(i.tax_rule.rate))
else: else:
return str(Decimal('0.00')) return str(Decimal('0.00'))
@@ -289,7 +291,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
bundles = InlineItemBundleSerializer(many=True, required=False) bundles = InlineItemBundleSerializer(many=True, required=False)
variations = InlineItemVariationSerializer(many=True, required=False) variations = InlineItemVariationSerializer(many=True, required=False)
program_times = InlineItemProgramTimeSerializer(many=True, required=False) program_times = InlineItemProgramTimeSerializer(many=True, required=False)
tax_rate = ItemTaxRateField(source='*', read_only=True) tax_rate = ItemTaxRateField(source='*', read_only=True, max_digits=7, decimal_places=4)
meta_data = MetaDataField(required=False, source='*') meta_data = MetaDataField(required=False, source='*')
picture = UploadedFileField(required=False, allow_null=True, allowed_types=( picture = UploadedFileField(required=False, allow_null=True, allowed_types=(
'image/png', 'image/jpeg', 'image/gif' 'image/png', 'image/jpeg', 'image/gif'

View File

@@ -41,7 +41,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.relations import SlugRelatedField from rest_framework.relations import SlugRelatedField
from rest_framework.reverse import reverse from rest_framework.reverse import reverse
from pretix.api.serializers import CompatibleJSONField from pretix.api.serializers import CompatDecimalField, CompatibleJSONField
from pretix.api.serializers.event import SubEventSerializer from pretix.api.serializers.event import SubEventSerializer
from pretix.api.serializers.forms import form_field_to_serializer_field from pretix.api.serializers.forms import form_field_to_serializer_field
from pretix.api.serializers.i18n import I18nAwareModelSerializer from pretix.api.serializers.i18n import I18nAwareModelSerializer
@@ -591,6 +591,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
country = CompatibleCountryField(source='*') country = CompatibleCountryField(source='*')
attendee_name = serializers.CharField(required=False) attendee_name = serializers.CharField(required=False)
plugin_data = OrderPositionPluginDataField(source='*', allow_null=True, read_only=True) plugin_data = OrderPositionPluginDataField(source='*', allow_null=True, read_only=True)
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta: class Meta:
list_serializer_class = OrderPositionListSerializer list_serializer_class = OrderPositionListSerializer
@@ -747,6 +748,8 @@ class OrderPaymentDateField(serializers.DateField):
class OrderFeeSerializer(I18nAwareModelSerializer): class OrderFeeSerializer(I18nAwareModelSerializer):
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta: class Meta:
model = OrderFee model = OrderFee
fields = ('id', 'fee_type', 'value', 'description', 'internal_type', 'tax_rate', 'tax_value', 'tax_rule', fields = ('id', 'fee_type', 'value', 'description', 'internal_type', 'tax_rate', 'tax_value', 'tax_rule',
@@ -1897,6 +1900,7 @@ class InlineInvoiceLineSerializer(I18nAwareModelSerializer):
position = LinePositionField(read_only=True) position = LinePositionField(read_only=True)
event_date_from = serializers.DateTimeField(read_only=True, source="period_start") event_date_from = serializers.DateTimeField(read_only=True, source="period_start")
event_date_to = serializers.DateTimeField(read_only=True, source="period_end") event_date_to = serializers.DateTimeField(read_only=True, source="period_end")
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta: class Meta:
model = InvoiceLine model = InvoiceLine
@@ -1980,6 +1984,7 @@ class BlockedTicketSecretSerializer(I18nAwareModelSerializer):
class TransactionSerializer(I18nAwareModelSerializer): class TransactionSerializer(I18nAwareModelSerializer):
order = serializers.SlugRelatedField(slug_field="code", read_only=True) order = serializers.SlugRelatedField(slug_field="code", read_only=True)
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta: class Meta:
model = Transaction model = Transaction

View File

@@ -0,0 +1,48 @@
# Generated by Django 5.2.12 on 2026-04-15 20:10
from decimal import Decimal
from django.db import migrations, models
import pretix.helpers.models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0298_pluggable_permissions'),
]
operations = [
migrations.AlterField(
model_name='cartposition',
name='tax_rate',
field=pretix.helpers.models.NormalizedDecimalField(decimal_places=4, default=Decimal('0'), max_digits=7),
),
migrations.AlterField(
model_name='invoiceline',
name='tax_rate',
field=pretix.helpers.models.NormalizedDecimalField(decimal_places=4, default=Decimal('0'), max_digits=7),
),
migrations.AlterField(
model_name='orderfee',
name='tax_rate',
field=pretix.helpers.models.NormalizedDecimalField(decimal_places=4, max_digits=7),
),
migrations.AlterField(
model_name='orderposition',
name='tax_rate',
field=pretix.helpers.models.NormalizedDecimalField(decimal_places=4, max_digits=7),
),
migrations.AlterField(
model_name='transaction',
name='tax_rate',
field=pretix.helpers.models.NormalizedDecimalField(decimal_places=4, max_digits=7),
),
migrations.AlterField(
model_name='taxrule',
name='rate',
field=pretix.helpers.models.NormalizedDecimalField(decimal_places=4, max_digits=7),
),
]

View File

@@ -49,6 +49,7 @@ from django_scopes import ScopedManager
from pretix.base.settings import COUNTRIES_WITH_STATE_IN_ADDRESS from pretix.base.settings import COUNTRIES_WITH_STATE_IN_ADDRESS
from pretix.helpers.countries import FastCountryField from pretix.helpers.countries import FastCountryField
from pretix.helpers.models import NormalizedDecimalField
def invoice_filename(instance, filename: str) -> str: def invoice_filename(instance, filename: str) -> str:
@@ -450,7 +451,7 @@ class InvoiceLine(models.Model):
description = models.TextField() description = models.TextField()
gross_value = models.DecimalField(max_digits=13, decimal_places=2) gross_value = models.DecimalField(max_digits=13, decimal_places=2)
tax_value = models.DecimalField(max_digits=13, decimal_places=2, default=Decimal('0.00')) tax_value = models.DecimalField(max_digits=13, decimal_places=2, default=Decimal('0.00'))
tax_rate = models.DecimalField(max_digits=7, decimal_places=2, default=Decimal('0.00')) tax_rate = NormalizedDecimalField(max_digits=7, decimal_places=4, default=Decimal('0'))
tax_name = models.CharField(max_length=190) tax_name = models.CharField(max_length=190)
tax_code = models.CharField(max_length=190, null=True, blank=True) tax_code = models.CharField(max_length=190, null=True, blank=True)
subevent = models.ForeignKey('SubEvent', null=True, blank=True, on_delete=models.PROTECT) subevent = models.ForeignKey('SubEvent', null=True, blank=True, on_delete=models.PROTECT)

View File

@@ -87,6 +87,7 @@ from pretix.base.timemachine import time_machine_now
from ...helpers import OF_SELF from ...helpers import OF_SELF
from ...helpers.countries import CachedCountries, FastCountryField from ...helpers.countries import CachedCountries, FastCountryField
from ...helpers.models import NormalizedDecimalField
from ...helpers.names import build_name from ...helpers.names import build_name
from ...testutils.middleware import debugflags_var from ...testutils.middleware import debugflags_var
from ._transactions import ( from ._transactions import (
@@ -2334,8 +2335,8 @@ class OrderFee(RoundingCorrectionMixin, models.Model):
) )
description = models.CharField(max_length=190, blank=True) description = models.CharField(max_length=190, blank=True)
internal_type = models.CharField(max_length=255, blank=True) internal_type = models.CharField(max_length=255, blank=True)
tax_rate = models.DecimalField( tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=2, max_digits=7, decimal_places=4,
verbose_name=_('Tax rate') verbose_name=_('Tax rate')
) )
tax_rule = models.ForeignKey( tax_rule = models.ForeignKey(
@@ -2533,8 +2534,8 @@ class OrderPosition(AbstractPosition):
max_digits=13, decimal_places=2, null=True, blank=True, max_digits=13, decimal_places=2, null=True, blank=True,
) )
tax_rate = models.DecimalField( tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=2, max_digits=7, decimal_places=4,
verbose_name=_('Tax rate') verbose_name=_('Tax rate')
) )
tax_rule = models.ForeignKey( tax_rule = models.ForeignKey(
@@ -3052,8 +3053,8 @@ class Transaction(models.Model):
price_includes_rounding_correction = models.DecimalField( price_includes_rounding_correction = models.DecimalField(
max_digits=13, decimal_places=2, default=Decimal("0.00") max_digits=13, decimal_places=2, default=Decimal("0.00")
) )
tax_rate = models.DecimalField( tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=2, max_digits=7, decimal_places=4,
verbose_name=_('Tax rate') verbose_name=_('Tax rate')
) )
tax_rule = models.ForeignKey( tax_rule = models.ForeignKey(
@@ -3168,8 +3169,8 @@ class CartPosition(AbstractPosition):
verbose_name=_("Limit for extending expiration date"), verbose_name=_("Limit for extending expiration date"),
null=True null=True
) )
tax_rate = models.DecimalField( tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=2, default=Decimal('0.00'), max_digits=7, decimal_places=4, default=Decimal('0'),
verbose_name=_('Tax rate') verbose_name=_('Tax rate')
) )
tax_code = models.CharField( tax_code = models.CharField(

View File

@@ -40,6 +40,7 @@ from pretix.base.decimal import round_decimal
from pretix.base.models.base import LoggedModel from pretix.base.models.base import LoggedModel
from pretix.base.templatetags.money import money_filter from pretix.base.templatetags.money import money_filter
from pretix.helpers.countries import FastCountryField from pretix.helpers.countries import FastCountryField
from pretix.helpers.models import NormalizedDecimalField
class TaxedPrice: class TaxedPrice:
@@ -335,9 +336,9 @@ class TaxRule(LoggedModel):
max_length=190, max_length=190,
choices=TAX_CODE_LISTS, choices=TAX_CODE_LISTS,
) )
rate = models.DecimalField( rate = NormalizedDecimalField(
max_digits=10, max_digits=7,
decimal_places=2, decimal_places=4,
validators=[ validators=[
MaxValueValidator( MaxValueValidator(
limit_value=Decimal("100.00"), limit_value=Decimal("100.00"),

View File

@@ -26,6 +26,8 @@ from babel.numbers import format_currency
from django import template from django import template
from django.conf import settings from django.conf import settings
from django.template.defaultfilters import floatformat from django.template.defaultfilters import floatformat
from django.utils import formats
from django.utils.safestring import mark_safe
from pretix.base.i18n import get_babel_locale from pretix.base.i18n import get_babel_locale
@@ -82,3 +84,19 @@ def money_numberfield_filter(value: Decimal, arg=''):
places = settings.CURRENCY_PLACES.get(arg, 2) places = settings.CURRENCY_PLACES.get(arg, 2)
return str(value.quantize(Decimal('1') / 10 ** places, ROUND_HALF_UP)) return str(value.quantize(Decimal('1') / 10 ** places, ROUND_HALF_UP))
@register.filter(is_safe=True)
def tax_rate_format(number):
"""
Display a Decimal to its significant decimal places, used for tax rates.
"""
assert isinstance(number, Decimal)
return mark_safe(
formats.number_format(
number.normalize(),
-number.as_tuple().exponent,
use_l10n=True,
force_grouping=False,
)
)

View File

@@ -156,11 +156,11 @@
<br/> <br/>
<small class="text-muted"> <small class="text-muted">
{% if not i.tax_rule.price_includes_tax %} {% if not i.tax_rule.price_includes_tax %}
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name %} {% blocktrans trimmed with rate=i.tax_rule.rate|tax_rate_format taxname=i.tax_rule.name %}
<strong>plus</strong> {{ rate }}% {{ taxname }} <strong>plus</strong> {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
{% else %} {% else %}
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=i.tax_rule.rate|tax_rate_format taxname=i.tax_rule.name|default:s_taxes %}
incl. {{ rate }}% {{ taxname }} incl. {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
{% endif %} {% endif %}

View File

@@ -670,7 +670,7 @@
{% if line.tax_rate %} {% if line.tax_rate %}
<br/> <br/>
<small> <small>
{% blocktrans trimmed with rate=line.tax_rate|floatformat:-2 taxname=line.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=line.tax_rate|tax_rate_format taxname=line.tax_rule.name|default:s_taxes %}
<strong>plus</strong> {{ rate }}% {{ taxname }} <strong>plus</strong> {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -680,7 +680,7 @@
{% if line.tax_rate and line.price %} {% if line.tax_rate and line.price %}
<br/> <br/>
<small> <small>
{% blocktrans trimmed with rate=line.tax_rate|floatformat:-2 taxname=line.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=line.tax_rate|tax_rate_format taxname=line.tax_rule.name|default:s_taxes %}
incl. {{ rate }}% {{ taxname }} incl. {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -720,7 +720,7 @@
{% if fee.tax_rate %} {% if fee.tax_rate %}
<br/> <br/>
<small> <small>
{% blocktrans trimmed with rate=fee.tax_rate|floatformat:-2 taxname=fee.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=fee.tax_rate|tax_rate_format taxname=fee.tax_rule.name|default:s_taxes %}
<strong>plus</strong> {{ rate }}% {{ taxname }} <strong>plus</strong> {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -730,7 +730,7 @@
{% if fee.tax_rate %} {% if fee.tax_rate %}
<br/> <br/>
<small> <small>
{% blocktrans trimmed with rate=fee.tax_rate|floatformat:-2 taxname=fee.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=fee.tax_rate|tax_rate_format taxname=fee.tax_rule.name|default:s_taxes %}
incl. {{ rate }}% {{ taxname }} incl. {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>

View File

@@ -23,6 +23,7 @@ import copy
from django.core.files import File from django.core.files import File
from django.db import models from django.db import models
from django.db.models.fields import DecimalField
class Thumbnail(models.Model): class Thumbnail(models.Model):
@@ -54,3 +55,15 @@ def flatten_choices(choices):
yield from label_or_nested yield from label_or_nested
else: else:
yield value_or_group, label_or_nested yield value_or_group, label_or_nested
class NormalizedDecimalField(DecimalField):
"""
Variant of DecimalField that never outputs the trailing zeros, so we always have normalized decimals internally.
Use this only for fields where the trailing zeros are pointless (e.g. percentages), not for monetary amounts.
"""
def from_db_value(self, value, expression, connection):
if value is not None:
value = value.normalize()
return value

View File

@@ -173,11 +173,11 @@
<small>{% trans "incl. taxes" %}</small> <small>{% trans "incl. taxes" %}</small>
{% endif %} {% endif %}
{% elif var.display_price.rate and var.display_price.gross and event.settings.display_net_prices %} {% elif var.display_price.rate and var.display_price.gross and event.settings.display_net_prices %}
<small>{% blocktrans trimmed with rate=var.display_price.rate|floatformat:-2 name=var.display_price.name %} <small>{% blocktrans trimmed with rate=var.display_price.rate|tax_rate_format name=var.display_price.name %}
<strong>plus</strong> {{ rate }}% {{ name }} <strong>plus</strong> {{ rate }}% {{ name }}
{% endblocktrans %}</small> {% endblocktrans %}</small>
{% elif var.display_price.rate and var.display_price.gross %} {% elif var.display_price.rate and var.display_price.gross %}
<small>{% blocktrans trimmed with rate=var.display_price.rate|floatformat:-2 name=var.display_price.name %} <small>{% blocktrans trimmed with rate=var.display_price.rate|tax_rate_format name=var.display_price.name %}
incl. {{ rate }}% {{ name }} incl. {{ rate }}% {{ name }}
{% endblocktrans %}</small> {% endblocktrans %}</small>
{% endif %} {% endif %}
@@ -313,11 +313,11 @@
<small>{% trans "incl. taxes" %}</small> <small>{% trans "incl. taxes" %}</small>
{% endif %} {% endif %}
{% elif item.display_price.rate and item.display_price.gross and event.settings.display_net_prices %} {% elif item.display_price.rate and item.display_price.gross and event.settings.display_net_prices %}
<small>{% blocktrans trimmed with rate=item.display_price.rate|floatformat:-2 name=item.display_price.name %} <small>{% blocktrans trimmed with rate=item.display_price.rate|tax_rate_format name=item.display_price.name %}
<strong>plus</strong> {{ rate }}% {{ name }} <strong>plus</strong> {{ rate }}% {{ name }}
{% endblocktrans %}</small> {% endblocktrans %}</small>
{% elif item.display_price.rate and item.display_price.gross %} {% elif item.display_price.rate and item.display_price.gross %}
<small>{% blocktrans trimmed with rate=item.display_price.rate|floatformat:-2 name=item.display_price.name %} <small>{% blocktrans trimmed with rate=item.display_price.rate|tax_rate_format name=item.display_price.name %}
incl. {{ rate }}% {{ name }} incl. {{ rate }}% {{ name }}
{% endblocktrans %}</small> {% endblocktrans %}</small>
{% endif %} {% endif %}

View File

@@ -357,7 +357,7 @@
{% if line.tax_rate and line.total %} {% if line.tax_rate and line.total %}
<br /> <br />
<small> <small>
{% blocktrans trimmed with rate=line.tax_rate|floatformat:-2 taxname=line.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=line.tax_rate|tax_rate_format taxname=line.tax_rule.name|default:s_taxes %}
<strong>plus</strong> {{ rate }}% {{ taxname }} <strong>plus</strong> {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -367,7 +367,7 @@
{% if line.tax_rate and line.total %} {% if line.tax_rate and line.total %}
<br /> <br />
<small> <small>
{% blocktrans trimmed with rate=line.tax_rate|floatformat:-2 taxname=line.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=line.tax_rate|tax_rate_format taxname=line.tax_rule.name|default:s_taxes %}
incl. {{ rate }}% {{ taxname }} incl. {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -416,7 +416,7 @@
{% if fee.tax_rate %} {% if fee.tax_rate %}
<br /> <br />
<small> <small>
{% blocktrans trimmed with rate=fee.tax_rate|floatformat:-2 taxname=fee.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=fee.tax_rate|tax_rate_format taxname=fee.tax_rule.name|default:s_taxes %}
<strong>plus</strong> {{ rate }}% {{ taxname }} <strong>plus</strong> {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -426,7 +426,7 @@
{% if fee.tax_rate %} {% if fee.tax_rate %}
<br /> <br />
<small> <small>
{% blocktrans trimmed with rate=fee.tax_rate|floatformat:-2 taxname=fee.tax_rule.name|default:s_taxes %} {% blocktrans trimmed with rate=fee.tax_rate|tax_rate_format taxname=fee.tax_rule.name|default:s_taxes %}
incl. {{ rate }}% {{ taxname }} incl. {{ rate }}% {{ taxname }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>

View File

@@ -207,13 +207,13 @@
{% endif %} {% endif %}
{% elif var.display_price.rate and var.display_price.gross and event.settings.display_net_prices %} {% elif var.display_price.rate and var.display_price.gross and event.settings.display_net_prices %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=var.display_price.rate|floatformat:-2 name=var.display_price.name %} {% blocktrans trimmed with rate=var.display_price.rate|tax_rate_format name=var.display_price.name %}
<strong>plus</strong> {{ rate }}% {{ name }} <strong>plus</strong> {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
{% elif var.display_price.rate and var.display_price.gross %} {% elif var.display_price.rate and var.display_price.gross %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=var.display_price.rate|floatformat:-2 name=var.display_price.name %} {% blocktrans trimmed with rate=var.display_price.rate|tax_rate_format name=var.display_price.name %}
incl. {{ rate }}% {{ name }} incl. {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -372,13 +372,13 @@
{% endif %} {% endif %}
{% elif item.display_price.rate and item.display_price.gross and event.settings.display_net_prices %} {% elif item.display_price.rate and item.display_price.gross and event.settings.display_net_prices %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=item.display_price.rate|floatformat:-2 name=item.display_price.name %} {% blocktrans trimmed with rate=item.display_price.rate|tax_rate_format name=item.display_price.name %}
<strong>plus</strong> {{ rate }}% {{ name }} <strong>plus</strong> {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
{% elif item.display_price.rate and item.display_price.gross %} {% elif item.display_price.rate and item.display_price.gross %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=item.display_price.rate|floatformat:-2 name=item.display_price.name %} {% blocktrans trimmed with rate=item.display_price.rate|tax_rate_format name=item.display_price.name %}
incl. {{ rate }}% {{ name }} incl. {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>

View File

@@ -201,13 +201,13 @@
{% endif %} {% endif %}
{% elif var.display_price.rate and var.display_price.gross and event.settings.display_net_prices %} {% elif var.display_price.rate and var.display_price.gross and event.settings.display_net_prices %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=var.display_price.rate|floatformat:-2 name=var.display_price.name %} {% blocktrans trimmed with rate=var.display_price.rate|tax_rate_format name=var.display_price.name %}
<strong>plus</strong> {{ rate }}% {{ name }} <strong>plus</strong> {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
{% elif var.display_price.rate and var.display_price.gross %} {% elif var.display_price.rate and var.display_price.gross %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=var.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=var.display_price.rate|floatformat:-2 name=var.display_price.name %} {% blocktrans trimmed with rate=var.display_price.rate|tax_rate_format name=var.display_price.name %}
incl. {{ rate }}% {{ name }} incl. {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
@@ -356,13 +356,13 @@
{% endif %} {% endif %}
{% elif item.display_price.rate and item.display_price.gross and event.settings.display_net_prices %} {% elif item.display_price.rate and item.display_price.gross and event.settings.display_net_prices %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.gross|money:event.currency %}{{ value }} incl. taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=item.display_price.rate|floatformat:-2 name=item.display_price.name %} {% blocktrans trimmed with rate=item.display_price.rate|tax_rate_format name=item.display_price.name %}
<strong>plus</strong> {{ rate }}% {{ name }} <strong>plus</strong> {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>
{% elif item.display_price.rate and item.display_price.gross %} {% elif item.display_price.rate and item.display_price.gross %}
<small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom"> <small data-toggle="tooltip" title="{% blocktrans trimmed with value=item.display_price.net|money:event.currency %}{{ value }} without taxes{% endblocktrans %}" data-placement="bottom">
{% blocktrans trimmed with rate=item.display_price.rate|floatformat:-2 name=item.display_price.name %} {% blocktrans trimmed with rate=item.display_price.rate|tax_rate_format name=item.display_price.name %}
incl. {{ rate }}% {{ name }} incl. {{ rate }}% {{ name }}
{% endblocktrans %} {% endblocktrans %}
</small> </small>

View File

@@ -1,5 +1,4 @@
'use strict'; 'use strict';
{ {
const globals = this; const globals = this;

View File

@@ -189,8 +189,8 @@ class WidgetCartTest(CartTestMixin, TestCase):
"current_unavailability_reason": None, "current_unavailability_reason": None,
"order_min": None, "order_min": None,
"max_price": None, "max_price": None,
"price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", "includes_mixed_tax_rate": False}, "price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19", "includes_mixed_tax_rate": False},
"suggested_price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", "includes_mixed_tax_rate": False}, "suggested_price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19", "includes_mixed_tax_rate": False},
"picture": None, "picture": None,
"picture_fullsize": None, "picture_fullsize": None,
"has_variations": 0, "has_variations": 0,
@@ -226,9 +226,9 @@ class WidgetCartTest(CartTestMixin, TestCase):
"id": self.shirt_red.pk, "id": self.shirt_red.pk,
'original_price': None, 'original_price': None,
"price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "", "price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "",
"rate": "19.00", "includes_mixed_tax_rate": False}, "rate": "19", "includes_mixed_tax_rate": False},
"suggested_price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "", "suggested_price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "",
"rate": "19.00", "includes_mixed_tax_rate": False}, "rate": "19", "includes_mixed_tax_rate": False},
"description": None, "description": None,
"avail": [100, None], "avail": [100, None],
"order_max": 2, "order_max": 2,
@@ -239,9 +239,9 @@ class WidgetCartTest(CartTestMixin, TestCase):
"id": self.shirt_blue.pk, "id": self.shirt_blue.pk,
'original_price': None, 'original_price': None,
"price": {"gross": "12.00", "net": "10.08", "tax": "1.92", "name": "", "price": {"gross": "12.00", "net": "10.08", "tax": "1.92", "name": "",
"rate": "19.00", "includes_mixed_tax_rate": False}, "rate": "19", "includes_mixed_tax_rate": False},
"suggested_price": {"gross": "12.00", "net": "10.08", "tax": "1.92", "name": "", "suggested_price": {"gross": "12.00", "net": "10.08", "tax": "1.92", "name": "",
"rate": "19.00", "includes_mixed_tax_rate": False}, "rate": "19", "includes_mixed_tax_rate": False},
"description": None, "description": None,
"avail": [100, None], "avail": [100, None],
"order_max": 2, "order_max": 2,
@@ -278,9 +278,9 @@ class WidgetCartTest(CartTestMixin, TestCase):
"current_unavailability_reason": None, "current_unavailability_reason": None,
"order_min": None, "order_min": None,
"max_price": None, "max_price": None,
"price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", "price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19",
"includes_mixed_tax_rate": False}, "includes_mixed_tax_rate": False},
"suggested_price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", "suggested_price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19",
"includes_mixed_tax_rate": False}, "includes_mixed_tax_rate": False},
"picture": None, "picture": None,
"picture_fullsize": None, "picture_fullsize": None,
@@ -343,9 +343,9 @@ class WidgetCartTest(CartTestMixin, TestCase):
"id": self.shirt_red.pk, "id": self.shirt_red.pk,
'original_price': None, 'original_price': None,
"price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "", "price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "",
"rate": "19.00", "includes_mixed_tax_rate": False}, "rate": "19", "includes_mixed_tax_rate": False},
"suggested_price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "", "suggested_price": {"gross": "14.00", "net": "11.76", "tax": "2.24", "name": "",
"rate": "19.00", "includes_mixed_tax_rate": False}, "rate": "19", "includes_mixed_tax_rate": False},
"description": None, "description": None,
"avail": [100, None], "avail": [100, None],
"order_max": 2, "order_max": 2,
@@ -395,8 +395,8 @@ class WidgetCartTest(CartTestMixin, TestCase):
"current_unavailability_reason": None, "current_unavailability_reason": None,
"order_min": None, "order_min": None,
"max_price": None, "max_price": None,
"price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", "includes_mixed_tax_rate": False}, "price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19", "includes_mixed_tax_rate": False},
"suggested_price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19.00", "includes_mixed_tax_rate": False}, "suggested_price": {"gross": "23.00", "net": "19.33", "tax": "3.67", "name": "", "rate": "19", "includes_mixed_tax_rate": False},
"picture": None, "picture": None,
"picture_fullsize": None, "picture_fullsize": None,
"has_variations": 0, "has_variations": 0,
@@ -481,7 +481,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
'gross': '14.00', 'gross': '14.00',
'net': '11.76', 'net': '11.76',
'tax': '2.24', 'tax': '2.24',
'rate': '19.00', 'rate': '19',
'name': '', 'name': '',
'includes_mixed_tax_rate': False 'includes_mixed_tax_rate': False
}, },
@@ -489,7 +489,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
'gross': '14.00', 'gross': '14.00',
'net': '11.76', 'net': '11.76',
'tax': '2.24', 'tax': '2.24',
'rate': '19.00', 'rate': '19',
'name': '', 'name': '',
'includes_mixed_tax_rate': False 'includes_mixed_tax_rate': False
}, },
@@ -601,7 +601,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
"net": "19.52", "net": "19.52",
"tax": "3.48", "tax": "3.48",
"name": "MIXED!", "name": "MIXED!",
"rate": "19.00", "rate": "19",
"includes_mixed_tax_rate": True "includes_mixed_tax_rate": True
} }