9 votes

How to validate a Peruvian RUC

Question: How can I verify that the format of a Peruvian RUC is valid?

What is the RUC? The Single Taxpayer Registry ( RUC ) is the computerized registry where taxpayers from all over Peru are registered. It is the tax code for individuals and companies issued by the Peruvian tax authority. SUNAT ( National Superintendency of Customs and Tax Administration (Superintendencia Nacional de Aduanas y de Administración Tributaria) ), registered since 1993 and regulated since 2004. [1] .

It is a unique password, of a permanent nature and mandatory use, for all natural or legal persons (nationals or foreigners). [2] . The SUNAT maintains the taxpayers' registry, associating the RUC with personal data [3] .

Each taxpayer is identified with an 11-digit number. The first 2 digits identify the type of person, the next 8 digits are the DNI or the number assigned to the company, and the last digit is a verification digit. [4] [5] .

2 ("10" Persona natural, "20" Persona jurídica) + 8 (DNI o número empresa) + 1 (dígito verificador)

What I tried: I used the same code used by SUNAT on its website to validate a RUC. However, it accepts incorrect RUCs and appears to have redundant calculations.

//Validación de SUNAT
function valruc(valor){
  valor = trim(valor)
  if ( esnumero( valor ) ) {
    if ( valor.length == 8 ){
      suma = 0
      for (i=0; i<valor.length-1;i++){
        digito = valor.charAt(i) - '0';
        if ( i==0 ) suma += (digito*2)
        else suma += (digito*(valor.length-i))
      }
      resto = suma % 11;
      if ( resto == 1) resto = 11;
      if ( resto + ( valor.charAt( valor.length-1 ) - '0' ) == 11 ){
        return true
      }
    } else if ( valor.length == 11 ){
      suma = 0
      x = 6
      for (i=0; i<valor.length-1;i++){
        if ( i == 4 ) x = 8
        digito = valor.charAt(i) - '0';
        x--
        if ( i==0 ) suma += (digito*x)
        else suma += (digito*x)
      }
      resto = suma % 11;
      resto = 11 - resto

      if ( resto >= 10) resto = resto - 10;
      if ( resto == valor.charAt( valor.length-1 ) - '0' ){
        return true
      }      
    }
  }
  return false
}
function trim(cadena){
  cadena2 = "";
  len = cadena.length;
  for ( var i=0; i <= len ; i++ )
    if (cadena.charAt(i) != " "){
      cadena2+=cadena.charAt(i);
    }
  return cadena2;
}
function esnumero(campo){
  return (!(isNaN( campo )));
}

//Prueba
var ruc    = '12345678903',
    valido = valruc(ruc);

console.log('El RUC', ruc,
            'es', (valido?'válido':'inválido'),
            'para SUNAT.');

Objective: I am interested in validating the format of a RUC entered by a user, which can accept characters such as hyphens or other punctuation marks between digits. I would use it as a preliminary step before submitting a form.
Additionally, if there were a way to check if the RUC exists and is active, it would be even better.

I am testing in JavaScript, but it can be in any popular language. The important thing is the algorithm.

Tests: I found the following list of manufacturing companies in empresas.regioncallao.gob.pe ( PDF) which can be used as test data.


