-
-
Save afgomez/5691823 to your computer and use it in GitHub Desktop.
/** | |
* ValidateSpanishID. Returns the type of document and checks its validity. | |
* | |
* Usage: | |
* ValidateSpanishID( str ); | |
* | |
* > ValidateSpanishID( '12345678Z' ); | |
* // { type: 'dni', valid: true } | |
* | |
* > ValidateSpanishID( 'B83375575' ); | |
* // { type: 'cif', valid: false } | |
* | |
* The algorithm is adapted from other solutions found at: | |
* - http://www.compartecodigo.com/javascript/validar-nif-cif-nie-segun-ley-vigente-31.html | |
* - http://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal | |
*/ | |
ValidateSpanishID = (function() { | |
'use strict'; | |
var DNI_REGEX = /^(\d{8})([A-Z])$/; | |
var CIF_REGEX = /^([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])$/; | |
var NIE_REGEX = /^[XYZ]\d{7,8}[A-Z]$/; | |
var ValidateSpanishID = function( str ) { | |
// Ensure upcase and remove whitespace | |
str = str.toUpperCase().replace(/\s/, ''); | |
var valid = false; | |
var type = spainIdType( str ); | |
switch (type) { | |
case 'dni': | |
valid = validDNI( str ); | |
break; | |
case 'nie': | |
valid = validNIE( str ); | |
break; | |
case 'cif': | |
valid = validCIF( str ); | |
break; | |
} | |
return { | |
type: type, | |
valid: valid | |
}; | |
}; | |
var spainIdType = function( str ) { | |
if ( str.match( DNI_REGEX ) ) { | |
return 'dni'; | |
} | |
if ( str.match( CIF_REGEX ) ) { | |
return 'cif'; | |
} | |
if ( str.match( NIE_REGEX ) ) { | |
return 'nie'; | |
} | |
}; | |
var validDNI = function( dni ) { | |
var dni_letters = "TRWAGMYFPDXBNJZSQVHLCKE"; | |
var letter = dni_letters.charAt( parseInt( dni, 10 ) % 23 ); | |
return letter == dni.charAt(8); | |
}; | |
var validNIE = function( nie ) { | |
// Change the initial letter for the corresponding number and validate as DNI | |
var nie_prefix = nie.charAt( 0 ); | |
switch (nie_prefix) { | |
case 'X': nie_prefix = 0; break; | |
case 'Y': nie_prefix = 1; break; | |
case 'Z': nie_prefix = 2; break; | |
} | |
return validDNI( nie_prefix + nie.substr(1) ); | |
}; | |
var validCIF = function( cif ) { | |
var match = cif.match( CIF_REGEX ); | |
var letter = match[1], | |
number = match[2], | |
control = match[3]; | |
var even_sum = 0; | |
var odd_sum = 0; | |
var n; | |
for ( var i = 0; i < number.length; i++) { | |
n = parseInt( number[i], 10 ); | |
// Odd positions (Even index equals to odd position. i=0 equals first position) | |
if ( i % 2 === 0 ) { | |
// Odd positions are multiplied first. | |
n *= 2; | |
// If the multiplication is bigger than 10 we need to adjust | |
odd_sum += n < 10 ? n : n - 9; | |
// Even positions | |
// Just sum them | |
} else { | |
even_sum += n; | |
} | |
} | |
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) ); | |
var control_letter = 'JABCDEFGHI'.substr( control_digit, 1 ); | |
// Control must be a digit | |
if ( letter.match( /[ABEH]/ ) ) { | |
return control == control_digit; | |
// Control must be a letter | |
} else if ( letter.match( /[KPQS]/ ) ) { | |
return control == control_letter; | |
// Can be either | |
} else { | |
return control == control_digit || control == control_letter; | |
} | |
}; | |
return ValidateSpanishID; | |
})(); |
Los NIF terminados en 0 siempre dan error, como @uiktiomasfeliz y @gtamborero indican. Eso es porque hay un error con la comprobación de éste. El enlace de wikipedia ( código de identificación fical ) dice que el código de verificación debe ser 10 - el último dígito de C, pero si C termina en 0, éste debe ser 0.
He modificado el código para sacar el control digit. Quedaría así:
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1)).toString().substr(-1) ;
De este modo lo que hago es obtener el último dígito de dicha resta, por lo que si hacemos 10-0, el resultado del código sería 0.
No valida bien NIF del tipo K
K0867756N
Aquí lo valida bien:
https://comunidadhorizontal.com/utiles/validar-cif-nif-nie/
He mirado el código y no lo reconoce de ninguno de los 3 type (DNI, CIF, NIE), pues la expresión regular de CIF no lo contempla:
([ABCDEFGHJKLMNPQRSUVW])(\d{7})([0-9A-J])
Veo que sólo permite letra final hasta J y en mi ejemplo tengo una N y es un NIF válido...
@afgomez Gracias por crear este gist. Lo he adaptado, he corregido la validación del CIF y lo he empaquetado como una pequeña librería en npm:
https://github.com/jvmonjo/spain-id
La corrección de @tompare está bien. Lo puedo confirmar al menos con un CIF de una SL (empiezan por B).
Aquí publico el gist con la corrección del dígito de control de @tompare:
https://gist.github.com/carlos-mg89/4aaafa310c9e4b91f5fb890540f38cae
He probado con el NIF K0867756N despues de aplicar la corrección y sigue sin funcionar.
Parece que no identifica los DNI "Españoles residentes menores 14 años sin DNI (NIF K)"
Adjunto enlace de la Agencia Tributaria:
https://www.agenciatributaria.es/AEAT.internet/Inicio/La_Agencia_Tributaria/Campanas/_Campanas_/Fiscalidad_de_no_residentes/_Identificacion_/Preguntas_frecuentes_sobre_obtencion_de_NIF_de_no_Residentes/_Que_tipos_de_NIF_de_personas_fisicas_utiliza_la_normativa_tributaria_espanola_.shtml
He probado actualmente con 4 CIF existentes y no me valida ninguno como true
Los problemas con CIFs que no validan (ejemplo "B72327000") se solucionan haciendo el módulo 10 para calcular el dígito de control.
Es decir, cambiar:
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) );
Por:
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) ) % 10;
En el replace faltaría añadir /g para que cambie todas ocurrecias:
str.toUpperCase().replace(/\s, '').replace('-', '');
str.toUpperCase().replace(/\s/g, '').replace('-', '');
Hola trabajo con Angular, me gustaría saber si tenéis algún validator form con este método. Gracias de antemano.
Buenas. Los CIF de organizaciones públicas que acaban en letra L no pasan por esta validación ¿no?
He encontrado un validador de TIN (aka NIF) que valida TIN de prácticamente toda Europa:
https://github.com/loophp/tin
Sin embargo no calcula bien los NIF de empresas y de personas que no tengan DNI o NIE.
Así que he creado una PR para solucionarlo:
loophp/tin#36
Sin embargo no he podido aportar referencias oficiales al algoritmo de validación (solo una explicación de la Junta de Andalucía) y parece que tienen la PR en espera (no se de qué, la verdad).
Si pudierais dar apoyo para que incluyan la PR sería genial.
Por cierto, el código de la PR está basado en el que ya publiqué aquí:
https://lab.fawno.com/2015/08/27/validacion-de-cif-nif/
Y que incluí en este otro proyecto:
https://github.com/fawno/AEAT
Los problemas con CIFs que no validan (ejemplo "B72327000") se solucionan haciendo el módulo 10 para calcular el dígito de control.
Es decir, cambiar:
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) );
Por:
var control_digit = (10 - (even_sum + odd_sum).toString().substr(-1) ) % 10;
Hola @qwertyllo creo que esta solución es más directa:
let controlDigit = (10 - (evenSum + oddSum) % 10) % 10;
No depende de convertir números a cadenas ni de usar funciones como substr(), lo que la hace más eficiente y menos propensa a errores.
Realiza el cálculo de manera más intuitiva y clara.
Este control es correcto según la definición de wikipedia https://es.wikipedia.org/wiki/C%C3%B3digo_de_identificaci%C3%B3n_fiscal donde indica que los CIFs que empiezan por A|B|E|H el digito de control debe ser un número.
Recientemente pero me han passado CIFs validos que empezando por E y por A tienen letra de control... y son validos, p.e E9729353D. Alguien sabe donde encontrar la especificación oficial sobre el calculo del digito/letra de control?