Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions account_ecotax/models/account_ecotax_classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ class AccountEcotaxClassification(models.Model):
)
intrastat_code = fields.Char()
scale_code = fields.Char()
country_ids = fields.Many2many(
"res.country",
string="Countries",
help="Ecotax will be applied when delivered in the listed countries (or all "
"countries if empty)",
)

@api.depends("ecotax_type")
def _compute_ecotax_vals(self):
Expand Down
12 changes: 10 additions & 2 deletions account_ecotax/models/account_move_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,26 @@ def _compute_ecotax(self):

def _get_new_vals_list(self):
self.ensure_one()
if not self.product_id:
return []
country = (
self.move_id.partner_shipping_id.country_id
or self.move_id.partner_id.country_id
)
new_vals_list = [
Command.create(
{
"classification_id": ecotaxline_prod.classification_id.id,
"force_amount_unit": ecotaxline_prod.force_amount,
}
)
for ecotaxline_prod in self.product_id.all_ecotax_line_product_ids
for ecotaxline_prod in self.product_id._get_country_eligible_classification(
country
)
]
return new_vals_list

@api.depends("product_id")
@api.depends("product_id", "move_id.partner_id", "move_id.partner_shipping_id")
def _compute_ecotax_line_ids(self):
"""Unlink and recreate ecotax_lines when modifying the product_id."""
for line in self:
Expand Down
5 changes: 5 additions & 0 deletions account_ecotax/models/ecotax_line_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ class EcotaxLineProduct(models.Model):
help="Ecotax Amount computed form Classification or forced ecotax amount",
store=True,
)
country_ids = fields.Many2many(
"res.country",
string="Countries",
related="classification_id.country_ids",
)
display_name = fields.Char(compute="_compute_display_name")

@api.depends("classification_id", "amount")
Expand Down
38 changes: 28 additions & 10 deletions account_ecotax/models/product_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,34 @@ def _search_all_ecotax_line_product_ids(self, operator, operand):
)
def _compute_product_ecotax(self):
for product in self:
amount_ecotax = 0.0
weight_based_ecotax = 0.0
fixed_ecotax = 0.0
for ecotaxline_prod in product.all_ecotax_line_product_ids:
ecotax_cls = ecotaxline_prod.classification_id
if ecotax_cls.ecotax_type == "weight_based":
weight_based_ecotax += ecotaxline_prod.amount
else:
fixed_ecotax += ecotaxline_prod.amount
amount_ecotax += ecotaxline_prod.amount
(
fixed_ecotax,
weight_based_ecotax,
amount_ecotax,
) = product._get_ecotax_amounts_from_classification(
product.all_ecotax_line_product_ids
)
product.fixed_ecotax = fixed_ecotax
product.weight_based_ecotax = weight_based_ecotax
product.ecotax_amount = amount_ecotax

def _get_ecotax_amounts_from_classification(self, classifications):
self.ensure_one()
amount_ecotax = 0.0
weight_based_ecotax = 0.0
fixed_ecotax = 0.0
for ecotaxline_prod in classifications:
ecotax_cls = ecotaxline_prod.classification_id
if ecotax_cls.ecotax_type == "weight_based":
weight_based_ecotax += ecotaxline_prod.amount
else:
fixed_ecotax += ecotaxline_prod.amount
amount_ecotax += ecotaxline_prod.amount
return fixed_ecotax, weight_based_ecotax, amount_ecotax

def _get_country_eligible_classification(self, country):
self and self.ensure_one()
return self.all_ecotax_line_product_ids.filtered(
lambda line: not line.country_ids
or (country and country in line.country_ids)
)
30 changes: 30 additions & 0 deletions account_ecotax/tests/test_ecotax.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,33 @@ def _test_05_product_variants(self):
variant_2.product_tmpl_id.ecotax_line_product_ids,
)

def _test_06_ecotax_by_country(self):
"""
Test default ecotax by country
"""
self.invoice_partner.write({"country_id": self.env.ref("base.fr").id})
invoice = self._make_invoice(products=self._make_product(self.ecotax_fixed))
# no country ecotax classification is set
self.assertEqual(
invoice.invoice_line_ids.ecotax_line_ids.classification_id,
self.ecotax_fixed,
)
# in case of wrong country, the ecotax is not set
self.ecotax_fixed.write(
{"country_ids": [Command.link(self.env.ref("base.de").id)]}
)
invoice.write({"partner_id": self.invoice_partner.id})
self.assertFalse(invoice.invoice_line_ids.ecotax_line_ids.classification_id)
# in case the same country is set, the ecotax is set as well
self.ecotax_fixed.write(
{"country_ids": [Command.link(self.env.ref("base.fr").id)]}
)
invoice.write({"partner_id": self.invoice_partner.id})
self.assertEqual(
invoice.invoice_line_ids.ecotax_line_ids.classification_id,
self.ecotax_fixed,
)