Sources:
<sup>Legislative Decree N° 943 - <a href="http://www.elperuano.com.pe/NormasElperuano/2015/06/16/1251160-1.html" rel="noreferrer">http://www.elperuano.com.pe/NormasElperuano/2015/06/16/1251160-1.html</a></sup>
<sup>SUNAT - Registro Único de Contribuyentes - Single Registry of Taxpayers <a href="http://www.sunat.gob.pe/legislacion/ruc/" rel="noreferrer">http://www.sunat.gob.pe/legislacion/ruc/</a></sup>
<sup>RUC Law Regulation (PDF) - <a href="http://mariano.freevar.com/ruc/REGLAMENTO%20DE%20LA%20LEY%20DEL%20RUC.pdf" rel="noreferrer">http://mariano.freevar.com/ruc/REGLAMENTO%20DE%20LA%20LEY%20DEL%20RUC.pdf</a></sup>
<sup>What is SUNAT? What is the RUC? - <a href="http://conexiontributaria.blogspot.com.ar/2011/10/que-es-la-sunat-que-es-el-ruc-que_9779.html" rel="noreferrer">http://conexiontributaria.blogspot.com.ar/2011/10/que-es-la-sunat-que-es-el-ruc-que_9779.html</a></sup>
<sup>Accounting forum - other RUC digits - <a href="http://www.perucontable.com/modules/newbb/viewtopic.php?post_id=57226" rel="noreferrer">http://www.perucontable.com/modules/newbb/viewtopic.php?post_id=57226</a></sup>

2 votes

Question and answer made by special request from friend @PedroÁvila.

0 votes

You can also consult any RUC of Peru in the new page consultaderuc.info loads fast and has no captchas.

12voto

Mariano Points 21056

Code:

We use 3 functions (each one calls the next one if the result is valid):

  1. validarInput(input)

    • Removes common punctuation marks and spaces
    • Verify that it is an integer
    • Displays the result with formatting
  2. rucValido(ruc)

    • Accepts a RUC as a number
    • Verify that it starts with 10, 15, 16, 17 or 20.
    • Checks that the check digit corresponds to
  3. obtenerDatosSUNAT(ruc)

    //Handler para el evento cuando cambia el input //Elimina cualquier caracter espacio o signos habituales y comprueba validez function validarInput(input) { var ruc = input.value.replace(/[-.,[]()\s]+/g,""), resultado = document.getElementById("resultado"), existente = document.getElementById("existente"), valido;

    existente.innerHTML = "";
    
    //Es entero?    
    if ((ruc = Number(ruc)) && ruc % 1 === 0
        && rucValido(ruc)) { //     Acá se comprueba
        valido = "Válido";
        resultado.classList.add("ok");
        obtenerDatosSUNAT(ruc);
    } else {
        valido = "No válido";
        resultado.classList.remove("ok");
    }
    
    resultado.innerText = "RUC: " + ruc + "\nFormato: " + valido;

    }

    // Devuelve un booleano si es un RUC válido // (deben ser 11 dígitos sin otro caracter en el medio) function rucValido(ruc) { //11 dígitos y empieza en 10,15,16,17 o 20 if (!(ruc >= 1e10 && ruc < 11e9 || ruc >= 15e9 && ruc < 18e9 || ruc >= 2e10 && ruc < 21e9)) return false;

    for (var suma = -(ruc%10<2), i = 0; i<11; i++, ruc = ruc/10|0)
        suma += (ruc % 10) * (i % 7 + (i/7|0) + 1);
    return suma % 11 === 0;

    }

    //Buscar datos del RUC y si existe function obtenerDatosSUNAT(ruc) { //Init var url = "https://cors-anywhere.herokuapp.com/wmtechnology.org/Consultar-RUC/?modo=1&btnBuscar=Buscar&nruc=" + ruc, existente = document.getElementById("existente"), xhr = false; if (window.XMLHttpRequest) //Crear XHR xhr = new XMLHttpRequest(); else if (window.ActiveXObject) xhr = new ActiveXObject("Microsoft.XMLHTTP"); else return false; //handler para respuesta xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { //200 OK var doc = document.implementation.createHTMLDocument() .documentElement, res = "", txt, campos, ok = false;

            doc.innerHTML = xhr.responseText;
            //Sólo el texto de las clases que nos interesa
            campos = doc.querySelectorAll(".list-group-item");
            if (campos.length) {
                for (txt of campos)
                    res += txt.innerText + "\n";
                //eliminar blancos por demás
                res = res.replace(/^\s+\n*|(:) *\n| +$/gm,"$1");
                //buscar si está el texto "ACTIVO" en el estado
                ok = /^Estado: *ACTIVO *$/m.test(res);
            } else
                res = "RUC: " + ruc + "\nNo existe.";
    
            //mostrar el texto formateado
            if (ok)
                existente.classList.add("ok");
            else 
                existente.classList.remove("ok");
            existente.innerText = res;
        }
    } //falta verificar errores en conexión
    xhr.open("POST", url, true);
    xhr.send(null);

    }

    resultado, #existente {

    background-color: red;
    color: white;
    font-weight: bold;
    margin-top: 20px;

    }

    resultado.ok, #existente.ok {

    background-color: green;

    }

    <label>RUC:</label> <input type="text" id="input_ruc" style="width:100%;" oninput="validarInput(this)" placeholder="Ingrese su RUC"> <pre id="resultado"></pre> <pre id="existente"></pre>

