Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube
JC Mouse Bolivia
Index / Proyectos / Facturación electrónica: El Código de Control

Facturación electrónica: El Código de Control

Autor jc mouse jueves, abril 7, 2016

¿Que es la facturación electrónica?

Una factura es un documento que sirve para describir el costo de los servicios y desglosar los impuestos correspondientes a pagar, por tanto una factura electrónica es la versión digital de las facturas tradicionales, legalmente válido como medio de respaldo de las operaciones comerciales entre contribuyentes se expide y recibe en formato electrónico.

Facturación electrónica en Bolivia

facturacion virtual

Cada país cuenta con su propia normativa en cuanto a la implementación de facturación virtual, para Bolivia esta se encuentra en el documento alojado en la web de Impuestos nacionales (SIN) «Sistema de Facturación Virtual«. Así mismo, este tipo de facturación debe contar con medidas de seguridad, por ejemplo un Código de Control:

«En el marco del Nuevo Sistema de Facturación implementado por la Administración Tributaria, se tiene prevista la incorporación de nuevos elementos de seguridad en las facturas emitidas por sistemas de facturación computarizada. En este sentido, toda factura emitida por este medio, deberá incorporar un Código de Control generado a partir de información de la misma.» [SIN]

¿Qué es el Código de Control?

Es un dato alfanumérico generado por un sistema de facturación computarizada a tiempo de emitir una factura. Constituye una representación única de una factura, que será empleada por el SIN (Servicio de Impuestos Nacionales) para que junto a otra información permitan determinar la validez o no de la misma.
Este código se genera en base a información de dosificación de la factura, información de la transacción comercial, y un dato alfanumérico denominado Llave de Dosificación, que el contribuyente recibirá por Internet cada vez que solicite dosificaciones de facturas para su sistema de facturación computarizada.

Generación del Código de Control

Algoritmos utilizados

Para generar un Código de Control, se hace uso de los siguientes algoritmos informáticos:

  • Alleged RC4. Un algoritmo de criptografía simétrica, basado en cifrado de flujo (stream cipher), muy utilizado por su rendimiento y simplicidad.
  • Verhoeff .Algoritmo de dígito verificador que trabaja con cadenas de dígitos decimales de cualquier tamaño. Además de detectar una amplia gama de errores en datos numéricos, este algoritmo también detecta casos de
    transposición de dígitos adyacentes.
  • Base 64. Algoritmo que convierte cifras en base 10 a base 64, utilizando divisiones sucesivas además de un
    diccionario de 64 caracteres.

Para generar un Código de Control, se requiere de la siguiente información

Datos de dosificación:

  • Número de autorización: Dato numérico de máximo 15 dígitos. (Ej.: 29040011007)
  • Número de factura: Dato numérico de máximo 12 dígitos. (Ej.:1503)

Datos de la transacción comercial:

  • CI o NIT del cliente: Dato numérico de máximo 12 dígitos. (Ej.: 4189179011)
  • Fecha de la transacción: Dato numérico de 8 dígitos, en el formato AAAAMMDD. (Ej.: 20070702)
  • Monto de la transacción: Importe de la factura sujeto a débito fiscal. Solo para efectos del Código de
    Control, este monto deberá expresarse sin centavos, redondeado al inmediato superior a partir de los
    50 centavos (Según Art. 11 de la RA Nº 05-0048-99). En el caso de Notas de Crédito – Débito, el monto a
    utilizarse será el de Monto Efectivo del Crédito – Débito.

Llave de Dosificación

  • Llave asignada por el SIN a la dosificación solicitada por el contribuyente. Constituye la llave privada
    utilizada por el algoritmo de criptografía. Dato alfanumérico de hasta 256 caracteres generado a partir
    del siguiente diccionario:
A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R, S, T, U, V, W, X, Y, Z,
a, b, c, d, e, f, g, h, i, j, k, m, n, p, q, r, s, t, u, v, w, x, y, z, 2,
3, 4, 5, 6, 7, 8, 9, =, #, (, ), *, +, -, _, \, @, [, ], {, }, %, $

El Código de Control generado a partir de los algoritmos mencionados, será un dato alfanumérico de hasta 10 caracteres, representado en grupos de 2 separados por el caracter «-«. Ej.: 6A-DC-53-05-14

Proyecto «Código de Control»

  • Lenguaje: Java 8
  • IDE: Netbeans

impuestos bolivia

