From 8f225d8aa3879d4942f8e0b8a082454311ac7a8a Mon Sep 17 00:00:00 2001 From: Jairo Llopis Date: Tue, 12 Nov 2024 11:34:16 +0000 Subject: [PATCH] [FIX] base_vat_optional_vies: don't block mass checks The whole point of this module is to allow VIES failures. However, when running mass checks, if one single partner failed, the whole process had to start again. FWIW that can be also problematic due to rate limits in VIES service. For that same reason, we now skip partners that are validated already, and those that are will inherit the status from their parent anyway. Now, the process will just continue and report failures at the end. It includes new tests, removes dead code, and reduces pre-existing tests verbosity. @moduon MT-7763 --- base_vat_optional_vies/README.rst | 14 ++++- base_vat_optional_vies/__manifest__.py | 1 + .../models/res_config_settings.py | 29 ++++++++-- base_vat_optional_vies/models/res_partner.py | 16 +----- .../readme/CONTRIBUTORS.rst | 1 + base_vat_optional_vies/readme/DESCRIPTION.rst | 2 +- .../static/description/index.html | 17 +++--- base_vat_optional_vies/tests/__init__.py | 1 + .../tests/tes_config_settings.py | 44 --------------- .../tests/test_config_settings.py | 54 +++++++++++++++++++ .../tests/test_res_partner.py | 4 ++ 11 files changed, 112 insertions(+), 71 deletions(-) delete mode 100644 base_vat_optional_vies/tests/tes_config_settings.py create mode 100644 base_vat_optional_vies/tests/test_config_settings.py diff --git a/base_vat_optional_vies/README.rst b/base_vat_optional_vies/README.rst index 4a86b1e7d..2cec14f83 100644 --- a/base_vat_optional_vies/README.rst +++ b/base_vat_optional_vies/README.rst @@ -32,7 +32,7 @@ This module extends base_vat module features allowing to know if VIES validation was passed or not. Then you can use "VIES validation passed" field in order to show VAT ID with -or without country preffix in invoices, for instance. +or without country prefix in invoices, for instance. *NOTE*: Although VIES validation is set in your company, this validation will not block VAT ID write (main difference to Odoo standard behavior) if this @@ -97,6 +97,7 @@ Contributors * Harald Panten * Eduardo de Miguel * Emilio Pascual +* Jairo Llopis (`Moduon `__) Maintainers ~~~~~~~~~~~ @@ -111,6 +112,17 @@ 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-yajo| image:: https://github.com/yajo.png?size=40px + :target: https://github.com/yajo + :alt: yajo +.. |maintainer-rafaelbn| image:: https://github.com/rafaelbn.png?size=40px + :target: https://github.com/rafaelbn + :alt: rafaelbn + +Current `maintainers `__: + +|maintainer-yajo| |maintainer-rafaelbn| + This module is part of the `OCA/account-financial-tools `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_vat_optional_vies/__manifest__.py b/base_vat_optional_vies/__manifest__.py index 280380bde..667a6a844 100644 --- a/base_vat_optional_vies/__manifest__.py +++ b/base_vat_optional_vies/__manifest__.py @@ -17,5 +17,6 @@ "author": "Tecnativa," "Odoo Community Association (OCA)", "website": "https://github.com/OCA/account-financial-tools", "license": "AGPL-3", + "maintainers": ["yajo", "rafaelbn"], "installable": True, } diff --git a/base_vat_optional_vies/models/res_config_settings.py b/base_vat_optional_vies/models/res_config_settings.py index 757d0bdf4..0da07c864 100644 --- a/base_vat_optional_vies/models/res_config_settings.py +++ b/base_vat_optional_vies/models/res_config_settings.py @@ -1,20 +1,41 @@ # Copyright 2022-2023 Moduon Team S.L. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from logging import getLogger from odoo import _, models +from odoo.exceptions import ValidationError + +_logger = getLogger(__name__) class ResConfigSettings(models.TransientModel): _inherit = "res.config.settings" def execute_update_check_vies(self): - # Only parent partners, children are synced from parent - count_partners = self.env["res.partner"].search_count([]) - self.env["res.partner"].search([]).check_vat() + """Bulk VAT check on company partners.""" + partners = self.env["res.partner"].search( + [ + ("is_company", "=", True), + ("parent_id", "=", False), + ("vat", "!=", False), + ("vies_passed", "=", False), + ] + ) + failures = 0 + for partner in partners: + try: + partner.check_vat() + except ValidationError: + _logger.warning("VAT check failed for %r", partner, exc_info=True) + failures += 1 return { "effect": { "fadeout": "slow", - "message": _("Vies passed calculated in %s partners") % count_partners, + "message": _( + "Vies passed calculated in %(partners)d partners (%(failures)d failures)", + partners=len(partners), + failures=failures, + ), "img_url": "/web/static/img/smile.svg", "type": "rainbow_man", } diff --git a/base_vat_optional_vies/models/res_partner.py b/base_vat_optional_vies/models/res_partner.py index b76b6c5f0..9c7d1a151 100644 --- a/base_vat_optional_vies/models/res_partner.py +++ b/base_vat_optional_vies/models/res_partner.py @@ -4,9 +4,7 @@ # Copyright 2022 Moduon - Eduardo de Miguel # Copyright 2023 Moduon - Emilio Pascual # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import _, api, fields, models - -from odoo.addons.base_vat.models.res_partner import _ref_vat +from odoo import api, fields, models class ResPartner(models.Model): @@ -61,15 +59,3 @@ class ResPartner(models.Model): return super( ResPartner, self.with_context(vat_partner=self) )._onchange_check_vies() - - @api.model - def _build_vat_error_message(self, country_code, wrong_vat, record_label): - return "\n" + _( - "The VAT number [%(wrong_vat)s] for %(record_label)s does not seem to be valid. " - "\nNote: the expected format is %(expected_format)s", - wrong_vat=wrong_vat, - record_label=record_label, - expected_format=_ref_vat.get( - country_code, "'CC##' (CC=Country Code, ##=VAT Number)" - ), - ) diff --git a/base_vat_optional_vies/readme/CONTRIBUTORS.rst b/base_vat_optional_vies/readme/CONTRIBUTORS.rst index c24f5cdc2..1edb0e39a 100644 --- a/base_vat_optional_vies/readme/CONTRIBUTORS.rst +++ b/base_vat_optional_vies/readme/CONTRIBUTORS.rst @@ -7,3 +7,4 @@ * Harald Panten * Eduardo de Miguel * Emilio Pascual +* Jairo Llopis (`Moduon `__) diff --git a/base_vat_optional_vies/readme/DESCRIPTION.rst b/base_vat_optional_vies/readme/DESCRIPTION.rst index c430079de..618b114cc 100644 --- a/base_vat_optional_vies/readme/DESCRIPTION.rst +++ b/base_vat_optional_vies/readme/DESCRIPTION.rst @@ -2,7 +2,7 @@ This module extends base_vat module features allowing to know if VIES validation was passed or not. Then you can use "VIES validation passed" field in order to show VAT ID with -or without country preffix in invoices, for instance. +or without country prefix in invoices, for instance. *NOTE*: Although VIES validation is set in your company, this validation will not block VAT ID write (main difference to Odoo standard behavior) if this diff --git a/base_vat_optional_vies/static/description/index.html b/base_vat_optional_vies/static/description/index.html index 1129df23b..42a64b68e 100644 --- a/base_vat_optional_vies/static/description/index.html +++ b/base_vat_optional_vies/static/description/index.html @@ -1,4 +1,3 @@ - @@ -9,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code { margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +301,7 @@ span.option { span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -373,7 +373,7 @@ ul.auto-toc {

