Buenas, hoy voy a escribir como crear un informe, en este caso una factura de un pedido de una tienda virtual, en PDF con la tecnología de Microsoft ASP.NET 2.0 y una librería existente de código abierto que se llama Gios.PDF.
Comenzamos :
Antes que nada, decir que es una librería gratuita que podemos descargar el código fuente y revisarlo. Debemos agregar las DLL en el directorio BIN de nuestra aplicación.
Vamos con el código…
Lo primero que debemos crear es el documento PDF donde vamos a meter todos los datos de la factura.
PdfDocument myPdfDocument = new PdfDocument( PdfDocumentFormat.InCentimeters( 21, 29.7));
La enumeración PdfDocumentFormat indica el tamaño del documento que vamos a crear. Tiene varias opciones como son A4, A4 Horizontal, letter8,5*11
En nuestro caso, le hemos indicado el tamaño por centímetros, ya que el PDF es un formato de impresión y no dependerá de la resolución de la pantalla.
A continuación creamos una tabla donde vamos a meter el desglose de la factura :
PdfTable myPdfTable = myPdfDocument.NewTable( new Font(“Verdana”, 12), DatosDesglose.Rows.Count, 3, 4);
A la tabla le indicamos que tenemos tantas filas como tiene el datatable, las columnas se las inndicamos manualmente ya que son fijas y le damos un cellPadding de 4.
Datos desglose es un DataTable que he rellenado anteriormente con los datos del pedido realizado.
DataTable desglose
{
get
{
// Creo el DataTable
DataTable dt = new DataTable();
// Le asigno las columnas
dt.Columns.Add(“Concepto”);
dt.Columns.Add(“Precio”);
dt.Columns.Add(“cantidad”);
// Obtengo los productos del pedido
DsProductosTableAdapters.Obtener_productos_pedidoTableAdapter TAProdPed =
new DsProductosTableAdapters.Obtener_productos_pedidoTableAdapter();
DsProductos.Obtener_productos_pedidoDataTable DTProd = TAProdPed.GetData( Int32.Parse(idped));
// Recorro los productos y los añado al DataTable creado anteriormente
foreach (DsProductos.Obtener_productos_pedidoRow prod in DTProd.Rows)
{
DataRow dr = dt.NewRow();
dr[0] = prod.nombre;
dr[1] = prod.precio.ToString() + “€”;
dr[2] = prod.cantidad.ToString();
dt.Rows.Add(dr);
}
}
// Devuelvo el datatable relleno con los datos de los productos del pedido
return dt;
}
Continuamos creando el PDF…
// Importamos los datos de los datatables con las cabeceras incluidas
myPdfTable.ImportDataTable(DatosDesglose);
Le damos un poco de diseño visual a la tabla de desglose :
// Color de la cabecera
myPdfTable.HeadersRow.SetColors(Color.White, Color.Navy);
// Especificamos el color de las letras, el color de fondo y el color de fondo de las filas alternadas
myPdfTable.SetColors(Color.Black, Color.White, Color.Gainsboro);
// Establecemos el color del borde y el grosor del mismo diciendole que lo aplique a todo el grid
myPdfTable.SetBorders(Color.Black, 1, BorderType.CompleteGrid);
Asignamos el ancho de las columnas
myPdfTable.SetColumnsWidth(new int[] { 80, 20 });
El ancho de las columnas no tiene que sumar 100, sino que es un ancho relativo dentro del documento. No es muy intuitivo y suele pasar que haya que hacer varias proebas hasta que las columnas se ajustan correctamente como queremos.
Comentar que se puede tener un número de columnas en el SetColumnsWidth inferior o igual al total de columnas de la tabla, y nunca superior, ya que si lo superamos, darña un error en tiempo de ejecución que te puede volver un poco loco.
Ahora creamos otra tabla de pdf para rellenarla con los datos de la empresa que emite la factura.
// DATOS DE la empresa en CABECERA
PdfTable TablaDanosNacho = myPdfDocument.NewTable( new Font(“Verdana”, 12), 4, 2, 4);
TablaDanosNacho.HeadersRow.SetColors(Color.White, Color.BurlyWood);
Damos una alineación al contenido
TablaDanosNacho.SetContentAlignment(ContentAlignment.MiddleCenter);
Le decimos que la columna 1 deberá tener el contenido en el centro a la izquierda
TablaDanosNacho.Columns[1].SetContentAlignment(ContentAlignment.MiddleLeft);
TablaDanosNacho.ImportDataTable(DataEmpresa);
TablaDanosNacho.SetColumnsWidth(new int[] { 20, 80 });
TablaDanosNacho.SetBorders(Color.Black, 1, BorderType.Bounds);
Unimos las celdas de las columnas con esta instrucción
TablaDanosNacho.HeadersRow.MergeCells();
Le asignamos a la cabecera un titular
TablaDanosNacho.HeadersRow.SetContent(“DATOS DE LA EMPRESA.”);
La variable DataEmpresa la rellenamos de la siguiente manera :
DataTable DataNacho
{
get
{
// Creamos el Datatable
DataTable dt = new DataTable();
// Creamos las dos columnas sin texto que luego unimos en el PDFTable y le asignamos un texto
dt.Columns.Add(“”);
dt.Columns.Add(“”);
// Creamos una fila y le asignamos el nombre
DataRow dr = dt.NewRow();
dr[0] = “Nombre”;
dr[1] = “Realce Online eMarketing y Diseño”;
dt.Rows.Add(dr);
// Otra fila y le asignamos el DNI
DataRow dr1 = dt.NewRow();
dr1[0] = “DNI”;
dr1[1] = “22.345.543K”;
dt.Rows.Add(dr1);
// Otra fila con la Dirección
DataRow dr2 = dt.NewRow();
dr2[0] = “Dirección”;
dr2[1] = “C/ La Quito 17 6º A”;
dt.Rows.Add(dr2);
// Y Otra fila con el resto de datos
DataRow dr3 = dt.NewRow();
dr2[0] = “CP.- “;
dr2[1] = “28015 Localidad: Huelva Provincia: Huelva”;
dt.Rows.Add(dr3);
// Devuelvo el dataTable Relleno
return dt;
}
}
Ahora creamos otra tabla con los datos del Cliente
// DATOS DEL CLIENTE
PdfTable TablaDanosCliente = myPdfDocument.NewTable( new Font(“Verdana”, 12), 3, 2, 4);
TablaDanosCliente.HeadersRow.SetColors( Color.White, Color.BurlyWood);
TablaDanosCliente.SetContentAlignment( ContentAlignment.MiddleCenter);
TablaDanosCliente.ImportDataTable( DatosCliente);
TablaDanosCliente.SetColumnsWidth(new int[] { 20, 80 });
TablaDanosCliente.SetBorders(Color.Black, 1, BorderType.Bounds);
TablaDanosCliente.HeadersRow.MergeCells();
TablaDanosCliente.HeadersRow.SetContent(“DATOS DEL CLIENTE.”);
En este código no hay nada nuevo, y basta con decir que el DataTable DatosCliente es rellenado de la misma forma que DatosEmpresa pero con los datos del cliente obtenidos de la base de datos que estemos usando.
A continuación Creamos el resto de tablas de los importes totales con y sin los IVA y la tabla de la fecha de la factura y el número de factura obligatorios en toda factura que se precie.
// DATOS FINALES
PdfTable TablaDanosFinales = myPdfDocument.NewTable( new Font(“Verdana”, 12), 1, 3, 4);
TablaDanosFinales.HeadersRow.SetColors( Color.White, Color.BurlyWood);
TablaDanosFinales.SetContentAlignment( ContentAlignment.MiddleCenter);
TablaDanosFinales.ImportDataTable( DatosFinales);
TablaDanosFinales.SetColumnsWidth( new int[] { 40, 20, 40 });
TablaDanosFinales.SetBorders( Color.Black, 1, BorderType.Bounds);
// DATOS FECHA
PdfTable TablaDanosFecha = myPdfDocument.NewTable( new Font(“Verdana”, 12), 2, 2, 4);
TablaDanosFecha.HeadersRow.SetColors(Color.White, Color.BurlyWood);
TablaDanosFecha.SetContentAlignment(ContentAlignment.MiddleCenter);
TablaDanosFecha.ImportDataTable(DatosFecha);
TablaDanosFecha.SetColumnsWidth(new int[] { 40, 40 });
TablaDanosFecha.SetBorders(Color.Black, 1, BorderType.Bounds);
TablaDanosFecha.VisibleHeaders = false;
Ahora vamos a cargar una imagen corporativa en el documento para que de sensación de corporatividad y de empresa seria.
PdfImage Logo = myPdfDocument.NewImage( HttpContext.Current.Server.MapPath(“~/imagenes/globo.jpg”));
Debe ser una imagen JPG ya que no acepta esta versión otro formato, aunque estoy seguro que en la versión 2.0 que se está preparando (no se si ya existe) de esta librería vendrá implementada muchas mejoras.
Ahora lleha la parte delicada de esta pelicula.
Tenemos que realizar un bucle para ir generando el PDF con los datos de las tablas que hemos ido creando anteriormente y posicionarlas de forma relativa en el documento.
// Here comienza el bucle para generar la tabla
while (!myPdfTable.AllTablePagesCreated)
{
// Generamos una nueva página en el documento que albergará las tablas anteriores
PdfPage newPdfPage = myPdfDocument.NewPage();
// Generamos una nueva página de tablas en el documento, indicandole la posición que llevará en el documento
PdfTablePage newPdfTablePage =
myPdfTable.CreateTablePage(new PdfArea(myPdfDocument, 48, 300, 500, 670));
// CREO LA TABLA DE LOS DATOS DE LA EMPRESA
PdfTablePage newPdfTablePage2 =
TablaDanosNacho.CreateTablePage(new PdfArea(myPdfDocument, 20, 20, 260, 100));
// CREO LA TABLA DEl CLIENTE
PdfTablePage newPdfTablePage3 =
TablaDanosCliente.CreateTablePage(new PdfArea(myPdfDocument, 20, 150, 260, 200));
// CREO LA TABLA DE FECHA Y Nº FACTURA
PdfTablePage newPdfTablePage5 =
TablaDanosFecha.CreateTablePage(new PdfArea(myPdfDocument, 300, 20, 150, 150));
// AGREGAMOS LOS OBJETOS A LA PAGINA PDF CREADA AL INICIO DEL BUCLE
newPdfPage.Add(Logo, 460, 20);
newPdfPage.Add(newPdfTablePage);
newPdfPage.Add(newPdfTablePage2);
newPdfPage.Add(newPdfTablePage3);
newPdfPage.Add(newPdfTablePage5);
if (myPdfTable.AllTablePagesCreated)
{
PdfTablePage newPdfTablePage4 =
TablaDanosFinales.CreateTablePage( new PdfArea( myPdfDocument, 120, 700, 300, 80));
newPdfPage.Add(newPdfTablePage4);
}
}// Fin del bucle
Guardamos los cambios en el documento
newPdfPage.SaveToDocument();
Ahora exportamos el fichero,
documentofactura.SaveToFile( HttpContext.Current.Server.MapPath(“~/Public/factura.pdf”));
Podemos guardar en un fichero físico en nuestro servidor o podemos ponerlo a descarga directa en el navegador.
Yo en mi caso, lo he guardado en un fichero fisico, que luego leo y envio por correo electrónico (donde no voy a entrar en este artículo, ya hablaremos de ello más adelante)
FileStream fich = File.Open( HttpContext.Current.Server.MapPath(“~/Public/factura.pdf”), FileMode.Open);
Creo mi objeto de la clase que envia el correo
Mail MailSender = new Mail();
Creo el cuerpo del mensaje
string body = “<html><body>Estimado usuario, adjunto se le envía la factura de su pedido. Si detecta algún fallo o anomalía contacte con la redacción a través de la web <a href=\”http://www.realceonline.com\”>AeRoLoCoS.eS. Gracias por la compra.</a></body></html>”;
Llamo a la función que envía el pdf adjunto al mail del usuario que ha realizado el pedido
MailSender.enviarMailPdfAdjunto(fich, “correoFROM@dominio”, email, “Factura de compra en www.realceonline.com”, body, “loginmailsmtp”, “passmailsmtp”);
Una vez enviado el fichero lo libero y lo elimino
fich.Close();
fich.Dispose();
File.Delete(HttpContext.Current.Server.MapPath(“~/Public/factura.pdf”));
Ahora lo que hago es poner el documento generado anteriormente en descarga directa en el navegador
//Descargo la factura
HttpContext.Current.Response.ClearHeaders();
HttpContext.Current.Response.AppendHeader(“Content-disposition”,
string.Format(“attachment;filename={0}”, “Factura.pdf”));
Le indico al navegador que le voy a enviar datos de tipo de aplicación PDF para que reconozca con que programa asociarlo
HttpContext.Current.Response.ContentType = “application/pdf”;
Le indico el tipo de codificación
HttpContext.Current.Response.Charset = “UTF-8″;
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.Default;
Devuelvo el fichero PDF generado como un Stream en memoria y se lo asocio al OutputStream de lo que voy a delvolver al navegador documentofactura.SaveToStream(HttpContext.Current.Response.OutputStream);
Finalizo la operación
HttpContext.Current.Response.End();
Como muestra un Botón :

Generación de PDF con ASP.NET. Desarrollo y diseño Web a medida.