martes, 19 de febrero de 2013

¿Cómo generar reportes de Access en Word?

Microsoft Access no soporta la exportación de reportes al formato de Microsoft Word, exceptuando la exportación a RTF (Rich Text Format), que tiene limitaciones como el uso de tablas o imágenes. En este artículo veremos una técnica muy poderosa para generar documentos Word desde Access, utilizando HTML y CSS.

Ventajas y desventajas

La lista de ventajas:
  • El reporte se visualiza en Word, donde puede ser modificado posteriormente a su generación.
  • Se permiten estilos más complejos que los soportados en Access. Por ejemplo, que el formato de un párrafo no sea todo igual y se permitan poner algunas palabras en negrita o colores y tamaños específicos.
  • Se permiten almacenar los formatos en tablas, lo que simplifica la utilización por ejemplo de encabezados similares para todos los reportes. Y facilita también un cambio en los mismos en forma centralizada.
  • El documento generado puede ser visible tanto en Microsoft Word como en un Browser. Podría ser por ejemplo publicado en una página web o en una extranet.
  • El reporte se genera usando la herramienta de reportes de Access lo cual nos brinda toda la potencia de manejar el detalle del reporte con mucha facilidad. Esto lo hace una mejor opción frente a otras como la combinación de documentos con Word y la generación de un documento vía programación.
  • El documento generado no posee ninguna dependencia con los datos a diferencia de una combinación con Word, lo cual lo hace menos dependiente a futuros cambios en la base de datos.
Las desventajas
  • Se requieren conocimientos de HTML y CSS

Enfoque de desarrollo

El enfoque de desarrollo tiene una serie de pasos conceptuales que son importantes:
  1. Se parte de la creación de un informe en Access
  2. Ese informe genera un documento HTML
  3. En lugar de mostrar el informe por pantalla, lo almacenamos como documento HTML
  4. Utilizando en forma programática las opciones de Word, convertimos el HTML a DOCX
  5. Previamente convertimos las imágenes vinculadas, como los logos, en imágenes incrustadas dentro del documento.
  6. Como último paso, abrimos Word y le mostramos al usuario el reporte creado.

Lo que ve el usuario

Para el usuario, es todo transparente. En principio, desde un lugar de la aplicación, tendrá un botón, para generar el reporte:


Luego, simplemente verá el documento creado en Word. En la imagen pueden ver detalles como el formato de la tabla, el encabezado y el uso de un logo:


Este pequeño log, nos muestra lo que el programa fue haciendo, no lo verá el usuario final:



El formato del archivo HTML

Uno de los puntos más importantes es entender cómo armar el formato HTML. En principio, podemos armarlo como cualquier página web con HTML y estilos CSS dentro de la misma página. Sólo tendremos que tener en cuenta los siguientes detalles:
  • Utilizar correctamente las opciones de encabezado y pie de página.
  • Utilizar campos como número de página si nos interesa.
  • Darle la opción al documento HTML de que se abra en el modo de vista de impresión y no en el modo de página web
Esto lo pueden probar desde cualquier editor de texto y luego abrir la página desde Word. A continuación les dejo un formato válido de archivo, que lo pueden utilizar incluso para cualquier aplicación web que desee tener una opción de descarga del documento en formato Word.

En este ejemplo están comentadas las opciones de primera página diferente, pero las dejé porque pueden ser útiles:
<html
xmlns:o='urn:schemas-microsoft-com:office:office'
xmlns:w='urn:schemas-microsoft-com:office:word'
xmlns='http://www.w3.org/TR/REC-html40'>
<head><title>Reporte 1</title>

<!--[if gte mso 9]><xml>
 <w:WordDocument>
  <w:View>Print</w:View>
  <w:Zoom>90</w:Zoom>
</w:WordDocument>
</xml><![endif]-->


<style>
p.MsoFooter, li.MsoFooter, div.MsoFooter
{
    margin:0in;
    margin-bottom:.0001pt;
    mso-pagination:widow-orphan;
    tab-stops:center 3.0in right 6.0in;
    font-size:12.0pt;
}

@page Section1
{
    size:8.5in 11.0in;
    margin:1.0in 1.0in 1.0in 1.0in;
    mso-header-margin:.5in;
    mso-footer-margin:.5in;
/*
    mso-title-page:yes;
*/
    mso-header: h1;
    mso-footer: f1;
/*
    mso-first-header: fh1;
    mso-first-footer: ff1;
*/
    mso-paper-source:0;
}


div.Section1
{
    page:Section1;
}

table#hrdftrtbl
{
    margin:0in 0in 0in 900in;
    width:1px;
    height:1px;
    overflow:hidden;
}

</style></head>

<body lang=EN-US style='tab-interval:.5in'>
<div class=Section1>

<p> CONTENT
<p>hola mundo</p>
<p>hola mundo</p>
<p>hola mundo</p>
<p>hola mundo</p>
<p>hola mundo</p>
<p>hola mundo</p>

</p>

