Blog alskare

.Net y lo que surja

Archive for the ‘WebServices’ Category

Validar Número de IVA VIES

Posted by alskare en 07/09/2009

El otro día, hablando con la contable de la empresa, me comentó la posibilidad de añadir en las aplicaciones la validación de unos “NIF” un poco especiales. Digo un poco especiales porque en principio no se trata de un número de identificación sino más bien es un registro de aquellas empresas “legalizadas” para poder trabajar con IVAs a nivel intracomunitario. Digo legalizada entre comillas puesto que desconozco totalmente si el medio para entrar en esa base de datos se realiza automáticamente al trabajar con empresas intracomunitarias o hace falta algún tipo de registro especial.

Bueno, el caso es que mala validación podemos crear si el origen es una base de datos, así que no me queda más remedio que empezar a buscar y encuentro lo que andaba buscando en lo que creo que es la AEAT Europea: http://ec.europa.eu/taxation_customs/vies/lang.do?fromWhichPage=vieshome&selectedLanguage=ES.

Dentro de los servicios informáticos con los que he trabajado, quizás éste sea uno de los más originales. De hecho, no existe una base de datos centralizada. Se trata de bases de datos con un ámbito del país local que va “replicando” con el resto de países (igual me he pasado al escribir “replicando”). Por otro lado, resulta que no todos los países atienden las 24 horas del día (igual los ordenadores se van a tomar un café): http://ec.europa.eu/taxation_customs/vies/viesspec.do

Al fin y al cabo, somos programadores y nuestros profes siempre nos han enseñado que debemos desglosar un problema gordo en problemas más pequeños para poder afrontarlos con mayor destreza, así que eso voy a hacer en estos momentos. Imagino que al final pasará como ha ocurrido con otra entrada en el blog (Validar NIF, NIE, CIF ), que empezó con una pequeña validación y se ha ido ampliando y mejorando con el tiempo. Así, el objetivo inicial será el de comprobar si el NIF introducido es correcto o no, siempre según el servicio de Fiscalidad y Unión Aduanera.

La primera me la doy en la frente. Resulta que para solicitar la validez de un Número de IVA, necesitamos el código del país y… ¿cómo no?, no encuentro ningún servicio que devuelva los países aceptados, así que hay que hacer una lectura del código HTML de la página para poder tenerlos todos. Para poder trabajar con los países y poder ponerlos como origen de datos de los controles se me ocurre hacer lo más sencillo, una clase List<T>.

Paises

using System;
using System.Collections.Generic;

namespace ValidacionVies
{
    class Pais : IComparable 
    {
        public string CodigoPais { get; set; }
        public string NombrePais { get; set; }

        public Pais(string codigoPais, string pais)
        {
            this.CodigoPais = codigoPais;
            this.NombrePais  = pais;
        }


        // Se implementa la interfaz IComparable para poder ordenar por el país 
        public int CompareTo(object obj)
        {
            return this.NombrePais.CompareTo(((Pais)obj).NombrePais);
        }
    }


    class Paises : List<Pais>
    {
        public Paises()
        {
            this.Add(new Pais("AT", "Austria"));
            this.Add(new Pais("BE", "Bélgica"));
            this.Add(new Pais("BG", "Bulgaria"));
            this.Add(new Pais("CY", "Chipre"));
            this.Add(new Pais("CZ", "Chequia"));
            this.Add(new Pais("DE", "Alemania"));
            this.Add(new Pais("DK", "Dinamarca"));
            this.Add(new Pais("EE", "Estonia"));
            this.Add(new Pais("EL", "Grecia"));
            this.Add(new Pais("ES", "España"));
            this.Add(new Pais("FI", "Finlandia"));
            this.Add(new Pais("FR", "Francia"));
            this.Add(new Pais("GB", "Reino Unido"));
            this.Add(new Pais("HU", "Hungría"));
            this.Add(new Pais("IE", "Irlanda"));
            this.Add(new Pais("IT", "Italia"));
            this.Add(new Pais("LT", "Lituania"));
            this.Add(new Pais("LU", "Luxemburgo"));
            this.Add(new Pais("LV", "Letonia"));
            this.Add(new Pais("MT", "Malta"));
            this.Add(new Pais("NL", "Países Bajos"));
            this.Add(new Pais("PL", "Polonia"));
            this.Add(new Pais("PT", "Portugal"));
            this.Add(new Pais("RO", "Rumania"));
            this.Add(new Pais("SE", "Suecia"));
            this.Add(new Pais("SI", "Eslovenia"));
            this.Add(new Pais("SK", "Eslovaquia"));

            this.Sort();
        }
    }

}

 

