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 / .Net / Codigo de Control en Visual Basic | Impuestos Bolivia

Codigo de Control en Visual Basic | Impuestos Bolivia

Por jc mouse martes, mayo 17, 2016

En esta oportunidad dejamos las fuentes del Generador de Código de Control de Impuestos Bolivia (Facturación Virtual), en un lenguaje bastante conocido que es Visual Basic .NET

¿Que es Visual Basic .NET?

VB.NET es un lenguaje de programación orientado a objetos que se puede considerar una evolución de Visual Basic implementada sobre el framework .NET. Su introducción resultó muy controvertida, ya que debido a cambios significativos en el lenguaje VB.NET no es retro compatible con Visual Basic, pero el manejo de las instrucciones es similar a versiones anteriores de Visual Basic, facilitando así el desarrollo de aplicaciones más avanzadas con herramientas modernas. Para mantener eficacia en el desarrollo de las aplicaciones.

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:

bolivia visual basic

AllegedRC4.vb

''' <summary>
''' Más información en https://www.jc-mouse.net/
''' </summary>
Public Class AllegedRC4

    ''' <summary>
    ''' Encripta usando AllegedRC4
    ''' </summary>
    ''' <param name="message">mensaje a encriptar</param>
    ''' <param name="key">llave de cifrado</param>
    ''' <param name="unscripted">TRUE sin guion separados</param>
    ''' <returns>mensaje encriptado</returns>
    Public Shared Function encryptMessageRC4(ByVal message As String, ByVal key As String, ByVal unscripted As Boolean) As String

        Dim state(256) As Integer
        Dim x As Integer = 0
        Dim y As Integer = 0
        Dim index1 As Integer = 0
        Dim index2 As Integer = 0
        Dim nmen As Integer
        Dim messageEncryption As String = ""

        For i = 0 To 255
            state(i) = i
        Next

        For i = 0 To 255
            index2 = (Asc(key(index1)) + state(i) + index2) Mod 256
            Dim aux As Integer = state(i)
            state(i) = state(index2)
            state(index2) = aux
            index1 = (index1 + 1) Mod Len(key)
        Next


        For i As Integer = 0 To Len(message) - 1
            x = (x + 1) Mod 256
            y = (state(x) + y) Mod 256
            Dim aux As Integer = state(x)
            state(x) = state(y)
            state(y) = aux
            nmen = Asc(message(i)) Xor state((state(x) + state(y)) Mod 256)
            Dim nmenHex As String = Hex(nmen)
            Dim hyphen As String = ""
            If Not unscripted Then hyphen = "-"
            If Len(nmenHex) = 1 Then nmenHex = "0" & nmenHex
            messageEncryption = messageEncryption & hyphen & nmenHex
        Next

        If unscripted Then
            Return messageEncryption
        Else
            Return messageEncryption.Substring(1, messageEncryption.Length - 1)
        End If
    End Function

End Class

Base64SIN.vb

''' <summary>
''' Más información en https://www.jc-mouse.net/
''' </summary>
Public Class Base64SIN

    ''' <summary>
    ''' Codificador base64
    ''' </summary>
    ''' <param name="value">Numero a codificar</param>                
    ''' <returns>Cadena codificada</returns>
    Public Shared Function convertBase64(ByVal value As Integer) As String

        Dim dictionary = New String() {"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", "+", "/"}
        Dim quotient As Integer = 1
        Dim remainder As Integer
        Dim word As String = ""
        While quotient > 0
            quotient = value \ 64
            remainder = value Mod 64
            word = dictionary(remainder) & word
            value = quotient
        End While
        Return word
    End Function

End Class

Verhoeff.vb

