[IMP] base_vat: add option to force online VIES check for EU VAT numbers
authorOlivier Dony <odo@openerp.com>
Mon, 28 Nov 2011 16:21:27 +0000 (17:21 +0100)
committerOlivier Dony <odo@openerp.com>
Mon, 28 Nov 2011 16:21:27 +0000 (17:21 +0100)
bzr revid: odo@openerp.com-20111128162127-a0e2n0c09noga0rq

addons/base_vat/__init__.py
addons/base_vat/__openerp__.py
addons/base_vat/base_vat.py
addons/base_vat/base_vat_view.xml

index 43dbd0c..1d7c143 100644 (file)
@@ -19,6 +19,7 @@
 #
 ##############################################################################
 
+import res_company
 import base_vat
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
index 5f7c1d2..147eb47 100644 (file)
@@ -33,6 +33,21 @@ be validated for all supported countries. The country is inferred from the
 2-letter country code that prefixes the VAT number, e.g. ``BE0477472701``
 will be validated using the Belgian rules.
 
+There are two different levels of VAT number validation:
+
+ * By default, a simple off-line check is performed using the known validation
+   rules for the country, usually a simple check digit. This is quick and 
+   always available, but allows numbers that are perhaps not truly allocated,
+   or not valid anymore.
+ * When the "VAT VIES Check" option is enabled (in the configuration of the user's
+   Company), VAT numbers will be instead submitted to the online EU VIES
+   database, which will truly verify that the number is valid and currently
+   allocated to a EU company. This is a little bit slower than the simple
+   off-line check, requires an Internet connection, and may not be available
+   all the time. If the service is not available or does not support the
+   requested country (e.g. for non-EU countries), a simple check will be performed
+   instead.
+
 Supported countries currently include EU countries, and a few non-EU countries
 such as Chile, Colombia, Mexico, Norway or Russia. For unsupported countries,
 only the country code will be validated.
index ba858d1..02471f6 100644 (file)
@@ -61,27 +61,48 @@ class res_partner(osv.osv):
         vat_country, vat_number = vat[:2].lower(), vat[2:].replace(' ', '')
         return vat_country, vat_number
 
-    def check_vat(self, cr, uid, ids, context=None):
+    def simple_vat_check(self, cr, uid, country_code, vat_number, context=None):
         '''
         Check the VAT number depending of the country.
         http://sima-pc.com/nif.php
         '''
-        country_obj = self.pool.get('res.country')
+        check_func_name = 'check_vat_' + country_code
+        check_func = getattr(self, check_func_name, None) or \
+                        getattr(vatnumber, check_func_name, None)
+        if not check_func:
+            # No VAT validation available, default to check that the country code exists
+            res_country = self.pool.get('res.country')
+            return bool(res_country.search(cr, uid, [('code', '=ilike', country_code)], context=context))
+        return check_func(vat_number)
+
+    def vies_vat_check(self, cr, uid, country_code, vat_number, context=None):
+        try:
+            # Validate against  VAT Information Exchange System (VIES)
+            # see also http://ec.europa.eu/taxation_customs/vies/
+            return vatnumber.check_vies(country_code.upper()+vat_number)
+        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.
+            return self.simple_vat_check(cr, uid, country_code, vat_number, context=context)
+
+    def check_vat(self, cr, uid, ids, context=None):
+        user_company = self.pool.get('res.users').browse(cr, uid, uid).company_id
+        if user_company.vat_check_vies:
+            # force full VIES online check
+            check_func = self.vies_vat_check
+        else:
+            # quick and partial off-line checksum validation
+            check_func = self.simple_vat_check
+
         for partner in self.browse(cr, uid, ids, context=context):
             if not partner.vat:
                 continue
             vat_country, vat_number = self._split_vat(partner.vat)
-            check_func_name = 'check_vat_' + vat_country
-            check_func = getattr(self, check_func_name, None) or \
-                            getattr(vatnumber, check_func_name, None)
-            if not check_func:
-                # No VAT validation available, default to check that the country code
-                # exists.
-                if country_obj.search(cr, uid, [('code', 'ilike', vat_country)], context=context):
-                    continue
-                # Country code not found, considered invalid
+            if not check_func(cr, uid, vat_country, vat_number, context=context):
                 return False
-            return check_func(vat_number)
         return True
 
     def vat_change(self, cr, uid, ids, value, context=None):
index 69a1870..fa53906 100644 (file)
@@ -7,12 +7,23 @@
             <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_payable" position="after">
-                <group colspan="2" col="6">
-                    <field name="vat" on_change="vat_change(vat)" colspan="4" />
-                    <field name="vat_subjected" colspan="1" groups="base.group_extended" />
-                </group>
+                <field name="property_account_payable" position="after">
+                    <group colspan="2" col="6">
+                        <field name="vat" on_change="vat_change(vat)" colspan="4" />
+                        <field name="vat_subjected" colspan="1" groups="base.group_extended" />
+                    </group>
+                </field>
             </field>
+        </record>
+
+        <record id="company_form_vat" model="ir.ui.view">
+            <field name="name">res.company.form.vat.inherit</field>
+            <field name="model">res.company</field>
+            <field name="inherit_id" ref="base.view_company_form"/>
+            <field name="arch" type="xml">
+                <field name="currency_id" position="after">
+                    <field name="vat_check_vies" groups="base.group_extended" />
+                </field>
             </field>
         </record>