Source code for shoop.default_tax.models
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals
from django.db import models
from django.db.models import Q
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from shoop.core.models import CustomerTaxGroup, Tax, TaxClass
from shoop.utils.patterns import Pattern, pattern_matches
[docs]class TaxRuleQuerySet(models.QuerySet):
[docs] def may_match_postal_code(self, postalcode):
null = Q(_postal_codes_min__isnull=True)
in_range = Q()
if postalcode:
in_range = Q(_postal_codes_min__lte=postalcode, _postal_codes_max__gte=postalcode)
return self.filter(null | in_range)
@python_2_unicode_compatible
[docs]class TaxRule(models.Model):
enabled = models.BooleanField(default=True, verbose_name=_('enabled'), db_index=True)
tax_classes = models.ManyToManyField(
TaxClass,
verbose_name=_("tax classes"), help_text=_(
"Tax classes of the items to be taxed"))
customer_tax_groups = models.ManyToManyField(
CustomerTaxGroup, blank=True,
verbose_name=_("customer tax groups"))
country_codes_pattern = models.CharField(
max_length=300, blank=True,
verbose_name=_("country codes pattern"))
region_codes_pattern = models.CharField(
max_length=500, blank=True,
verbose_name=_("region codes pattern"))
postal_codes_pattern = models.CharField(
max_length=500, blank=True,
verbose_name=_("postal codes pattern"))
_postal_codes_min = models.CharField(max_length=100, blank=True, null=True)
_postal_codes_max = models.CharField(max_length=100, blank=True, null=True)
priority = models.IntegerField(
default=0,
verbose_name=_("priority"), help_text=_(
"Rules with same priority define added taxes (e.g. US taxes) "
"and rules with different priority define compound taxes "
"(e.g. Canada Quebec PST case)"))
override_group = models.IntegerField(
default=0,
verbose_name=_("override group number"), help_text=_(
"If several rules match, only the rules with the highest "
"override group number will be effective. This can be "
"used, for example, to implement tax exemption by adding "
"a rule with very high override group that sets a zero tax."))
tax = models.ForeignKey(Tax, on_delete=models.PROTECT, verbose_name=_('tax'))
objects = TaxRuleQuerySet.as_manager()
[docs] def matches(self, taxing_context):
"""
Check if this tax rule matches given taxing context.
:type taxing_context: shoop.core.taxing.TaxingContext
"""
if taxing_context.customer_tax_group:
tax_groups = set(self.customer_tax_groups.all())
if tax_groups:
if taxing_context.customer_tax_group not in tax_groups:
return False
if self.country_codes_pattern:
if not pattern_matches(self.country_codes_pattern, taxing_context.country_code):
return False
if self.region_codes_pattern:
if not pattern_matches(self.region_codes_pattern, taxing_context.region_code):
return False
if self.postal_codes_pattern:
if not pattern_matches(self.postal_codes_pattern, taxing_context.postal_code):
return False
return True
[docs] def save(self, *args, **kwargs):
if self.postal_codes_pattern:
min_value, max_value = Pattern(self.postal_codes_pattern).get_alphabetical_limits()
self._postal_codes_min = min_value
self._postal_codes_max = max_value
return super(TaxRule, self).save(*args, **kwargs)
def __str__(self):
return _("Tax rule {} ({})").format(self.pk, self.tax)