lunes, 25 de marzo de 2013

Cálculo del dígito verificador utilizando la función Módulo11

El código de control es un mecanismo de detección de errores utilizado para verificar la corrección de un dato, generalmente en soporte informático [1]. Los dígitos de control o dígitos verificadores se usan principalmente para detectar errores en el tecleo o transmisión de los datos. Generalmente consisten en uno o más caracteres numéricos o alfabéticos añadidos al dato original y calculados a partir de éste mediante un determinado algoritmo. Algunos de los ejemplos de uso frecuentes son los números de identificación personal, códigos de barras, tarjetas de crédito y códigos bancarios, como es el caso del Sistema de Rentas Internas (SRI) del Ecuador que utiliza el dígito de verificación como parte de su clave de acceso dentro del proceso de solicitud de números de autorización utilizando el mecanismo del Módulo 11.
Módulo 11
En el caso del SRI el dígito verificador será aplicado sobre toda la clave de acceso (48 dígitos) y deberá ser incorporado por el contribuyente a través del método denominado Módulo 11, con un factor de chequeo ponderado (2), este mecanismo de detección de errores, será verificado al momento de la recepción del comprobante. Cuando el resultado del dígito verificador obtenido sea igual a once (11), el digito verificador será el cero (0) y cuando el resultado del dígito verificador obtenido sea igual a diez 10, el digito verificador será el uno (1).

Como podemos ver en la figura siguiente, el dígito verificador forma parte de la estructura que debemos enviarle al WS del SRI. Para este ejemplo les mostraré una manera de implementar dicha función a través de un método en Java.


El algoritmo deberá realizar el siguiente procedimiento:

public class Modulo11 {

    public String invertirCadena(String cadena) {
        String cadenaInvertida = "";
        for (int x = cadena.length() - 1; x >= 0; x--) {
            cadenaInvertida = cadenaInvertida + cadena.charAt(x);
        }
        return cadenaInvertida;
    }

    public int obtenerSumaPorDigitos(String cadena) {
        int pivote = 2;
        int longitudCadena = cadena.length();
        int cantidadTotal = 0;
        int b = 1;
        for (int i = 0; i < longitudCadena; i++) {
            if (pivote == 8) {
                pivote = 2;
            }
            int temporal = Integer.parseInt("" + cadena.substring(i, b));
            b++;
            temporal *= pivote;
            pivote++;
            cantidadTotal += temporal;
        }
        cantidadTotal = 11 - cantidadTotal % 11;
        return cantidadTotal;
    }

    public static void main(String args[]) throws Exception {
        Modulo11 a = new Modulo11();
        System.out.println(a.obtenerSumaPorDigitos(a.invertirCadena("41261533")));
    }
}
Espero que esta explicación les sea de utilidad y cualquier consulta no duden en comentarla. Saludos.

Y para los interesados, brindamos asesoría en el tema de facturación electrónica. El temario del taller lo pueden descargar aquí: Temario del Taller.

24 comentarios:

David Ortega Mazzini dijo...

Gracias me sirve pero pana, una pregunta que no entiendo todavia de donde sale la cadena de verificacion.,41261533 ?

Guillermo Granizo dijo...

Creo que falta incluir algo como esto en el método obtenerSumaPorDigitos, antes del return cantidadTotal

switch (cantidadTotal) {
case 10:
cantidadTotal = 1;
break;
case 11:
cantidadTotal = 0;
break;
}

Favio Samanéz dijo...

Saludos, esa cadena es uno de los tantos numeros, llamados claves que pueden ser para pruebas o para producción,que el SRI entrega al contribuyente

Hugo R.González B. dijo...

Hola Rolando:
Grcias por la información, sin embargo me surge la siguiente duda los números base, se multiplican iniciando con 2,3,4, hasta 7, e inicia nuevamente la cadena al llegar a 7, me surgen las siguientes interrogantes:
¿Porque después de 7 no se continua con 8,y 9?
¿Existe una regla universal para el uso del Modulo 11?
¿Utilizando está formula en varios números, solamente valido 3 números de 6)
¿Pero si utilizo el número 8 después del 7 valida todos los números, 6 en total?
¿Es esto correcto?
Agradeciendo de antemano las respuestas a las interrogantes planteadas, gracias anticipadas.

Hugo R.González B.

Anónimo dijo...

