#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This file is part of Pymetrick.  The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

"""Modulo para gestionar identificacion fiscal y monedas"""

try:
    from pymetrick.version import __author__, __version__, __license__, __copyright__
except ImportError:
    raise ImportError(
        'Failed to find (autogenerated) version.py '
    )

__date__ = '2012-09-21'
__credits__ = ''
__text__ = 'Tratamiento fiscal, bancos y monedas'
__file__ = 'exchequer.py'

#--- CHANGES ------------------------------------------------------------------
# 2012-09-21 v0.01 PL: - First version

import sys
# sin bytecode
sys.dont_write_bytecode = True
import os
import string
import re
import urllib.request
import ssl
import zeep
import logging
import logging.handlers

try:
    import simplejson as json
except:
    import json

'''
DEBUG - debug message
INFO - info message
WARNING - warn message
ERROR - error message
CRITICAL - critical message
'''
LOG_LEVEL_VALUE = {'DEBUG':10,'INFO':20,'WARNING':30,'ERROR':40,'CRITICAL':50}
if str(os.environ.get('PYMETRICK_LOG_LEVEL',None)).upper() in LOG_LEVEL_VALUE:
    LOG_LEVEL = LOG_LEVEL_VALUE[str(os.environ.get('PYMETRICK_LOG_LEVEL')).upper()]
else:
    LOG_LEVEL = 30
LOG_FILENAME = '-'.join([os.path.abspath(__file__).split(os.sep)[len(os.path.abspath(__file__).split(os.sep))-1],])[:-3]
LOG = logging.getLogger(LOG_FILENAME)

if 'LD_LIBRARY_PATH' in list(os.environ.keys()):
    # CGI environment
    sys.stdout = sys.stderr
    logging.basicConfig(stream = sys.stderr, level=LOG_LEVEL, format='%(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s')
else:
    # not CGI environment
    logging.basicConfig(stream=sys.stderr)
    hdlr = logging.handlers.RotatingFileHandler(filename=LOG_FILENAME+'.log',mode='a', encoding='utf-8', maxBytes=1048576, backupCount=3)
    formatter = logging.Formatter('%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s - %(message)s')
    hdlr.setFormatter(formatter)
    LOG.addHandler(hdlr)
    LOG.setLevel(LOG_LEVEL)

'''
País	Tarifa cero?	Tarifa reducida	Tarifa estándar
Austria	      No           10% o 12%	20%
Bélgica	      Sí	   6% o 12%	21%
Bulgaria	No	   9%	        20%
República Checa	No	   15%	        21%
Croacia	        No	  5% o 13%	25%
Chipre	        Sí	  5% o 9%	19%
Dinamarca	Sí	     -	        25%
Estonia	        Sí	     9%	        20%
Finlandia	Sí	10% o 14%	24%
Francia	        No	2.1% o 5.5% o 10%	20%
Alemania	No	7%	19%
Grecia	        No	6.5% o 13%	23%
Hungría	        No	5% o 18%	27%
Irlanda	        Sí	4.8% o 9% o 13.5%	23%
Italia	        Sí	4% o 10%	22%
Letonia	        No	12%	        21%
Lituania	No	5% o 9%	        21%
Luxemburgo	No	3% o 8%	        17%
Malta	        Sí	5% o 7%	        18%
Países Bajos	No	6%	        21%
Polonia	        Sí	5% o 8%	        23%
Portugal	No	6% o 13%	23%
Rumania	        No	5% o 9%	        24%
Eslovenia	No	9.5%	        22%
Eslovaquia	No	10%	        20%
España	        No	4% o 10%	21%
Suecia	        Sí	6% o 12%	25%
Reino Unido	Sí	5%	        20%
'''

ISO_COUNTRY_2_TAX_LIST = ['AT','BE','BG','CY','CZ','DE','DK','EE','EL','ES','FI','FR','HR','HU','IE','IT','LT','LU','LV','MT','NL','PL','PT','RO','GB','SE','SI','SK']

