El CIF de las empresas (Código de Indentificación Fiscal) está sujeto a unas normas y a un protocolo de verificación.
En este truco te mostramos ambas cosas, y una función Delphi para validar el código de control.
Un CIF debe tener 9 cifras.
La primera cifra (Una letra), indica el tipo de sociedad al que hace referencia, según esta tabla:
A - Sociedades Anónimas
B - Sociedades de responsabilidad limitada
C - Sociedades colectivas
D - Sociedades comanditarias
E - Comunidades de bienes
F - Sociedades cooperativas
G - Asociaciones y otros tipos no definidos
H - Comunidades de propietarios
P - Corporaciones locales
Q - Organismos autónomos
S - Organos de la administración
K, L y M - seguramente para compatibilidad con formatos antiguos
X - Extranjeros, que en lugar del D.N.I. tienen el N.I.E.
|
La ultima cifra es el dígito de control, que puede ser o bien un número o bien una letra, en función del tipo de sociedad.
A las categorias P (Ayuntamientos) y X (Extranjeros) les corresponde una letra en lugar de un número.
El dígito de control se calcula con las 7 cifras restantes del CIF (quitando la primera y la ultima), con el siguiente algoritmo:
Vamos a usar este cif como ejemplo:
- Quitamos la primera y la ultima cifra:
- Sumamos las cifras pares:
- Ahora sumamos cada cifra impar multiplicada por dos, y, sumamos las cifras del resultado:
5 * 2 = 10 ==> 1 + 0 = 1
8 * 2 = 16 ==> 1 + 6 = 7
8 * 2 = 16 ==> 1 + 6 = 7
0 * 2 = 0 ==> 0
|
- y volvemos a sumar esos resultados a la suma anterior:
- Al final de este proceso, tenemos que Suma=29, pues bien, nos quedamos con la cifra de las unidades (9)
- Restamos esta cifra de las unidades de 10, dándonos un 1, que es el código de control para todos los tipos de sociedades exceptuando la X y la P.
- Para las sociedades X y P, habria que sumar un 64 al digito de control que hemos calculado para hallar el ASCII de la letra de control:
Chr(64+ (10-(Suma mod 10)))
|
Por último, aqui tienes una función que incorpora todo el rollo anterior, que sirve para validar CIFs:
procedure TForm1.Button1Click(Sender: TObject);
function ValidaCIF(Cif: string):boolean;
var
Suma,
Control : integer;
n : byte;
begin
Result:=False;
Cif:=UpperCase(Cif);
{El cif debe ser de 9 cifras}
if Length(Cif)=9 then
begin
Suma:= StrToInt(Cif[3])+
StrToInt(Cif[5])+
StrToInt(Cif[7]);
for n:=1 to 4 do
begin
Suma:=Suma+ ( (2*StrToInt(Cif[2*n])) mod 10 )+
( (2*StrToInt(Cif[2*n])) div 10 );
end;
if Pos(Cif[1],'XP')<>0
then
{Control tipo letra}
Result:= ( Cif[9] = Chr(64+ (10-(Suma mod 10))) )
else
{Control tipo número}
Result:= ( StrToInt(Cif[9]) = (10-(Suma mod 10)) );
end;
end;
begin
If ValidaCIF('A58818501') then ShowMessage('Válido')
else ShowMessage('No válido');
{El mismo Cif para un ayuntamiento:}
// If ValidaCIF('P5881850A') then ShowMessage('Válido')
// else ShowMessage('No válido');
end;
|
Juan Serrano (jserrano@tudistrito.es) nos comentaba:
He encontrado un pequeño fallo para unos casos especiales. Por ejemplo, para el CI: B14507610 el valor final de (10 - (Suma mod 10)) es 10. Con lo que el resultado de salida de la función sería False, pero este CIF es correcto.
Solo habría que usar la variable Control que no es usada en todo el procedimiento:
procedure TForm1.Button1Click(Sender: TObject);
function ValidaCIF(Cif: string):boolean;
var Suma, Control : integer;
n : byte;
begin
Result:=False;
Cif:=UpperCase(Cif);
{El cif debe ser de 9 cifras}
if Length(Cif)=9 then
begin
Suma:= StrToInt(Cif[3])+
StrToInt(Cif[5])+
StrToInt(Cif[7]);
for n:=1 to 4 do
begin
Suma:=Suma+ ( (2*StrToInt(Cif[2*n])) mod 10 )+
( (2*StrToInt(Cif[2*n])) div 10 );
end;
Control := 10-(Suma mod 10);
if Pos(Cif[1],'XP')<>0
then
{Control tipo letra}
Result:= ( Cif[9] = Chr(64+ Control))
else
begin
{Control tipo número}
if Control =10 then Control := 0;
Result:= ( StrToInt(Cif[9]) = Control);
end;
end;
end;
begin
If ValidaCIF('A58818501') then ShowMessage('Válido')
else ShowMessage('No válido');
{El mismo Cif para un ayuntamiento:}
// If ValidaCIF('P5881850A') then ShowMessage('Válido')
// else ShowMessage('No válido');
end;
|
Enviado por Manuel Castaño (mcastano@teleline.es)
Según varios NIF extranjeros (que comienzan por X) el calculo es similar al de los NIF individuales segun el resto de dividir entre 23.
Os remito mi funcion en FoxPro:
*****************************************************************************
FUNCTION LEE (ACTNIF)
*****************************************************************************
STORE "TRWAGMYFPDXBNJZSQVHLCKE" TO TABLA
STORE .T. TO ERROR
STORE ACTNIF TO LENIF
STORE " " TO LETRA
STORE 0 TO DNI
STORE 0 TO NAUX
STORE 0 TO SUMA
STORE "CORRECTO*"+ACTNIF TO RDONIF
* limpiamos el nif de caracteres no deseados
LENIF=STRTRAN(LENIF,"-","")
LENIF=STRTRAN(LENIF,"/","")
LENIF=UPPER(ALLTRIM(LENIF))
IF ISALPHA(LENIF)
LETRA=UPPER(SUBSTR(LENIF,1,1))
IF LETRA$"ABCDEFGHPQSKLM"
IF LEN(LENIF)=9 THEN
SUMA=VAL(SUBSTR(LENIF,3,1))+VAL(SUBSTR(LENIF,5,1))+VAL(SUBSTR(LENIF,7,1))
*SUMAMOS CIFRAS EN LUGARES IMPARES Y PARES POR 2N
FOR I=1 TO 4
SUMA = SUMA+ MOD(2*VAL(SUBSTR(LENIF,2*I,1)),10)+ INT(2*VAL(SUBSTR(LENIF,2*I,1))/10)
NEXT I
*SI LAS LETRAS SON X O P ACABA EN LETRA QUE SE CALCULA ASI
IF LETRA$"PQ" THEN
IF SUBSTR(LENIF,9,1)=CHR(64+(10-MOD(SUMA,10))) THEN
STORE .F. TO ERROR
ELSE
RDONIF="ERROR*"
ENDIF
*SI NO SON LAS LETRAS DE ARRIBA COMPROBAMOS
ELSE
IF MOD(10-MOD(SUMA,10),10)=VAL(SUBSTR(LENIF,9,1)) THEN
STORE .F. TO ERROR
ELSE
RDONIF="ERROR*"
ENDIF
ENDIF
ELSE
*ERROR EN LA LONGITUD DEL NIF
RDONIF="ERROR*"
ENDIF
ELSE
IF LETRA="X" THEN
LETRA=RIGHT(LENIF,1)
DNI=VAL(SUBSTR(LENIF,2,8))
STORE MOD(DNI,23) TO NAUX
IF LETRA=SUBSTR(TABLA,NAUX+1,1)
STORE .F. TO ERROR
IF LEN(LENIF)<9
LENIF="X"+replicate("0",9-len(alltrim(LENIF)))+alltrim(SUBSTR(LENIF,2,8))
STORE .T. TO ERROR
RDONIF="ERROR*"+LENIF
ENDIF
ELSE
STORE MOD(DNI,23) TO NAUX
STORE " " TO LENIF
STORE "X"+RTRIM(LTRIM(STR(INT(DNI))+SUBSTR(TABLA,NAUX+1,1))) TO LENIF
IF LEN(LENIF)<9
LENIF="X"+replicate("0",9-len(alltrim(LENIF)))+alltrim(SUBSTR(LENIF,2,8))
ENDIF
RDONIF="ERROR*"+LENIF
ENDIF
ELSE
*NO COMIENZA POR LETRA VALIDA
RDONIF="ERROR*"
ENDIF
ENDIF
ELSE
LETRA=RIGHT(LENIF,1)
LETRA=UPPER(LETRA)
DNI=VAL(LENIF)
STORE MOD(DNI,23) TO NAUX
IF LETRA=SUBSTR(TABLA,NAUX+1,1)
STORE .F. TO ERROR
IF LEN(LENIF)<9
LENIF=replicate("0",9-len(alltrim(LENIF)))+alltrim(LENIF)
STORE .T. TO ERROR
RDONIF="ERROR*"+LENIF
ENDIF
ELSE
STORE MOD(DNI,23) TO NAUX
STORE " " TO LENIF
STORE RTRIM(LTRIM(STR(INT(DNI))+SUBSTR(TABLA,NAUX+1,1))) TO LENIF
IF LEN(LENIF)<9
LENIF=replicate("0",9-len(alltrim(LENIF)))+alltrim(LENIF)
ENDIF
RDONIF="ERROR*"+LENIF
ENDIF
ENDIF
RETURN(RDONIF)
|
(Si alguien se anima a probarla y a pasarla a Delphi, pues que me la envie...)
Enviado por: Jose Vte. Vergara (jvergara@aaa.upv.es)
Ante todo, ehorabuena porque TRUCOMANIA es de lo mejor que hay.
Me llamo Jose, programador de profresión y Licenciado en Informática en mis ratos libres que son muy pocos :(
Uso el DELPHI como es de suponer y a la hora de necesitar algún truco uso los de TRUCOMANIA.
El caso que me ataña es que he ido a usar el truco de la Validación del CIF y me ha dado problemas en la validacion de CIF's de extranjeros (X), ya que no me valida correctamente ninguno.
Indagando un poco (o sea haciendo pruebas y comprobando resultados erroneos) me he dado cuenta que para validar el CIF de un extranjero hay que comprobar que el número y la letra restantes de eliminar la X del CIF corresponde con un NIF correcto (poniendo un cero a la izquierda claro).
O sea, en un ejemplo si tenemos el el CIF--> X1234567L deberemos comprobar que 01234567L es un NIF correcto.
He llegado ha esta conclusion usando algunos CIF's de extranjeros reales.
Espero que puedas confirmar si es correcto, ya que yo aún no lo he podido hacer (aunque sigo utilizando esta variación).
Otra cosa, realizando pruebas me ha surgido la duda de si la validación de CIF tipo P es correcta (ya que me fallaba la X), ya que si la variable
control sólo puede tomar valores de 0 a 9, el caracter de control del CIF tipo P estará entre la 'A' y la 'J' ¿es correcto?
Adjunto modificacion:
procedure TForm1.Button1Click(Sender: TObject);
function ValidaCIF(Cif: string):boolean;
var Suma, Control : integer;
n : byte;
begin
Result:=False;
Cif:=UpperCase(Cif);
{El cif debe ser de 9 cifras}
if Length(Cif)=9 then
begin
{ varicaión para CIF tipo X }
if (Cif[1] = 'X') then
begin
{ extranjero calculamos el NIF }
{ usamos la función NIF del truco [9] que calula la letra del DNI }
result := NIF(copy(cif,2,7))=Cif[9];
end
else
begin
Suma := StrToInt(Cif[3]) +
StrToInt(Cif[5]) +
StrToInt(Cif[7]);
for n := 1 to 4 do
begin
Suma := Suma + ((2 * StrToInt(Cif[2 * n])) mod 10) +
((2 * StrToInt(Cif[2 * n])) div 10);
end;
Control := 10 - (Suma mod 10);
if Cif[1] = 'P' then
{Control tipo letra}
begin
Result := (Cif[9] = Chr(64 + Control))
end
else
begin
{Control tipo número}
if Control = 10 then Control := 0;
Result := (StrToInt(Cif[9]) = Control);
end;
end;
end;
end;
begin
if ValidaCIF('X1234567L') then ShowMessage('Válido')
else ShowMessage('No válido');
// if ValidaCIF('A58818501') then ShowMessage('Válido')
// else ShowMessage('No válido');
{El mismo Cif para un ayuntamiento:}
// if ValidaCIF('P5881850A') then ShowMessage('Válido')
// else ShowMessage('No válido');
end;
|
Bien, parece que alguien se animó a meterse con la función Fox:
Enviado por: David Herrero (dherrero@cisspraxis.es)
Hola, indicabas en el truco 337 que si alguien se atrevía a probar y pasar una rutina que das en FoxPro a Delphi que te la hiciese llegar... pues bien, aquí hay un loco que lo ha hecho... yo, te la paso:
{--------------------------------------------------------------------------}
{- Inicio de la función Lee -----------------------------------------------}
{--------------------------------------------------------------------------}
Function Lee( ActNIF : String ) : String;
const
Tabla = 'TRWAGMYFPDXBNJZSQVHLCKE';
var
Error : Boolean;
LeNIF, RDONIF, Letra : String;
DNI, nAux, Suma, I : Integer;
{--------------------------------------------------------------}
Function StrTran( cTexto, cCharOrg, cCharChg : String ): String;
var
nLoop : Integer;
begin
for nLoop := 1 to length( cTexto ) do
if copy( cTexto, nLoop, 1 ) = cCharOrg then
Result := Result + cCharChg
else
Result := Result + copy( cTexto, nLoop, 1 );
end;
{--------------------------------------------------------------}
Function IsAlpha( cNif : String ) : Boolean;
begin
cNif := UpperCase( cNif );
Result := ( ( copy( cNif, 1, 1 ) >= 'A' ) and ( copy( cNif, 1, 1 ) <= 'Z' ) );
end;
{--------------------------------------------------------------}
Function Replicate( cCaracter : String; nVeces : Integer ) : String;
begin
repeat
Result := Result + cCaracter;
nVeces := nVeces - 1;
until nVeces <= 0;
end;
{--------------------------------------------------------------}
begin
Error := True;
LENif := ActNif;
Letra := ' ';
Dni := 0;
nAux := 0;
Suma := 0;
RDONIF := 'CORRECTO*' + ActNIF;
{ limpiamos el nif de caracteres no deseados }
LeNIF := StrTran( LeNif, '-', '' );
LeNIF := StrTran( LeNif, '/', '' );
LeNIF := UpperCase( Trim( LeNif ) );
if IsAlpha( LeNif )then
begin
Letra := UpperCase( Copy( LeNif, 1, 1 ) );
if pos( Letra, 'ABCDEFGHPQSKLM' ) <> 0 then
begin
if Length( LeNif ) = 9 then
begin
Suma := StrToInt( Copy( LeNIF, 3, 1 ) ) + StrToInt( Copy( LeNIF, 5, 1 ) ) +
StrToInt( Copy( LeNIF, 7, 1 ) );
{ SUMAMOS CIFRAS EN LUGARES IMPARES Y PARES POR 2N }
For i := 1 to 4 do
begin
Suma := Suma + ( ( 2 * StrToInt( Copy( LeNIF, 2 * I, 1 ) ) ) mod 10 );
Suma := Suma + ( ( 2 * StrToInt( Copy( LeNIF, 2 * I, 1 ) ) ) div 10 );
end;
{ *SI LAS LETRAS SON X O P ACABA EN LETRA QUE SE CALCULA ASI }
if Pos( Letra, 'PQ' ) <> 0 then
if Copy( LeNIF, 9, 1) = CHR( 64 + ( 10 - ( Suma mod 10 ) ) ) then
Error := False
else
RDONIF := 'ERROR*'
else { SI NO SON LAS LETRAS DE ARRIBA COMPROBAMOS }
begin
if ( ( 10 - ( SUMA mod 10 ) ) mod 10 ) = StrToInt( Copy( LeNIF, 9, 1 ) ) then
Error := False
else
RDONIF := 'ERROR*';
end;
end
else
RDONIF := 'ERROR*'; { *ERROR EN LA LONGITUD DEL NIF }
end
else
if Letra = 'X' then
begin
Letra := Copy( LeNIF, 1, 1 );
DNI := StrToInt( Copy( LeNIF, 2, 8 ) );
nAux := DNI mod 23;
if Letra = Copy( Tabla, nAux + 1, 1 ) then
begin
Error := False;
if length( LeNif ) < 9 then
begin
LeNIF := 'X' + Replicate( '0', 9 - length( trim( LeNIF ) ) ) +
trim( copy( LeNIF, 2, 8 ) );
ERROR := True;
RDONIF := 'ERROR*' + LeNIF;
end;
end
else
begin
nAux := DNI mod 23;
LeNif := Replicate( ' ', 9 );
LeNif := 'X' + IntToStr( DNI ) + Copy( TABLA, nAux + 1, 1 );
if length( LeNIF ) < 9 then
LeNIF := 'X' + replicate( '0', 9 - length( trim( LeNIF ) ) ) +
trim( Copy( LeNIF, 2, 8 ) );
RDONIF := 'ERROR*' + LeNIF;
end;
end
else { *NO COMIENZA POR LETRA VALIDA }
RDONIF := 'ERROR*';
end
else
begin
Letra := UpperCase( Copy( LeNif, 1, 1 ) );
DNI := StrToInt( LeNIF );
nAux := DNI mod 23;
if Letra = Copy( Tabla, nAux + 1, 1 ) then
begin
Error := False;
if Length( LeNIF ) < 9 then
begin
LeNIF := Replicate( '0', 9 - length( trim( LeNIF ) ) ) + trim( LeNIF );
Error := True;
RDONIF := 'ERROR*' + LeNIF;
end
else
begin
nAux := DNI mod 23;
LeNif := Replicate( ' ', 9 );
LeNif := IntToStr( DNI ) + Copy( Tabla, nAux + 1, 1 );
if Length( LeNif ) < 9 then
LeNif := Replicate( '0', 9 - length( trim( LeNIF ) ) ) + trim( LeNIF );
RDONIF := 'ERROR*' + LENIF;
end;
end;
end;
Result := RdoNIF;
end;
{--------------------------------------------------------------------------}
{- Fin de la función Lee --------------------------------------------------}
{--------------------------------------------------------------------------}
|
Enviado por: José Antonio García Navarro (enetesystems@wanadoo.es)
Uniendo todos los mensajes aparecidos hasta el momento sobre el tema de la validación del CIF, he hecho un algoritmo entre todos ellos, que creo que funciona para todos los casos. Algunas de las funciones utilizadas están en Trucomanía.
{Cambiar un carácter por otro en una cadena.}
function CadCambioCar(Cadena, CarOrig, CarCambio : String) : String;
var
i : Integer;
Temp : String;
begin
Temp := '';
for i := 1 to Length(Cadena) do
if Copy(Cadena, i, 1) = CarOrig then
Temp := Temp + CarCambio
else
Temp := Temp + Copy(Cadena, i, 1);
Result := Temp;
end;
{ Validar si un CIF introducido es correcto}
function EsCif(Cif : String) : Boolean;
var
Suma, Control : Integer;
n : Byte;
begin
Result := False;
{Se pasa todo a mayúsculas limpio de espacios y de caracteres especiales}
Cif := UpperCase(Trim(Cif));
{Se limpia de los caracteres '-' y '/'. }
Cif := CadCambioCar(Cif,'-','');
Cif := CadCambioCar(Cif,'/','');
{El cif debe ser de 9 cifras}
if Length(Cif) = 9 then
begin
{Comprobamos que sea un NIF}
if EsNumero(Cif[1]) then
Result := EsNif(Cif)
else
{Se comprueba que la letra que designa el tipo de cif sea correcta}
if (Pos(Cif[1], 'ABCDEFGHPQSKLMX') = 0) then
Result := False
else
{Se comprueba si es un extranjero,
en ese caso se calcula el nif, cambiando la X, por 0}
if Cif[1] = 'X' then
Result := EsNif('0'+Copy(Cif,2,8))
else
begin
Suma:= StrToInt(Cif[3])+StrToInt(Cif[5])+StrToInt(Cif[7]);
for n := 1 to 4 do
Suma := Suma + ((2*StrToInt(Cif[2*n])) mod 10)+((2*StrToInt(Cif[2*n])) div 10);
Control := 10 - (Suma mod 10);
{Se comprueba si es de tipo 'P' o 'S', es decir,
Corporaciones Locales (Ayuntamientos, etc.)
y Organismos públicos.}
if Pos(Cif[1],'PS')<>0 then
{Control tipo letra}
Result := (Cif[9] = Chr(64+Control))
else
{Resto de tipos de CIF}
begin
{Control tipo número}
if Control = 10 then
Control := 0;
Result:= ( StrToInt(Cif[9]) = Control);
end;
end;
end;
end;
|
Actualizado el 13/11/99 For n:=1 to 4 en lugar de for n:=1 to 3
Actualizado el 17/04/2000 Correccion de Juan Serrano
Actualizado el 09/03/2001 (Funcion en FoxPro)
Actualizado el 21/03/2001 (Traduccion de la función Fox a Delphi)
Actualizado el 18/04/2001 (La recopilación de José Antonio)
|