La cadena a validar son los 49 dígitos del contenido del campo ClaveAcceso específicamente los 48 primeros (que constituiría el dato de entrada para los métodos expuestos), el ultimo es el verificador..

Anónimo dijo...

Como puedo obtener el mismo resultado pero con un código diferente?

Anónimo dijo...

En Ruby podría ser algo así:

def mod11(s)
c = 1
sum = s.reverse.chars.map{ |v| c = (c < 7)? c+=1 : 2; c * v.to_i }.sum
11 - (sum % 11)
end

mod11 '41261533'
=> 6

Aunque podría mejorar :)

polexito2002 dijo...

Si la cadena a validar son los 48 primeros digitos del campo claveAcceso, ¿por que en el ejemplo usan la cadena de verificacion 41261533 de apenas 8 digitos.? Podrían poner un ejemplo real por favor, con el ruc, la composición de los 48 digitos y luego el dígito verificador.

Anónimo dijo...

El algoritmo da un ejemplo de una cadena pequeña la cual el SRI la pone como lo explica aquí http://es.wikipedia.org/wiki/C%C3%B3digo_de_control
Debes de coger los 48 dígitos en invertirlos para la secuencia de calculo que empieza con 2 y termina en 7, después sumas todo y ejecutas la función mod(resulado_de_suma, 11) , restas 11 menos el resultado del mod() .Cuando el resultado del dígito verificador obtenido sea igual a once (11), el digito verificador será el cero (0) y cuando el resultado del dígito verificador obtenido sea igual a diez 10, el digito verificador será el uno (1).
Suerte.

Anónimo dijo...

Buenas noches una ayuda, el codigo numerico que es parte de acceso de donde lo saco. Como la genero??.Gracias por su ayuda

Rolando Palermo Rodríguez Cruz dijo...

Normalmente en este campo colocamos el secuencial que manejamos a nivel de nuestra aplicación (completando a 8 ceros por la izquierda, si es necesario).
Saludos.

Anónimo dijo...

Saludos, Tengo esta cadena 060820140109928098410011001001000101253002199121, haciendo el algoritmo que me indican me sale como resultado como dígito verificador de (10) esto se debe que la suma de los 48 dígitos multiplicados por los valores que van del (2) al (7) me da como resultado 518 y si a eso hago la operación de [11 - (518 mod 11)] y este resultado da 1, entonces 11 - 1 = 10.... Que esta mal....

Anónimo dijo...

me podrian ayudar con la programacion en c# ... gracias

Anónimo dijo...

Buenos Dias me Podrian ayudar con este codigo en lenguaje c#.. gracias

Anónimo dijo...

Tengo el codigo en VB.net

Anónimo dijo...

Me podian ayudar con el codigo en NSIS.
Please--!.

Iván López dijo...

El Código en VFP

FUNCTION MODULO11
PARAMETER AIL
* *
* --------------------------------------------------------------------------------------------- *
* ESTE PROGRAMA SE ENCARGA DE RECIBIR UNA CADENA DE 48 DIGITOS Y DEVOLVER EL DIGITO VERIFICADOR *
* CON EL MODULO 11 CON UN CHEQUE PONDERADO DE 2 *
* SE UTILIZA PARA LA FACTUACION ELECTRONICA *
* --------------------------------------------------------------------------------------------- *
* *
LOCAL FEA01,FEA02,FEA03,FEA04,I,PIVOTE,CANTIDADTOTAL,CADENAINVERTIDA
*
FEA01=ALLTRIM(AIL)
FEA02=LEN(FEA01)
*
CADENAINVERTIDA=''
FOR I=FEA02 TO 1 STEP -1
CADENAINVERTIDA=CADENAINVERTIDA+SUBSTR(FEA01,I,1)
ENDFOR
*
*
PIVOTE=2
CANTIDADTOTAL=0
FOR I=1 TO FEA02
IF PIVOTE=8
PIVOTE=2
ENDIF
FEA03=INT(VAL(SUBSTR(CADENAINVERTIDA,I,1)))*PIVOTE
CANTIDADTOTAL=CANTIDADTOTAL+FEA03
PIVOTE=PIVOTE+1
ENDFOR
CANTIDADTOTAL=11-MOD(CANTIDADTOTAL,11)
IF CANTIDADTOTAL=11
CANTIDADTOTAL=0
ELSE
IF CANTIDADTOTAL=10
CANTIDADTOTAL=1
ENDIF
ENDIF
RETURN(CANTIDADTOTAL)

