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:
Nuestro proyecto es el siguiente:
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)
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
Llave para mega: !GJlnvrrn9hUipaRbAIHkk78G5hBSpWHNCKw2CZjwWek
enjoy!!!!
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, es una aplicación android gratuita que te permite enviar un mensaje de auxilio (S.O.S.) hasta 4 personas que tu[...]
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[...]
La policia, el FBI u otros organismos similares utilizaban a dibujantes para realizar el «retrato hablado» de algún male[...]
Continuación del tutorial «Utiliza 2 bases de datos diferentes en una aplicación» La Interfaz frmSelected.java: Haciendo[...]
PHPUnit es un framework que se utiliza para escribir tests en PHP, Netbeans nos permite configurarlo y usarlo fácilmente[...]