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
136 changes: 136 additions & 0 deletions partner_vat_manual_check_vies/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
========================================
Manual validation of European VAT number
========================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:b5c065825fe93d47826c9c18e6210074880e19010f97c405b3cbcca60f7fc298
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--financial--tools-lightgray.png?logo=github
:target: https://github.com/OCA/account-financial-tools/tree/18.0/partner_vat_manual_check_vies
:alt: OCA/account-financial-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/account-financial-tools-18-0/account-financial-tools-18-0-partner_vat_manual_check_vies
: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-financial-tools&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module extends the functionality of base_vat module to display
validation status of VAT number for EU partners using VIES validation
service. It allows to request a new validation in case validation failed
when first entering VAT number.

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

This module is an extension of Odoo base_vat module which allows to
display VAT validation status. This module is only useful for EU
partners if you would use VAT validation using EU VIES service.

Quite often, VIES validation service responds with a timeout or a
MS_MAX_CONCURRENT_REQ error. In this case, there is no way to request
new validation to VIES service.

This module adds validation status next to VAT and a button to request
validation in case it is not yet validated.

Usage
=====

To use this module, you need to:

- Go to *Invoicing* / Configuration / Settings menu

- Check **Verify VAT Numbers**

- Go to *Contacts*

- In “Contact” form for an EU based partner, next to VAT number you get
either a check sign (if validated) of question mark (if validation
failed) or cross sign (if invalid) |image1|

- If validation failed, you get a new button **Validate with VIES**
which allows you to request a new validation from VIES |image2|

- You can check chatter looking for error messages related to VIES
validation

- If VAT number is invalid, you should correct if or remove it, you get
a new button **Clear invalid VAT** that would remove VAT and replace
by "/" |image3|

You also get 2 planned action (cron job), disabled by default that will
try to request new validation for the first 20 partners with failed
validation, and another one that would clear VAT from all partners with
invalid VAT.

.. |image1| image:: https://raw.githubusercontent.com/OCA/account-financial-tools/18.0/partner_vat_manual_check_vies/static/description/valid.png
.. |image2| image:: https://raw.githubusercontent.com/OCA/account-financial-tools/18.0/partner_vat_manual_check_vies/static/description/validation_failed.png
.. |image3| image:: https://raw.githubusercontent.com/OCA/account-financial-tools/18.0/partner_vat_manual_check_vies/static/description/invalid.png

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-financial-tools/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 <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20partner_vat_manual_check_vies%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* Le Filament
* Odoo S.A.

Contributors
------------

