Aprende Java Aprende Php Aprende C++ Aprende HTML 5 Aprende JavaScript Aprende JSON Aprende MySQL Aprende SQLServer Aprende Visual Basic 6 Aprende PostgreSQL Aprende SQLite Aprende Redis Aprende Kotlin Aprende XML Aprende Linux VSC Aprende Wordpress Aprende Laravel Aprende VueJS Aprende JQuery Aprende Bootstrap Aprende Netbeans Aprende Android
Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube Sigueme en TikTok Sigueme en Whatsapp
Home / C Sharp / Impuestos Bolivia :: C贸digo de Control en C#

Impuestos Bolivia :: C贸digo de Control en C#

Por jc mouse mi茅rcoles, abril 20, 2016

Hola 馃檪 en esta聽post聽se deja a disposici贸n de la comunidad de programadores 聽que quiera aprender un poquito sobre聽Facturaci贸n Virtual, 聽el generador de C贸digo de Control versi贸n 7.0 construido聽seg煤n聽la documentaci贸n provista聽por Impuestos Nacionales de Bolivia (SIN).

驴Que es C#?

C# es un lenguaje de programaci贸n que se ha dise帽ado para compilar diversas aplicaciones que se ejecutan en .NET Framework. C# es simple, eficaz, con seguridad de tipos y orientado a objetos. Las numerosas innovaciones de C# permiten desarrollar aplicaciones r谩pidamente y mantener la expresividad y elegancia de los lenguajes de estilo de C.

Recordemos los algoritmos utilizados por el generador de C贸digo de Control son:

  • 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.

Nuestro proyecto es el siguiente:

SFV

El c贸digo del generador se encuentra en el proyecto ControlCodeV7, las clases son:

AllegedRC4.cs

public static class AllegedRC4
    {
        /// <summary>
        /// Criptografia simetrica
        /// <see cref="http://jc-mouse.net/"/>
        /// <param name="message">texto a encriptar</param>                
        /// <param name="key">llave para encriptacion</param>                
        /// <param name="unscripted">con guion o sin guion</param>                
        /// <returns>mensaje encriptado</returns>
        /// </summary>       
        public static String encryptMessageRC4(String message, String key, Boolean unscripted)
        {
            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 = (((int)key[index1]) + state[i] + index2) % 256;             
                int aux = state[i];
                state[i] = state[index2];
                state[index2] = aux;                
                index1 = (index1 + 1) % key.Length;
            }
            
            for (int i = 0; i < message.Length; i++)
            {            
                x = (x + 1) % 256;             
                y = (state[x] + y) % 256;                
                int aux = state[x];
                state[x] = state[y];
                state[y] = aux;                
                nmen = ((int)message[i]) ^ state[(state[x] + state[y]) % 256];                
                String nmenHex = nmen.ToString("X").ToUpper();                
                messageEncryption = messageEncryption + ((unscripted)?"":"-") + ((nmenHex.Length == 1) ? ("0" + nmenHex) : nmenHex);
            }            
            return (unscripted)?messageEncryption:messageEncryption.Substring(1, messageEncryption.Length-1);
        }
      
    }

Base64SIN.cs

public class Base64SIN
    {
        /// <summary>
        /// Codificador base64
        /// <see cref="http://jc-mouse.net/"/>
        /// <param name="value">Numero a codificar</param>                
        /// <returns>Cadena codificada</returns>
        /// </summary>
        public static String convertBase64(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;
        }
    }

Verhoeff.cs