def validate_EORI(iso_country='ES',nif=''):
    '''Tax license validation
       @parameters
           iso_country: ISO country. ES(default)
           nif:   tax license
       @return
           iso_country.nif  <-- if it's right
           &iso_country.nif <-- if it's wrong
    '''
    try:
        iso_country_2 = ''.join(re.findall("^[a-zA-Z]{2}",nif)).upper() if ''.join(re.findall("^[a-zA-Z]{2}",nif)).upper() in ISO_COUNTRY_2_TAX_LIST else iso_country
        # elimina las siglas de iso_country_2 en nif 
        _nif = " ".join(re.findall("[a-zA-Z0-9]+",nif)).upper().replace(' ','')[len(''.join(re.findall("^[a-zA-Z]{2}",nif))):]
        if iso_country_2=='AT':
            # AUSTRIA ATU99999999 = AT + 1 bloque con una "U" seguida de 8 dígitos numéricos p.e.:ATU12345675
            # FORMATO
            #          A(1)+N(1-7)+C(1)
            #          A(1)={U}
            # S=N(1)+2#N(2)+N(3)+2#N(4)+N(5)+2#N(6)+N(7)
            # C(1)=10-(S+4)%10; si C(1)=10, C(1)=0
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='BE':
            # BELGICA BE9999999999 = BE + 1 bloque de 10 dígitos numéricos, el primero "0" o "1". p.e.:BE1234567894
            # FORMATO
            #         N(1-8)+C(1-2)
            #         N(2)>1
            # C(1-2)=97-N(1-7)%97
            # 
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='BG':
            # BULGARIA BG9999999999 = BG + 1 bloque de 9 o 10 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{9,10}",_nif))
            if len(__nif) == 9 or len(__nif) == 10 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal CZ incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='CY':
            # CHIPRE CY99999999L = CY + 1 bloque de 8 dígitos numéricos y al final 1 letra
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='CZ':
            # CHEQUIA CZ9999999999 = CZ + 1 bloque de 8, 9 o 10 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8,10}",_nif))
            if len(__nif) == 8 or len(__nif) == 9 or len(__nif) == 10 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal CZ incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='DE':
            # ALEMANIA DE999999999 = DE + 1 bloque de 9 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{9}",_nif))
            if len(__nif) == 9 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal DE incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='DK':
            # DINAMARCA DK99 99 99 99 = DK + 4 bloques de 2 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8}",_nif))
            if len(__nif) == 8 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal DK incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='EE':
            # ESTONIA EE999999999 = EE + 1 bloque de 9 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{9}",_nif))
            if len(__nif) == 9 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal EE incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='EL':
            # GRECIA EL999999999 = EL + 1 bloque de 9 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{9}",_nif))
            if len(__nif) == 9 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal EL incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='ES':
            # ESX9999999X = ES + 1 bloque de 9 caracteres (primero y último: letra o dígitos, resto: sólo dígitos).
            _nif = " ".join(re.findall("[a-zA-Z0-9]+",nif)).upper().replace(' ','')
            if _nif[:2] == iso_country_2:
                _nif = _nif[2:]
            ''' NIF 8 digitos + 1 caracter o 1 caracter + 7 digitos + 1 caracter
                CIF 7 digitos + 1 caracter de control
            '''
            ALPHA_NIF = 'TRWAGMYFPDXBNJZSQVHLCKE'
            '''Entidades juridicas con animo de lucro'''
            ALPHA_CIF_a = 'JABCDEFGHI'
            '''Personas juridicas sin animo de lucro '''
            ALPHA_CIF_b = 'NPQRSW'
            '''Personas fisicas extranjeras, menores de 14 o no residentes'''
            ALPHA_CIF_c = 'KLMXYZ'
            '''Comprobar si es un NIF'''
            if len(_nif)>0:
                if _nif[0] in '0123456789':
                    _nif_number = ' '.join(re.findall("[0-9]+",_nif))
                    ctrl = (int(_nif_number))%23
                    __nif = _nif_number+ALPHA_NIF[ctrl]
                    if __nif.strip().upper() == _nif:
                        __nif = _nif_number.zfill(8)+ALPHA_NIF[ctrl]
                        return (iso_country_2,__nif)
                else:
                    '''Comprobar si es una Persona fisica extranjera, menor de 14 o no residente'''
                    if _nif[0] in ALPHA_CIF_c:
                        _nif_number = ' '.join(re.findall("[0-9]+",_nif))
                        '''Si contiene 7 digitos y comienza por X Y Z, sustituir X Y Z por 0 1 2'''
                        ctrl = int(_nif_number)
                        if len(_nif_number) == 7 and len(_nif) == 9:
                            if _nif[0] in 'XYZ':
                                n = {'X':'0','Y':'1','Z':'2'}
                                ctrl = int(n[_nif[0]]+_nif_number)
                        ctrl = ctrl%23
                        __nif = _nif[0]+_nif_number+ALPHA_NIF[ctrl]
                        if __nif.strip().upper() == _nif:
                            __nif = _nif[0]+_nif_number.zfill(7)+ALPHA_NIF[ctrl]
                            return (iso_country_2,__nif)
                    '''Comprobar si es una Persona juridica sin animo de lucro'''
                    if _nif[0] in ALPHA_CIF_a:
                        if 7<len(_nif)<=9:
                            _nif_number = ' '.join(re.findall("[0-9]+",_nif))
                            '''obtener posicion par e impar'''
                            n = 0
                            n_ctrl = 0
                            for n in range(0,len(_nif_number)-1):
                                if (n+1)%2 == 0:
                                    n_ctrl += int(_nif_number[n])
                                else:
                                    n_ctrl += (int(_nif_number[n])*2%10)+int(int(_nif_number[n])*2/10)
                            ctrl = n_ctrl%10
                            ctrl = 10 - ctrl
                            if ctrl>9:
                                ctrl = 0
                            __nif = _nif[0]+_nif_number[0:7]+repr(ctrl)
                            if __nif.strip().upper() == _nif:
                                __nif = _nif[0]+_nif_number[0:7].zfill(7)+repr(ctrl)
                                return (iso_country_2,__nif)
                    '''Comprobar si es una Persona juridica sin animo de lucro'''
                    if _nif[0] in ALPHA_CIF_b:
                        if 7<len(_nif)<=9:
                            _nif_number = ' '.join(re.findall("[0-9]+",_nif))
                            '''obtener posicion par e impar'''
                            n = 0
                            n_ctrl = 0
                            for n in range(0,len(_nif_number)):
                                if (n+1)%2 == 0:
                                    n_ctrl += int(_nif_number[n])
                                else:
                                    n_ctrl += (int(_nif_number[n])*2%10)+int(int(_nif_number[n])*2/10)
                            ctrl = n_ctrl%10
                            ctrl = 10 - ctrl
                            __nif = _nif[0]+_nif_number[0:7]+chr(ctrl+64).upper()
                            if __nif.strip().upper() == _nif:
                                __nif = (_nif[0]+_nif_number[0:7].zfill(7)+chr(ctrl+64)).upper()
                                return (iso_country_2,__nif)
            # identificacion fiscal ES incorrecta
            return (iso_country_2,'&'+_nif)
        elif iso_country_2=='FI':
            # FINLANDIA FI99999999 = FI + 1 bloque de 8 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8}",_nif))
            if len(__nif) == 8 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal FI incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='FR':
            # FRANCIA FRXX 999999999 = FR + 1 bloque de 2 caracteres y otro de 9 dígitos numéricos 
            # FORMATO  p.e. 32123456789
            # Sistema antiguo	C(1-2)+N(1-9)
            #                   N(1-9)>0	
            # C(1-2)=(N(1-9)*100+12)%97
            # Sistema nuevo p.e. 2H123456789
            #                   C(1-2)+N(1-9)
            #                   N(1-9)>0
            #                   C(1-2)={A-H,J-N,P-Z} | {0-9}
            #                   si C(1) es alfabético, C(2) ha de ser numérico y al revés.	
            #                   Para un N(1-9) dado, hay más de un C(1-2) posible, por tanto, no se puede calcular éste.
            # C{0-9,A-H,J-N,P-Z} → C{0-33}
            # si C(1)<10, S=C(1)*24+C(2)-10
            # si C(1)>9, S=C(1)*34+C(2)-100
            # X=S%11
            # S=S\11+1
            # Y=(N(1-9)+S)%11
            # si X=Y, correcto
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='HR':
            # CROACIA
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='HU':
            # HUNGRIA HU99999999 = HU + 1 bloque de 8 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8}",_nif))
            if len(__nif) == 8 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal HU incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='IE':
            # IRLANDA IE9S99999L = IE + 1 bloque de 8 dígitos. "S" puede ser letra (A-Z), dígito (0-9); "+" o "*".
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='IT':
            # ITALIA IT99999999999 = IT + 1 bloque de 11 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{11}",_nif))
            if len(__nif) == 11 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal IT incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='LT':
            # LITUANIA LT999999999999 = LT + 1 bloque de 9 o 12 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{9,12}",_nif))
            if len(__nif) == 9 or len(__nif) == 12 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal LT incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='LU':
            # LUXEMBURGO LU99999999 = LU + 1 bloque de 8 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8}",_nif))
            if len(__nif) == 8 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal LU incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='LV':
            # LETONIA LV99999999999 = LV + 1 bloque de 11 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{11}",_nif))
            if len(__nif) == 11 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal LV incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='MT':
            # MALTA MT99999999 = MT + 1 bloque de 8 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8}",_nif))
            if len(__nif) == 8 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal MT incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='NL':
            # PAISES BAJOS NL999999999B99 = NL + 1 bloque de 12 caracteres, siendo el décimo siempre "B".
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='PL':
            # POLONIA PL9999999999 = PL + 1 bloque de 10 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{10}",_nif))
            if len(__nif) == 10 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal PL incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='PT':
            # PORTUGAL PT999999999 = PT + 1 bloque de 9 dígitos numéricos p.e.:123456789
            # FORMATO
            #          N(1-8)+C(1)
            #          N(1)>0
            # S=9*N(1)+8*N(2)+7*N(3)+6*N(4)+5*N(5)+4*N(6)+3*N(7)+2*N(8)
            # C(1)=11-S%11; si C(1)=10, C(1)=0; si C(1)=11, C(1)=0
            if len(_nif)==9:
                n = [ int(x) for x in _nif ]
                s = n[0]*9+n[1]*8+n[2]*7+n[3]*6+n[4]*5+n[5]*4+n[6]*3+n[7]*2
                c = 11-s%11
                dc = '0' if c == 10 or c == 11 else str(c)
                __nif = _nif[:8]+dc
                if __nif.strip().upper() == _nif:
                    return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+__nif)
            # identificacion fiscal PT incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='RO':
            # RUMANIA RO9999999999 = RO + 1 bloque de 2 a 10 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{2,10}",_nif))
            if len(__nif) >= 2 and len(__nif) <= 10 :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal RO incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='GB':
            # REINO UNIDO GB999 9999 99 999 = GR + 3 bloques de 3, 4 y 2 dígitos numéricos.
            #             Empresas de grupos: + otro de 3 dígitos.  /  Dep. .gubernamentales: GBGD999  /  Autoridades sanitarias: GBHA999
            return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='SE':
            # SUECIA SE999999999901 = 1 bloque de 12 dígitos numéricos, los dos últimos siempre "01"
            __nif = ''.join(re.findall("[0-9]{12}",_nif))
            if len(__nif) == 12 and __nif[10:]=='01' :
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal SE incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='SI':
            # ESLOVENIA SI99999999 = SI + 1 bloque de 8 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{8}",_nif))
            if len(__nif) == 8:
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal SI incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        elif iso_country_2=='SK':
            # ESLOVAQUIA SK9999999999 = SK + 1 bloque de 10 dígitos numéricos
            __nif = ''.join(re.findall("[0-9]{10}",_nif))
            if len(__nif) == 10:
                return (iso_country_2,''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
            # identificacion fiscal SK incorrecta
            return (iso_country_2,'&'+''.join(re.findall("^[a-zA-Z]{2}",nif)).upper()+_nif)
        else:
            # identificacion fiscal ajena
            return ('00',_nif)

        # identificacion fiscal NO comprobada
        return (iso_country_2,_nif)
    except Exception as e:
        if hasattr(e, 'message'):
            LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
        else:
            LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

#******************************************* Consulta de situación de contribuyentes en el registro de operadores intracomunitarios. ******************

VAT_NUMBER_REGEXPS = {
    'AT': re.compile(r'^U\d{8}$', re.IGNORECASE),
    'BE': re.compile(r'^\d{9,10}$'),
    'BG': re.compile(r'^\d{9,10}$'),
    'CY': re.compile(r'^\d{8}[a-z]$', re.IGNORECASE),
    'CZ': re.compile(r'^\d{8,10}$'),
    'DE': re.compile(r'^\d{9}$'),
    'DK': re.compile(r'^\d{8}$'),
    'EE': re.compile(r'^\d{9}$'),
    'EL': re.compile(r'^\d{9}$'),
    'ES': re.compile(r'^[\da-z]\d{7}[\da-z]$', re.IGNORECASE),
    'FI': re.compile(r'^\d{8}$'),
    'FR': re.compile(r'^[\da-hj-np-z]{2}\d{9}$', re.IGNORECASE),
    'GB': re.compile(r'^((\d{9})|(\d{12})|(GD\d{3})|(HA\d{3}))$', re.IGNORECASE),
    'HR': re.compile(r'^\d{11}$'),
    'HU': re.compile(r'^\d{8}$'),
    'IE': re.compile(r'^((\d{7}[a-z])|(\d[a-z]\d{5}[a-z])|(\d{6,7}[a-z]{2}))$', re.IGNORECASE),
    'IT': re.compile(r'^\d{11}$'),
    'LT': re.compile(r'^((\d{9})|(\d{12}))$'),
    'LU': re.compile(r'^\d{8}$'),
    'LV': re.compile(r'^\d{11}$'),
    'MT': re.compile(r'^\d{8}$'),
    'NL': re.compile(r'^\d{9}B\d{2,3}$', re.IGNORECASE),
    'PL': re.compile(r'^\d{10}$'),
    'PT': re.compile(r'^\d{9}$'),
    'RO': re.compile(r'^\d{2,10}$'),
    'SE': re.compile(r'^\d{12}$'),
    'SI': re.compile(r'^\d{8}$'),
    'SK': re.compile(r'^\d{10}$'),
}



#client = Client('https://ec.europa.eu/taxation_customs/vies/checkVatTestService.wsdl')

class ViesValidationError(Exception):
    """
    Exception thrown by the Vies object when there is a
    validation problem.
    """
    pass


class ViesHTTPError(Exception):
    """
    Exception thrown by the Vies object when there is an
    HTTP error interacting with Vies.
    """
    pass


class ViesError(Exception):
    """
    Base Exception thrown by the Vies object when there is a
    general problem when interacting with Vies service.
    """
    pass

class Vies(object):
    '''Consulta de situación de contribuyentes en el registro de operadores intracomunitarios.
       ejemplo:
       v = Vies()
       v.request(vat_number='PTddddddddd')
       v.request(vat_number='Bdddddddd',vat_country_code='ES')
       v.request(vat_number='ESBdddddddd',vat_country_code='ES')

    @parameteres
       vat_country: ISO country. ES(default)
       vat_number : tax license

    @return
        {
        'countryCode': 'PT',
        'vatNumber': 'ddddddddd',
        'requestDate': datetime.date(2022, 4, 3),
        >'valid': True|False, <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        'traderName': 'NOMBRE SUPUESTO',
        'traderCompanyType': '---',
        'traderAddress': 'DIRECCION COMPLETA SUPUESTA',
        'traderStreet': None,
        'traderPostcode': None,
        'traderCity': None,
        'traderNameMatch': None,
        'traderCompanyTypeMatch': None,
        'traderStreetMatch': None,
        'traderPostcodeMatch': None,
        'traderCityMatch': None,
        'requestIdentifier': None
        }

    '''

    WS_ENDPOINT = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'
    
    def __init__(self):
        super(Vies, self).__init__()

    def request(self, vat_number, vat_country_code=None, extended_info=True):
        try:
            vat_number = vat_number.replace(' ','')
            
            if vat_country_code is not None:
                vat_country_code = vat_country_code.replace(' ','').upper()

            else:
                vat_country_code = vat_number[:2]

            if vat_country_code not in VAT_NUMBER_REGEXPS.keys():
                vat_country_code = 'ES'

            if vat_number[:2].upper() == vat_country_code:
                vat_number = vat_number[2:]    

            if vat_country_code=='EL':
                vat_country_code = 'GR'

            if vat_country_code not in VAT_NUMBER_REGEXPS.keys():
                raise ViesValidationError('Invalid VAT country')

            # check VIES
            try:
                client = zeep.Client(wsdl=self.WS_ENDPOINT)
                client.settings(raw_response=True, force_https=True)
                
            except Exception as e:
                raise ViesHTTPError('VIES service unreachable. %s' % str(e))

            try:
                if extended_info is True:
                    result = client.service.checkVatApprox(vat_country_code, vat_number)
                else:
                    result = client.service.checkVat(vat_country_code, vat_number)
            except Exception as e:
                raise ViesError('Got error from vies: %s' % str(e))


            return result            
                
        except Exception as e:
            if hasattr(e, 'message'):
                LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
            else:
                LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))
                return {}


