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/>.
#
import json
import re
from django.db.models import prefetch_related_objects
from rest_framework import serializers
@@ -135,3 +136,30 @@ class SalesChannelMigrationMixin:
else:
value["sales_channels"] = value["limit_sales_channels"]
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 pretix.api.serializers import (
CompatibleJSONField, SalesChannelMigrationMixin,
CompatDecimalField, CompatibleJSONField, SalesChannelMigrationMixin,
)
from pretix.api.serializers.fields import PluginsField
from pretix.api.serializers.i18n import I18nAwareModelSerializer
@@ -681,6 +681,7 @@ class TaxRuleSerializer(CountryFieldMixin, I18nAwareModelSerializer):
required=False,
allow_null=True,
)
rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta:
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 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.fields import UploadedFileField
from pretix.api.serializers.i18n import I18nAwareModelSerializer
@@ -276,10 +278,10 @@ class ItemAddOnSerializer(serializers.ModelSerializer):
return value
class ItemTaxRateField(serializers.Field):
class ItemTaxRateField(CompatDecimalField):
def to_representation(self, i):
if i.tax_rule:
return str(Decimal(i.tax_rule.rate))
return super().to_representation(Decimal(i.tax_rule.rate))
else:
return str(Decimal('0.00'))
@@ -289,7 +291,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
bundles = InlineItemBundleSerializer(many=True, required=False)
variations = InlineItemVariationSerializer(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='*')
picture = UploadedFileField(required=False, allow_null=True, allowed_types=(
'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.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.forms import form_field_to_serializer_field
from pretix.api.serializers.i18n import I18nAwareModelSerializer
@@ -591,6 +591,7 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
country = CompatibleCountryField(source='*')
attendee_name = serializers.CharField(required=False)
plugin_data = OrderPositionPluginDataField(source='*', allow_null=True, read_only=True)
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta:
list_serializer_class = OrderPositionListSerializer
@@ -747,6 +748,8 @@ class OrderPaymentDateField(serializers.DateField):
class OrderFeeSerializer(I18nAwareModelSerializer):
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta:
model = OrderFee
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)
event_date_from = serializers.DateTimeField(read_only=True, source="period_start")
event_date_to = serializers.DateTimeField(read_only=True, source="period_end")
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta:
model = InvoiceLine
@@ -1980,6 +1984,7 @@ class BlockedTicketSecretSerializer(I18nAwareModelSerializer):
class TransactionSerializer(I18nAwareModelSerializer):
order = serializers.SlugRelatedField(slug_field="code", read_only=True)
tax_rate = CompatDecimalField(max_digits=7, decimal_places=4)
class Meta:
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.helpers.countries import FastCountryField
from pretix.helpers.models import NormalizedDecimalField
def invoice_filename(instance, filename: str) -> str:
@@ -450,7 +451,7 @@ class InvoiceLine(models.Model):
description = models.TextField()
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_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_code = models.CharField(max_length=190, null=True, blank=True)
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.countries import CachedCountries, FastCountryField
from ...helpers.models import NormalizedDecimalField
from ...helpers.names import build_name
from ...testutils.middleware import debugflags_var
from ._transactions import (
@@ -2334,8 +2335,8 @@ class OrderFee(RoundingCorrectionMixin, models.Model):
)
description = models.CharField(max_length=190, blank=True)
internal_type = models.CharField(max_length=255, blank=True)
tax_rate = models.DecimalField(
max_digits=7, decimal_places=2,
tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=4,
verbose_name=_('Tax rate')
)
tax_rule = models.ForeignKey(
@@ -2533,8 +2534,8 @@ class OrderPosition(AbstractPosition):
max_digits=13, decimal_places=2, null=True, blank=True,
)
tax_rate = models.DecimalField(
max_digits=7, decimal_places=2,
tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=4,
verbose_name=_('Tax rate')
)
tax_rule = models.ForeignKey(
@@ -3052,8 +3053,8 @@ class Transaction(models.Model):
price_includes_rounding_correction = models.DecimalField(
max_digits=13, decimal_places=2, default=Decimal("0.00")
)
tax_rate = models.DecimalField(
max_digits=7, decimal_places=2,
tax_rate = NormalizedDecimalField(
max_digits=7, decimal_places=4,
verbose_name=_('Tax rate')
)
tax_rule = models.ForeignKey(
@@ -3168,8 +3169,8 @@ class CartPosition(AbstractPosition):
verbose_name=_("Limit for extending expiration date"),
null=True
)
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'),
verbose_name=_('Tax rate')
)
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.templatetags.money import money_filter
from pretix.helpers.countries import FastCountryField
from pretix.helpers.models import NormalizedDecimalField
class TaxedPrice:
@@ -335,9 +336,9 @@ class TaxRule(LoggedModel):
max_length=190,
choices=TAX_CODE_LISTS,
)
rate = models.DecimalField(
max_digits=10,
decimal_places=2,
rate = NormalizedDecimalField(
max_digits=7,
decimal_places=4,
validators=[
MaxValueValidator(
limit_value=Decimal("100.00"),

View File

@@ -26,6 +26,8 @@ from babel.numbers import format_currency
from django import template
from django.conf import settings
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
@@ -82,3 +84,19 @@ def money_numberfield_filter(value: Decimal, arg=''):
places = settings.CURRENCY_PLACES.get(arg, 2)
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/>
<small class="text-muted">
{% 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 }}
{% endblocktrans %}
{% 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 }}
{% endblocktrans %}
{% endif %}

View File

@@ -670,7 +670,7 @@
{% if line.tax_rate %}
<br/>
<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 }}
{% endblocktrans %}
</small>
@@ -680,7 +680,7 @@
{% if line.tax_rate and line.price %}
<br/>
<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 }}
{% endblocktrans %}
</small>
@@ -720,7 +720,7 @@
{% if fee.tax_rate %}
<br/>
<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 }}
{% endblocktrans %}
</small>
@@ -730,7 +730,7 @@
{% if fee.tax_rate %}
<br/>
<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 }}
{% endblocktrans %}
</small>

