Mostrando las entradas con la etiqueta MemoryStream. Mostrar todas las entradas
Mostrando las entradas con la etiqueta MemoryStream. Mostrar todas las entradas

martes, 19 de mayo de 2015

El Demo del Día: Obtener el Tipo de Cambio de la Pagina de la SUNAT

Obtener el Tipo de Cambio de la Pagina de la SUNAT

Después de mucho tiempo de no publicar un Demo, vamos a compartir un pedido de una persona que necesitaba ingresar a la pagina de la SUNAT diariamente y copiar el tipo de cambio para ingresarlo en su sistema, lo ideal seria tener un Servicio Web de uso libre, pero ante la falta de este o si existe necesitaríamos las credenciales, les dejo esta solución.

Requerimiento

Obtener diariamente en forma automática el tipo de cambio de la SUNAT publicado en la siguiente dirección: http://www.sunat.gob.pe/cl-at-ittipcam/tcS01Alias

Solución

Vamos a crear una aplicación Windows en C# .NET que use la clase HttpClient para hacer una llamada asíncrona a la dirección de la pagina, bajarla a memoria, crear una cadena con el contenido y extraer la parte que corresponde al tipo de cambio del ultimo día: las 3 ultimas celdas de la ultima fila de la segunda tabla de la página.

Restricción

La aplicación podría fallar en un futuro si la SUNAT cambia su contenido agregando o quitando tablas y habría que hacer los ajustes respectivos al código, pero aun así es una ayuda por mientras.

Crear una Aplicación Windows Forms en C#

Abrir Visual Studio y crear una aplicación Windows Forms en C# llamada "TipoCambioSUNAT", cambiarle de nombre al formulario por "frmSUNAT" y realizar el diseño similar a la figura mostrada:


Hacer una referencia a la librería: "System.Net.Http.dll" y escribir el siguiente código en el formulario:

using System;
using System.Collections.Generic; //List
using System.Text; //Encoding
using System.Windows.Forms;
using System.Net.Http; //HttpClient, HttpResponseMessage
using System.IO; //File, MemoryStream

namespace TipoCambioSUNAT
{
    public partial class frmSUNAT : Form
    {
        public frmSUNAT()
        {
            InitializeComponent();
        }

        private void btnConsultar_Click(object sender, EventArgs e)
        {
            HttpClient cliente = new HttpClient();
            cliente.BaseAddress = new Uri("http://www.sunat.gob.pe/");
            HttpResponseMessage rpta = cliente.GetAsync("cl-at-ittipcam/tcS01Alias").Result;
            if (rpta != null&&rpta.IsSuccessStatusCode)
            {
                string contenido = "";
                using(MemoryStream ms= (MemoryStream)
                rpta.Content.ReadAsStreamAsync().Result)
                {
                    byte[] buffer = ms.ToArray();
                    contenido = Encoding.UTF8.GetString(buffer);
                    contenido = contenido.ToLower();
                }
                if (contenido.Length > 0)
                {
                    File.WriteAllText("Sunat.txt", contenido);
                    int posInicioT1= contenido.IndexOf("<table");
                    int posFinT1 = contenido.IndexOf("</table");                  
                    if (posInicioT1 > -1&&posFinT1>-1)
                    {
                        int posInicioT2 = contenido.IndexOf("<table",posInicioT1+1);
                        int posFinT2 = contenido.IndexOf("</table", posFinT1 + 1);
                        string tabla = contenido.Substring(posInicioT2, posFinT2 - posInicioT2 + 8);
                        File.WriteAllText("Tabla.txt", tabla);
                        posInicioT1 = 0;
                        tabla = tabla.Replace("</strong>", "");
                        List<string> valores = new List<string>();
                        for (int i = 1; i < 4; i++)
                        {
                            posInicioT1 = tabla.LastIndexOf("</td");
                            if (posInicioT1 > -1)
                            {
                                tabla = tabla.Substring(0,posInicioT1).Trim();
                                posFinT1 = tabla.LastIndexOf(">");
                                if (posFinT1 > -1)
                                {
                                    valores.Add(tabla.Substring(posFinT1 + 1,
                                    tabla.Length - posFinT1 -1).Trim());
                                }
                            }
                        }
                        if (valores.Count > 0)
                        {
                            txtVenta.Text = valores[0];
                            txtCompra.Text = valores[1];
                            txtFecha.Text = valores[2];
                        }
                    }                  
                }
            }
        }
    }
}

