2
0

[ADD] base_vat_optional_vies

* Disable VIES test
  * Fixes to avoid exception when using default _construct_constraint_msg method
This commit is contained in:
Antonio Espinosa 2015-10-06 11:10:40 +02:00 committed by Rodrigo
parent 90eb5b8081
commit 6ba2b16969
10 changed files with 342 additions and 0 deletions

View File

@ -0,0 +1,78 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
===================================
Optional validation of VAT via VIES
===================================
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.
*NOTE*: Altought VIES validation is actived in your company, this validation
will not block VAT ID write (main different to Odoo standard behavior) if this
VAT ID is valid in its country.
Configuration
=============
In order to activate VIES validation, you must set this option in your company:
Settings > Companies > Companies > Your Company > Configuration > Accounting > VIES VAT Check
Usage
=====
When VIES VAT Check is activated:
* Odoo will try to validate VAT against VIES online service
* If passed, then "VIES validation passed" field will be True
* If not passed, then try to validate using country validation method
* If validated, then "VIES validation passed" field will be False
* If not validated, then a ValidationError will be shown to user
When VIES VAT Check is not activated:
* "VIES validation passed" field will be always False
You must preffix VAT with country code (ISO 3166-1 alpha-2) and if you want to
bypass country validation you can use "EU" code
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 smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/account-financial-tools/issues/new?body=module:%20base_vat_optional_vies%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Rafael Blasco <rafabn@antiun.com>
* Antonio Espinosa <antonioea@antiun.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
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.
To contribute to this module, please visit http://odoo-community.org.

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# License AGPL-3: Antiun Ingenieria S.L. - Antonio Espinosa
# See README.rst file on addon root folder for more details
from . import models

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# License AGPL-3: Antiun Ingenieria S.L. - Antonio Espinosa
# See README.rst file on addon root folder for more details
{
'name': "Optional validation of VAT via VIES",
'category': 'Accounting',
'version': '8.0.1.0.0',
'depends': [
'base_vat',
],
'external_dependencies': {
'python': ['vatnumber'],
},
'data': [
'views/res_partner_view.xml',
],
'author': 'Antiun Ingeniería S.L., '
'Odoo Community Association (OCA)',
'website': 'http://www.antiun.com',
'license': 'AGPL-3',
'images': [],
'installable': True,
}

View File

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# License AGPL-3: Antiun Ingenieria S.L. - Antonio Espinosa
# See README.rst file on addon root folder for more details
from . import res_partner

View File

@ -0,0 +1,137 @@
# -*- coding: utf-8 -*-
# License AGPL-3: Antiun Ingenieria S.L. - Antonio Espinosa
# See README.rst file on addon root folder for more details
import logging
import re
from openerp import models, fields, api
from openerp.exceptions import ValidationError
_logger = logging.getLogger(__name__)
try:
import vatnumber
except ImportError:
_logger.warning(
"VAT validation partially unavailable because the `vatnumber` Python "
"library cannot be found. Install it to support more countries, "
"for example with `easy_install vatnumber` or "
"`pip install vatnumber`.")
vatnumber = None
class ResPartner(models.Model):
_inherit = 'res.partner'
vies_passed = fields.Boolean(
string="VIES validation passed", readonly=True)
def __init__(self, pool, cr):
super(ResPartner, self).__init__(pool, cr)
self._constraints = []
@api.constrains('vat')
def check_vat(self):
for partner in self:
if (not self.env.context.get('avoid_check_vat') and
not partner.parent_id):
if not partner.validate_vat():
raise ValidationError(partner._construct_constraint_msg())
@api.multi
def button_check_vat(self):
if not self.validate_vat():
raise ValidationError(self._construct_constraint_msg())
return True
def _split_vat(self, vat, country=False):
"""
@summary: Split Partner vat into country_code and number
@result: (vat_country, vat_number)
"""
vat_country = 'XX'
vat_number = vat
if vat and re.match(r'[A-Za-z]{2}', vat):
vat_country = vat[:2].upper()
vat_number = vat[2:].replace(' ', '')
elif country:
vat_country = country
return vat_country, vat_number
@api.multi
def validate_vat(self):
self.ensure_one()
if self.company_id.vat_check_vies:
# VIES online check
check_func = self.vies_vat_optional_check
else:
# quick and partial off-line checksum validation
check_func = self.simple_vat_optional_check
vat_country, vat_number = self._split_vat(self.vat)
if vat_number and vat_country == 'XX':
_logger.info("VAT country not found!")
raise ValidationError(self._construct_constraint_msg())
if vat_number and not check_func(vat_country, vat_number):
_logger.info("VAT Number [%s] is not valid !" % vat_number)
return False
return True
@api.multi
def simple_vat_optional_check(self, country_code, vat_number):
"""
Check the VAT number depending of the country.
http://sima-pc.com/nif.php
"""
self.ensure_one()
res = self.simple_vat_check(country_code.lower(), vat_number)
data = {}
if res and self.vies_passed and not self.company_id.vat_check_vies:
# Can not be sure that this VAT is signed up in VIES
data['vies_passed'] = False
if res:
vat = country_code + vat_number
if self.vat != vat:
data['vat'] = vat
if data:
self.with_context(avoid_check_vat=True).write(data)
return res
@api.multi
def vies_vat_optional_check(self, country_code, vat_number):
self.ensure_one()
data = {}
res = False
try:
# Validate against VAT Information Exchange System (VIES)
# see also http://ec.europa.eu/taxation_customs/vies/
vat = country_code + vat_number
res = vatnumber.check_vies(vat)
if res and not self.vies_passed:
data['vies_passed'] = True
except Exception:
# See:
# http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl
# Fault code may contain INVALID_INPUT, SERVICE_UNAVAILABLE,
# MS_UNAVAILABLE, TIMEOUT or SERVER_BUSY. There is no way we can
# validate the input with VIES if any of these arise, including
# the first one (it means invalid country code or empty
# VAT number), so we fall back to the simple check.
pass
if not res:
res = self.simple_vat_optional_check(country_code, vat_number)
if self.vies_passed:
data['vies_passed'] = False
if res:
vat = country_code + vat_number
if self.vat != vat:
data['vat'] = vat
if data:
self.with_context(avoid_check_vat=True).write(data)
return res
# Delete old api constraint defined in base_vat addon
@api.multi
def _validate_fields(self, field_names):
self._constraints = [x for x in self._constraints if 'vat' not in x[2]]
super(ResPartner, self)._validate_fields(field_names)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# License AGPL-3: Antiun Ingenieria S.L. - Antonio Espinosa
# See README.rst file on addon root folder for more details
from . import test_res_partner

