Skip to content

Commit 8519221

Browse files
quiqueportaarthurdejong
authored andcommitted
Add Spanish CAE Number
Closes #446
1 parent 0f94ca6 commit 8519221

File tree

2 files changed

+500
-0
lines changed

2 files changed

+500
-0
lines changed

stdnum/es/cae.py

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
# cae.py - functions for handling Spanish CAE number
2+
# coding: utf-8
3+
#
4+
# Copyright (C) 2024 Quique Porta
5+
#
6+
# This library is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU Lesser General Public
8+
# License as published by the Free Software Foundation; either
9+
# version 2.1 of the License, or (at your option) any later version.
10+
#
11+
# This library is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
# Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public
17+
# License along with this library; if not, write to the Free Software
18+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19+
# 02110-1301 USA
20+
21+
"""CAE (Código de Actividad y Establecimiento, Spanish activity establishment code).
22+
23+
The Código de Actividad y Establecimiento (CAE) is assigned by the Spanish
24+
Tax Agency companies or establishments that carry out activities related to
25+
products subject to excise duty. It identifies an activity and the
26+
establishment in which it is carried out.
27+
28+
The number consists of 13 characters where the sixth and seventh characters
29+
identify the managing office in which the territorial registration is carried
30+
out and the eighth and ninth characters identify the activity that takes
31+
place.
32+
33+
34+
More information:
35+
36+
* https://www.boe.es/boe/dias/2006/12/28/pdfs/A46098-46100.pdf
37+
* https://www2.agenciatributaria.gob.es/L/inwinvoc/es.aeat.dit.adu.adce.cae.cw.AccW?fAccion=consulta
38+
39+
>>> validate('ES00008V1488Q')
40+
'ES00008V1488Q'
41+
>>> validate('00008V1488') # invalid check length
42+
Traceback (most recent call last):
43+
...
44+
InvalidLength: ...
45+
>>> is_valid('ES00008V1488Q')
46+
True
47+
>>> is_valid('00008V1488')
48+
False
49+
>>> compact('ES00008V1488Q')
50+
'ES00008V1488Q'
51+
"""
52+
53+
from stdnum.exceptions import *
54+
from stdnum.util import clean, isdigits
55+
56+
57+
_OFFICES = {
58+
'01', # Álava
59+
'02', # Albacete
60+
'03', # Alicante
61+
'04', # Almería
62+
'05', # Ávila
63+
'06', # Badajoz
64+
'07', # Illes Balears
65+
'08', # Barcelona
66+
'09', # Burgos
67+
'10', # Cáceres
68+
'11', # Cádiz
69+
'12', # Castellón
70+
'13', # Ciudad Real
71+
'14', # Córdoba
72+
'15', # A Coruña
73+
'16', # Cuenca
74+
'17', # Girona
75+
'18', # Granada
76+
'19', # Guadalajara
77+
'20', # Guipúzcoa
78+
'21', # Huelva
79+
'22', # Huesca
80+
'23', # Jaén
81+
'24', # León
82+
'25', # Lleida
83+
'26', # La Rioja
84+
'27', # Lugo
85+
'28', # Madrid
86+
'29', # Málaga
87+
'30', # Murcia
88+
'31', # Navarra
89+
'32', # Ourense
90+
'33', # Oviedo
91+
'34', # Palencia
92+
'35', # Las Palmas
93+
'36', # Pontevedra
94+
'37', # Salamanca
95+
'38', # Santa Cruz de Tenerife
96+
'39', # Santander
97+
'40', # Segovia
98+
'41', # Sevilla
99+
'42', # Soria
100+
'43', # Tarragona
101+
'44', # Teruel
102+
'45', # Toledo
103+
'46', # Valencia
104+
'47', # Valladolid
105+
'48', # Bizcaia
106+
'49', # Zamora
107+
'50', # Zaragoza
108+
'51', # Cartagena
109+
'52', # Gijón
110+
'53', # Jerez de la Frontera
111+
'54', # Vigo
112+
'55', # Ceuta
113+
'56', # Melilla
114+
}
115+
116+
_ACTIVITY_KEYS = {
117+
'A1', # Fábricas de alcohol
118+
'B1', # Fábricas de bebidas derivadas
119+
'B9', # Elaboradores de productos intermedios distintos de los comprendidos en B-0
120+
'B0', # Elaboradores de productos intermedios en régimen especial
121+
'BA', # Fábricas de bebidas alcohólicas
122+
'C1', # Fábricas de cerveza
123+
'DA', # Destiladores artesanales
124+
'EC', # Fábricas de extractos y concentrados alcohólicos
125+
'F1', # Elaboradores de otras bebidas fermentadas
126+
'V1', # Elaboradores de vinos
127+
'A7', # Depósitos fiscales de alcohol
128+
'AT', # Almacenes fiscales de alcohol
129+
'B7', # Depósitos fiscales de bebidas derivadas
130+
'BT', # Almacenes fiscales de bebidas alcohólicas
131+
'C7', # Depósitos fiscales de cerveza
132+
'DB', # Depósitos fiscales de bebidas alcohólicas
133+
'E7', # Depósitos fiscales de extractos y concentrados alcohólicos exclusivamente
134+
'M7', # Depósitos fiscales de productos intermedios
135+
'OA', # Operadores registrados de alcohol
136+
'OB', # Operadores registrados de bebidas alcohólicas
137+
'OE', # Operadores registrados de extractos y concentrados alcohólicos
138+
'OV', # Operadores registrados de vinos y de otras bebidas fermentadas
139+
'V7', # Depósitos fiscales de vinos y de otras bebidas fermentadas
140+
'B6', # Plantas embotelladoras de bebidas derivadas
141+
'A2', # Centros de investigación
142+
'A6', # Usuarios de alcohol totalmente desnaturalizado
143+
'A9', # Industrias de especialidades farmacéuticas
144+
'A0', # Centros de atención médica
145+
'AC', # Usuarios con derecho a devolución
146+
'AV', # Usuarios de alcohol parcialmente desnaturalizado con desnaturalizante general
147+
'AW', # Usuarios de alcohol parcialmente desnaturalizado con desnaturalizante especial
148+
'AX', # Fábricas de vinagre
149+
'H1', # Refinerías de crudo de petróleo
150+
'H2', # Fábricas de biocarburante, consistente en alcohol etílico
151+
'H4', # Fábricas de biocarburante o biocombustible con sistente en biodiesel
152+
'H6', # Fábricas de biocarburante o biocombustible con sistente en alcohol metílico
153+
'H9', # Industrias extractoras de gas natural y otros productos gaseosos
154+
'H0', # Las demás industrias que obtienen productos gravados
155+
'HD', # Industrias o establecimientos que someten productos a un tratamiento definido o,
156+
# Previa solicitud, a una transformación química
157+
'HH', # Industrias extractoras de crudo de petróleo
158+
'H7', # Depósitos fiscales de hidrocarburos
159+
'H8', # Depósitos fiscales exclusivamente de biocarburantes
160+
'HB', # Obtención accesoria de productos sujetos alimpuesto
161+
'HF', # Almacenes fiscales para el suministro directo a instalaciones fijas
162+
'HI', # Depósitos fiscales exclusivamente para la distribución de querosenos y gasolinas de aviación
163+
'HJ', # Depósitos fiscales exclusivamente de productos de la tarifa segunda
164+
'HK', # Instalaciones de venta de gas natural con tipo general y tipo reducido
165+
'HL', # Almacenes fiscales exclusivamente de productos de la tarifa segunda
166+
'HM', # Almacenes fiscales para la gestión de aceites usados destinados a su utilización como combustibles
167+
'HN', # Depósitos fiscales constituidos por una red de oleoductos
168+
'HT', # Almacenes fiscales para el comercio al por mayor de hidrocarburos
169+
'HU', # Almacenes fiscales constituidos por redes de transporte o distribución de gas natural
170+
'HV', # Puntos de suministro marítimo de gasóleo
171+
'HX', # Depósitos fiscales constituidos por una red de gasoductos
172+
'HZ', # Detallistas de gasóleo
173+
'OH', # Operadores registrados de hidrocarburos
174+
'HA', # Titulares de aeronaves que utilizan instalaciones privadas
175+
'HC', # Explotaciones industriales y proyectos piloto con derecho a devolución
176+
'HE', # Los demás usuarios con derecho a exención
177+
'HP', # Inyección en altos hornos
178+
'HQ', # Construcción, modificación, pruebas y mantenimiento de aeronaves y embarcaciones
179+
'HR', # Producción de electricidad en centrales eléctricas o producción de electricidad o
180+
# cogeneración de electricidad y de calor en centrales combinadas
181+
'HS', # Transporte por ferrocarril
182+
'HW', # Consumidores de combustibles y carburantes a tipo reducido (artículos 106.4 y 108
183+
# del Reglamento de los Impuestos Especiales)
184+
'T1', # Fábricas de labores del tabaco
185+
'OT', # Operadores registrados de labores del tabaco
186+
'T7', # Depósitos fiscales de labores del tabaco
187+
'TT', # Almacenes fiscales de labores del tabaco
188+
'L1', # Fábricas de electricidad en régimen ordinario
189+
'L2', # Generadores o conjunto de generadores de potencia total superior a 100 kilovatios
190+
'L0', # Fábricas de electricidad en régimen especial
191+
'L3', # Los demás sujetos pasivos
192+
'L7', # Depósitos fiscales de electricidad
193+
'AF', # Almacenes fiscales de bebidas alcohólicas y de labores del tabaco
194+
'DF', # Depósitos fiscales de bebidas alcohólicas y de labores del tabaco
195+
'DM', # Depósitos fiscales de bebidas alcohólicas y de labores del tabaco situados en
196+
# puertos y aeropuertos y que funcionen exclusivamente como establecimientos minoristas
197+
'DP', # Depósitos fiscales para el suministro de bebidas alcohólicas y de labores del
198+
# tabaco para consumo o venta a bordo de buques y/o aeronaves
199+
'OR', # Operadores registrados de bebidas alcohólicas y de labores del tabaco
200+
'PF', # Industrias o usuarios en régimen de perfeccionamiento fiscal
201+
'RF', # Representantes fiscales
202+
'VD', # Empresas de ventas a distancia
203+
}
204+
205+
206+
def compact(number):
207+
"""Convert the number to the minimal representation. This strips the
208+
number of any valid separators and removes surrounding whitespace."""
209+
return clean(number).upper().strip()
210+
211+
212+
def validate(number):
213+
"""Check if the number provided is a valid CAE number. This checks the
214+
length and formatting."""
215+
number = compact(number)
216+
if len(number) != 13:
217+
raise InvalidLength()
218+
if number[:2] != 'ES':
219+
raise InvalidFormat()
220+
if number[2:5] != '000':
221+
raise InvalidFormat()
222+
if number[5:7] not in _OFFICES:
223+
raise InvalidFormat()
224+
if number[7:9] not in _ACTIVITY_KEYS:
225+
raise InvalidFormat()
226+
if not isdigits(number[9:12]):
227+
raise InvalidFormat()
228+
if not number[12].isalpha():
229+
raise InvalidFormat()
230+
return number
231+
232+
233+
def is_valid(number):
234+
"""Check if the number provided is a valid CAE number. This checks the
235+
length and formatting."""
236+
try:
237+
return bool(validate(number))
238+
except ValidationError:
239+
return False

0 commit comments

Comments
 (0)