''' <summary>
''' For more information cf. http://en.wikipedia.org/wiki/Verhoeff_algorithm
''' Dihedral Group: http://mathworld.wolfram.com/DihedralGroup.html
''' </summary>
''' <remarks></remarks>
Public Class Verhoeff

    'The multiplication table
    Shared ReadOnly d(,) As Integer =
    {{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
    Shared ReadOnly p(,) As Integer =
    {{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
    Shared ReadOnly inv() As Integer = {0, 4, 3, 2, 1, 5, 6, 7, 8, 9}

    ''' <summary>
    ''' Validates that an entered number is Verhoeff compliant.
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns>True if Verhoeff compliant, otherwise false</returns>
    ''' <remarks>Make sure the check digit is the last one!</remarks>
    Public Shared Function validateVerhoeff(ByVal num As String) As Boolean

        Dim c As Integer = 0
        Dim myArray() As String = StringToReversedIntArray(num)

        For i As Integer = 0 To myArray.Length - 1
            c = d(c, p((i Mod 8), myArray(i)))
        Next i

        Return c.Equals(0)

    End Function

    ''' <summary>
    ''' For a given number generates a Verhoeff digit
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns>Verhoeff check digit as string</returns>
    ''' <remarks>Append this check digit to num</remarks>
    Public Shared Function generateVerhoeff(ByVal num As String) As String

        Dim c As Integer = 0
        Dim myArray() As String = StringToReversedIntArray(num)

        For i As Integer = 0 To myArray.Length - 1
            c = d(c, p(((i + 1) Mod 8), Convert.ToInt32(myArray(i))))
        Next i

        Return inv(c).ToString

    End Function

    ''' <summary>
    ''' Converts a string to a reversed integer array.
    ''' </summary>
    ''' <param name="str"></param>
    ''' <returns>Reversed integer array</returns>
    ''' <remarks></remarks>
    Private Shared Function StringToReversedIntArray(ByVal str As String) As String()

        Dim myArray(str.Length - 1) As String
        For i As Integer = 0 To str.Length - 1
            myArray(i) = str.Substring(i, 1)
        Next
        Array.Reverse(myArray)
        Return myArray

    End Function
End Class

ControlCode.vb

''' <summary>
''' Más información en https://www.jc-mouse.net/
''' </summary>
Public Class ControlCode

    ''' <summary>
    ''' Genera codigo de control
    ''' </summary>
    ''' <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>
    Public Shared Function generateControlCode(ByVal authorizationNumber As String, ByVal invoiceNumber As String, ByVal nitci As String,
                           ByVal dateOfTransaction As String, ByVal transactionAmount As String, ByVal dosageKey As String) As String

        ''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)

        Dim sumOfVariables As Long
        Try
            sumOfVariables = CLng(invoiceNumber) _
                                      + CLng(nitci) _
                                      + CLng(dateOfTransaction) _
                                      + CLng(transactionAmount)
        Catch ex As FormatException
            If (ex.Source <> vbNull) Then
                Console.WriteLine("FormatException source: {0}", ex.Source)
            End If
        End Try

        ''A la suma total se añde 5 digitos Verhoeff
        Dim sumOfVariables5Verhoeff As String = addVerhoeffDigit(sumOfVariables.ToString(), 5)

        '' ======================== PASO 2 =============================
        Dim fiveDigitsVerhoeff As String = sumOfVariables5Verhoeff.Substring(sumOfVariables5Verhoeff.Length - 5)
        Dim numbers(5) As Integer
        For i = 1 To 5
            numbers(i - 1) = Int32.Parse(fiveDigitsVerhoeff(i - 1).ToString()) + 1
        Next

        Dim string1 As String = dosageKey.Substring(0, numbers(0))
        Dim string2 As String = dosageKey.Substring(numbers(0), numbers(1))
        Dim string3 As String = dosageKey.Substring(numbers(0) + numbers(1), numbers(2))
        Dim string4 As String = dosageKey.Substring(numbers(0) + numbers(1) + numbers(2), numbers(3))
        Dim string5 = dosageKey.Substring(numbers(0) + numbers(1) + numbers(2) + numbers(3), numbers(4))

        Dim authorizationNumberDKey As String = authorizationNumber & string1
        Dim invoiceNumberdKey As String = invoiceNumber & string2
        Dim NITCIDKey As String = nitci & string3
        Dim dateOfTransactionDKey As String = dateOfTransaction & string4
        Dim transactionAmountDKey As String = transactionAmount & string5

        '' ======================== PASO 3 =============================

        Dim stringDKey As String = authorizationNumberDKey & invoiceNumberdKey & NITCIDKey & dateOfTransactionDKey & transactionAmountDKey
        Dim keyForEncryption As String = dosageKey + fiveDigitsVerhoeff
        Dim allegedRC4String As String = AllegedRC4.encryptMessageRC4(stringDKey, keyForEncryption, True)
        ''Console.WriteLine("stringDKey ----------------->" & stringDKey)

        '' ======================== PASO 4 =============================
        Dim totalAmount As Integer = 0
        Dim sp1 As Integer = 0
        Dim sp2 As Integer = 0
        Dim sp3 As Integer = 0
        Dim sp4 As Integer = 0
        Dim sp5 As Integer = 0

        Dim asciiBytes() As Byte = System.Text.Encoding.ASCII.GetBytes(allegedRC4String)
        Dim tmp As Integer = 1
        For i = 0 To asciiBytes.Length - 1
            totalAmount += asciiBytes(i)
            Select Case tmp
                Case 1
                    sp1 += asciiBytes(i)
                Case 2
                    sp2 += asciiBytes(i)
                Case 3
                    sp3 += asciiBytes(i)
                Case 4
                    sp4 += asciiBytes(i)
                Case 5
                    sp5 += asciiBytes(i)
            End Select
            If (tmp < 5) Then tmp += 1 Else tmp = 1
        Next

        '' ======================== PASO 5 =============================
        Dim tmp1 As Integer = totalAmount * sp1 \ numbers(0)
        Dim tmp2 As Integer = totalAmount * sp2 \ numbers(1)
        Dim tmp3 As Integer = totalAmount * sp3 \ numbers(2)
        Dim tmp4 As Integer = totalAmount * sp4 \ numbers(3)
        Dim tmp5 As Integer = totalAmount * sp5 \ numbers(4)

        Dim sumProduct As Integer = tmp1 + tmp2 + tmp3 + tmp4 + tmp5
        Dim base64SIN As String = ControlCodeV7vb.Base64SIN.convertBase64(sumProduct)

        '' ======================== PASO 6 =============================
        Return ControlCodeV7vb.AllegedRC4.encryptMessageRC4(base64SIN, String.Concat(dosageKey, fiveDigitsVerhoeff), False)

    End Function

    ''' <summary>
    ''' Agrega N digitos d Verhoeff a una cadena
    ''' </summary>
    ''' <param name="value">cadena donde agregar digitos de Verhoeff</param>
    ''' <param name="max">cantidad de digitos a agregar</param>
    ''' <returns>cadena original + N digitos de Verhoeff</returns>
    Private Shared Function addVerhoeffDigit(ByVal value As String, ByVal max As Integer) As String
        For i = 1 To max
            value = String.Concat(value, Verhoeff.generateVerhoeff(value))
        Next
        Return value
    End Function


    ''' <summary>
    ''' redonde un numero hacia arriba 
    ''' </summary>
    ''' <param name="value">cadena que contiene el numero a redondear de la forma 123 ; 123.6 123,6</param>
    ''' <returns>el numero redondeado</returns>
    Public Shared Function roundUp(ByVal value As String) As String
        Dim nfi As System.Globalization.NumberFormatInfo = New System.Globalization.CultureInfo("es-ES", False).NumberFormat
        If nfi.CurrencyDecimalSeparator = "," Then
            value = Replace(value, ".", ",")
        ElseIf nfi.CurrencyDecimalSeparator = "." Then
            value = Replace(value, ",", ".")
        End If

        Dim d As Decimal = System.Convert.ToDecimal(value)
        Return Math.Round(d, MidpointRounding.AwayFromZero).ToString
    End Function

End Class

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

Dim cc As String = ControlCodeV7vb.ControlCode.generateControlCode("29040011007", "1503", "4189179011", "20070702", "2500", "9rCB7Sv4X29d)5k7N%3ab89p-3(5[A")
Console.WriteLine(cc)

SIN Bolivia

La realización de este código y del resto de de las fuentes en Java, PHP, JavaScript, C#,etc se llevaron a cabo siguiendo los pasos descritos en la documentación brindada por Impuestos Nacionales ¿Que si puede optimizarse? claro que si 🙂 pero ese es tu trabajo, este articulo solo tiene propósitos educativos.

Eso es todo 🙂

Detalles de proyecto

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

Llave para mega: !GJlnvrrn9hUipaRbAIHkk78G5hBSpWHNCKw2CZjwWek

enjoy!!!!

Tags

Artículos similares

Java Webservices – Servicios Web

Un servicio web (Web Services) es un sistema de software en la web que nos ofrece la posibilidad de realizar una o múlti[...]

HELP ME – Envía un SMS de auxilio con tu ubicación

HELP ME, es una aplicación android gratuita que te permite enviar un mensaje de auxilio (S.O.S.) hasta 4 personas que tu[...]

DOM4J: Creación de archivos XML

DOM4J es una de las librerías para java más populares para el trabajo con XML ya que nos permite crea, editar y leer doc[...]

jFace – Crea retratos hablados

La policia, el FBI u otros organismos similares utilizaban a dibujantes para realizar el «retrato hablado» de algún male[...]

base de datos multiple – parte II

Continuación del tutorial «Utiliza 2 bases de datos diferentes en una aplicación» La Interfaz frmSelected.java: Haciendo[...]

Pruebas Unitarias con PHPUnit

PHPUnit es un framework que se utiliza para escribir tests en PHP, Netbeans nos permite configurarlo y usarlo fácilmente[...]