#******************************************* End Consulta de situación de contribuyentes en el registro de operadores intracomunitarios. ******************

def currencyExchangeEUR(dest=None):
    '''Get daily list of changes from ECB in XML format
       and extract currency exchange information from 1 EUR
       @parameters
           dest: ISO currency
       @return
           [changes,symbol]  <-- if it's right
           [0,'']            <-- if it's wrong
    '''
    try:
        currency_list = list()
        currency_dict = dict()
        url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"
        if (not os.environ.get('PYTHONHTTPSVERIFY', '') and getattr(ssl, '_create_unverified_context', None)): 
            ssl._create_default_https_context = ssl._create_unverified_context
        currency = urllib.request.urlopen(url, context=ssl.SSLContext()).read()
        buscar = b"currency\s\'[\w{3}]\s\'?rate=\'(\d{4,7}.)\'/>"
        l_currency = re.findall(b"currency='[\w]{3}'\srate='[\d]{1,5}[.]?[\d]{1,5}'",currency)
        for m in l_currency:
            currency_list = list(m.decode().replace('currency=','').replace(' rate','').replace("'",'').split('='))
            currency_dict[currency_list[0]]=float(currency_list[1])
        if dest is not None and dest in currency_dict:
            symbol = currencyCode(code=dest)[-1]
            return [currency_dict[dest],symbol]
        else:
            return [0,'']
    except Exception as e:
        if hasattr(e, 'message'):
            LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
        else:
            LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))