<br/>
    <table id='hrdftrtbl' border='0' cellspacing='0' cellpadding='0'>
    <tr><td>

    <div style='mso-element:header' id=h1 >
        <p class=MsoHeader ><p>&nbsp;CABECERA</p></p>
    </div>

    </td>
    <td>
    <div style='mso-element:footer' id=f1>

        <p>&nbsp;PIE</p>
        <p class=MsoFooter>
        <span style=mso-tab-count:2></span>
            Pag. <span style='mso-field-code: PAGE '><span style='mso-no-proof:yes'></span></span> de <span style='mso-field-code: NUMPAGES '></span>
        </p>

    </div>


<!-- PRIMERA PAGINA DISTINTA

    <div style='mso-element:header' id=fh1>

    <p class=MsoHeader><span lang=EN-US style='mso-ansi-language:EN-US'>&nbsp;CABECERA (primera hoja)<o:p></o:p></span></p>

    </div>

    <div style='mso-element:footer' id=ff1>

    <p class=MsoFooter><span lang=EN-US style='mso-ansi-language:EN-US'>&nbsp;PIE (primera hoja)<o:p></o:p></span></p>

    </div>

-->
    </td></tr>
    </table>

</body></html>


El armado del informe en Access

Esta parte consiste en crear un reporte desde cero en el que completaremos tres secciones:
  • Encabezado del informe (no de la página)
  • Detalle
  • Pie del informe (no de la página)
Agregamos una etiqueta en el encabezado en donde incluiremos como contenido el HTML completo desde el inicio hasta la cabecera del contenido del detalle. Por ejemplo un tag TABLE.

Luego en el detalle agregamos un cuadro de texto en donde mezclamos tags HTML con campos de la base de datos.

Finalmente cerramos el HTML en el Pie del informe. En la siguiente imagen, se puede ver el informe en tiempo de diseño:



La visión en tiempo de ejecución carece de sentido, porque mostrará código HTML. Pero no es problema, porque no la usaremos.

Un punto importante es que el código puede ser guardado en parte en tablas, para facilitar la re-utilización. En este artículo lo hemos dejado dentro del reporte con fines didácticos.


El código para generar el documento

Finalmente, debemos generar el documento. El siguiente código nos muestra cómo hacerlo. Los puntos conceptuales más importantes son:
  • La exportación del informe a un archivo de texto para crear el HTML.
  • La utilización del SaveAs de Word para convertir el documento a DOCX.
  • La incrustación de las imágenes, tanto del documento, domo de los encabezados.
Dim camino
Dim archivo
Dim archivoHTML
Dim archivoDOCX

' Obtengo el path en donde se ejecuta la aplicación
camino = CurrentProject.Path + "\"
archivo = "temporal_30"
archivoHTML = camino + archivo + ".html"
archivoDOCX = camino + archivo + ".docx"
Log.Caption = "Path detectado." + vbNewLine

' Abro el archivo HTML
DoCmd.OutputTo acOutputReport, "Informe1", acFormatTXT, archivoHTML
Dim theWord As Object
Set theWord = CreateObject("Word.Application")
Dim theDoc As Object
Set theDoc = theWord.Documents.Open(archivoHTML)
Log.Caption = Log.Caption + "Archivo HTML abierto." + vbNewLine

' Incrusto las imágenes en el documento
For Each shapeLoop In theDoc.InlineShapes
 With shapeLoop
  .LinkFormat.SavePictureWithDocument = True
  .LinkFormat.BreakLink
  Log.Caption = Log.Caption + "Imagen incrustada (InlineShape)." + vbNewLine
 End With
Next shapeLoop

' Incrusto las imágenes en el documento (Headers)
For Each sectionsLoop In theDoc.Sections
 Log.Caption = Log.Caption + "Sección detectada." + vbNewLine
 With sectionsLoop
 For Each headersLoop In .Headers
  Log.Caption = Log.Caption + "Header detectado." + vbNewLine
  With headersLoop
  For Each shapeheaderLoop In .Range.InlineShapes
   With shapeheaderLoop
   .LinkFormat.SavePictureWithDocument = True
   .LinkFormat.BreakLink
   Log.Caption = Log.Caption + "Imagen incrustada (InlineShape / Header)." + vbNewLine
   End With
  Next shapeheaderLoop
  End With
 Next headersLoop
 End With
Next sectionsLoop

' Convierto el archivo HTML en DOCX
theDoc.SaveAs FileName:=archivoDOCX, FileFormat:=wdFormatDocument
Log.Caption = Log.Caption + "Archivo DOCX generado." + vbNewLine

' Cierro todo
theWord.Documents(archivoDOCX).Close
theWord.Quit
Set theWord = Nothing
Log.Caption = Log.Caption + "Archivo DOCX cerrado." + vbNewLine

' Abro Word con el archivo DOCX convertido
Application.FollowHyperlink archivoDOCX
Log.Caption = Log.Caption + "Documento abierto en Word." + vbNewLine


Conclusión

Aquí finaliza. Este enfoque nos brinda mucho poder según mi criterio porque:
  • Permite al usuario modificar los reportes en su herramienta preferida: Word.
  • Permite estilos complejos.
  • Genera dos formatos por el mismo precio.

Bibliografía

A continuación les dejo un conjunto de artículos que me han servido enormemente para vencer todos los problemas que fui encontrando. Se los recomiendo, especialmente el primero, que es el de la idea:

Hasta la próxima!