1 parent
ad9f7bf8f2
commit
642ff61ab4
9 files changed
+129
-7
No files matched your search
@@ -1,3 +1,4 @@
|
||||
* Add organization as criteria
|
||||
|
||||
Version 8.0.0 - 2026-04-20
|
||||
--------------------------
|
||||
|
||||
@@ -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 TaxRule(metaclass=PoolMeta):
|
||||
|
||||
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 @@ class _TaxRuleLineMixin:
|
||||
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 @@ class _TaxRuleLineMixin:
|
||||
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 @@ class TaxRuleLine(_TaxRuleLineMixin, metaclass=PoolMeta):
|
||||
__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:
|
||||
|
||||
@@ -11,8 +11,9 @@ Tax Rule
|
||||
|
||||
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:
|
||||
|
||||
@@ -35,10 +35,14 @@ class AccountTaxRuleCountryTestCase(CompanyTestMixin, ModuleTestCase):
|
||||
@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 @@ class AccountTaxRuleCountryTestCase(CompanyTestMixin, ModuleTestCase):
|
||||
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",
|
||||
@@ -126,6 +134,34 @@ class AccountTaxRuleCountryTestCase(CompanyTestMixin, ModuleTestCase):
|
||||
|
||||
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"
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user