def currencyCode(code='EUR'):
    '''Check currency
       @parameters
           code: ISO currency
       @return
           [ISO currency,symbol]  <-- if it's right
           ['','']                <-- if it's wrong
    '''
    try:
        _code =''
        # return [ISO, symbol]
        _code_list = ['','']
        currency_dict = {'USD':'$',
                        'EUR':'eur|€',
                        'JPY':'yen|円|¥',
                        'BGN':'lev|leva|лев|лева',
                        'CZK':'koruna česká|Kč',
                        'DKK':'krone|kroner|kr',
                        'GBP':'pound sterling|£',
                        'HUF':'forint',
                        'PLN':'esloti|złoty|zł',
                        'RON':'leu|lei',
                        'SEK':'krona|kronor',
                        'CHF':'franken|franc|franco',
                        'ISK':'króna|krónur|kr',
                        'NOK':'krone|kroner|kr',
                        'HRK':'kuna',
                        'RUB':'rublo|рубль|₽',
                        'TRY':'lira|Türk lirası',
                        'AUD':'australian dollar',
                        'BRL':'real|reais|R$',
                        'CAD':'canadian dollar|dollar canadien',
                        'CNY':'renminbi|RMB|yuan|人民币|人民幣|¥',
                        'HKD':'港元|港幣|HK$',
                        'IDR':'rupia|rupiah|Rp',
                        'ILS':'שקל חדש|₪',
                        'INR':'rupia|रुपया| روپیہ|₹',
                        'KRW':'대한민국 원|大韓民國 圓|daehan minguk weon|taehan minkuk wŏn|원|圓|weon|wŏn|₩',
                        'MXN':'peso mexicano|$',
                        'MYR':'ringgit|ريڠݢيت مليسيا|RM',
                        'NZD':'new zealand dollar|NZ$',
                        'PHP':'piso|php|₱',
                        'SGD':'singaporean dollar|元|வெள்ளி|ringgit|新加坡元|சிங்கப்பூர் வெள்ளி|S$',
                        'THB':'baht|บาท|฿',
                        'ZAR':'rand|R'
                       }
        if code.upper() in currency_dict.keys():
            _code = code
        else:
            for n in currency_dict.keys():
                currency_list = {x.lower() if type(x).__name__=='str' else x for x in currency_dict[n].split('|')}
                if code in currency_list:
                    _code = n
        if len(_code)>0 and _code in currency_dict.keys():
            # [ISO, symbol]
            _code_list = [_code,currency_dict[_code].split('|')[-1]]
        return _code_list
    except Exception as e:
        if hasattr(e, 'message'):
            LOG.error('<%s> in line %s !!!' % (e.message,format(sys.exc_info()[-1].tb_lineno)))
        else:
            LOG.error('<%s> in line %s !!!' % (e,format(sys.exc_info()[-1].tb_lineno)))

if __name__ == '__main__' :
    """
    print ('''copyright {0}'''.format( __copyright__))
    print ('''license {0}'''.format( __license__))
    print ('''version {0}'''.format( __version__))
    if len(sys.argv) < 2:
        sys.stderr.write("for help use -h o --help")
    elif sys.argv[1]=='-h' or sys.argv[1]=='--help':
        print ('''
        Tratamiento de identificaciones fiscales\n\n
        y gestion de monedas  ''')
    """