This module extends base_vat module features allowing to know if VIES validation was passed or not.

Then you can use “VIES validation passed” field in order to show VAT ID with -or without country preffix in invoices, for instance.

+or without country prefix in invoices, for instance.

NOTE: Although VIES validation is set in your company, this validation will not block VAT ID write (main difference to Odoo standard behavior) if this VAT ID is valid in its country.

@@ -441,15 +441,20 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
  • Harald Panten <harald.panten@sygel.es>
  • Eduardo de Miguel <edu@moduon.team>
  • Emilio Pascual <emilio@moduon.team>
  • +
  • Jairo Llopis (Moduon)
  • Maintainers

    This module is maintained by the OCA.

    -Odoo Community Association + +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:

    +

    yajo rafaelbn

    This module is part of the OCA/account-financial-tools project on GitHub.

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

    diff --git a/base_vat_optional_vies/tests/__init__.py b/base_vat_optional_vies/tests/__init__.py index d57d215f9..cea88474a 100644 --- a/base_vat_optional_vies/tests/__init__.py +++ b/base_vat_optional_vies/tests/__init__.py @@ -1 +1,2 @@ +from . import test_config_settings from . import test_res_partner diff --git a/base_vat_optional_vies/tests/tes_config_settings.py b/base_vat_optional_vies/tests/tes_config_settings.py deleted file mode 100644 index 93cd36873..000000000 --- a/base_vat_optional_vies/tests/tes_config_settings.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2022-2023 Moduon Team S.L. -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from unittest import mock - -from odoo.tests import common - - -class TestConfigSettings(common.TransactionCase): - def setUp(self): - super(TestConfigSettings, self).setUp() - self.company = self.env.user.company_id - self.partner1_test = self.env["res.partner"].create( - { - "name": "Test partner", - "is_company": True, - "vat": "ESB87530432", - "country_id": self.env.ref("base.be").id, - } - ) - self.partner2_test = self.env["res.partner"].create( - { - "name": "Test partner2", - "is_company": True, - "vat": "ESB87530432", - } - ) - self.vatnumber_path = "odoo.addons.base_vat.models.res_partner.check_vies" - - def test_execute_update_check_vies_validate(self): - with mock.patch(self.vatnumber_path) as mock_vatnumber: - self.company.vat_check_vies = True - mock_vatnumber.check_vies.return_value = True - self.env["res.config.settings"].execute_update_check_vies() - self.assertTrue(self.partner1_test.vies_passed) - self.assertFalse(self.partner2_test.vies_passed) - - def test_execute_update_check_vies_no_validate(self): - with mock.patch(self.vatnumber_path) as mock_vatnumber: - self.company.vat_check_vies = False - mock_vatnumber.check_vies.return_value = False - self.env["res.config.settings"].execute_update_check_vies() - self.assertFalse(self.partner1_test.vies_passed) - self.assertFalse(self.partner2_test.vies_passed) diff --git a/base_vat_optional_vies/tests/test_config_settings.py b/base_vat_optional_vies/tests/test_config_settings.py new file mode 100644 index 000000000..907052dec --- /dev/null +++ b/base_vat_optional_vies/tests/test_config_settings.py @@ -0,0 +1,54 @@ +# Copyright 2024 Moduon Team S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from unittest import mock + +from odoo.tests import common +from odoo.tools import mute_logger + + +class TestConfigSettings(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner1, cls.partner2 = ( + cls.env["res.partner"] + .with_context(no_vat_validation=True) + .create( + [ + { + "name": "Test partner", + "is_company": True, + "vat": "ESB87530432", + "country_id": cls.env.ref("base.es").id, + }, + { + "name": "Test partner2", + "is_company": True, + "vat": "ES00000000T", + "country_id": cls.env.ref("base.es").id, + }, + ] + ) + ) + cls.config = cls.env["res.config.settings"].create({"vat_check_vies": True}) + + def setUp(self): + super().setUp() + self.mock_check_vies = self.startPatcher( + mock.patch( + "odoo.addons.base_vat.models.res_partner.check_vies", + side_effect=(lambda vat: {"valid": vat == "ESB87530432"}), + ) + ) + + @mute_logger( + "odoo.addons.base_vat_optional_vies.models.res_config_settings", + "odoo.addons.base_vat.models.res_partner", + ) + def test_batch_checking(self): + self.config.execute_update_check_vies() + self.mock_check_vies.assert_any_call("ESB87530432") + self.mock_check_vies.assert_any_call("ES00000000T") + self.assertTrue(self.partner1.vies_passed) + self.assertFalse(self.partner2.vies_passed) diff --git a/base_vat_optional_vies/tests/test_res_partner.py b/base_vat_optional_vies/tests/test_res_partner.py index 770525686..f6ca96b06 100644 --- a/base_vat_optional_vies/tests/test_res_partner.py +++ b/base_vat_optional_vies/tests/test_res_partner.py @@ -8,6 +8,7 @@ from unittest.mock import patch from odoo.exceptions import ValidationError from odoo.tests import common +from odoo.tools import mute_logger class TestResPartner(common.TransactionCase): @@ -26,6 +27,7 @@ class TestResPartner(common.TransactionCase): cls._vies_check_func = check_vies + @mute_logger("odoo.addons.base_vat.models.res_partner") def test_validate_vat_vies(self): with patch(self.vatnumber_path, type(self)._vies_check_func): values = {"vat": "ESB87530432", "country_id": self.env.ref("base.be").id} @@ -40,6 +42,7 @@ class TestResPartner(common.TransactionCase): self.partner.write(values) self.assertEqual(self.partner.vies_passed, True) + @mute_logger("odoo.addons.base_vat.models.res_partner") def test_exception_vat_vies(self): with patch(self.vatnumber_path, side_effect=Exception()): values = {"vat": "87530432", "country_id": self.env.ref("base.es").id} @@ -69,6 +72,7 @@ class TestResPartner(common.TransactionCase): self.partner.country_id = self.env.ref("base.mx") self.assertEqual(self.partner.vies_passed, False) + @mute_logger("odoo.addons.base_vat.models.res_partner") def test_validate_vies_passed_false_when_vat_set_to_false(self): with patch(self.vatnumber_path) as mock_vatnumber: mock_vatnumber.check_vies.return_value = True