2
2
# Part of Odoo. See LICENSE file for full copyright and licensing details.
3
3
4
4
import datetime
5
- import logging
6
5
import string
7
6
import re
8
-
9
- _logger = logging .getLogger (__name__ )
10
- try :
11
- import vatnumber
12
- except ImportError :
13
- _logger .warning ("VAT validation partially unavailable because the `vatnumber` Python library cannot be found. "
14
- "Install it to support more countries, for example with `easy_install vatnumber`." )
15
- vatnumber = None
16
-
17
- # Although stdnum is a dependency of vatnumber, the import of the latter is surrounded by a try/except
18
- # if it is not installed. Therefore, we cannot be sure stdnum is installed in all cases.
19
- try :
20
- import stdnum
21
- except ImportError :
22
- stdnum = None
7
+ import stdnum
23
8
24
9
from odoo import api , models , tools , _
25
10
from odoo .tools .misc import ustr
32
17
_eu_country_vat_inverse = {v : k for k , v in _eu_country_vat .items ()}
33
18
34
19
_ref_vat = {
20
+ 'al' : 'ALJ91402501L' ,
21
+ 'ar' : 'AR200-5536168-2 or 20055361682' ,
35
22
'at' : 'ATU12345675' ,
36
23
'be' : 'BE0477472701' ,
37
24
'bg' : 'BG1234567892' ,
38
25
'ch' : 'CHE-123.456.788 TVA or CHE-123.456.788 MWST or CHE-123.456.788 IVA' , # Swiss by Yannick Vaucher @ Camptocamp
39
26
'cl' : 'CL76086428-5' ,
40
27
'co' : 'CO213123432-1 or CO213.123.432-1' ,
41
- 'cy' : 'CY12345678F ' ,
28
+ 'cy' : 'CY10259033P ' ,
42
29
'cz' : 'CZ12345679' ,
43
30
'de' : 'DE123456788' ,
44
31
'dk' : 'DK12345674' ,
32
+ 'do' : 'DO1-01-85004-3 or 101850043' ,
33
+ 'ec' : 'EC1792060346-001' ,
45
34
'ee' : 'EE123456780' ,
46
35
'el' : 'EL12345670' ,
47
36
'es' : 'ESA12345674' ,
48
37
'fi' : 'FI12345671' ,
49
- 'fr' : 'FR32123456789 ' ,
38
+ 'fr' : 'FR23334175221 ' ,
50
39
'gb' : 'GB123456782 or XI123456782' ,
51
40
'gr' : 'GR12345670' ,
52
41
'hu' : 'HU12345676' ,
53
42
'hr' : 'HR01234567896' , # Croatia, contributed by Milan Tribuson
54
43
'ie' : 'IE1234567FA' ,
44
+ 'is' : 'IS062199' ,
55
45
'it' : 'IT12345670017' ,
56
46
'lt' : 'LT123456715' ,
57
47
'lu' : 'LU12345613' ,
58
48
'lv' : 'LV41234567891' ,
49
+ 'mc' : 'FR53000004605' ,
59
50
'mt' : 'MT12345634' ,
60
- 'mx' : 'ABC123456T1B ' ,
51
+ 'mx' : 'MXGODE561231GR8 or GODE561231GR8 ' ,
61
52
'nl' : 'NL123456782B90' ,
62
53
'no' : 'NO123456785' ,
63
54
'pe' : '10XXXXXXXXY or 20XXXXXXXXY or 15XXXXXXXXY or 16XXXXXXXXY or 17XXXXXXXXY' ,
64
55
'pl' : 'PL1234567883' ,
65
56
'pt' : 'PT123456789' ,
66
57
'ro' : 'RO1234567897' ,
58
+ 'rs' : 'RS101134702' ,
59
+ 'ru' : 'RU123456789047' ,
67
60
'se' : 'SE123456789701' ,
68
61
'si' : 'SI12345679' ,
69
62
'sk' : 'SK0012345675' ,
@@ -92,7 +85,7 @@ def simple_vat_check(self, country_code, vat_number):
92
85
if not ustr (country_code ).encode ('utf-8' ).isalpha ():
93
86
return False
94
87
check_func_name = 'check_vat_' + country_code
95
- check_func = getattr (self , check_func_name , None ) or getattr (vatnumber , check_func_name , None )
88
+ check_func = getattr (self , check_func_name , None ) or getattr (stdnum . util . get_cc_module ( country_code , 'vat' ), 'is_valid' , None )
96
89
if not check_func :
97
90
# No VAT validation available, default to check that the country code exists
98
91
if country_code .upper () == 'EU' :
@@ -108,7 +101,7 @@ def simple_vat_check(self, country_code, vat_number):
108
101
def _check_vies (self , vat ):
109
102
# Store the VIES result in the cache. In case an exception is raised during the request
110
103
# (e.g. service unavailable), the fallback on simple_vat_check is not kept in cache.
111
- return vatnumber .check_vies (vat )
104
+ return stdnum . eu . vat .check_vies (vat )
112
105
113
106
@api .model
114
107
def vies_vat_check (self , country_code , vat_number ):
@@ -230,6 +223,26 @@ def _ie_check_char(self, vat):
230
223
checksum = extra + sum ((8 - i ) * int (x ) for i , x in enumerate (vat [:7 ]))
231
224
return 'WABCDEFGHIJKLMNOPQRSTUV' [checksum % 23 ]
232
225
226
+ def check_vat_co (self , rut ):
227
+ '''
228
+ Check Colombian RUT number.
229
+ Method copied from vatnumber 1.2 lib https://code.google.com/archive/p/vatnumber/
230
+ '''
231
+ if len (rut ) != 10 :
232
+ return False
233
+ try :
234
+ int (rut )
235
+ except ValueError :
236
+ return False
237
+ nums = [3 , 7 , 13 , 17 , 19 , 23 , 29 , 37 , 41 , 43 , 47 , 53 , 59 , 67 , 71 ]
238
+ sum = 0
239
+ for i in range (len (rut ) - 2 , - 1 , - 1 ):
240
+ sum += int (rut [i ]) * nums [len (rut ) - 2 - i ]
241
+ if sum % 11 > 1 :
242
+ return int (rut [- 1 ]) == 11 - (sum % 11 )
243
+ else :
244
+ return int (rut [- 1 ]) == sum % 11
245
+
233
246
def check_vat_ie (self , vat ):
234
247
""" Temporary Ireland VAT validation to support the new format
235
248
introduced in January 2013 in Ireland, until upstream is fixed.
@@ -322,6 +335,43 @@ def check_vat_pe(self, vat):
322
335
dig_check = 1
323
336
return int (vat [10 ]) == dig_check
324
337
338
+ def check_vat_ru (self , vat ):
339
+ '''
340
+ Check Russia VAT number.
341
+ Method copied from vatnumber 1.2 lib https://code.google.com/archive/p/vatnumber/
342
+ '''
343
+ if len (vat ) != 10 and len (vat ) != 12 :
344
+ return False
345
+ try :
346
+ int (vat )
347
+ except ValueError :
348
+ return False
349
+
350
+ if len (vat ) == 10 :
351
+ check_sum = 2 * int (vat [0 ]) + 4 * int (vat [1 ]) + 10 * int (vat [2 ]) + \
352
+ 3 * int (vat [3 ]) + 5 * int (vat [4 ]) + 9 * int (vat [5 ]) + \
353
+ 4 * int (vat [6 ]) + 6 * int (vat [7 ]) + 8 * int (vat [8 ])
354
+ check = check_sum % 11
355
+ if check % 10 != int (vat [9 ]):
356
+ return False
357
+ else :
358
+ check_sum1 = 7 * int (vat [0 ]) + 2 * int (vat [1 ]) + 4 * int (vat [2 ]) + \
359
+ 10 * int (vat [3 ]) + 3 * int (vat [4 ]) + 5 * int (vat [5 ]) + \
360
+ 9 * int (vat [6 ]) + 4 * int (vat [7 ]) + 6 * int (vat [8 ]) + \
361
+ 8 * int (vat [9 ])
362
+ check = check_sum1 % 11
363
+
364
+ if check != int (vat [10 ]):
365
+ return False
366
+ check_sum2 = 3 * int (vat [0 ]) + 7 * int (vat [1 ]) + 2 * int (vat [2 ]) + \
367
+ 4 * int (vat [3 ]) + 10 * int (vat [4 ]) + 3 * int (vat [5 ]) + \
368
+ 5 * int (vat [6 ]) + 9 * int (vat [7 ]) + 4 * int (vat [8 ]) + \
369
+ 6 * int (vat [9 ]) + 8 * int (vat [10 ])
370
+ check = check_sum2 % 11
371
+ if check != int (vat [11 ]):
372
+ return False
373
+ return True
374
+
325
375
# VAT validation in Turkey, contributed by # Levent Karakas @ Eska Yazilim A.S.
326
376
def check_vat_tr (self , vat ):
327
377
@@ -365,19 +415,22 @@ def check_vat_tr(self, vat):
365
415
366
416
return False
367
417
368
- def check_vat_al (self , vat ):
418
+ def check_vat_ua (self , vat ):
419
+ '''
420
+ Check Ukraine VAT number.
421
+ Method copied from vatnumber 1.2 lib https://code.google.com/archive/p/vatnumber/
422
+ '''
423
+ if len (vat ) != 8 :
424
+ return False
369
425
try :
370
- import stdnum . al
371
- return stdnum . al . vat . is_valid ( vat )
372
- except ImportError :
373
- return True
426
+ int ( vat )
427
+ except ValueError :
428
+ return False
429
+ return True
374
430
375
431
def check_vat_cl (self , vat ):
376
432
return stdnum .util .get_cc_module ('cl' , 'vat' ).is_valid (vat ) if stdnum else True
377
433
378
- def check_vat_co (self , vat ):
379
- return stdnum .util .get_cc_module ('co' , 'vat' ).is_valid (vat ) if stdnum else True
380
-
381
434
def check_vat_nl (self , vat ):
382
435
"""
383
436
Temporary Netherlands VAT validation to support the new format introduced in January 2020,
@@ -431,25 +484,15 @@ def check_vat_nl(self, vat):
431
484
432
485
return False
433
486
434
- def check_vat_ua (self , vat ):
435
- res = []
436
- for partner in self :
437
- if partner .commercial_partner_id .country_id .code == 'MX' :
438
- if len (vat ) == 10 :
439
- res .append (True )
440
- else :
441
- res .append (False )
442
- elif partner .commercial_partner_id .is_company :
443
- if len (vat ) == 12 :
444
- res .append (True )
445
- else :
446
- res .append (False )
447
- else :
448
- if len (vat ) == 10 or len (vat ) == 9 :
449
- res .append (True )
450
- else :
451
- res .append (False )
452
- return all (res )
487
+ def _fix_vat_number (self , vat ):
488
+ vat_country , vat_number = self ._split_vat (vat )
489
+ stdnum_vat_fix_func = getattr (stdnum .util .get_cc_module (vat_country , 'vat' ), 'compact' , None )
490
+ #If any localization module need to define vat fix method for it's country then we give first priority to it.
491
+ format_func_name = 'format_vat_' + vat_country
492
+ format_func = getattr (self , format_func_name , None ) or stdnum_vat_fix_func
493
+ if format_func :
494
+ vat_number = format_func (vat_number )
495
+ return vat_country .upper () + vat_number
453
496
454
497
def check_vat_xi (self , vat ):
455
498
""" Temporary Nothern Ireland VAT validation following Brexit
0 commit comments