View File

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
# License AGPL-3: Antiun Ingenieria S.L. - Antonio Espinosa
# See README.rst file on addon root folder for more details
from openerp.tests.common import TransactionCase
class TestResPartner(TransactionCase):
def setUp(self):
super(TestResPartner, self).setUp()
self.m_partner = self.env['res.partner']
self.m_company = self.env['res.company']
self.company = self.m_company.browse(self.ref('base.main_company'))
self.partner = self.m_partner.browse(self.ref('base.res_partner_1'))
def test_split_vat(self):
cases = (
# vat, country, => vat_country, vat_number
('ESB12345678', False, 'ES', 'B12345678'),
('B12345678', False, 'XX', 'B12345678'),
('1EB12345678', False, 'XX', '1EB12345678'),
('ESB12345678', 'DE', 'ES', 'B12345678'),
('B12345678', 'ES', 'ES', 'B12345678'),
)
for vat, country, vat_country, vat_number in cases:
res_country, res_number = self.m_partner._split_vat(vat, country)
self.assertEqual(res_country, vat_country)
self.assertEqual(res_number, vat_number)
def _test_validate_vat(self, cases):
for vat, res_vat, res_vies in cases:
self.partner.write({
'vat': vat,
})
self.assertEqual(self.partner.vat, res_vat)
self.assertEqual(self.partner.vies_passed, res_vies)
# AEA: Can't use this test in Travis, VIES checking returns always False
# because of timeout
# def test_validate_vat_vies(self):
# """
# Validate VAT when company 'vat_check_vies' option is True
# All VATs are valid, but some are not signed up in VIES database
# """
# self.company.vat_check_vies = True
# cases = (
# # vat => vat, vies_passed
# # VATs signed up in VIES
# ('ESB84718550', 'ESB84718550', True),
# ('de222070543', 'DE222070543', True),
# # Valid VATs don't signed up in VIES
# ('DE253130868', 'DE253130868', False),
# ('esB87286357', 'ESB87286357', False),
# )
# self._test_validate_vat(cases)
def test_validate_vat_no_vies(self):
"""
Validate VAT when company 'vat_check_vies' option is False
"""
self.company.vat_check_vies = False
cases = (
# vat => vat, vies_passed
('ESB84718550', 'ESB84718550', False),
('de222070543', 'DE222070543', False),
('DE253130868', 'DE253130868', False),
('esB87286357', 'ESB87286357', False),
)
self._test_validate_vat(cases)

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_partner_property_form" model="ir.ui.view">
<field name="name">Add VAT country and VIES passed fields</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="property_account_position" position="after">
<field name="vies_passed"/>
</field>
</field>
</record>
</data>
</openerp>