Nota: En este Demo los datos de la consulta van a 3 TextBoxs pero pueden ir directamente a la BD en vez de mostrarse en pantalla.

Ejecutar y Probar la Aplicación Windows Forms

Grabar la aplicación y pulsar F5 para ejecutarla, luego clic al botón "Consultar" y se mostrarán los datos del último día, el tipo de cambio compra y el tipo de cambio venta, tal como se muestra en la siguiente figura:


Comentarios

Muchas veces queremos obtener un cierto dato de una pagina y tenemos que entrar manualmente, en este post hemos visto como usando el método "GetAsync" de la clase "HttpClient" del Namespace "System.Net.Http" podemos hacerlo vía código.

En este caso lo hemos aplicado a la pagina de la SUNAT, la cual se analizó su HTML y se observó que tiene varias tablas, la segunda corresponde a la tabla con los datos de los tipos de cambios de la última semana, para lo cual se obtuvo la última fila y de esta las 3 últimas celdas.

No se hizo mediante XML porque el HTML estaba mal formado y no generaría bien el XML DOM, es por eso que trabajamos con texto puro y substrings.

Este Demo lo terminamos en colaboración con mis alumnos del Taller de los Domingos a los cuales les doy las gracias por estar siempre pendientes de aprender y querer mejorar.

Si alguien de ustedes tiene alguna URL de algún Servicio Web que consideren útil compartir por ejemplo el del Tipo de Cambio o Consulta de RUC de la SUNAT, DNI de la RENIEC, ONPE, etc. seria bueno hacer otro post pero ya usando Servicios.

Descarga del Código
DemoDia_TipoCambioSUNAT

jueves, 18 de septiembre de 2014

El Demo del Día: Copiar Datos de Excel en el DataGridView de WinForms

Copiar Datos de Excel en el DataGridView de WinForms

Después de un tiempo, volvemos a publicar un nuevo Demo, esta vez a pedido de un alumno, que desea copiar que su aplicación tenga la funcionalidad de copiar datos de la Grilla (DataGridView) a Excel (esto es automático, no es necesario programar nada) y desde Excel hacia la aplicación (esto si requiere de programar usando el objeto Clipboard de WinForms).

Como siempre nuestro desarrollo lo haremos con Listas de Objetos (como debe ser para ahorrar memoria y no con DataSet), ademas usaremos Reflection para convertir los datos que vienen como cadenas desde Excel al tipo de datos adecuado del objeto.

Crear una Aplicación Windows Forms en C#

Crear un nuevo proyecto de tipo Windows Forms y llamarle "CopiarExcel". Cambiarle de nombre al formulario por el de "frmProducto".

Crear la clase: "beProducto" para la lista de objetos

using System;
namespace CopiarExcel
{
    public class beProducto
    {
        public int IdProducto { get; set; }
        public string Nombre { get; set; }
        public decimal Precio { get; set; }
        public short Stock { get; set; }
    }
}

Agregar un control DataGridView sobre el formulario, cambiarle al nombre de "dgvProducto" y acoplarlo para que se vea similar a la siguiente figura:


Escribir el siguiente código en el formulario:

using System.IO;
using System.Reflection;

namespace CopiarExcel
{
    public partial class frmProducto : Form
    {
        private List<beProducto> lbeProducto;

        public frmProducto()
        {
            InitializeComponent();
        }