- Rémi Cazeanave (https://le-filament.com)

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-remi-filament| image:: https://github.com/remi-filament.png?size=40px
:target: https://github.com/remi-filament
:alt: remi-filament

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-remi-filament|

This module is part of the `OCA/account-financial-tools <https://github.com/OCA/account-financial-tools/tree/18.0/partner_vat_manual_check_vies>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions partner_vat_manual_check_vies/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
20 changes: 20 additions & 0 deletions partner_vat_manual_check_vies/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "Manual validation of European VAT number",
"version": "18.0.1.0.0",
"development_status": "Beta",
"category": "Accounting/Accounting",
"website": "https://github.com/OCA/account-financial-tools",
"author": "Le Filament, Odoo S.A., Odoo Community Association (OCA)",
"maintainers": ["remi-filament"],
"license": "LGPL-3",
"application": False,
"installable": True,
"preloadable": True,
"depends": [
"base_vat",
],
"data": [
"data/ir_cron_data.xml",
"views/res_partner_view.xml",
],
}
28 changes: 28 additions & 0 deletions partner_vat_manual_check_vies/data/ir_cron_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2025 Le Filament (https://le-filament.com)
License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->

<odoo>

<record id="ir_cron_check_vies" model="ir.cron">
<field name="name">Partner: Validate VAT with EU VIES</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="nextcall" eval="(DateTime.now().replace(hour=2, minute=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')" />
<field name="model_id" ref="base.model_res_partner"/>
<field name="code">model._cron_check_vies()</field>
<field name="state">code</field>
<field name="active" eval="False" />
</record>
<record id="ir_cron_clear_vat" model="ir.cron">
<field name="name">Partner: Replace VAT by "/" on partners with invalid VAT (according to EU VIES validation)</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="nextcall" eval="(DateTime.now().replace(hour=4, minute=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')" />
<field name="model_id" ref="base.model_res_partner"/>
<field name="code">model._cron_clear_vat()</field>
<field name="state">code</field>
<field name="active" eval="False" />
</record>

</odoo>
1 change: 1 addition & 0 deletions partner_vat_manual_check_vies/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import res_partner
132 changes: 132 additions & 0 deletions partner_vat_manual_check_vies/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Copyright 2025 Le Filament (https://le-filament.com)
# Copyright (c) 2004-2015 Odoo S.A.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import logging

from stdnum.eu.vat import check_vies
from stdnum.exceptions import InvalidComponent

from odoo import _, api, fields, models
from odoo.tools import zeep

_logger = logging.getLogger(__name__)


class ResPartner(models.Model):
_inherit = "res.partner"

# Field representing whether VIES validation should be requested
request_vies_validation = fields.Boolean(compute="_compute_request_vies_validation")
vies_invalid = fields.Boolean()

@api.depends_context("company")
def _compute_request_vies_validation(self):
self.request_vies_validation = self.env.company.vat_check_vies

def action_check_vies(self):
self._compute_vies_valid()

def action_clear_vat(self):
for partner in self.filtered("vies_invalid"):
partner.vat = "/"
partner.vies_invalid = False

def _cron_check_vies(self, limit=20):
# Nothing to do if no company uses VIES validation
if (
not self.env["res.company"]
.sudo()
.search_count([("vat_check_vies", "=", True)])
):
return False
partners = self.search(
[("vies_valid", "!=", True), ("vies_invalid", "!=", True)], limit=limit
)
for partner in partners.filtered("vies_vat_to_check"):
# Avoid pre-fetching after each cache invalidation due to committing.
partner = partner[0]
partner._compute_vies_valid()

def _cron_clear_vat(self):
# Nothing to do if no company uses VIES validation
if (
not self.env["res.company"]
.sudo()
.search_count([("vat_check_vies", "=", True)])
):
return False
partners = self.search(
[
("vies_valid", "!=", True),
("vies_invalid", "=", True),
("vat", "not in", [False, "/"]),
]
)
partners.action_clear_vat()

@api.depends("vies_vat_to_check")
def _compute_vies_valid(self):
"""
This function is rewritten from base_vat module (from Odoo v18 CE module)
Check the VAT number with VIES, if enabled.
There are 2 changes with respect to Odoo code :
- sync vies_invalid with parent_id
- set vies_invalid to True in case VIES reports an invalid VAT ID
"""
if (
not self.env["res.company"]
.sudo()
.search_count([("vat_check_vies", "=", True)])
):
self.vies_valid = False
return

for partner in self:
if not partner.vies_vat_to_check:
partner.vies_valid = False
continue
if (
partner.parent_id
and partner.parent_id.vies_vat_to_check == partner.vies_vat_to_check
):
partner.vies_valid = partner.parent_id.vies_valid
# Added sync of vies_invalid with parent
partner.vies_invalid = partner.parent_id.vies_invalid
continue
try:
_logger.info(
"Calling VIES service to check VAT for validation: %s",
partner.vies_vat_to_check,
)
vies_valid = check_vies(partner.vies_vat_to_check, timeout=10)
partner.vies_valid = vies_valid["valid"]
# Added set vies_invalid in case VIES reports invalid VAT id
if not vies_valid["valid"]:
partner.vies_invalid = True
except (OSError, InvalidComponent, zeep.exceptions.Fault) as e:
if partner._origin.id:
msg = ""
if isinstance(e, OSError):
msg = _(
"Connection with the VIES server failed. The VAT number %s "
"could not be validated.",
partner.vies_vat_to_check,
)
elif isinstance(e, InvalidComponent):
msg = _(
"The VAT number %s could not be interpreted by the VIES "
"server.",
partner.vies_vat_to_check,
)
elif isinstance(e, zeep.exceptions.Fault):
msg = _(
"The request for VAT validation was not processed. VIES "
"service has responded with the following error: %s",
e.message,
)
partner._origin.message_post(body=msg)
_logger.warning(
"The VAT number %s failed VIES check.", partner.vies_vat_to_check
)
partner.vies_valid = False
3 changes: 3 additions & 0 deletions partner_vat_manual_check_vies/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
7 changes: 7 additions & 0 deletions partner_vat_manual_check_vies/readme/CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module is an extension of Odoo base_vat module which allows to display VAT validation status.
This module is only useful for EU partners if you would use VAT validation using EU VIES service.

Quite often, VIES validation service responds with a timeout or a MS_MAX_CONCURRENT_REQ error.
In this case, there is no way to request new validation to VIES service.

This module adds validation status next to VAT and a button to request validation in case it is not yet validated.
1 change: 1 addition & 0 deletions partner_vat_manual_check_vies/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Rémi Cazeanave <remi-filament> (https://le-filament.com)
2 changes: 2 additions & 0 deletions partner_vat_manual_check_vies/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This module extends the functionality of base_vat module to display validation status of VAT number for EU partners using VIES validation service.
It allows to request a new validation in case validation failed when first entering VAT number.
15 changes: 15 additions & 0 deletions partner_vat_manual_check_vies/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
To use this module, you need to:

- Go to *Invoicing* / Configuration / Settings menu
- Check **Verify VAT Numbers**
- Go to *Contacts*
- In “Contact” form for an EU based partner, next to VAT number you get either a check sign (if validated) of question mark (if validation failed) or cross sign (if invalid)
![](static/description/valid.png)

- If validation failed, you get a new button **Validate with VIES** which allows you to request a new validation from VIES
![](static/description/validation_failed.png)
- You can check chatter looking for error messages related to VIES validation
- If VAT number is invalid, you should correct if or remove it, you get a new button **Clear invalid VAT** that would remove VAT and replace by "/"
![](static/description/invalid.png)

You also get 2 planned action (cron job), disabled by default that will try to request new validation for the first 20 partners with failed validation, and another one that would clear VAT from all partners with invalid VAT.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading