sábado, 19 de abril de 2014

Funciones básicas de manejo de DNI, NIF Y CIF. (Sólo España)

Resulta muy habitual en programación la verificación del NIF y CIF en prácticamente todas las aplicaciones que manejan clientes o proveedores de cualquier tipo. Resulta absurdo programar una y otra vez las mismas funciones. En programación orientada a objetos lo lógico es implementar estas funciones en un pequeño módulo de utilidades o en una clase y utilizarlas desde el código de cliente una y otra vez sin tener la necesidad de estar tocándolas o reprogramándolas constantemente, a no ser que cambie la legislación o el método de cálculo. Cosa que si sucediera bastaría con adaptar estas funciones y no habría que rastrear otra vez todo el código de  los programas para cambiarlo de nuevo, esa es la verdadera potencia de la programación orientada a objetos.
A continuación el código en VB.NET para calcular la letra del DNI, NIF,CIF a partir de sus números.


Calcular letra DNI


Imports System.Text

Module Funciones_Basicas

    'Calcula la letra del NIF a partir de sus Números
    Private Function CalculaNIF(ByVal strA As String) As String

        Const cCADENA As String = "TRWAGMYFPDXBNJZSQVHLCKE"
        Const cNUMEROS As String = "0123456789"
        Dim a, b, c, NIF As Integer
        Dim sb As New StringBuilder

        strA = Trim(strA)
        If Len(strA) = 0 Then Return ""

        ' Dejar sólo los números
        For i As Integer = 0 To strA.Length - 1
            If cNUMEROS.IndexOf(strA(i)) > -1 Then
                sb.Append(strA(i))
            End If
        Next

        strA = sb.ToString
        a = 0
        NIF = CInt(Val(strA))
        Do
            b = CInt(Int(NIF / 24))
            c = NIF - (24 * b)
            a = a + c
            NIF = b
        Loop While b <> 0
        b = CInt(Int(a / 23))
        c = a - (23 * b)

        Return strA & Mid(cCADENA, CInt(c + 1), 1)
    End Function

Aprovechando la función anterior podemos crear otras dos funciónes, la primera verifica un CIF y la segunda un NIF.
    'Verifica si un CIF introducido es correcto, devuelve true si es correcto y false en caso contrario
    Public Function Verificar_CIF(ByVal valor As String) As Boolean
        Dim strLetra As String, strNumero As String, strDigit As String
        Dim strDigitAux As String
        Dim auxNum As Integer
        Dim i As Integer
        Dim suma As Integer
        Dim letras As String

        letras = "ABCDEFGHKLMPQSX"

        valor = UCase(valor)

        If Len(valor) < 9 OrElse Not IsNumeric(Mid(valor, 2, 7)) Then
            Return False
        End If

        strLetra = Mid(valor, 1, 1)     ' letra del CIF
        strNumero = Mid(valor, 2, 7)    ' Código de Control
        strDigit = Mid(valor, 9)        ' CIF menos primera y última posición

        If InStr(letras, strLetra) = 0 Then ' comprobamos la letra del CIF (1ª posición)
            Return False
        End If

        For i = 1 To 7
            If i Mod 2 = 0 Then
                suma = suma + CInt(Mid(strNumero, i, 1))
            Else
                auxNum = CInt(Mid(strNumero, i, 1)) * 2
                suma = suma + (auxNum \ 10) + (auxNum Mod 10)
            End If
        Next
        suma = (10 - (suma Mod 10)) Mod 10

        Select Case strLetra
            Case "K", "P", "Q", "S"
                suma = suma + 64
                strDigitAux = Chr(suma)
            Case "X"
                strDigitAux = Mid(CalculaNIF(strNumero), 8, 1)
            Case Else
                strDigitAux = CStr(suma)
        End Select

        If strDigit = strDigitAux Then
            Return True
        Else
            Return False
        End If
    End Function

Esta función verifica la validez de un  NIF

    'Verifica si un NIF introducido es correcto, devuelve true si es correcto y false en caso contrario

    Public Function Verificar_NIF(ByVal valor As String) As Boolean
        Dim aux As String

        valor = valor.ToUpper ' ponemos la letra en mayúscula
        aux = valor.Substring(0, valor.Length - 1) ' quitamos la letra del NIF

        If aux.Length >= 7 AndAlso IsNumeric(aux) Then
            aux = CalculaNIF(aux) ' calculamos la letra del NIF para comparar con la que tenemos
        Else
            Return False
        End If

        If valor <> aux Then ' comparamos las letras
            Return False
        End If

        Return True
    End Function

