File: res_partner.py

package info (click to toggle)
oca-core 11.0.20180730-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 509,684 kB
  • sloc: xml: 258,806; python: 164,081; sql: 217; sh: 92; makefile: 16
file content (103 lines) | stat: -rw-r--r-- 4,176 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

import logging
import re

from odoo import api, models

from suds.client import Client

_logger = logging.getLogger(__name__)

try:
    import stdnum.eu.vat as stdnum_vat
    if not hasattr(stdnum_vat, "country_codes"):
        # stdnum version >= 1.9
        stdnum_vat.country_codes = stdnum_vat._country_codes
except ImportError:
    _logger.warning('Python `stdnum` library not found, unable to call VIES service to detect address based on VAT number.')
    stdnum_vat = None


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

    @api.onchange('vat')
    def vies_vat_change(self):
        def _check_city(lines, country='BE'):
            if country == 'GB':
                ukzip = '[A-Z]{1,2}[0-9][0-9A-Z]?\s?[0-9][A-Z]{2}'
                if re.match(ukzip, lines[-1]):
                    cp = lines.pop()
                    city = lines.pop()
                    return (cp, city)
            elif country == 'SE':
                result = re.match('([0-9]{3}\s?[0-9]{2})\s?([A-Z]+)', lines[-1])
                if result:
                    lines.pop()
                    return (result.group(1), result.group(2))
            else:
                result = re.match('((?:L-|AT-)?[0-9\-]+[A-Z]{,2}) (.+)', lines[-1])
                if result:
                    lines.pop()
                    return (result.group(1), result.group(2))
            return False

        def _set_address_field(partner, field, value):
            partner[field] = value
            non_set_address_fields.remove(field)

        if stdnum_vat is None:
            return {}

        for partner in self:
            # If a field is non set in this algorithm
            # wipe it anyway
            non_set_address_fields = set(['street2', 'city', 'zip', 'state_id', 'country_id'])
            if not partner.vat:
                return {}
            if len(partner.vat) > 5 and partner.vat[:2].lower() in stdnum_vat.country_codes:
                # Equivalent to stdnum_vat.check_vies(partner.vat).
                # However, we want to add a custom timeout to the suds.client
                # because by default, it's 120 seconds and this is to long.
                try:
                    client = Client(stdnum_vat.vies_wsdl, timeout=5)
                    partner_vat = stdnum_vat.compact(partner.vat)
                    result = client.service.checkVat(partner_vat[:2], partner_vat[2:])
                except:
                    # Avoid blocking the client when the service is unreachable/unavailable
                    return {}

                if not result['valid']:
                    return {}

                if (not partner.name) and (result['name'] != '---'):
                    partner.name = result['name']

                #parse the address from VIES and fill the partner's data
                if result['address'] == '---': return {}

                lines = [x for x in result['address'].split("\n") if x]
                if len(lines) == 1:
                    lines = [x.strip() for x in lines[0].split(',') if x]
                if len(lines) == 1:
                    lines = [x.strip() for x in lines[0].split('   ') if x]

                vals = partner._split_street_with_params(', '.join(lines.pop(0).rsplit(' ', 1)), '%(street_name)s, %(street_number)s/%(street_number2)s')
                partner.update(vals)

                if len(lines) > 0:
                    res = _check_city(lines, result['countryCode'])
                    if res:
                        _set_address_field(partner, 'zip', res[0])
                        _set_address_field(partner, 'city', res[1])
                if len(lines) > 0:
                    _set_address_field(partner, 'street2', lines.pop(0))

                country = self.env['res.country'].search([('code', '=', result['countryCode'])], limit=1)
                _set_address_field(partner, 'country_id', country and country.id or False)

                for field in non_set_address_fields:
                    if partner[field]:
                        partner[field] = False