El problema lo encontraré el día que haya que hacer alguna modificación, así que tomo nota de la mejora que podría hacerse creando un XML o un simple TXT para poder almacenar los países.

Una vez tenemos los países, conociendo los resultados que nos devuelve el WebService, es cuestión de empezar a preparar un entorno de interacción con el usuario:

- <element name="checkVatResponse">
- <complexType>
- <sequence>
  <element name="countryCode" type="xsd:string" /> 
  <element name="vatNumber" type="xsd:string" /> 
  <element name="requestDate" type="xsd:date" /> 
  <element name="valid" type="xsd:boolean" /> 
  <element name="name" type="xsd:string" /> 
  <element name="address" type="xsd:string" /> 
  </sequence>
  </complexType>
  </element>

Como que me hace gracia jugar un poco con las llamadas asíncronas al Web Service, opto por crear una aplicación WinForms que me permita realizar las primeras pruebas, así, me sale algo así como lo siguiente (ya dice mi jefe que lo mío no es el diseño):

image

 

De hecho, en el formulario no hay nada raro, un combo en el que se cargan los países (cboPaises), un textBox en el que deberá teclearse el número a validar (txtVatNumber) y los textBox de resultado (rstXXXX).

Al lío:

Código del formulario

using System;
using System.Windows.Forms;
using ValidacionVies.eu.europa.ec;


namespace ValidacionVies
{
    public partial class Form1 : Form
    {
        checkVatService cvs;

        public Form1()
        {
            InitializeComponent();

            // Asignación de eventos
            this.Load += new EventHandler(Form1_Load);
            this.cmdValida.Click += new EventHandler(cmdValida_Click);
        }

        void Form1_Load(object sender, EventArgs e)
        {
            lblProgreso.Text = string.Empty;

            // Carga de paises y asignación al combo
            Paises paises = new Paises();
            cboPaises.DataSource = paises;
            cboPaises.DisplayMember = "NombrePais";
            cboPaises.ValueMember = "CodigoPais";
            cboPaises.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            cboPaises.AutoCompleteSource = AutoCompleteSource.ListItems;

            // Asignación del evento IndexChanged para el combo.
            cboPaises.SelectedIndexChanged += new EventHandler(cboPaises_SelectedIndexChanged);
            txtCountryCode.Text = cboPaises.SelectedValue.ToString();
        }


        void cboPaises_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cbo = (ComboBox)sender;
            txtCountryCode.Text = cbo.SelectedValue.ToString();
        }


        void cmdValida_Click(object sender, EventArgs e)
        {
            lblProgreso.Text = "Consultando";

            // Llamada asíncrona al WebService
            cvs = new checkVatService();
            cvs.checkVatCompleted += new checkVatCompletedEventHandler(cvs_checkVatCompleted);
            cvs.checkVatAsync(txtCountryCode.Text, txtVatNumber.Text);
        }


        void cvs_checkVatCompleted(object sender, checkVatCompletedEventArgs e)
        {
            // Respuesta de la llamada asíncrona al WebService
            try
            {
                if (!e.Cancelled)
                {
                    lblProgreso.Text = string.Empty;
                    rstAddress.Text = e.address;
                    rstCountryCode.Text = e.countryCode;
                    rstName.Text = e.name;
                    rstResult.Text = e.Result.ToShortDateString();
                    rstCorrecto.Text = e.valid ? "Sí" : "No";
                }
                else
                {
                    lblProgreso.Text = string.Empty;
                    rstAddress.Text = string.Empty;
                    rstCountryCode.Text = string.Empty;
                    rstName.Text = string.Empty;
                    rstResult.Text = string.Empty;
                    rstCorrecto.Text = string.Empty;
                }
            }
            catch (System.Reflection.TargetInvocationException ex)
            {
                lblProgreso.Text = ex.Message;
            }
            catch (Exception ex)
            {
                lblProgreso.Text = "Se ha producido un error " + ex.GetType().ToString();

            }
        }
    }
}

Ya está. ¡Qué bonitas se ven las cosas cuando están acabadas!

Por cierto, se si alguien tiene interés, puede descargar el proyecto en VisualStudio2008: Descargar

Anuncios

Posted in C#, Helpers, WebServices, WinForms | 3 Comments »

Obtener información de una IP

Posted by alskare en 25/01/2009

Jugando con el tema del consumo de servicios Web, me encuentro un servicio que permite obtener, en base a una dirección IP, su localización geográfica. La dirección de los servicios es : http://www.webservicex.net/geoipservice.asmx

Creación de la aplicación

Ya que trabajo poco con C#, opto por hacer las pruebas, precisamente con este lenguaje, así nos vamos familiarizando un poco con él. Siempre me ha apetecido dar el salto de VB a C#, pero mantengo demasiadas aplicaciones en VBA, VB6 y VB.Net como para empezar a habituarme.

