Codigo de Control en Visual Basic | Impuestos Bolivia

Creado 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 http://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 http://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 http://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!!!!

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

Sobre el autor y el sitio web

Yo soy yo :) Mouse o como algunos de ustedes me llaman 'El Cochinote', 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! :)

ENTRADAS QUE TE PUEDEN INTERESAR

1 comentario en “Codigo de Control en Visual Basic | Impuestos Bolivia”

  1. Juan carlos dice:

    Muchas gracias por tu aporte. Me pregunta es: como podria utlizar estos modulos para trabajar en VBA para Excel ya que mi sistema de facturacion esta en ese lenguaje. Gracias anticipadas. Un saludo.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *


*

Comparte lo que sabes

Categorias

Android Bolivia

Bandera en Alto

Ultimas entradas

En este oportunidad comparto una pequeña aplicación hecha en java para recortar partes de una imagen seleccionado con el...

En este post crearemos un componente que solo hay en android y que no esta disponible en la paleta de controles de Netbe...

Radio.Garden es un proyecto interactivo desarrollado por el Instituto Holandés para el Sonido y la Visión en cooperación...

Una cola doblemente terminada o deque es una estructura de datos lineal que permite insertar y eliminar elementos por am...

Web amigas