diff --git a/account_ecotax_tax/README.rst b/account_ecotax_tax/README.rst new file mode 100644 index 000000000..95b34358c --- /dev/null +++ b/account_ecotax_tax/README.rst @@ -0,0 +1,152 @@ +================================= +Ecotax Management (with Odoo tax) +================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:325b4d53ac93f3760030128a6c45ca9e12cef59c1998fc54a3044f230150da9a + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/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 + :target: https://github.com/OCA/account-fiscal-rule/tree/17.0/account_ecotax_tax + :alt: OCA/account-fiscal-rule +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-fiscal-rule-17-0/account-fiscal-rule-17-0-account_ecotax_tax + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-fiscal-rule&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to compute the ecotax amounts from Odoo tax +mechanism. The advantages compared to the base account_ecotax module is +that it allows to : - Manage ecotax amount as included or excluded from +the price of the product - Isolate the amount of the ecotax in a +specific accounting account (set on the tax) + +Then the ecotax amounts are not considered as turnover, which could be +good or not depending on your country's legislation or accountant +preferences. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +1. Create a tax group named **"Ecotaxes"**. The sequence must be lower + than other tax groups. + + - Set the **Preceding Subtotal** field to **"Without Ecotax"**. + +2. Create two taxes named **"Fixed Ecotax"** and **"Weight-Based + Ecotax"**. + + - Check the **Ecotax** checkbox. + - Set the correct Python code: + + - For the fixed ecotax: + + .. code:: python + + result = quantity and product.fixed_ecotax * quantity or 0.0 + + - For the weight-based ecotax: + + .. code:: python + + result = quantity and product.weight_based_ecotax * quantity or 0.0 + + - Check the **Included in Base Amount** option. + - The sequence for Ecotax must be lower than the VAT tax. + +3. For VAT taxes, check the **Base Affected by Previous Taxes?** option. +4. Add an ecotax classification via the menu **Accounting > + Configuration > Taxes > Ecotax Classification**. + + - The ecotax classification can be either a fixed ecotax or a + weight-based ecotax. + - Ecotax classification information can be used for legal + declarations. + - For the fixed ecotax, the ecotax amount is used as a default + value, which can be overridden on the product. + - For the weight-based ecotax, define one ecotax by a coefficient + applied to the weight (depending on the product's materials). + - Set the appropriate tax in the **Sale Ecotax** field. + +5. Assign one or more ecotax classifications to a product. + + - The ecotax amount can also be manually overridden on the product. + +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. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Akretion + +Contributors +------------ + +- Mourad EL HADJ MIMOUNE +- Florian da Costa + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-mourad-ehm| image:: https://github.com/mourad-ehm.png?size=40px + :target: https://github.com/mourad-ehm + :alt: mourad-ehm +.. |maintainer-florian-dacosta| image:: https://github.com/florian-dacosta.png?size=40px + :target: https://github.com/florian-dacosta + :alt: florian-dacosta + +Current `maintainers `__: + +|maintainer-mourad-ehm| |maintainer-florian-dacosta| + +This module is part of the `OCA/account-fiscal-rule `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_ecotax_tax/__init__.py b/account_ecotax_tax/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/account_ecotax_tax/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_ecotax_tax/__manifest__.py b/account_ecotax_tax/__manifest__.py new file mode 100644 index 000000000..b5ed80d19 --- /dev/null +++ b/account_ecotax_tax/__manifest__.py @@ -0,0 +1,24 @@ +# © 2014-2023 Akretion (http://www.akretion.com) +# @author Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Ecotax Management (with Odoo tax)", + "summary": "Use Odoo tax mechanism to compute the ecotaxes ", + "version": "17.0.1.0.1", + "author": "Akretion, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-fiscal-rule", + "category": "Localization/Account Taxes", + "license": "AGPL-3", + "maintainers": ["mourad-ehm", "florian-dacosta"], + "depends": [ + "account_ecotax", + "account_tax_python", + ], + "data": [ + "views/account_ecotax_classification_view.xml", + "views/account_tax_view.xml", + "views/account_move_view.xml", + "report/invoice.xml", + ], + "installable": True, +} diff --git a/account_ecotax_tax/i18n/account_ecotax_tax.pot b/account_ecotax_tax/i18n/account_ecotax_tax.pot new file mode 100644 index 000000000..5513dc7d4 --- /dev/null +++ b/account_ecotax_tax/i18n/account_ecotax_tax.pot @@ -0,0 +1,63 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_ecotax_tax +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_ecotax_tax +#: model:ir.model,name:account_ecotax_tax.model_account_ecotax_classification +msgid "Account Ecotax Classification" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_move_line__subtotal_ecotax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_tax__is_ecotax +msgid "Ecotax" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_move_line__ecotax_amount_unit +msgid "Ecotax Unit" +msgstr "" + +#. module: account_ecotax_tax +#: model_terms:ir.ui.view,arch_db:account_ecotax_tax.ecotax_classification_form +msgid "Ecotaxes" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model,name:account_ecotax_tax.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_ecotax_classification__purchase_ecotax_ids +msgid "Purchase EcoTax" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_ecotax_classification__sale_ecotax_ids +msgid "Sale EcoTax" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model,name:account_ecotax_tax.model_account_tax +msgid "Tax" +msgstr "" + +#. module: account_ecotax_tax +#: model:ir.model.fields,help:account_ecotax_tax.field_account_tax__is_ecotax +msgid "" +"Warning : To include Ecotax in the VAT tax check this :\n" +"1: check \"included in base amount \"\n" +"2: The Ecotax sequence must be less then VAT tax (in sale and purchase)" +msgstr "" diff --git a/account_ecotax_tax/i18n/it.po b/account_ecotax_tax/i18n/it.po new file mode 100644 index 000000000..5ec49d081 --- /dev/null +++ b/account_ecotax_tax/i18n/it.po @@ -0,0 +1,71 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_ecotax_tax +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-02-07 00:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: account_ecotax_tax +#: model:ir.model,name:account_ecotax_tax.model_account_ecotax_classification +msgid "Account Ecotax Classification" +msgstr "Classificazione conto imposta ecologica" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_move_line__subtotal_ecotax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_tax__is_ecotax +msgid "Ecotax" +msgstr "Imposta ecologica" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_move_line__ecotax_amount_unit +msgid "Ecotax Unit" +msgstr "Unità imposta ecologica" + +#. module: account_ecotax_tax +#: model_terms:ir.ui.view,arch_db:account_ecotax_tax.ecotax_classification_form +msgid "Ecotaxes" +msgstr "Imposte ecologiche" + +#. module: account_ecotax_tax +#: model:ir.model,name:account_ecotax_tax.model_account_move_line +msgid "Journal Item" +msgstr "Movimento contabile" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_ecotax_classification__purchase_ecotax_ids +msgid "Purchase EcoTax" +msgstr "Imposta ecologica acquisti" + +#. module: account_ecotax_tax +#: model:ir.model.fields,field_description:account_ecotax_tax.field_account_ecotax_classification__sale_ecotax_ids +msgid "Sale EcoTax" +msgstr "Imposta ecologica vendite" + +#. module: account_ecotax_tax +#: model:ir.model,name:account_ecotax_tax.model_account_tax +msgid "Tax" +msgstr "Imposta" + +#. module: account_ecotax_tax +#: model:ir.model.fields,help:account_ecotax_tax.field_account_tax__is_ecotax +msgid "" +"Warning : To include Ecotax in the VAT tax check this :\n" +"1: check \"included in base amount \"\n" +"2: The Ecotax sequence must be less then VAT tax (in sale and purchase)" +msgstr "" +"Attenzione: per includere l'imposta ecologica nell'imposta IVA, controllare " +"quanto segue:\n" +"1: seleziona \"incluso nell'importo base\"\n" +"2: la sequenza dell'imposta ecologica deve essere inferiore all'imposta IVA (" +"in vendita e acquisto)" diff --git a/account_ecotax_tax/models/__init__.py b/account_ecotax_tax/models/__init__.py new file mode 100644 index 000000000..62a42c959 --- /dev/null +++ b/account_ecotax_tax/models/__init__.py @@ -0,0 +1,3 @@ +from . import account_ecotax_classification +from . import account_move_line +from . import account_tax diff --git a/account_ecotax_tax/models/account_ecotax_classification.py b/account_ecotax_tax/models/account_ecotax_classification.py new file mode 100644 index 000000000..e9ac21f0a --- /dev/null +++ b/account_ecotax_tax/models/account_ecotax_classification.py @@ -0,0 +1,26 @@ +# © 2014-2023 Akretion (http://www.akretion.com) +# @author Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountEcotaxClassification(models.Model): + _inherit = "account.ecotax.classification" + + sale_ecotax_ids = fields.Many2many( + "account.tax", + "ecotax_classif_taxes_rel", + "ecotax_classif_id", + "tax_id", + string="Sale EcoTax", + domain=[("is_ecotax", "=", True), ("type_tax_use", "=", "sale")], + ) + purchase_ecotax_ids = fields.Many2many( + "account.tax", + "ecotax_classif_purchase_taxes_rel", + "ecotax_classif_id", + "tax_id", + string="Purchase EcoTax", + domain=[("is_ecotax", "=", True), ("type_tax_use", "=", "purchase")], + ) diff --git a/account_ecotax_tax/models/account_move_line.py b/account_ecotax_tax/models/account_move_line.py new file mode 100644 index 000000000..0db95748b --- /dev/null +++ b/account_ecotax_tax/models/account_move_line.py @@ -0,0 +1,96 @@ +# © 2014-2023 Akretion (http://www.akretion.com) +# @author Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class AcountMoveLine(models.Model): + _inherit = "account.move.line" + + # replace compute method because we want to change the invalidation fields + # (api.depends) and not add some. (we want to remove the ones on ecotax_line_ids) + # because ecotax_line_ids now depends on the 2 next fields. + subtotal_ecotax = fields.Float(compute="_compute_ecotax_tax") + ecotax_amount_unit = fields.Float( + compute="_compute_ecotax_tax", + ) + + def _get_ecotax_amounts(self): + self.ensure_one() + ecotax_ids = self.tax_ids.filtered(lambda tax: tax.is_ecotax) + + if self.display_type == "tax" or not ecotax_ids: + return 0.0, 0.0 + if self.display_type == "product" and self.move_id.is_invoice(True): + amount_currency = self.price_unit * (1 - self.discount / 100) + handle_price_include = True + quantity = self.quantity + else: + amount_currency = self.amount_currency + handle_price_include = False + quantity = 1 + compute_all_currency = ecotax_ids.compute_all( + amount_currency, + currency=self.currency_id, + quantity=quantity, + product=self.product_id, + partner=self.move_id.partner_id or self.partner_id, + is_refund=self.is_refund, + handle_price_include=handle_price_include, + include_caba_tags=self.move_id.always_tax_exigible, + ) + subtotal_ecotax = 0.0 + for tax in compute_all_currency["taxes"]: + subtotal_ecotax += tax["amount"] + + amount_unit = subtotal_ecotax / quantity if quantity else subtotal_ecotax + return amount_unit, subtotal_ecotax + + @api.depends( + "currency_id", + "tax_ids", + "quantity", + "product_id", + ) + def _compute_ecotax_tax(self): + return self._compute_ecotax() + + def _get_new_vals_list(self): + if not self.subtotal_ecotax: + return [] + return super()._get_new_vals_list() + + # ensure lines are re-generated in case ecotax_amount_unit of invoice line change + # without changing the product + @api.depends("ecotax_amount_unit", "subtotal_ecotax") + def _compute_ecotax_line_ids(self): + return super()._compute_ecotax_line_ids() + + def _get_computed_taxes(self): + tax_ids = super()._get_computed_taxes() + ecotax_ids = self.env["account.tax"] + 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") + 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") + ecotax_ids = purchase_ecotaxs.filtered( + lambda tax: tax.company_id == self.move_id.company_id + ) + + if ecotax_ids and self.move_id.fiscal_position_id: + ecotax_ids = self.move_id.fiscal_position_id.map_tax(ecotax_ids) + if ecotax_ids: + tax_ids |= ecotax_ids + + return tax_ids diff --git a/account_ecotax_tax/models/account_tax.py b/account_ecotax_tax/models/account_tax.py new file mode 100644 index 000000000..fd592c692 --- /dev/null +++ b/account_ecotax_tax/models/account_tax.py @@ -0,0 +1,32 @@ +# © 2014-2024 Akretion (http://www.akretion.com) +# @author Mourad EL HADJ MIMOUNE +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class AccountTax(models.Model): + _inherit = "account.tax" + + is_ecotax = fields.Boolean( + "Ecotax", + help="Warning : To include Ecotax " + "in the VAT tax check this :\n" + '1: check "included in base amount "\n' + "2: The Ecotax sequence must be less then " + "VAT tax (in sale and purchase)", + ) + + @api.onchange("is_ecotax") + def onchange_is_ecotax(self): + if self.is_ecotax: + self.amount_type = "code" + self.include_base_amount = True + self.python_compute = """ +# price_unit +# product: product.product object or None +# 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 + """ diff --git a/account_ecotax_tax/pyproject.toml b/account_ecotax_tax/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/account_ecotax_tax/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_ecotax_tax/readme/CONTRIBUTORS.md b/account_ecotax_tax/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..1a5b4cc01 --- /dev/null +++ b/account_ecotax_tax/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Mourad EL HADJ MIMOUNE \<\> +- Florian da Costa \<\> diff --git a/account_ecotax_tax/readme/DESCRIPTION.md b/account_ecotax_tax/readme/DESCRIPTION.md new file mode 100644 index 000000000..95ee47165 --- /dev/null +++ b/account_ecotax_tax/readme/DESCRIPTION.md @@ -0,0 +1,9 @@ +This module allows to compute the ecotax amounts from Odoo tax +mechanism. The advantages compared to the base account_ecotax module is +that it allows to : - Manage ecotax amount as included or excluded from +the price of the product - Isolate the amount of the ecotax in a +specific accounting account (set on the tax) + +Then the ecotax amounts are not considered as turnover, which could be +good or not depending on your country's legislation or accountant +preferences. diff --git a/account_ecotax_tax/readme/ROADMAP.md b/account_ecotax_tax/readme/ROADMAP.md new file mode 100644 index 000000000..b6bf735f3 --- /dev/null +++ b/account_ecotax_tax/readme/ROADMAP.md @@ -0,0 +1,5 @@ +Since an update in Odoo + +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. diff --git a/account_ecotax_tax/readme/USAGE.md b/account_ecotax_tax/readme/USAGE.md new file mode 100644 index 000000000..b3ddd2dd5 --- /dev/null +++ b/account_ecotax_tax/readme/USAGE.md @@ -0,0 +1,35 @@ +1. Create a tax group named **"Ecotaxes"**. The sequence must be lower + than other tax groups. + - Set the **Preceding Subtotal** field to **"Without Ecotax"**. +2. Create two taxes named **"Fixed Ecotax"** and **"Weight-Based + Ecotax"**. + - Check the **Ecotax** checkbox. + - Set the correct Python code: + - For the fixed ecotax: + + ``` python + result = quantity and product.fixed_ecotax * quantity or 0.0 + ``` + + - For the weight-based ecotax: + + ``` python + result = quantity and product.weight_based_ecotax * quantity or 0.0 + ``` + - Check the **Included in Base Amount** option. + - The sequence for Ecotax must be lower than the VAT tax. +3. For VAT taxes, check the **Base Affected by Previous Taxes?** + option. +4. Add an ecotax classification via the menu **Accounting \> + Configuration \> Taxes \> Ecotax Classification**. + - The ecotax classification can be either a fixed ecotax or a + weight-based ecotax. + - Ecotax classification information can be used for legal + declarations. + - For the fixed ecotax, the ecotax amount is used as a default + value, which can be overridden on the product. + - For the weight-based ecotax, define one ecotax by a coefficient + applied to the weight (depending on the product's materials). + - Set the appropriate tax in the **Sale Ecotax** field. +5. Assign one or more ecotax classifications to a product. + - The ecotax amount can also be manually overridden on the product. diff --git a/account_ecotax_tax/report/invoice.xml b/account_ecotax_tax/report/invoice.xml new file mode 100644 index 000000000..eae52f23c --- /dev/null +++ b/account_ecotax_tax/report/invoice.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/account_ecotax_tax/static/description/icon.png b/account_ecotax_tax/static/description/icon.png new file mode 100644 index 000000000..ee185a69f Binary files /dev/null and b/account_ecotax_tax/static/description/icon.png differ diff --git a/account_ecotax_tax/static/description/index.html b/account_ecotax_tax/static/description/index.html new file mode 100644 index 000000000..02b19acc2 --- /dev/null +++ b/account_ecotax_tax/static/description/index.html @@ -0,0 +1,500 @@ + + + + + +Ecotax Management (with Odoo tax) + + + +
+