SIN Bolivia pone a disposición de aquel que este interesado en el tema de documentación bastante detallada el cual solo debemos seguir paso a paso.  «DOCUMENTO DE ESPECIFICACIONES TÉCNICAS DEL CÓDIGO DE CONTROL – VERSIÓN 7.0«.

Algoritmo de Verhoeff (Documentación)

/**
 * @see <a href="http://en.wikipedia.org/wiki/Verhoeff_algorithm">More Info</a>
 * @see <a href="http://en.wikipedia.org/wiki/Dihedral_group">Dihedral Group</a>
 * @see <a href="http://mathworld.wolfram.com/DihedralGroupD5.html">Dihedral Group Order 10</a>
 * @author Colm Rice
 */
public class Verhoeff {
    
    // The multiplication table
    static int[][] d  = new int[][]
    {
        {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 
        {1, 2, 3, 4, 0, 6, 7, 8, 9, 5}, 
        {2, 3, 4, 0, 1, 7, 8, 9, 5, 6}, 
        {3, 4, 0, 1, 2, 8, 9, 5, 6, 7}, 
        {4, 0, 1, 2, 3, 9, 5, 6, 7, 8}, 
        {5, 9, 8, 7, 6, 0, 4, 3, 2, 1}, 
        {6, 5, 9, 8, 7, 1, 0, 4, 3, 2}, 
        {7, 6, 5, 9, 8, 2, 1, 0, 4, 3}, 
        {8, 7, 6, 5, 9, 3, 2, 1, 0, 4}, 
        {9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
    };
	
    // The permutation table
    static int[][] p = new int[][]
    {
        {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 
        {1, 5, 7, 6, 2, 8, 3, 0, 9, 4}, 
        {5, 8, 0, 3, 7, 9, 6, 1, 4, 2}, 
        {8, 9, 1, 6, 0, 4, 3, 5, 2, 7}, 
        {9, 4, 5, 3, 1, 2, 6, 8, 7, 0}, 
        {4, 2, 8, 6, 5, 7, 3, 9, 0, 1}, 
        {2, 7, 9, 3, 8, 0, 6, 4, 1, 5}, 
        {7, 0, 4, 6, 9, 1, 3, 2, 5, 8}
    };
	
    // The inverse table
    static int[] inv = {0, 4, 3, 2, 1, 5, 6, 7, 8, 9};
    
    /* 
     * For a given number generates a Verhoeff digit    
     */
    public static String generateVerhoeff(String num){
        int c = 0;
	int[] myArray = stringToReversedIntArray(num);
	for(int i = 0; i < myArray.length; i++){
            c = d[c][p[((i + 1) % 8)] [myArray[i]]];
        }		
        return Integer.toString(inv[c]);
    }
	
    /*
    * Validates that an entered number is Verhoeff compliant.
    * NB: Make sure the check digit is the last one.
    */
    public static boolean validateVerhoeff(String num){		
        int c = 0;
        int[] myArray = stringToReversedIntArray(num);        
        for (int i = 0; i < myArray.length; i++){
            c = d[c][p[(i % 8)][myArray[i]]];
        }		
        return (c == 0);
    }
	
    /*
     * Converts a string to a reversed integer array.
     */
    private static int[] stringToReversedIntArray(String num){		
        int[] myArray = new int[num.length()];		
        for(int i = 0; i < num.length(); i++){
            myArray[i] = Integer.parseInt(num.substring(i, i + 1));					
        }		
        myArray = reverse(myArray);		
        return myArray;	
    }
	
    /*
    * Reverses an int array
    */
    private static int[] reverse(int[] myArray){
        int[] reversed = new int[myArray.length];		
        for(int i = 0; i < myArray.length ; i++){
            reversed[i] = myArray[myArray.length - (i + 1)];			
        }
        return reversed;
    }	
}

Algoritmo Base 64 (Documentación)

/**
 * @see https://www.jc-mouse.net/
 * @author mouse
 */
public class Base64SIN {
    
    public static String convert(int value){
        String[] dictionary = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 
                                "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
                                "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", 
                                "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
                                "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", 
                                "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", 
                                "y", "z", "+", "/" };
        int quotient = 1; 
        int remainder;         
        String word = "";
        while (quotient > 0)
        {
                quotient = value / 64;
                remainder = value % 64;
                word = dictionary[remainder] + word;
                value = quotient;
        }
        return word;
    }
}

Algoritmo Alleged RC4 (Documentacion)

/**
 * @see https://www.jc-mouse.net/
 * @author Mouse
 */
public class AllegedRC4 {
    
/**
     * Retorna mensaje encriptado
     * @param message mensaje a encriptar
     * @param key llave 
     * @return String mensaje encriptado
     */
    public static String encryptMessageRC4(String message, String key){
        int state[] = new int[256];
        int x=0;
        int y=0;
        int index1=0;
        int index2=0;        
        int nmen;        
        String messageEncryption="";
        
        for(int i=0;i<=255;i++){
            state[i]=i;
        }
        
        for(int i=0;i<=255;i++){
            //Index2 = ( ObtieneASCII(key[Index1]) + State[I] + Index2 ) MODULO 256
            index2 =  ( ( (int) key.toCharArray()[index1] ) +  state[i] + index2) % 256;
            //IntercambiaValor( State[I], State[Index2] )
            int aux = state[i];
            state[i] = state[index2];
            state[index2] = aux;
            //Index1 = (Index1 + 1) MODULO LargoCadena(Key)
            index1 = (index1 + 1 ) % key.length();
        }
        
        //PARA I = 0 HASTA LargoCadena(Mensaje)-1 HACER
        for(int i=0; i<message.length();i++ ){
            //X = (X + 1) MODULO 256
            x = (x + 1) % 256;
            //Y = (State[X] + Y) MODULO 256
            y = (state[x] + y) % 256;
            //IntercambiaValor( State[X] , State[Y] )
            int aux = state[x];
            state[x] = state[y];
            state[y] = aux; 
            //NMen = ObtieneASCII(Mensaje[I]) XOR State[(State[X] + State[Y]) MODULO 256]
            nmen = ( (int) message.toCharArray()[i]) ^ state[(state[x]+state[y]) % 256];
            //MensajeCifrado = MensajeCifrado + "-" + RellenaCero(ConvierteAHexadecimal(NMen))            
            String nmenHex = Integer.toHexString(nmen).toUpperCase();
            messageEncryption = messageEncryption + "-" + ((nmenHex.length()==1)?("0"+nmenHex):nmenHex);            
        }
        //RETORNAR ObtieneSubCadena(MensajeCifrado, 1, LargoCadena(MensajeCifrado) - 1);
        return messageEncryption.substring(1,messageEncryption.length());
    }
        
    /**
     * Retorna mensaje encriptado sin guion (-)
     * @param message mensaje a encriptar
     * @param key llave 
     * @return String mensaje encriptado
     */
    public static String encryptMessageRC4Unscripted(String message,String key){        
        String resul = encryptMessageRC4(message, key);
        resul=resul.replace("-","");
        return resul;
    }
}

Clase para generar código de control: ControlCode.java (Documentación)

Una vez que tenemos listos las clases de los diferentes algoritmos, guiándonos con la documentacion de SIN desarrollamos la siguiente clase:

import java.math.BigDecimal;
import java.util.ArrayList;
/**
 * @see https://www.jc-mouse.net/ 
 * @author Mouse
 */
public class ControlCode {
    
    //datos para generar codigo de control
    private String authorizationNumber; //Número de Autorización 
    private String invoiceNumber; //Número de Factura
    private String NITCI;
    private String dateOfTransaction; //Fecha de la Transacción
    private String transactionAmount; //Monto de la Transacción
    private String dosageKey;//Llave de Dosificación
    //otras variables 🙂
    private String fiveDigitsVerhoeff;
    private String stringDKey;
    private int sumProduct;
    private String base64SIN;
    
    /**
     * Constructor de clase
     */
    public ControlCode(){}
    
    /**
     * Genera el codigo de control
     * @param aNumber Numero de autorizacion
     * @param iNumber Numero de factura
     * @param nitci NIT o CI 
     * @param dTransaction fecha de transaccion de la forma:
     *                       2007/07/02 a 20070702
     * @param tAmount Monto de la transacción 
     * @param dKey Llave de dosificacion
     * @return String Codigo de control
     */
    public String generate(String aNumber, String iNumber, String nitci, 
                           String dTransaction, String tAmount, String dKey){
        this.authorizationNumber = aNumber;
        this.invoiceNumber = iNumber;
        this.NITCI =nitci;
        this.dateOfTransaction = dTransaction;
        this.transactionAmount = roundUp(tAmount);
        this.dosageKey = dKey;
        
        /* ========== PASO 1 ============= */
        invoiceNumber = addVerhoeffDigit(invoiceNumber,2);
        NITCI = addVerhoeffDigit(NITCI,2);
        dateOfTransaction = addVerhoeffDigit(dateOfTransaction,2);
        this.transactionAmount = addVerhoeffDigit(transactionAmount,2);
        //se suman todos los valores obtenidos
        Long sumOfVariables = Long.valueOf(invoiceNumber)
                              + Long.valueOf(NITCI)
                              + Long.valueOf(dateOfTransaction)
                              + Long.valueOf(transactionAmount);
        //A la suma total se añade 5 digitos Verhoeff
        String sumOfVariables5Verhoeff = addVerhoeffDigit(String.valueOf(sumOfVariables),5);        
                
        /* ========== PASO 2 ============= */
        fiveDigitsVerhoeff = sumOfVariables5Verhoeff.substring(sumOfVariables5Verhoeff.length()-5);
        
        String[] ary = fiveDigitsVerhoeff.split("");//java 8
        int[] numbers = new int[ary.length];
        for(int i=0;i<ary.length;i++){
             numbers[i] = Integer.parseInt(ary[i]) + 1;
        }
                
        String string1 = dosageKey.substring(0, numbers[0] );
        String string2 = dosageKey.substring(numbers[0], numbers[0]+numbers[1] );
        String string3 = dosageKey.substring(numbers[0]+numbers[1], numbers[0]+numbers[1]+numbers[2] );
        String string4 = dosageKey.substring(numbers[0]+numbers[1]+numbers[2], numbers[0]+numbers[1]+numbers[2]+numbers[3] );
        String string5 = dosageKey.substring(numbers[0]+numbers[1]+numbers[2]+numbers[3], numbers[0]+numbers[1]+numbers[2]+numbers[3]+numbers[4] );
        
        String authorizationNumberDKey = authorizationNumber + string1;
        String invoiceNumberdKey = invoiceNumber + string2;
        String NITCIDKey = NITCI + string3;
        String dateOfTransactionDKey = dateOfTransaction + string4;        
        String transactionAmountDKey = transactionAmount + string5;
        
        /* ========== PASO 3 ============= */        
        //se concatena cadenas de paso 2
        stringDKey = authorizationNumberDKey + invoiceNumberdKey + NITCIDKey + dateOfTransactionDKey + transactionAmountDKey; 
        //Llave para cifrado + 5 digitos Verhoeff generado en paso 2
        String keyForEncryption = dosageKey + fiveDigitsVerhoeff;      
        //se aplica AllegedRC4
        String allegedRC4String = AllegedRC4.encryptMessageRC4Unscripted(stringDKey, keyForEncryption);
        
        /* ========== PASO 4 ============= */
        //cadena encriptada en paso 3 se convierte a un Array 
        ArrayList<Character> chars = new ArrayList();
        for (char c : allegedRC4String.toCharArray()) {
            chars.add(c);
        }
        //se suman valores ascii
        int totalAmount=0;
        int sp1=0;
        int sp2=0;
        int sp3=0;
        int sp4=0;
        int sp5=0;
        
        int tmp=1;
        for(char c:chars){
            totalAmount += (int)c;
            switch(tmp){
                case 1: sp1 += (int)c; break;
                case 2: sp2 += (int)c; break;
                case 3: sp3 += (int)c; break;
                case 4: sp4 += (int)c; break;
                case 5: sp5 += (int)c; break;
            }            
            tmp = (tmp<5)?tmp+1:1;
        }
                
        /* ========== PASO 5 ============= */    
        //suma total * sumas parciales dividido entre resultados obtenidos 
        //entre el dígito Verhoeff correspondiente más 1 (paso 2)
        int tmp1 = totalAmount*sp1/numbers[0];
        int tmp2 = totalAmount*sp2/numbers[1];
        int tmp3 = totalAmount*sp3/numbers[2];
        int tmp4 = totalAmount*sp4/numbers[3];
        int tmp5 = totalAmount*sp5/numbers[4];
        //se suman todos los resultados
        sumProduct = tmp1 + tmp2 + tmp3 + tmp4 +tmp5;        
        //se obtiene base64
        base64SIN= Base64SIN.convert(sumProduct);
        
        /* ========== PASO 6 ============= */        
        //Aplicar el AllegedRC4 a la anterior expresión obtenida
        return AllegedRC4.encryptMessageRC4(base64SIN, dosageKey+fiveDigitsVerhoeff);
        
    }//end:generateControlCode
        
    /**
     * Añade N digitos Verhoeff a una cadena de texto
     * @param value String
     * @param max numero de digitos a agregar
     * @return String cadena original + N digitos Verhoeff
     */
    private String addVerhoeffDigit(String value,int max){
        for(int i=1;i<=max;i++)
            value += Verhoeff.generateVerhoeff(value);            
        return value;
    }
    
    /**
     * Redondea hacia arriba
     * @param value cadena con valor numerico de la forma 123 123.4 123,4
     */
    private String roundUp(String value){        
        //reemplaza (,) por (.)
        value = value.replace(",", ".");
        //redondea a 0 decimales
        BigDecimal valueBD = new BigDecimal(Double.parseDouble(value));
        valueBD = valueBD.setScale(0, BigDecimal.ROUND_HALF_UP);        
        return String.valueOf(valueBD);
    }
    
    /* metodos usados solo para realizar el testeo */
    public String getFiveDigitsVerhoeff() {
        return fiveDigitsVerhoeff;
    }

    public String getStringDKey() {
        return stringDKey;
    }

    public int getSumProduct() {
        return sumProduct;
    }

    public String getBase64SIN() {
        return base64SIN;
    }
    
}//end:class

Test

Impuestos brinda recursos necesarios para verificar la correcta generación del Código de Control.

  • 5000 Casos de prueba para la generación del Código de Control (XLS)
  • 5000 Casos de prueba para la generación del Código de Control (TXT)

Para testear este código haremos uso del archivo de texto con 5000 registros, la clase es la siguiente:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import net.jc_mouse.controlcode.ControlCode;
/**
 * @see https://www.jc-mouse.net/
 * @author mouse
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        ControlCode controlCode = new ControlCode();                
        //direccion del archivo de texto
        String fileName = "C:\\Users\\SOYTUBURLA\\Documents\\impuestos\\5000CasosPruebaCCVer7.txt";        
        
        int count=0;        
        int fiveDigitsVerhoeffCount=0;
        int stringDKeyCount=0;
        int sumProductCount=0;
        int base64SINCount=0;
        int ccCount=0;
        
        try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = br.readLine()) != null) {
                count+=1;
                //reemplaza "|" por "/-/" por no ser compatible con el metodo split
                line = line.replace("|", "/-/");
                String[] ary = line.split("/-/");
                //genera codigo de control
                String cc = controlCode.generate(ary[0], ary[1], ary[2], ary[3].replace("/", ""), ary[4], ary[5]);                
                //controla errores
                if(!ary[6].equals(controlCode.getFiveDigitsVerhoeff()))fiveDigitsVerhoeffCount+=1;                
                if(!ary[7].equals(controlCode.getStringDKey()))stringDKeyCount+=1;                
                if(!ary[8].equals(String.valueOf(controlCode.getSumProduct())))sumProductCount+=1;                      
                if(!ary[9].equals(String.valueOf(controlCode.getBase64SIN())))base64SINCount+=1;                      
                if(!ary[10].equals(cc))ccCount+=1;
            }
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
                
        System.out.println("Error 5 digitos Verhoeff: " + fiveDigitsVerhoeffCount);
        System.out.println("Error Cadena de dosificación: " + stringDKeyCount);
        System.out.println("Error Suma Producto: " + sumProductCount);
        System.out.println("Error Base64: " + base64SINCount);
        System.out.println("Error codigo de control: " + ccCount);
        System.out.println("---------------------------------------------");
        System.out.println("Total Registros testeados: " + count);        
    }
    
}//end:class

Después de unos segundos dependiendo de la maquina que tengamos veremos algo como esto:

test code

El código funciona 🙂

Proyecto «Control Code»

Documentación PDF

enjoy!!!

Fuente: www.impuestos.gob.bo

Tags

Si te ha gustado podrías compartirlo o dejar un comentario. ¡Muchas gracias!
Autor: JC Mouse

Yo soy yo :) JC Mouse, Soy orgullosamente boliviano soy fundador y CEO de la web jc-Mouse.net uno de las pocas web en emprendimiento y tecnología en Bolivia.

Toda la información que encuentres en este sitio es y sera completamente gratis siempre, puedes copiar, descargar y re-publicar si así lo deseas en otros blogs o sitios web, solo te pido a cambio que dejes una referencia a esta web. Esto nos ayuda a crecer y seguir aportando. Bye

Enjoy! :)

También Te Podría Interesar

Como saber el tipo de objeto que contiene un hashmap

Como saber el tipo de objeto que contiene un hashmap

La clase hashMap es muy util para almacenar objetos de la forma ( Clave, Objeto ), donde Clave es un identificador único...

Ajustar imagen de fondo a diferentes resoluciones

Ajustar imagen de fondo a diferentes resoluciones

Si diseñamos paginas web, nos habremos topado con el problema de colocar una imagen de fondo y que este se adapte a toda...

Personalización de Componentes Swing Java I

Personalización de Componentes Swing Java I

Hace tiempo pidieron un video tutorial sobre como crear sus propios componentes swing java, lamentablemente debo decir q...

Animación de JProgressBar con hilos

Animación de JProgressBar con hilos

Si nuestra aplicación tiene que llevar a cabo un cierto trabajo que no sabemos cuanto durará y que a la vez consume much...

Blog MVC – Carga de páginas estáticas [p4]

Blog MVC – Carga de páginas estáticas [p4]

Cuarta parte de esta pequeña serie de tutoriales sobre [Crea tu blog con el patrón MVC y php] En esta cuarta entrega ver...

Conectar C Sharp con MySQL

Conectar C Sharp con MySQL

Ya tengo varios post sobre conexión a base de datos en varios lenguajes y claro no podía faltar c#, el siguiente tutoria...

8 comentarios en “Facturación electrónica: El Código de Control”

  1. manuel dice:

    Gracias sirvio de muhco eres un maestro. Haber si pasas el de la nueva normativa con el codigo QR

    1. Mouse dice:

      la que actualmente se usa y es el de esta pagina es la v7 según la pagina de impuestos. El generador de código QR lo estaré posteando en los siguientes días. saludos

  2. Hola Mouse,
    Te comento que queremos implementar la solución de timbrado con Bolivia pero no termino de tener claro cual es el documento vigente para el 2017.

    ¿Podrías ayudarme con ese dato?

    Un saludo, muchas gracias!

    1. Mouse dice:

      adjunto en el post están los documentos de la pagina de Impuestos Bolivia, segun entiendo en la web el Codigo de Control V7 es el que esta vigente, pero le sugiero visitar la web de http://www.impuestos.gob.bo/ y preguntar ahi para una respuesta oficial. saludos

  3. Marco Callisaya dice:

    Felicidades por la gran colaboracion para los desarrolladores …. Fue de mucha ayuda
    Solo una pregunta ¿El codigo qr debe estar si o si en la factura ? y si es asi donde encontrar el algoritmo para generarlo

    1. Mouse dice:

      Hola, el código QR si debe ir en la factura, te recomiendo leer la documentación de Impuestos Nacionales, ahí te indican entre otras cosas, el tamaño y calidad del QR.
      Para generar el Código QR existen, según el lenguaje que utilices, existen varios plugins en la internet que te facilitaran el trabajo

  4. CARLOS FABIAN ANUS dice:

    Hola Mouse, Soy de Argentina, he leido con atención tu muy buena descripcion sobre los algoritmos para la generación de los códigos de control, pero estoy por instalar un software de cobro para un estacionamiento en Bolivia, y no conozco como debe ser el formato de la boleta a imprimir o si hay algun modelo de impresora en particular que este homologada o si no es necesario imprimirla.
    A donde puedo recurrir o con quien podria hablar para que me asesore profesionalmente.
    Grcias

    1. Mouse dice:

      le recomiendo visitar la pagina oficial de Impuestos Bolivia y descargar la documentación sobre la Facturación Virtual ahí le explican el formato de las facturas, tipo de papel aceptado y demás cosas.

      saludos

Los comentarios estan cerrados

Comparte lo que sabes

Categorias

Últimas entradas

Por lo general se usan transacciones a nivel base de datos y posteriormente se llaman estos a través de procedimientos a...

En este post, aprenderemos como conectar Visual Basic 6 con SQL Server, abrir una tabla, leer su contenido y mostrar est...

Lo que veremos en este post es la configuración del driver para PHP de SQL Server que ha creado Microsoft el cual permit...

Google Bard la inteligencia artificial de Google se actualiza con una mejora que entra a competir con el resto de IAs y...

Herramientas

Generador de Enlaces a Whatsapp