View File

@@ -23,6 +23,7 @@ import copy
from django.core.files import File
from django.db import models
from django.db.models.fields import DecimalField
class Thumbnail(models.Model):
@@ -54,3 +55,15 @@ def flatten_choices(choices):
yield from label_or_nested
else:
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>
{% endif %}
{% 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 }}
{% endblocktrans %}</small>
{% 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 }}
{% endblocktrans %}</small>
{% endif %}
@@ -313,11 +313,11 @@
<small>{% trans "incl. taxes" %}</small>
{% endif %}
{% 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 }}
{% endblocktrans %}</small>
{% 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 }}
{% endblocktrans %}</small>
{% endif %}

View File

@@ -357,7 +357,7 @@
{% if line.tax_rate and line.total %}
<br />
<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 }}
{% endblocktrans %}
</small>
@@ -367,7 +367,7 @@
{% if line.tax_rate and line.total %}
<br />
<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 }}
{% endblocktrans %}
</small>
@@ -416,7 +416,7 @@
{% if fee.tax_rate %}
<br />
<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 }}
{% endblocktrans %}
</small>
@@ -426,7 +426,7 @@
{% if fee.tax_rate %}
<br />
<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 }}
{% endblocktrans %}
</small>

View File

@@ -207,13 +207,13 @@
{% endif %}
{% 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">
{% 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 }}
{% endblocktrans %}
</small>
{% 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">
{% 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 }}
{% endblocktrans %}
</small>
@@ -372,13 +372,13 @@
{% endif %}
{% 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">
{% 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 }}
{% endblocktrans %}
</small>
{% 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">
{% 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 }}
{% endblocktrans %}
</small>

View File

@@ -201,13 +201,13 @@
{% endif %}
{% 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">
{% 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 }}
{% endblocktrans %}
</small>
{% 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">
{% 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 }}
{% endblocktrans %}
</small>
@@ -356,13 +356,13 @@
{% endif %}
{% 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">
{% 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 }}
{% endblocktrans %}
</small>
{% 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">
{% 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 }}
{% endblocktrans %}
</small>

View File

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

View File

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