Ecotax Management (with Odoo tax)

+ + +

Beta License: AGPL-3 OCA/account-fiscal-rule Translate me on Weblate Try me on Runboat

+

This module allows to compute the ecotax amounts from Odoo tax +mechanism. The advantages compared to the base account_ecotax module is +that it allows to : - Manage ecotax amount as included or excluded from +the price of the product - Isolate the amount of the ecotax in a +specific accounting account (set on the tax)

+

Then the ecotax amounts are not considered as turnover, which could be +good or not depending on your country’s legislation or accountant +preferences.

+

Table of contents

+ +
+

Usage

+
    +
  1. Create a tax group named “Ecotaxes”. The sequence must be lower +than other tax groups.

    +
      +
    • Set the Preceding Subtotal field to “Without Ecotax”.
    • +
    +
  2. +
  3. Create two taxes named “Fixed Ecotax” and “Weight-Based +Ecotax”.

    +
      +
    • Check the Ecotax checkbox.

      +
    • +
    • Set the correct Python code:

      +
        +
      • For the fixed ecotax:

        +
        +result = quantity and product.fixed_ecotax * quantity or 0.0
        +
        +
      • +
      • For the weight-based ecotax:

        +
        +result = quantity and product.weight_based_ecotax * quantity or 0.0
        +
        +
      • +
      +
    • +
    • Check the Included in Base Amount option.

      +
    • +
    • The sequence for Ecotax must be lower than the VAT tax.

      +
    • +
    +
  4. +
  5. For VAT taxes, check the Base Affected by Previous Taxes? option.

    +
  6. +
  7. Add an ecotax classification via the menu Accounting > +Configuration > Taxes > Ecotax Classification.

    +
      +
    • The ecotax classification can be either a fixed ecotax or a +weight-based ecotax.
    • +
    • Ecotax classification information can be used for legal +declarations.
    • +
    • For the fixed ecotax, the ecotax amount is used as a default +value, which can be overridden on the product.
    • +
    • For the weight-based ecotax, define one ecotax by a coefficient +applied to the weight (depending on the product’s materials).
    • +
    • Set the appropriate tax in the Sale Ecotax field.
    • +
    +
  8. +
  9. Assign one or more ecotax classifications to a product.

    +
      +
    • The ecotax amount can also be manually overridden on the product.
    • +
    +
  10. +