Pues eso, creamos una aplicación de C# WinForms para ver los resultados:

image

Dentro de Proyecto | Agregar referencia Web haremos referencia al servicio que usaremos en la aplicación:

image

En este caso podemos apreciar como sólo tenemos un servicio disponible en el servidor, GetGeoIPContext y una clase, GetGeoIP que, como veremos más adelante, se encargará de encapsular la información devuelta por las operaciones del servicio.

Preparación del entorno

Creamos un formulario que tendrá doble utilidad. Por un lado, permitirá al usuario introducir la dirección IP que quiere consultar y, por otro, mostrará los datos que se extraigan de la clase GetGeoIP.

image

Los datos de respuesta son todos los que vienen incluidos en la clase GetGeoIP, salvo el DomainName, que lo he incluido de “cosecha propia” gracias a la inmensa librería de clases de .NetFramework.

El programa

Al final del artículo se incluye la aplicación completa, por tanto, sólo se hace mención especial a los fragmentos de código más característicos de la aplicación.

Comprobar que la Ip introducida es correcta

Creo una función que permite comprobar que la IP que introduce el usuario es una IP válida, haciendo uso del método TryParse de la clase System.Net.IPAddress:

/// <summary>
/// Confirma que la dirección IP sea válida. 
/// </summary>
/// <param name="Ip">string introducido por el usuario</param>
/// <returns>En caso de introducir 2 es válido, puesto que toma 0.0.0.2</returns>
private bool ConfirmIP(string Ip)
{
    System.Net.IPAddress ipTemp = null;
    return System.Net.IPAddress.TryParse(Ip, out ipTemp);
}

Es importante destacar, en el código anterior, que una dirección del tipo 12.12 será considerada como válida, puesto que la interpretará como 0.0.12.12.

Para obtener el nombre del servidor, hacemos uso de la clase System.Net.Dns, concretamente, del método estático GetHostEntry.

/// <summary>
/// Devuelve el nombre del servidor asociado a la IP.
/// </summary>
/// <returns></returns>
private string GetInfoServer()
{
    IPHostEntry ip = Dns.GetHostEntry(txtIpIn.Text);
    return ip.HostName;
}

 

Por tanto, una vez definidos los campos estáticos de la clase,

// Clase de WebService que contiene información de la localización de una IP.
private wsWhois.GeoIP IpInfo;

// Clase de WebService que permite consultar una Ip.
private wsWhois.GeoIPService wsService;

// Nombre del Servidor.
private string serverName = null;

Sólo quedará hacer una llamada al servicio GetGeoIPContext y escribir los datos resultantes:

private void cmdGo_Click(object sender, EventArgs e)
{
    IpInfo = null;
    WriteInfo();
    if (!ConfirmIP(this.txtIpIn.Text))
    {
        MessageBox.Show("Invalid IP Address");
    }
    else
    {
        //Get info from Country of Ip
        wsService = new wsWhois.GeoIPService();
        IpInfo = wsService.GetGeoIP(this.txtIpIn.Text);

        // GetInfo From Domain
        serverName = GetInfoServer();

        WriteInfo();
    }
}

Incluyo también el método writeInfo que, por lo menos a mí, me llama la atención por la sencillez y potencia del operador ternario para poder mostrar los datos en el caso que nos encontremos con resultados correctos o bien, una “limpieza” de los controles del formulario en el caso que no se haya recibido una respuesta correcta:

/// <summary>
/// Muestra la información resultante en pantalla o limpia los datos del formulario
/// </summary>
private void WriteInfo()
{
    bool resultOk = IpInfo != null;

    this.txtIp.Text = (resultOk) ? IpInfo.IP : string.Empty;
    this.txtCountryCode.Text = (resultOk) ? IpInfo.CountryCode.ToString() : string.Empty;
    this.txtCountryName.Text = (resultOk) ? IpInfo.CountryName : string.Empty;
    this.txtReturnCode.Text = (resultOk) ? IpInfo.ReturnCode.ToString() : string.Empty;
    this.txtReturnCodeDetails.Text = (resultOk) ? IpInfo.ReturnCodeDetails : string.Empty;
    this.txtDomainName.Text = (resultOk) ? serverName : string.Empty;
}

 

Dejo el enlace al proyecto completo. Yo supongo que sí que irá, pero es la primera vez que tenía que dejar un archivo, así que he optado por dejarlo en SkyDrive y colocar el enlace desde aquí. Ahora me queda probar si puedo subir ficheros directamente en WordPress.

Descarga del enlace: aquí

Posted in C#, WebServices, WinForms | Comentarios desactivados en Obtener información de una IP