Anónimo dijo...

private String invertirCadena(String cadena) {
String cadenaInvertida = "";
for (int x = cadena.length() - 1; x >= 0; x--) {
cadenaInvertida = cadenaInvertida + cadena.charAt(x);
}
return cadenaInvertida;
}

private int obtenerSumaPorDigitos(String cadena) {
cadena = this.invertirCadena(cadena);
int pares = 0;
int impares = 0;
int cantidadTotal = 0;
int b = 1;
int longitudCadena = cadena.length();
for(int i = 0;i < longitudCadena;i++){
if(b%2 == 0){
pares = pares+Integer.parseInt(Character.toString(cadena.charAt(i)));
}
else{
impares = impares+Integer.parseInt(Character.toString(cadena.charAt(i)));
}
b++;
}
impares = impares*3;
int sumaTotal = pares+impares;
int decena = 100;
while(sumaTotal > decena){
decena = decena+10;
}
cantidadTotal = decena-sumaTotal;
switch (cantidadTotal) {
case 10:
cantidadTotal = 0;
break;
case 11:
cantidadTotal = 1;
break;
}
return cantidadTotal;
}

Mejoré un poco el código siguiendo el algoritmo para codigos de barras E.A.N,
Salud. --anondeco!

Franklin Maza Pineda dijo...

Gracias Ivan Lopez, de pronto tienes el codigo para firnar el archivo XML con la firma electronica en formato P12 desde vfp gracias mil

Ronald Chonillo dijo...

En PHP:



function invertirCadena($cadena)
{
$cadenaInvertida = "";
for ($x = strlen($cadena) - 1; $x >= 0; $x--)
{
$cadenaInvertida = $cadenaInvertida.substr($cadena, $x,1);

}
return $cadenaInvertida;
}

function obtenerSumaPorDigitos($cadena)
{
$pivote = 2;
$longitudCadena = strlen($cadena);
$cantidadTotal = 0;
$b = 1;
for ($i = 0; $i < $longitudCadena; $i++)
{
if ($pivote == 8)
{
$pivote = 2;
}
//$temporal = intval(substr($cadena,$i, $b));
$temporal = intval(substr($cadena,$i, 1));
$b++;
$temporal = $temporal * $pivote;
$pivote++;
$cantidadTotal = $cantidadTotal + $temporal;
}
$cantidadTotal = 11 - $cantidadTotal % 11;
return $cantidadTotal;
}

Anónimo dijo...

En el codigo php hay un pequeño problema, en la linea:
$temporal = intval(substr($cadena,$i, 1));
en lugar de 1, es la variable $b
.. Gracias por el aporte

Anónimo dijo...

No me funciono el codigo en php, pero si me funciono el siguiente:

function obtenerSumaPorDigitos($_rol) {
/* Bonus: remuevo los ceros del comienzo. */
while($_rol[0] == "0") {
$_rol = substr($_rol, 1);
}
$factor = 2;
$suma = 0;
for($i = strlen($_rol) - 1; $i >= 0; $i--) {
$suma += $factor * $_rol[$i];
$factor = $factor % 7 == 0 ? 2 : $factor + 1;
}
$dv = 11 - $suma % 11;
/* Por alguna razón me daba que 11 % 11 = 11. Esto lo resuelve. */
$dv = $dv == 11 ? 0 : ($dv == 10 ? "K" : $dv);
echo '
El digito verificador es: '.$dv.'
';
return $dv;
}

Bryan Molina M. dijo...

Es porque al algoritmo le falta la ultima validacion que es la siguiente "Si el resultado es 11 el dígito de control es 0 y si el resultado es 10 el dígito de control resultante es 1."
entonces antes del return faltaria estas dos lineas

if (cantidadTotal==11)cantidadTotal=0;
if (cantidadTotal==10)cantidadTotal=1;


return cantidadTotal;

Bryan Molina M. dijo...

Hola el algoritmo en java está muy bien pero falta considerar 2 casos al final que es cuando el digito verificado es 10 u 11, es lo siguiente "Si el resultado es 11 el dígito de control es 0 y si el resultado es 10 el dígito de control resultante es 1."
entonces antes del return faltaria estas dos lineas

if (cantidadTotal==11)cantidadTotal=0;
if (cantidadTotal==10)cantidadTotal=1;

Publicar un comentario