martes, 26 de febrero de 2013

¿Cómo saber si un archivo existe?

El siguiente código nos puede ayudar a saber desde Access si un archivo existe:

If Dir("C:\Prueba\Prueba.doc") = "" Then
  Msgbox "El archivo no existe"
Else
  Msgbox "El archivo existe"
End If

Más información en:

¿Cómo incluir SQL en un Control Source?

En caso que necesitemos incluir SQL en la propiedad Control Source de un Text Box, podemos usar la función DLookUp tal como se muestra en el siguiente código:

=DLookUp("campo","tabla","un_campo = 'un_valor'")

Más información y otras opciones en: http://stackoverflow.com/questions/1311885/sql-as-control-source-for-access-form-field

¿Cómo eliminar un archivo desde Access?

Kill nos puede ayudar a eliminar un archivo desde Access con una simple línea de código:

Kill("TestFile")

Más información en: http://msdn.microsoft.com/en-us/library/ey1w10ch(v=vs.80).aspx

viernes, 22 de febrero de 2013

¿Cómo pasar una parámetro a un Reporte?

Supongamos que queremos pre-filtrar un informe, por ejemplo pasando un ID como parámetro. Esta es la forma en que podemos hacerlo:

DoCmd.OpenReport "Anexo_AML", acViewPreview, , "[ID]=" & Me("ID")

jueves, 21 de febrero de 2013

Automatizar el envío de correo electrónico con SQL Server (parte 1)

El propósito de este artículo es describir un método para automatizar el envío de correos electrónicos a partir de información disponible en una base de datos SQL Server, lo cual puede ser muy útil si utilizan Access con SQL Server. 

En este primer artículo, explicaremos cómo configurar el servicio de DatabaseMail de SQL Server 2008 R2 Express. Probaremos dos configuraciones:

  • Una con un servicio gratuito como GMail
  • Otra con un servicio de correo provisto por un Hosting, en este caso BlueHost

En un segundo artículo, vamos a explicar como enviar los datos a partir de información disponible en nuestra base de datos, cómo darle formato al correo y cómo automatizar su envío.

Comencemos… 

 

1. Habilitar DatabaseMail en SQL Server 2008 R2 Express

En la versión Express de SQL Server no disponemos del asistente para configurar DatabaseMail, por lo cual deberemos hacer el trabajo en forma manual. Primero abrimos SQL Server Management Studio y nos conectamos:

image

Con el botón derecho del mouse sobre el nombre de nuestro servidor ir a la opción Facets. Es posible que esta opción se demore en abrir:

image

Luego vamos a la opción Surface Area Configuration / DatabaseMailEnabled.

Ponemos el valor True.

image

Luego reiniciamos SQL Server con el botón derecho del mouse sobre el servidor, haciendo clic en Restart.

image

 

2. Configurar DatabaseMail para ser usado con GMail

Dentro de la base msdb vamos a utilizar un conjunto de procedimientos almacenados para configurar el correo, en este caso usando GMail como SMTP:

sysmail_add_account_sp  
     @account_name =  'Prueba',
     @email_address =  'micuenta@gmail.com' ,
     @display_name =  'Prueba DataBaseMail' ,
     @replyto_address =  'noresponder@gmail.com' ,
     @mailserver_name =  'smtp.gmail.com',
     @mailserver_type =  'SMTP' ,
     @port =  587,
     @username =  'micuenta@gmail.com',
     @password =  '-----',
     @enable_ssl =  TRUE

sysmail_add_profile_sp @profile_name = 'Profile de prueba'

sysmail_add_profileaccount_sp
    @profile_name = 'Profile de prueba' ,
    @account_name = 'Prueba',
    @sequence_number = 1

 

3. Enviar un correo de prueba

Para enviar un correo de prueba, podemos utilizar un procedimiento como el siguiente, siempre dentro de la base de datos msdb:

EXEC sp_send_dbmail @profile_name='Profile de prueba',
@recipients='jpussacq@gmail.com',
@subject='Mensaje de prueba',
@body='Mi primer prueba de Database Mail'

Y obtendremos un mensaje como el siguiente:

Mail queued.

Si todo funcionó bien, recibiremos el correo sin problemas. Sino, podemos explorar algunas de las opciones de la siguiente sección.

 

4 Análisis de problemas

Las siguientes consultas, nos pueden ayudar a hacer un análisis de los problemas y a conocer en qué estado quedaron nuestros correos:

select * from msdb.dbo.sysmail_sentitems
select * from msdb.dbo.sysmail_unsentitems
select * from msdb.dbo.sysmail_faileditems

Esta consulta nos puede brindar más información si el estado es failed:

