details: https://code.tryton.org/tryton/commit/73989a49f837
branch: default
user: Cédric Krier <[email protected]>
date: Tue Apr 14 17:29:07 2026 +0200
description:
Add country organization as criteria of tax rule
Closes #14771
diffstat:
modules/account_tax_rule_country/CHANGELOG | 1 +
modules/account_tax_rule_country/account.py | 70
+++++++++-
modules/account_tax_rule_country/doc/design.rst | 5 +-
modules/account_tax_rule_country/tests/test_module.py | 36
+++++
modules/account_tax_rule_country/view/tax_rule_line_form.xml | 9 +
modules/account_tax_rule_country/view/tax_rule_line_template_form.xml | 9 +
modules/account_tax_rule_country/view/tax_rule_line_template_tree.xml | 2 +
modules/account_tax_rule_country/view/tax_rule_line_tree.xml | 2 +
modules/account_tax_rule_country/view/tax_rule_line_tree_sequence.xml | 2 +
9 files changed, 129 insertions(+), 7 deletions(-)
diffs (288 lines):
diff -r b0af9504b4a6 -r 73989a49f837 modules/account_tax_rule_country/CHANGELOG
--- a/modules/account_tax_rule_country/CHANGELOG Mon Apr 13 13:12:59
2026 +0200
+++ b/modules/account_tax_rule_country/CHANGELOG Tue Apr 14 17:29:07
2026 +0200
@@ -1,3 +1,4 @@
+* Add organization as criteria
Version 8.0.0 - 2026-04-20
--------------------------
diff -r b0af9504b4a6 -r 73989a49f837 modules/account_tax_rule_country/account.py
--- a/modules/account_tax_rule_country/account.py Mon Apr 13 13:12:59
2026 +0200
+++ b/modules/account_tax_rule_country/account.py Tue Apr 14 17:29:07
2026 +0200
@@ -3,7 +3,8 @@
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
-from trytond.pyson import Eval
+from trytond.pyson import Bool, Eval, If
+from trytond.transaction import Transaction
class TaxRule(metaclass=PoolMeta):
@@ -32,9 +33,29 @@
class _TaxRuleLineMixin:
__slots__ = ()
+
+ from_organization = fields.Many2One(
+ 'country.organization', "From Organization", ondelete='RESTRICT',
+ domain=[
+ If(Eval('from_country'),
+ ('id', '=', -1),
+ ()),
+ ],
+ states={
+ 'invisible': Bool(Eval('from_country')),
+ },
+ help="Apply only to the addresses from this organization.")
from_country = fields.Many2One(
'country.country', 'From Country', ondelete='RESTRICT',
- help="Apply only to addresses of this country.")
+ domain=[
+ If(Eval('from_organization'),
+ ('id', '=', -1),
+ ()),
+ ],
+ states={
+ 'invisible': Bool(Eval('from_organization')),
+ },
+ help="Apply only to the addresses from this country.")
from_subdivision = fields.Many2One(
'country.subdivision', "From Subdivision", ondelete='RESTRICT',
domain=[
@@ -43,10 +64,29 @@
states={
'invisible': ~Eval('from_country'),
},
- help="Apply only to addresses in this subdivision.")
+ help="Apply only to the addresses from this subdivision.")
+ to_organization = fields.Many2One(
+ 'country.organization', "To Organization", ondelete='RESTRICT',
+ domain=[
+ If(Eval('to_country'),
+ ('id', '=', -1),
+ ()),
+ ],
+ states={
+ 'invisible': Bool(Eval('to_country')),
+ },
+ help="Apply only to the addresses of this organization.")
to_country = fields.Many2One(
'country.country', 'To Country', ondelete='RESTRICT',
- help="Apply only to addresses of this country.")
+ domain=[
+ If(Eval('to_organization'),
+ ('id', '=', -1),
+ ()),
+ ],
+ states={
+ 'invisible': Bool(Eval('to_organization')),
+ },
+ help="Apply only to the addresses to this country.")
to_subdivision = fields.Many2One(
'country.subdivision', "To Subdivision", ondelete='RESTRICT',
domain=[
@@ -55,7 +95,7 @@
states={
'invisible': ~Eval('to_country'),
},
- help="Apply only to addresses in this subdivision.")
+ help="Apply only to the addresses to this subdivision.")
class TaxRuleLineTemplate(_TaxRuleLineMixin, metaclass=PoolMeta):
@@ -85,6 +125,26 @@
__name__ = 'account.tax.rule.line'
def match(self, pattern):
+ pool = Pool()
+ Date = pool.get('ir.date')
+ Country = pool.get('country.country')
+
+ with Transaction().set_context(company=self.rule.company.id):
+ date = pattern.get('date') or Date.today()
+
+ for organization, name in [
+ (self.from_organization, 'from_country'),
+ (self.to_organization, 'to_country'),
+ ]:
+ if organization:
+ pattern = pattern.copy()
+ country = pattern.pop(name, None)
+ if not country:
+ return False
+ country = Country(country)
+ if not country.is_member(organization, date=date):
+ return False
+
for name in ['from_subdivision', 'to_subdivision']:
subdivision = getattr(self, name)
if name not in pattern:
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/doc/design.rst
--- a/modules/account_tax_rule_country/doc/design.rst Mon Apr 13 13:12:59
2026 +0200
+++ b/modules/account_tax_rule_country/doc/design.rst Tue Apr 14 17:29:07
2026 +0200
@@ -11,8 +11,9 @@
When the *Account Tax Rule Country Module* is activated, the *Tax Rule* gains
additional criteria for the origin and destination `Country
-<country:model-country.country>` and `Subdivision
-<country:model-country.subdivision>` to match against.
+<country:model-country.country>`, `Subdivision
+<country:model-country.subdivision>` and `Organization
+<country:model-country.organization>` to match against.
The countries and subdivisions are taken from the origin document that applies
the tax rule:
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/tests/test_module.py
--- a/modules/account_tax_rule_country/tests/test_module.py Mon Apr 13
13:12:59 2026 +0200
+++ b/modules/account_tax_rule_country/tests/test_module.py Tue Apr 14
17:29:07 2026 +0200
@@ -35,10 +35,14 @@
@classmethod
def _create_countries(cls):
pool = Pool()
+ Organization = pool.get('country.organization')
Country = pool.get('country.country')
Subdivision = pool.get('country.subdivision')
+ organization1 = Organization(name="Org 1")
+ organization1.save()
country1 = Country(name="Country 1")
+ country1.members = [{'organization': organization1}]
country1.save()
subdivision1 = Subdivision(
country=country1, name="Subdivision 1", code="SUB1",
@@ -48,7 +52,11 @@
country=country1, parent=subdivision1,
name="Sub-Subdivision 1", code="SUBSUB1", type='province')
subdivision11.save()
+
+ organization2 = Organization(name="Org 2")
+ organization2.save()
country2 = Country(name="Country 2")
+ country2.members = [{'organization': organization2}]
country2.save()
subdivision2 = Subdivision(
country=country2, name="Subdivision 2", code="SUB2",
@@ -127,6 +135,34 @@
self.assertListEqual(tax_rule.apply(tax, pattern), [target_tax.id])
@with_transaction()
+ def test_tax_rule_organization(self):
+ "Test tax rule with organization"
+ country1, country2 = self._create_countries()
+ organization1 = country1.organizations[0]
+ organization2 = country2.organizations[0]
+ company = create_company()
+ with set_company(company):
+ create_chart(company, tax=True)
+ tax, target_tax = self._get_taxes()[:2]
+ tax_rule = self._create_rule([{
+ 'from_organization': organization1.id,
+ 'to_organization': organization2.id,
+ 'origin_tax': tax.id,
+ 'tax': target_tax.id,
+ }])
+
+ for pattern, result in [
+ ({'from_country': country1.id, 'to_country': country2.id},
+ [target_tax.id]),
+ ({'from_country': country2.id, 'to_country': country1.id},
+ [tax.id]),
+ ({'from_country': None, 'to_country': country2.id},
+ [tax.id]),
+ ]:
+ with self.subTest(pattern=pattern):
+ self.assertListEqual(tax_rule.apply(tax, pattern), result)
+
+ @with_transaction()
def test_tax_rule_no_subdivision(self):
"Test tax rule without subdivision"
country = self._create_countries()[0]
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/view/tax_rule_line_form.xml
--- a/modules/account_tax_rule_country/view/tax_rule_line_form.xml Mon Apr
13 13:12:59 2026 +0200
+++ b/modules/account_tax_rule_country/view/tax_rule_line_form.xml Tue Apr
14 17:29:07 2026 +0200
@@ -3,10 +3,19 @@
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='origin_tax']" position="after">
+ <label name="from_organization"/>
+ <field name="from_organization"/>
+ <newline/>
+
<label name="from_country"/>
<field name="from_country"/>
<label name="from_subdivision"/>
<field name="from_subdivision"/>
+
+ <label name="to_organization"/>
+ <field name="to_organization"/>
+ <newline/>
+
<label name="to_country"/>
<field name="to_country"/>
<label name="to_subdivision"/>
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/view/tax_rule_line_template_form.xml
--- a/modules/account_tax_rule_country/view/tax_rule_line_template_form.xml
Mon Apr 13 13:12:59 2026 +0200
+++ b/modules/account_tax_rule_country/view/tax_rule_line_template_form.xml
Tue Apr 14 17:29:07 2026 +0200
@@ -3,10 +3,19 @@
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/field[@name='origin_tax']" position="after">
+ <label name="from_organization"/>
+ <field name="from_organization"/>
+ <newline/>
+
<label name="from_country"/>
<field name="from_country"/>
<label name="from_subdivision"/>
<field name="from_subdivision"/>
+
+ <label name="to_organization"/>
+ <field name="to_organization"/>
+ <newline/>
+
<label name="to_country"/>
<field name="to_country"/>
<label name="to_subdivision"/>
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/view/tax_rule_line_template_tree.xml
--- a/modules/account_tax_rule_country/view/tax_rule_line_template_tree.xml
Mon Apr 13 13:12:59 2026 +0200
+++ b/modules/account_tax_rule_country/view/tax_rule_line_template_tree.xml
Tue Apr 14 17:29:07 2026 +0200
@@ -3,8 +3,10 @@
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='origin_tax']" position="after">
+ <field name="from_organization" expand="1"/>
<field name="from_country" expand="1"/>
<field name="from_subdivision" expand="1"/>
+ <field name="to_organization" expand="1"/>
<field name="to_country" expand="1"/>
<field name="to_subdivision" expand="1"/>
</xpath>
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/view/tax_rule_line_tree.xml
--- a/modules/account_tax_rule_country/view/tax_rule_line_tree.xml Mon Apr
13 13:12:59 2026 +0200
+++ b/modules/account_tax_rule_country/view/tax_rule_line_tree.xml Tue Apr
14 17:29:07 2026 +0200
@@ -3,8 +3,10 @@
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='origin_tax']" position="after">
+ <field name="from_organization" expand="1"/>
<field name="from_country" expand="1"/>
<field name="from_subdivision" expand="1"/>
+ <field name="to_organization" expand="1"/>
<field name="to_country" expand="1"/>
<field name="to_subdivision" expand="1"/>
</xpath>
diff -r b0af9504b4a6 -r 73989a49f837
modules/account_tax_rule_country/view/tax_rule_line_tree_sequence.xml
--- a/modules/account_tax_rule_country/view/tax_rule_line_tree_sequence.xml
Mon Apr 13 13:12:59 2026 +0200
+++ b/modules/account_tax_rule_country/view/tax_rule_line_tree_sequence.xml
Tue Apr 14 17:29:07 2026 +0200
@@ -3,8 +3,10 @@
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/tree/field[@name='origin_tax']" position="after">
+ <field name="from_organization" expand="1"/>
<field name="from_country" expand="1"/>
<field name="from_subdivision" expand="1"/>
+ <field name="to_organization" expand="1"/>
<field name="to_country" expand="1"/>
<field name="to_subdivision" expand="1"/>
</xpath>