class TestInvoiceEcotax(TestInvoiceEcotaxCommon):
def test_01_default_fixed_ecotax(self):
Expand All @@ -421,3 +448,6 @@ def test_04_mixed_ecotax(self):

def test_05_product_variants(self):
self._test_05_product_variants()

def test_06_ecotax_by_country(self):
self._test_06_ecotax_by_country()
2 changes: 2 additions & 0 deletions account_ecotax/views/account_ecotax_classification_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
/>
<field name="categ_id" />
<field name="product_status" />
<field name="country_ids" widget="many2many_tags" optional="hide" />
</tree>
</field>
</record>
Expand Down Expand Up @@ -58,6 +59,7 @@
</group>
<separator string="Ecotaxes settings" />
<group col="4" name="ecotax_settings">
<field name="country_ids" widget="many2many_tags" />
<field name="ecotax_type" />
<field
name="ecotax_coef"
Expand Down
1 change: 1 addition & 0 deletions account_ecotax/views/product_template_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<field name="classification_id" />
<field name="force_amount" />
<field name="amount" />
<field name="country_ids" widget="many2many_tags" />
</tree>
</field>
</div>
Expand Down
3 changes: 3 additions & 0 deletions account_ecotax/views/product_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<field name="classification_id" />
<field name="force_amount" />
<field name="amount" />
<field name="country_ids" widget="many2many_tags" />
</tree>
</field>
</div>
Expand All @@ -43,6 +44,7 @@
<field name="classification_id" />
<field name="force_amount" />
<field name="amount" />
<field name="country_ids" widget="many2many_tags" />
</tree>
</field>
</div>
Expand Down Expand Up @@ -73,6 +75,7 @@
<field name="classification_id" />
<field name="force_amount" />
<field name="amount" />
<field name="country_ids" widget="many2many_tags" />
</tree>
</field>
</div>
Expand Down
12 changes: 10 additions & 2 deletions account_ecotax_sale/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,26 @@ def _compute_ecotax(self):

def _get_new_vals_list(self):
self.ensure_one()
if not self.product_id:
return []
country = (
self.order_id.partner_shipping_id.country_id
or self.order_id.partner_id.country_id
)
new_vals_list = [
Command.create(
{
"classification_id": ecotaxline_prod.classification_id.id,
"force_amount_unit": ecotaxline_prod.force_amount,
}
)
for ecotaxline_prod in self.product_id.all_ecotax_line_product_ids
for ecotaxline_prod in self.product_id._get_country_eligible_classification(
country
)
]
return new_vals_list

@api.depends("product_id")
@api.depends("product_id", "order_id.partner_id", "order_id.partner_shipping_id")
def _compute_ecotax_line_ids(self):
"""Unlink and recreate ecotax_lines when modifying the product_id."""
for line in self:
Expand Down
32 changes: 32 additions & 0 deletions account_ecotax_sale/tests/test_sale_ecotax.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# @author Mourad EL HADJ MIMOUNE <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import Command
from odoo.tests.common import Form

from odoo.addons.account_ecotax.tests.test_ecotax import TestInvoiceEcotaxCommon
Expand Down Expand Up @@ -106,10 +107,41 @@ def _test_02_classification_ecotax(self):
self.assertEqual(self.sale.amount_total, 1000.0)
self.assertEqual(self.sale.amount_ecotax, 47.0)

def _test_03_ecotax_by_country(self):
"""
Test default ecotax by country
"""
partner12 = self.env.ref("base.res_partner_12")
partner12.write({"country_id": self.env.ref("base.fr").id})
sale = self.create_sale_partner(
partner_id=partner12, products_and_qty=[(self.product_a, 1.0)]
)
# no country ecotax classification is set, ecotax is taken by default
self.assertEqual(
sale.order_line.ecotax_line_ids.classification_id, self.ecotax_fixed
)
# in case of wrong country, the ecotax is not set
self.ecotax_fixed.write(
{"country_ids": [Command.link(self.env.ref("base.de").id)]}
)
sale.write({"partner_id": partner12.id})
self.assertFalse(sale.order_line.ecotax_line_ids.classification_id)
# in case the same country is set, the ecotax is set as well
self.ecotax_fixed.write(
{"country_ids": [Command.link(self.env.ref("base.fr").id)]}
)
sale.write({"partner_id": sale.partner_id.id})
self.assertEqual(
sale.order_line.ecotax_line_ids.classification_id, self.ecotax_fixed
)


class TestsaleEcotax(TestsaleEcotaxCommon):
def test_01_classification_weight_based_ecotax(self):
self._test_01_classification_weight_based_ecotax()

def test_02_classification_ecotax(self):
self._test_02_classification_ecotax()

def test_03_ecotax_by_country(self):
self._test_03_ecotax_by_country()
20 changes: 15 additions & 5 deletions account_ecotax_sale_tax/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ def _get_new_vals_list(self):
def _compute_ecotax_line_ids(self):
return super()._compute_ecotax_line_ids()