+
+
+

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.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainers:

+

mourad-ehm florian-dacosta

+

This module is part of the OCA/account-fiscal-rule project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/account_ecotax_tax/tests/__init__.py b/account_ecotax_tax/tests/__init__.py new file mode 100644 index 000000000..88a931bae --- /dev/null +++ b/account_ecotax_tax/tests/__init__.py @@ -0,0 +1 @@ +from . import test_ecotax diff --git a/account_ecotax_tax/tests/test_ecotax.py b/account_ecotax_tax/tests/test_ecotax.py new file mode 100644 index 000000000..84df19023 --- /dev/null +++ b/account_ecotax_tax/tests/test_ecotax.py @@ -0,0 +1,329 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + + +from odoo.addons.account_ecotax.tests.test_ecotax import TestInvoiceEcotaxCommon + + +class TestInvoiceEcotaxTaxComon(TestInvoiceEcotaxCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + + # ACCOUNTING STUFF + # Main use case for using ecotax with tax is to manage the ecotax as not + # included with tax not included (B2B case) + # Also for this version, the included use case using tax is broken because + # of a bug in Odoo core (check readme) + cls.invoice_tax.price_include = False + cls.invoice_ecotax_account = cls.env["account.account"].create( + { + "code": "707120", + "name": "Ecotax Account", + "account_type": "income", + "company_id": cls.env.user.company_id.id, + } + ) + cls.invoice_fixed_ecotax = cls.env["account.tax"].create( + { + "name": "Fixed Ecotax", + "type_tax_use": "sale", + "company_id": cls.env.user.company_id.id, + "price_include": False, + "amount_type": "code", + "include_base_amount": True, + "sequence": 0, + "is_ecotax": True, + "python_compute": "result = (quantity and" + " product.fixed_ecotax * quantity or 0.0)", + "tax_exigibility": "on_invoice", + "invoice_repartition_line_ids": [ + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "base", + }, + ), + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "tax", + "account_id": cls.invoice_ecotax_account.id, + }, + ), + ], + "refund_repartition_line_ids": [ + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "base", + }, + ), + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "tax", + "account_id": cls.invoice_ecotax_account.id, + }, + ), + ], + } + ) + cls.invoice_weight_based_ecotax = cls.env["account.tax"].create( + { + "name": "Weight Based Ecotax", + "type_tax_use": "sale", + "company_id": cls.env.user.company_id.id, + "amount_type": "code", + "include_base_amount": True, + "price_include": False, + "sequence": 0, + "is_ecotax": True, + "python_compute": "result = (quantity and" + " product.weight_based_ecotax * quantity or 0.0)", + "tax_exigibility": "on_invoice", + "invoice_repartition_line_ids": [ + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "base", + }, + ), + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "tax", + "account_id": cls.invoice_ecotax_account.id, + }, + ), + ], + "refund_repartition_line_ids": [ + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "base", + }, + ), + ( + 0, + 0, + { + "factor_percent": 100, + "repartition_type": "tax", + "account_id": cls.invoice_ecotax_account.id, + }, + ), + ], + } + ) + # ECOTAXES + # 1- Fixed ecotax + cls.ecotax_fixed.sale_ecotax_ids = cls.invoice_fixed_ecotax + # 2- Weight-based ecotax + cls.ecotax_weight.sale_ecotax_ids = cls.invoice_weight_based_ecotax + + +class TestInvoiceEcotaxTax(TestInvoiceEcotaxTaxComon): + def test_01_default_fixed_ecotax(self): + """Test default fixed ecotax + + Ecotax classification data for this test: + - fixed type + - default amount: 5.0 + Product data for this test: + - list price: 100 + - fixed ecotax + - no manual amount + + Expected results (with 1 line and qty = 1): + - invoice ecotax amount: 5.0 + - invoice total amount: 115.5 + - line ecotax unit amount: 5.0 + - line ecotax total amount: 5.0 + """ + invoice = self._make_invoice(products=self._make_product(self.ecotax_fixed)) + self._run_checks( + invoice, + {"amount_ecotax": 5.0, "amount_total": 115.5}, + [{"ecotax_amount_unit": 5.0, "subtotal_ecotax": 5.0}], + ) + new_qty = self._set_invoice_lines_random_quantities(invoice)[0] + self._run_checks( + invoice, + {"amount_ecotax": 5.0 * new_qty, "amount_total": 115.5 * new_qty}, + [{"ecotax_amount_unit": 5.0, "subtotal_ecotax": 5.0 * new_qty}], + ) + + def test_02_force_fixed_ecotax_on_product(self): + """Test manual fixed ecotax + + Ecotax classification data for this test: + - fixed type + - default amount: 5.0 + Product data for this test: + - list price: 100 + - fixed ecotax + - Force ecotax amount: 10 + + Expected results (with 1 line and qty = 1): + - invoice ecotax amount: 10.0 + - invoice total amount: 121.0 + - line ecotax unit amount: 10.0 + - line ecotax total amount: 10.0 + """ + product = self._make_product(self.ecotax_fixed) + product.ecotax_line_product_ids[0].force_amount = 10 + invoice = self._make_invoice(products=product) + self._run_checks( + invoice, + {"amount_ecotax": 10.0, "amount_total": 121.0}, + [{"ecotax_amount_unit": 10.0, "subtotal_ecotax": 10.0}], + ) + new_qty = self._set_invoice_lines_random_quantities(invoice)[0] + self._run_checks( + invoice, + {"amount_ecotax": 10.0 * new_qty, "amount_total": 121.0 * new_qty}, + [{"ecotax_amount_unit": 10.0, "subtotal_ecotax": 10.0 * new_qty}], + ) + + def test_03_weight_based_ecotax(self): + """Test weight based ecotax + + Ecotax classification data for this test: + - weight based type + - coefficient: 0.04 + Product data for this test: + - list price: 100 + - weight based ecotax + - weight: 100 + + Expected results (with 1 line and qty = 1): + - invoice ecotax amount: 4.0 + - invoice total amount: 114.4 + - line ecotax unit amount: 4.0 + - line ecotax total amount: 4.0 + """ + invoice = self._make_invoice(products=self._make_product(self.ecotax_weight)) + self._run_checks( + invoice, + {"amount_ecotax": 4.0, "amount_total": 114.4}, + [{"ecotax_amount_unit": 4.0, "subtotal_ecotax": 4.0}], + ) + new_qty = self._set_invoice_lines_random_quantities(invoice)[0] + self._run_checks( + invoice, + {"amount_ecotax": 4.0 * new_qty, "amount_total": 114.4 * new_qty}, + [{"ecotax_amount_unit": 4.0, "subtotal_ecotax": 4.0 * new_qty}], + ) + + def test_04_mixed_ecotax(self): + """Test mixed ecotax within the same invoice + + Creating an invoice with 3 lines (one per type with types tested above) + + Expected results (with 3 lines and qty = 1): + - invoice ecotax amount: 19.0 + - invoice total amount: 350.9 + - line ecotax unit amount (fixed ecotax): 5.0 + - line ecotax total amount (fixed ecotax): 5.0 + - line ecotax unit amount (manual ecotax): 10.0 + - line ecotax total amount (manual ecotax): 10.0 + - line ecotax unit amount (weight based ecotax): 4.0 + - line ecotax total amount (weight based ecotax): 4.0 + """ + default_fixed_product = self._make_product(self.ecotax_fixed) + manual_fixed_product = self._make_product(self.ecotax_fixed) + manual_fixed_product.ecotax_line_product_ids[0].force_amount = 10 + weight_based_product = self._make_product(self.ecotax_weight) + invoice = self._make_invoice( + products=default_fixed_product | manual_fixed_product | weight_based_product + ) + self._run_checks( + invoice, + {"amount_ecotax": 19.0, "amount_total": 350.9}, + [ + {"ecotax_amount_unit": 5.0, "subtotal_ecotax": 5.0}, + {"ecotax_amount_unit": 10.0, "subtotal_ecotax": 10.0}, + {"ecotax_amount_unit": 4.0, "subtotal_ecotax": 4.0}, + ], + ) + new_qtys = self._set_invoice_lines_random_quantities(invoice) + self._run_checks( + invoice, + { + "amount_ecotax": 5.0 * new_qtys[0] + + 10.0 * new_qtys[1] + + 4.0 * new_qtys[2], + "amount_total": 115.5 * new_qtys[0] + + 121.0 * new_qtys[1] + + 114.4 * new_qtys[2], + }, + [ + {"ecotax_amount_unit": 5.0, "subtotal_ecotax": 5.0 * new_qtys[0]}, + {"ecotax_amount_unit": 10.0, "subtotal_ecotax": 10.0 * new_qtys[1]}, + {"ecotax_amount_unit": 4.0, "subtotal_ecotax": 4.0 * new_qtys[2]}, + ], + ) + + def test_05_product_variants(self): + """ + Data: + A product template with two variants + Test Case: + Add additional ecotax line to one variant + Expected result: + The additional ecotax line is not associated to second variant + the all ecotax lines of the variant contains both the ecotax + line of the product template and the additional ecotax line + """ + variants = self._make_product_variants(self.ecotax_fixed) + self.assertEqual(len(variants), 2) + variant_1 = variants[0] + variant_2 = variants[1] + self.assertEqual( + variant_1.all_ecotax_line_product_ids, + variant_2.all_ecotax_line_product_ids, + ) + variant_1.additional_ecotax_line_product_ids = [ + ( + 0, + 0, + { + "classification_id": self.ecotax_weight.id, + }, + ) + ] + all_additional_ecotax = ( + variant_1.additional_ecotax_line_product_ids + | variant_1.product_tmpl_id.ecotax_line_product_ids + ) + self.assertEqual( + len(variant_1.all_ecotax_line_product_ids), + 2, + ) + self.assertEqual( + len(variant_2.all_ecotax_line_product_ids), + 1, + ) + self.assertEqual( + variant_1.all_ecotax_line_product_ids, + all_additional_ecotax, + ) + self.assertEqual( + variant_2.all_ecotax_line_product_ids, + variant_2.product_tmpl_id.ecotax_line_product_ids, + ) diff --git a/account_ecotax_tax/views/account_ecotax_classification_view.xml b/account_ecotax_tax/views/account_ecotax_classification_view.xml new file mode 100644 index 000000000..5575c5b1b --- /dev/null +++ b/account_ecotax_tax/views/account_ecotax_classification_view.xml @@ -0,0 +1,30 @@ + + + + + account.ecotax.classification + + + + + + + + + + + + diff --git a/account_ecotax_tax/views/account_move_view.xml b/account_ecotax_tax/views/account_move_view.xml new file mode 100644 index 000000000..32d86d661 --- /dev/null +++ b/account_ecotax_tax/views/account_move_view.xml @@ -0,0 +1,12 @@ + + + + account.move.line + + + + 1 + + + + diff --git a/account_ecotax_tax/views/account_tax_view.xml b/account_ecotax_tax/views/account_tax_view.xml new file mode 100644 index 000000000..3e1a4864f --- /dev/null +++ b/account_ecotax_tax/views/account_tax_view.xml @@ -0,0 +1,18 @@ + + + + + l10n_fr_ecotax.account.tax.form + account.tax + + 300 + + + + + + +