/// <summary>
    /// For more information cf. http://en.wikipedia.org/wiki/Verhoeff_algorithm
    /// Dihedral Group stuff: http://en.wikipedia.org/wiki/Dihedral_group
    /// Dihedral Group order 10: http://mathworld.wolfram.com/DihedralGroupD5.html
    /// </summary>
    public static 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 };


        /// <summary>
        /// Validates that an entered number is Verhoeff compliant.
        /// NB: Make sure the check digit is the last one!
        /// </summary>
        /// <param name="num"></param>
        /// <returns>True if Verhoeff compliant, otherwise false</returns>
        public static bool 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;

        }

        /// <summary>
        /// For a given number generates a Verhoeff digit
        /// Append this check digit to num
        /// </summary>
        /// <param name="num"></param>
        /// <returns>Verhoeff check digit as string</returns>
        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 inv[c].ToString();
        }


        /// <summary>
        /// Converts a string to a reversed integer array.
        /// </summary>
        /// <param name="num"></param>
        /// <returns>Reversed integer array</returns>
        private static int[] StringToReversedIntArray(string num)
        {
            int[] myArray = new int[num.Length];

            for (int i = 0; i < num.Length; i++)
            {
                try {
                    myArray[i] = int.Parse(num.Substring(i, 1));
                }
                catch (FormatException e) {
                    if (e.Source != null)
                        Console.WriteLine("FormatException source: {0}", e.Source);
                    throw;
                }                
            }

            Array.Reverse(myArray);
            return myArray;
        }

    }