@api.depends("product_id", "company_id")
@api.depends(
"product_id",
"company_id",
"order_id.partner_id",
"order_id.partner_shipping_id",
)
def _compute_tax_id(self):
res = super()._compute_tax_id()
for line in self:
Expand All @@ -63,10 +68,15 @@ def _compute_tax_id(self):

def _get_computed_ecotaxes(self):
self.ensure_one()
sale_ecotaxes = self.product_id.all_ecotax_line_product_ids.mapped(
"classification_id"
).mapped("sale_ecotax_ids")
ecotax_ids = sale_ecotaxes.filtered(
country = (
self.order_id.partner_shipping_id.country_id
or self.order_id.partner_id.country_id
)
eligible_classifications = self.product_id._get_country_eligible_classification(
country
)
sale_ecotaxs = eligible_classifications.classification_id.sale_ecotax_ids
ecotax_ids = sale_ecotaxs.filtered(
lambda tax: tax.company_id == self.order_id.company_id
)

Expand Down
3 changes: 3 additions & 0 deletions account_ecotax_sale_tax/tests/test_sale_ecotax.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,6 @@ def test_02_classification_ecotax(self):
self.assertEqual(sale_line2.subtotal_ecotax, 32)
self.assertEqual(self.sale.amount_total, 1047.0)
self.assertEqual(self.sale.amount_ecotax, 47.0)

def test_03_ecotax_by_country(self):
self._test_03_ecotax_by_country()
8 changes: 3 additions & 5 deletions account_ecotax_tax/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=================================
Ecotax Management (with Odoo tax)
=================================
Expand All @@ -17,7 +13,7 @@ Ecotax Management (with Odoo tax)
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--fiscal--rule-lightgray.png?logo=github
Expand Down Expand Up @@ -89,6 +85,8 @@ Known issues / Roadmap
Since an update in Odoo https://github.com/odoo/odoo/commit/13e9833e0bc809a26843890363586f61a37d061c the case with ecotax as tax included and another tax included does not work anymore.
The ecotax tax should only be used along with price excluded tax, or be configured as price excluded itself.

There is a limitation with the country restriction on ecotax classification when using the account_ecotax_tax and account_ecotax_sale_tax modules.OIt is currently not possible to have multiple classificaiton restricted to different countries for a same product.

Bug Tracker
===========

Expand Down
1 change: 1 addition & 0 deletions account_ecotax_tax/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import account_ecotax_classification
from . import account_move_line
from . import account_tax
from . import product_product
29 changes: 23 additions & 6 deletions account_ecotax_tax/models/account_move_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,40 @@ def _get_new_vals_list(self):
def _compute_ecotax_line_ids(self):
return super()._compute_ecotax_line_ids()

@api.depends(
"product_id",
"product_uom_id",
"move_id.partner_id",
"move_id.partner_shipping_id",
)
def _compute_tax_ids(self):
return super()._compute_tax_ids()

def _get_computed_taxes(self):
tax_ids = super()._get_computed_taxes()
ecotax_ids = self.env["account.tax"]
country = (
self.move_id.partner_shipping_id.country_id
or self.move_id.partner_id.country_id
)
if self.move_id.is_sale_document(include_receipts=True):
# Out invoice.
sale_ecotaxs = self.product_id.all_ecotax_line_product_ids.mapped(
"classification_id"
).mapped("sale_ecotax_ids")
eligible_classifications = (
self.product_id._get_country_eligible_classification(country)
)
sale_ecotaxs = eligible_classifications.classification_id.sale_ecotax_ids
ecotax_ids = sale_ecotaxs.filtered(
lambda tax: tax.company_id == self.move_id.company_id
)

elif self.move_id.is_purchase_document(include_receipts=True):
# In invoice.
purchase_ecotaxs = self.product_id.all_ecotax_line_product_ids.mapped(
"classification_id"
).mapped("purchase_ecotax_ids")
eligible_classifications = (
self.product_id._get_country_eligible_classification(country)
)
purchase_ecotaxs = (
eligible_classifications.classification_id.purchase_ecotax_ids
)
ecotax_ids = purchase_ecotaxs.filtered(
lambda tax: tax.company_id == self.move_id.company_id
)
Expand Down
5 changes: 4 additions & 1 deletion account_ecotax_tax/models/account_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ def onchange_is_ecotax(self):
# partner: res.partner object or None
# for weight based ecotax
# result = quantity and product.weight_based_ecotax * quantity or 0.0
result = quantity and product.fixed_ecotax * quantity or 0.0
# for fix ecotax
# result = quantity and product.fixed_ecotax * quantity or 0.0
# to manage both weight and fix with only one ecotax tax
result = quantity and product.ecotax_amount * quantity or 0.0
"""
Loading