SELECT
items.subject,
items.last_mod_date,
l.description
FROM dbo.sysmail_faileditems as items
INNER JOIN dbo.sysmail_event_log AS l
ON items.mailitem_id = l.mailitem_id

Si reciben un error como el siguiente “The server response was: 5.7.0 Must issue a STARTTLS command first”, lo más probable es que hayamos olvidado configurar la opción de SSL en la cuenta.

 

5. Configurar DatabaseMail para ser usado con BlueHost

Es similar al caso de Gmail, pero con las opciones de Blue Host. 

USE msdb
GO
sysmail_add_account_sp  
     @account_name =  'Blue Host Mail',
     @email_address =  'cuenta@midominio.com' ,
     @display_name =  '---' ,
     @replyto_address =  'noresponder@---' ,
     @mailserver_name =  'mail.midominio.com',
     @mailserver_type =  'SMTP' ,
     @port =  26,
     @username =  'cuenta@midominio.com',
     @password =  '---',
     @enable_ssl =  FALSE
GO
sysmail_add_profile_sp @profile_name = 'Perfil Blue Host'
GO
sysmail_add_profileaccount_sp
    @profile_name = 'Perfil Blue Host' ,
    @account_name = 'Blue Host Mail',
    @sequence_number = 1
GO
EXEC sp_send_dbmail @profile_name='Perfil Blue Host',
@recipients='jpussacq@gmail.com',
@subject='Mensaje de prueba',
@body='Este es un mensaje de prueba del sistema'

 

Artículos relacionados:

¿Cómo evitar el clic en un vínculo si es un registro nuevo?

En ocasiones colocamos valores en una grilla de tipo "vínculos" que disparan una acción al hacer clic sobre ellos. Este puede ser el caso para imprimir un reporte o conocer información más detallada sobre un registro.

Sin embargo, a veces queremos que la acción de clic no se ejecute cuando aún no terminamos de crear el registro, como se ve en la siguiente imagen:


En esos casos podemos utilizar el siguiente código:

Private Sub Reporte_Click()
    Dim intnewrec As Integer
    intnewrec = Me.NewRecord
    If intnewrec = False Then
        On Error Resume Next
        DoCmd.OpenReport "Nota_Componentes", acViewPreview, , "[ID Nota]=" & Me("ID")
        If Err = 2501 Then Err.Clear
        DoCmd.Maximize
        DoCmd.RunCommand acCmdZoom100
    End If
End Sub

¿Cómo abrir un reporte en modo vista previa al 100% de zoom?

¿Cómo abrir un reporte en modo vista previa al 100% de zoom?

DoCmd.OpenReport "Nota_Componentes", acViewPreview, , "[ID Nota]=" & Me("ID")
DoCmd.Maximize
DoCmd.RunCommand acCmdZoom100

¿Cómo evitar que un informe genere un error 2501 si no hay datos?

Es posible que si no tenemos la información suficiente para generar un reporte, se produzca un error 2501:

Run-time error 2501 - The OpenReport action was canceled

Si queremos atrapar el error para que nuestra aplicación no cancele, usamos el siguiente código:

On Error Resume Next
DoCmd.OpenReport "Nota_Componentes", acViewPreview, , "[ID Nota]=" & Me("ID")
If Err = 2501 Then Err.Clear

Si además queremos generar un mensaje específico al usuario, aclarando que no hay información suficiente, usamos el siguiente código:

Private Sub Report_NoData(Cancel As Integer)
    MsgBox "No existen datos suficientes para generar el reporte."
    Cancel = True
End Sub

Más información en:

The expression On Click you entered as the event property setting produced the following error: Return withouth GoSub

Al abrir una base de datos Access con la que vienes trabajando sin problemas, recibes el siguiente mensaje:


The expression On Click you entered 
as the event property setting produced the following error: 
Return withouth GoSub


La forma de resolverlo es:

  1. Ejecutar el comando "C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE /decompile"
  2. Luego ejecutar la acción que producía el inconveniente
  3. Luego ejecutar el comando "Compact and Repair Database"
Cerrar Access, volver a abrir nuestro proyecto y a seguir trabajando. 
Espero les resulte útil!

Enlaces:

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!

domingo, 17 de febrero de 2013

¿Cómo posicionarse dentro de un control de navegación?

Imaginen que poseen un control de navegación como el que muestra la imagen y necesitan posicionarse mediante programación en una solapa especifica:


Usamos el siguiente código:

DoCmd.OpenForm "Inicio", acNormal

DoCmd.BrowseTo ObjectType:=acBrowseToForm, ObjectName:="Inicio_Propuestas", PathToSubformControl:="Inicio.NavigationSubform"

En este caso se abrirá el formulario "Inicio_Propuestas" que se encuentra en la opción "Gestión de Propuestas" de las páginas verticales.