Demo para móviles


Description:

The first step is to remove the characters we are not interested in ( -.,[]() \t\r\n\f ):

var ruc = input.value.replace(/[-.,[\]()\s]+/g,"");
  • within the square brackets you can add any character you want to ignore.

Then, we check that we have a whole:

if ((ruc = Number(ruc)) && ruc % 1 === 0) {

And with the integer, we call the main function:

rucValido(ruc);

Within the function, we see that it is 11 digits and starts at 10, 15, 16, 17 or 20:

if (!(ruc >= 1e10 && ruc < 11e9
   || ruc >= 15e9 && ruc < 18e9
   || ruc >= 2e10 && ruc < 21e9)) {

And, if all of the above are met, we can verify that the last digit (verifier) is correct.

How is the verification digit of a RUC validated?

SUNAT uses an adaptation of the method for control codes called Module 11 o ISBN 10 . It is a method widely used in these cases to detect errors in a single digit, or single or double interchanges (essentially, typing errors). It consists of:

  1. Multiply each of the first 10 digits by a fixed factor, according to its position (the first digit by 5, the second by 4, *3, *2, *7, *6, *5, *4, *3, *2).
  2. Add each of the results of the previous point.
  3. Calculate the remainder by dividing by 11 ( suma % 11 ).
  4. Obtain the 11's complement ( 11 - resto ).
  5. Verify if the last digit of the previous item matches the last digit of the RUC ( if (ruc % 10 == complemento % 10) ).

Diagrama ejemplificando los pasos

That is, for each digit, we will add the last digit of the RUC ( ruc % 10 ) and multiply it by its factor ( i % 7 + (i/7|0) + 1 ) -yes, this gives us 1, 2, 3, 4, 5, 5, 6, 7, 2, 3, 4, 5, for each value of i .

At each iteration of i we remove the last digit ( ruc = ruc/10|0 ).

It should be noted that, to simplify the operation even further, we include the check digit in the same account (with factor 1 for i=0 ). We only need to adjust in the cases that in step 4 If it is 10 or 11, it means that the last digit is 0 or 1, and in those cases 1 is subtracted from the total sum ( suma = -(ruc%10<2) ).

Then we are left with:

for (var suma = -(ruc%10<2), i = 0; i<11; i++, ruc = ruc/10|0)
    suma += (ruc % 10) * (i % 7 + (i/7|0) + 1);

And it is proven when:

suma % 11 === 0;

If this last condition is true, then the check digit is checked, and the RUC is valid.

0 votes

Thank you very much Mariano! Your code helped me a lot. In the function getSUNATData(ruc) What is the availability of queries in this method? How many data checks can I do? Greetings.

0 votes

@Lucas is a service that is not mine, which is only put as an example. I don't know... I recommend you to contact them to ask them.

0 votes

@Mariano Excellent work

HolaDevs.com

HolaDevs is an online community of programmers and software lovers.
You can check other people responses or create a new question if you don't find a solution

Powered by:

X