End Module


Creadas estas tres funciones podemos hacer uso de ellas desde el código cliente, por ejemplo podemos definir una clase CDatosGenericos que verifique los datos introducidos, la clase también incluye las porpiedades para introducir l datos genéricos como el nombre, dirección. Y un pequeño método que verifique que un código postal tiene 5 posiciones.

Public Class CDatosGenericos

    Private m_cif_nif As String
    Private m_nombre As String
    Private m_direccion As String
    Private m_ciudad As String
    Private m_cp As String
    Private m_provincia As String
    Private m_observaciones As String
    Private m_activo As Boolean

    'Esp es true si el NIF/CIF es español, en ese caso valida la letra, si esp es False permite cualquier formato.
    'Persona_Fisica es True si es un NIF (fisico), false si es CIF (Juridico), indiferente si Esp es False
    Public Property CIF_NIF(ByVal Esp As Boolean, ByVal Persona_Fisica As Boolean) As String
        Get
            Return m_cif_nif
        End Get
        Set(ByVal Value As String)
            If Esp = True Then
                If Persona_Fisica = True Then
                    'Aqui valida la letra del NIF 
                    If Verificar_NIF(Value) = True Then
                        m_cif_nif = Value
                    Else
                        MsgBox("El NIF es incorrecto")
                    End If
                Else
                    'Aqui valida la letra del CIF
                    If Verificar_CIF(Value) = True Then
                        m_cif_nif = Value
                    Else
                        MsgBox("El CIF es incorrecto")
                    End If
                End If
            Else
                'SI no es español no lo verifica
                m_cif_nif = Value
            End If
        End Set
    End Property

    Public Property Nombre() As String
        Get
            Return m_nombre
        End Get
        Set(ByVal Value As String)
            m_nombre = Value
        End Set
    End Property

    Public Property Direccion() As String
        Get
            Return m_direccion
        End Get
        Set(ByVal Value As String)
            m_direccion = Value
        End Set
    End Property

    Public Property Ciudad(ByVal Esp As Boolean) As String
        Get
            Return m_ciudad
        End Get
        Set(ByVal Value As String)
            m_ciudad = Value
        End Set
    End Property

    'Esp es true si el CP es español, en ese caso valida a 5 posiciones, si esp es False CP extranjero permite cualquier longitud.
    Public Property CP(ByVal Esp As Boolean) As String
        Get
            Return m_cp
        End Get
        Set(ByVal Value As String)
            If Esp = True Then
                If Len(Value) = 5 Then
                    m_cp = Value
                Else
                    MsgBox("El Código postal debe tener 5 carácteres")
                End If
            Else
                m_cp = Value
            End If
        End Set
    End Property

    Public Property Provincia() As String
        Get
            Return m_provincia
        End Get
        Set(ByVal Value As String)
            m_provincia = Value
        End Set
    End Property

    Public Property Observaciones() As String
        Get
            Return m_observaciones
        End Get
        Set(ByVal Value As String)
            m_observaciones = Value
        End Set
    End Property

    Public Property Activo() As Boolean
        Get
            Return m_activo
        End Get
        Set(ByVal Value As Boolean)
            m_activo = Value
        End Set
    End Property

End Class



2 comentarios:

  1. HOLA
    SOY MUY NOVATO EN VISUAL ESTUDIO Y YA PROGRAME VARIAS APLICACIONES EN FOXPRO Y ME PREPARE EL CODIGO PARA CALCULAR EL DNI, NIF PERO NO ENGO CLARO TU CODIGO PARA VB.NET
    YO TENGO DOS CAMPOS, EL 1º DOND ELIJO QUE TIPO DE DOCUMENTO ES Y EL 2º EL QUE CALCULA.
    EN TU EJEMPLO ME GUSTARIA VER EN PROYECTO COMO ES PARA PROBARLO, SI CABE SEA POSIBILIDAD ME LO PRODRIS MANDAR A FALONSOGP@GMAIL.COM.
    MUCHAS GRACIAS

    ResponderEliminar