Files
tsUtilidades/ValidacionDocumentosIdentidadVIES.vb

177 lines
5.4 KiB
VB.net

Imports System.Net.Http
Imports System.Text.Json
Imports System.Text.Json.Serialization
Imports System.Text.RegularExpressions
Imports System.Threading.Tasks
' ============================================================
' CLASES DE MODELO PARA EL JSON DEVUELTO POR VIES (REST)
' ============================================================
Public Class ViesApproximate
<JsonPropertyName("matchName")>
Public Property MatchName As Integer
<JsonPropertyName("matchStreet")>
Public Property MatchStreet As Integer
<JsonPropertyName("matchPostalCode")>
Public Property MatchPostalCode As Integer
<JsonPropertyName("matchCity")>
Public Property MatchCity As Integer
<JsonPropertyName("matchCompanyType")>
Public Property MatchCompanyType As Integer
End Class
Public Class ViesRestResponse
<JsonPropertyName("isValid")>
Public Property IsValid As Boolean
<JsonPropertyName("requestDate")>
Public Property RequestDate As Date
<JsonPropertyName("userError")>
Public Property UserError As String
<JsonPropertyName("name")>
Public Property Name As String
<JsonPropertyName("address")>
Public Property Address As String
<JsonPropertyName("requestIdentifier")>
Public Property RequestIdentifier As String
<JsonPropertyName("originalVatNumber")>
Public Property OriginalVatNumber As String
<JsonPropertyName("vatNumber")>
Public Property VatNumber As String
<JsonPropertyName("viesApproximate")>
Public Property ViesApproximate As ViesApproximate
' Campo adicional para errores locales
Public Property LocalError As String
End Class
' ============================================================
' VALIDADOR COMPLETO VAT + VIES REST
' ============================================================
Public Class ValidacionDocumentosIdentidadVIES
' -----------------------------
' 1) Validación de formato VAT
' -----------------------------
Private Shared ReadOnly Patterns As New Dictionary(Of String, String) From {
{"AT", "^[A-Z]U[0-9]{8}$"},
{"BE", "^[0-9]{10}$"},
{"BG", "^[0-9]{9,10}$"},
{"CY", "^[0-9]{8}[A-Z]$"},
{"CZ", "^[0-9]{8,10}$"},
{"DE", "^[0-9]{9}$"},
{"DK", "^[0-9]{8}$"},
{"EE", "^[0-9]{9}$"},
{"EL", "^[0-9]{9}$"},
{"ES", "^[A-Z0-9][0-9]{7}[A-Z0-9]$"},
{"FI", "^[0-9]{8}$"},
{"FR", "^[A-Z0-9]{2}[0-9]{9}$"},
{"HR", "^[0-9]{11}$"},
{"HU", "^[0-9]{8}$"},
{"IE", "^[0-9]{7}[A-W][A-I]?$"},
{"IT", "^[0-9]{11}$"},
{"LT", "^[0-9]{9}|[0-9]{12}$"},
{"LU", "^[0-9]{8}$"},
{"LV", "^[0-9]{11}$"},
{"MT", "^[0-9]{8}$"},
{"NL", "^[0-9]{9}B[0-9]{2}$"},
{"PL", "^[0-9]{10}$"},
{"PT", "^[0-9]{9}$"},
{"RO", "^[0-9]{2,10}$"},
{"SE", "^[0-9]{12}$"},
{"SI", "^[0-9]{8}$"},
{"SK", "^[0-9]{10}$"},
{"XI", "^[0-9]{9}$"}
}
Public Shared Function IsValidVatFormat(countryCode As String,
vatNumber As String) As Boolean
countryCode = countryCode.ToUpper().Trim()
vatNumber = vatNumber.ToUpper().Trim()
If Not Patterns.ContainsKey(countryCode) Then
Return False
End If
Return Regex.IsMatch(vatNumber, Patterns(countryCode))
End Function
' -----------------------------
' 2) Cliente HTTP compartido
' -----------------------------
Private Shared ReadOnly _http As New HttpClient() With {
.Timeout = TimeSpan.FromSeconds(10)
}
' -----------------------------
' 3) Validación VIES vía REST (ASÍNCRONA)
' -----------------------------
Public Shared Async Function ValidateVatAsync(countryCode As String,
vatNumber As String) As Task(Of ViesRestResponse)
Dim result As New ViesRestResponse()
Try
' Normalización
countryCode = countryCode.Trim().ToUpper()
vatNumber = vatNumber.Trim().ToUpper()
' Validación de formato previa
If Not IsValidVatFormat(countryCode, vatNumber) Then
result.LocalError = $"Formato VAT inválido para {countryCode}"
Return result
End If
Dim url = $"https://ec.europa.eu/taxation_customs/vies/rest-api/ms/{countryCode}/vat/{vatNumber}"
Dim json As String = Await _http.GetStringAsync(url).ConfigureAwait(False)
result = JsonSerializer.Deserialize(Of ViesRestResponse)(json)
Catch ex As HttpRequestException
result.LocalError = "Error HTTP: " & ex.Message
Catch ex As TaskCanceledException
result.LocalError = "Timeout al consultar VIES"
Catch ex As Exception
result.LocalError = "Error inesperado: " & ex.Message
End Try
Return result
End Function
' -----------------------------
' 4) Validación VIES vía REST (SINCRONA SEGURA PARA WPF)
' -----------------------------
Public Shared Function ValidateVat(countryCode As String,
vatNumber As String) As ViesRestResponse
Return Task.Run(
Async Function()
Return Await ValidateVatAsync(countryCode, vatNumber).ConfigureAwait(False)
End Function
).Result
End Function
End Class