ControlCode.cs

    public static class ControlCode
    {
        /// <summary>
        /// Genera codigo de control
        /// <see cref="http://jc-mouse.net/"/>
        /// <param name="authorizationNumber">Numero de autorizacion</param>        
        /// <param name="invoiceNumber">Numero de factura</param>        
        /// <param name="nitci">N煤mero de Identificaci贸n Tributaria o Carnet de Identidad</param>        
        /// <param name="dateOfTransaction">fecha de transaccion de la forma AAAAMMDD</param>        
        /// <param name="transactionAmount">Monto de la transacci贸n</param>        
        /// <param name="dosageKey">Llave de dosificaci贸n</param>        
        /// <returns>Codigo de Control generado de la forma 6A-DC-53-05-14</returns>
        /// </summary>
        public static String generateControlCode(String authorizationNumber, String invoiceNumber, String nitci,
                           String dateOfTransaction, String transactionAmount, String dosageKey)
        {

            //redondea monto de transaccion 
            transactionAmount = roundUp(transactionAmount);
            /* ========== PASO 1 ============= */
            invoiceNumber = addVerhoeffDigit(invoiceNumber, 2);
            nitci = addVerhoeffDigit(nitci, 2);
            dateOfTransaction = addVerhoeffDigit(dateOfTransaction, 2);
            transactionAmount = addVerhoeffDigit(transactionAmount, 2);
            //se suman todos los valores obtenidos                  
            Int64 sumOfVariables=0;
            try {
                sumOfVariables = Int64.Parse(invoiceNumber)
                                  + Int64.Parse(nitci)
                                  + Int64.Parse(dateOfTransaction)
                                  + Int64.Parse(transactionAmount);
            }
            catch (FormatException e) {
                if (e.Source != null)
                    Console.WriteLine("FormatException source: {0}", e.Source);
                throw;
            }
            
            //A la suma total se a帽ade 5 digitos Verhoeff
            String sumOfVariables5Verhoeff = addVerhoeffDigit(sumOfVariables.ToString(), 5);

            /* ========== PASO 2 ============= */
            String fiveDigitsVerhoeff = sumOfVariables5Verhoeff.Substring(sumOfVariables5Verhoeff.Length - 5);
            int[] numbers = new int[5];
            for (int i = 0; i < 5; i++)
            {
                numbers[i] = Int32.Parse(fiveDigitsVerhoeff[i].ToString()) + 1;
            }
            
            String string1 = dosageKey.Substring(0, numbers[0]);
            String string2 = dosageKey.Substring(numbers[0], numbers[1]);
            String string3 = dosageKey.Substring(numbers[0] + numbers[1], numbers[2]);
            String string4 = dosageKey.Substring(numbers[0] + numbers[1] + numbers[2], numbers[3]);
            String string5 = dosageKey.Substring(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
            String 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.encryptMessageRC4(stringDKey, keyForEncryption,true);

            /* ========== PASO 4 ============= */          
            //se suman valores ascii
            int totalAmount = 0;
            int sp1 = 0;
            int sp2 = 0;
            int sp3 = 0;
            int sp4 = 0;
            int sp5 = 0;
            byte[] asciiBytes = Encoding.ASCII.GetBytes(allegedRC4String);
            int tmp = 1;
            for (int i=0; i< asciiBytes.Length;i++)
            {
                totalAmount += asciiBytes[i];
                switch (tmp)
                {
                    case 1: sp1 += asciiBytes[i]; break;
                    case 2: sp2 += asciiBytes[i]; break;
                    case 3: sp3 += asciiBytes[i]; break;
                    case 4: sp4 += asciiBytes[i]; break;
                    case 5: sp5 += asciiBytes[i]; 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
            int sumProduct = tmp1 + tmp2 + tmp3 + tmp4 + tmp5;
            //se obtiene base64
            String base64SIN = Base64SIN.convertBase64(sumProduct);

            /* ========== PASO 6 ============= */
            //Aplicar el AllegedRC4 a la anterior expresi贸n obtenida
            return AllegedRC4.encryptMessageRC4(base64SIN, String.Concat(dosageKey,fiveDigitsVerhoeff),false);
        }
        
        /// <summary>
        /// A帽ade N digitos Verhoeff a una cadena de texto
        /// <param name="value">cadena donde se a帽adiran digitos Verhoeff</param>        
        /// <param name="max">cantidad de digitos a agregar</param>        
        /// <returns>cadena original + N digitos Verhoeff</returns>
        /// </summary>
        private static String addVerhoeffDigit(String value, int max)
        {
            for (int i = 1; i <= max; i++) {                
                value= String.Concat(value, Verhoeff.generateVerhoeff(value));
            }                
            return value;
        }
        
        /// <summary>
        /// Transforma string a numero y redondea hacia arriba
        /// <param name="value">String numero de la forma 123 | 123.45 | 123,45 </param>        
        /// <returns>String con el numero redondeado sin decimales</returns>
        /// </summary>
        private static String roundUp(String value)
        {            
            char a = Convert.ToChar(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);            
            value = (a == ',') ? value.Replace(".", ",") : (a=='.')? value.Replace(",", ".") : value;
            decimal decimalVal = System.Convert.ToDecimal(value);
            //redondea a 0 decimales                                    
            return Math.Round(decimalVal, MidpointRounding.AwayFromZero).ToString();
        }
    }

En el proyecto TestControlCode, implementamos el c贸digo necesario para testeat los 5000 casos que nos brinda Impuestos Nacionales. Por ejemplo para 1 caso podemos hacer lo siguiente:

String code = ControlCode.generateControlCode("29040011007",
                                              "1503", 
                                              "4189179011", 
                                              "20070702", 
                                              "2500", 
                                              "9rCB7Sv4X29d)5k7N%3ab89p-3(5[A"
               );
MessageBox.Show( code );

sfv bolivia

Eso es todo 馃檪

Detalles de proyecto

  • Lenguaje: C#
  • Desarrollado: Visual Studio 2015
  • Framework: .NET Framework 4.5.2
  • Enlace de descarga <<AQUI>>

enjoy!!!!

Tags

Art铆culos similares

ODBC acces y php POO

En este tuto crearemos una clase para conectarse con una base de datos Access y ademas se implementan dos metodos para r[...]

MVC Java y Base de Datos Tutorial

En post pasados [Ejemplo pr谩ctico de MVC java Swing con Netbeans,聽3 en raya java con MVC y Netbeans ,聽MVC: Modelo, Vista[...]

Empaquetado de texturas en LibGDX

Continuando con los tutoriales sobre LibGDX (Librer铆a para el desarrollo de videojuegos), en esta ocasi贸n veremos como e[...]

Conversor decimal a binario

Desde que Google anuncio de que dejara de dar soporte al plugin de Eclipse y se concentrara en Android Studio, quienes t[...]

Uso de Arrays: Ejemplo pr谩ctico

En este post iremos conociendo de un modo pr谩ctico que es y como se utiliza un Array en java, para esto partiremos de un[...]

Melody ML: Separa f谩cilmente pistas de audio usando IA

Melody.ml聽 es un aplicaci贸n online que usa la I.A (Inteligencia Artificial) para procesar archivos MP3 y separar en pist[...]