        private void cargarProductos(object sender, EventArgs e)
        {
            lbeProducto = new List<beProducto>();
            Random oRandom = new Random();
            beProducto obeProducto;
            for(int i=1;i<=10;i++)
            {
                obeProducto = new beProducto();
                obeProducto.IdProducto = i;
                obeProducto.Nombre = String.Format("Producto {0}", i);
                obeProducto.Precio = oRandom.Next(100)+10;
                obeProducto.Stock = (short)(oRandom.Next(10) + 1);
                lbeProducto.Add(obeProducto);
            }
            dgvProducto.DataSource = lbeProducto;
        }

        private void pegarExcel(object sender, KeyEventArgs e)
        {
            if (e.Control && e.KeyCode == Keys.V)
            {
                string formato = DataFormats.CommaSeparatedValue;
                object contenido = Clipboard.GetData(formato);
                if (contenido != null && contenido is MemoryStream)
                {
                    byte[] buffer;
                    using (MemoryStream ms = (MemoryStream)contenido) buffer = ms.ToArray();
                    string lista = Encoding.UTF8.GetString(buffer).Replace("\r\n", ",");
                    string[] data = lista.Split(',');
                    PropertyInfo[] propiedades = lbeProducto[0].GetType().GetProperties();
                    if ((data.Length - 1) % propiedades.Length == 0)
                    {
                        beProducto obeProducto = null;
                        PropertyInfo propiedad;
                        int c = 0;
                        Type tipo = null;
                        while (c < data.Length - 1)
                        {
                            for (int i = 0; i < propiedades.Length; i++)
                            {
                                if (i == 0) obeProducto = new beProducto();
                                propiedad = obeProducto.GetType().GetProperty(propiedades[i].Name);
                                tipo = propiedad.PropertyType;
                                propiedad.SetValue(obeProducto, Convert.ChangeType(data[c], tipo));
                                if (i == propiedades.Length - 1) lbeProducto.Add(obeProducto);
                                c++;
                            }
                        }
                        dgvProducto.DataSource = null;
                        dgvProducto.DataSource = lbeProducto;
                    }
                    else MessageBox.Show
                    ("Numero de columnas a copiar del Excel y la Grilla deben ser iguales");
                }
                else MessageBox.Show("No hay un rango de celdas a copiar");
            }
        }
    }
}

Nota: Para copiar desde Excel a la grilla se debe pulsar la tecla Ctrl + V y la cantidad de columnas debe ser la misma que la de la grilla (en realidad la de las propiedades de la clase beProducto o la que fuera).

Probar la Aplicación Creada

Grabar el proyecto y ejecutarlo con F5. Se mostrará la siguiente ventana con los datos de los productos creados en el evento Load del formulario:


Crear un archivo de Excel con la misma estructura de los Productos, tal como se muestra a continuación:


Copiar (Ctrl + C) el rango de celdas que se desea llevar a la aplicación (sin incluir las cabeceras) y en cualquier celda de la grilla Pegar (Ctrl + V), y se copiaran los registros seleccionados en Excel, tal como se muestra a continuación:


Si desean se puede ir copiando por partes (filas) pero si es necesario seleccionar todas las columnas, ya que el objeto necesita de valores.

Nota: El procedimiento contrario, es decir desde la Aplicación (DataGridView) a Excel es automatico, solo hay que marcar el rango de celdas del DataGridView, Ctrl + C y luego en Excel Ctrl + V.

Comentario Final

En este post hemos visto como agregar la funcionalidad de Copiar Datos Externos a la aplicación, en este caso desde Excel, pero el procedimiento sera similar desde cualquier origen. Para ello hemos usado el objeto ClipBoard y para trabajar con objetos hemos usado Reflection, lo que quiere decir que el demo lo puedes probar con cualquier objeto que definan.

Saludos a todos los visitantes asiduos del Blog y ya saben que pueden hacer sus pedidos en los comentarios.

Descarga: