Sharepoint 2010 + Infopath 2010: Como asegurarnos de que una carpeta existe antes de exportar a PDF una vista actual.

En esta serie de posts en relación a InfoPath 2010, tuve que incluir una porción de código para asegurarme de que la carpeta en la cual se van a almacenar los documentos PDF exportados exista. Es necesario agregar una referencia using System.IO; y luego incluir el siguiente código.

 if(!Directory.Exists(@”c:\temp”))
{
Directory.CreateDirectory(@”C:\temp”);
}

Sharepoint 2010 + Infopath 2010: Limitante al exportar vista en PDF y agregarlo como adjunto en un correo

En mi post anterior Sharepoint 2010 – Aprobación de workflows para dispositivos móviles – Parte 3: Código para envío de correo electrónico de notificación, había publicado la siguiente porción de código:

/*Crea un document PDF con la vista actual*/
this.CurrentView.Export(@”c:\temp\” + OrdenCompra + “_MemoMetalicos.pdf”, ExportFormat
.Pdf); /*Importante detener al menos por 10 segundos mientras se crea el documento caso contrario genera un error*/
Thread
.Sleep(10000);

 

El problema resulta que el document PDF que se crea con la function CurrentView no aparace en el directorio destino hasta que toda la función o hilo de ejecución finaliza, por tal motive es que cuando al tartar de agregarlo como adjunto de un correo en el mismo paso (hilo de ejecución) se presenta un mensaje de error en relación a que el documento no existe. Al parecer el método Sleep detiene por complete todo el hilo de ejecución por lo que no da paso a que el documento aparezca en el path de destino.

He invertido ya un gran tiempo en internet buscando información al respecto pero solo encontré un enlace indicando el mismo problema pero sin una solución específica.

SOLUCIÓN: tomando en cuenta la limitante antes expuesta tuve que dividir en dos botones tanto la generación del documento como el envío del correo con el adjunto.

Actualización: este es el único URL que encontré donde se menciona el mismo problema: http://www.infopathdev.com/forums/t/22835.aspx

Sharepoint 2010 – Aprobación de workflows para dispositivos móviles – Parte 4: Código Javascript en la página de webparts de Sharepoint

Para completar el ciclo, es necesario crear la página de webparts, agregar un CEW y colocar ahí el código JavaScript necesario para hacer el llamado al servicio web de actualización de items de la biblioteca de documentos.

En específico el CEW debe contener el siguiente código:

<script src=”/Scripts/jquery.min.js” type=”text/javascript”></script>
<script type=”text/javascript”>

function gup( name )
{
  name = name.replace(/[\[]/,”\\\[“).replace(/[\]]/,”\\\]”);
  var regexS = “[\\?&]”+name+”=([^&#]*)”;
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return “”;
  else
    return results[1];
}

function ActualizaEmbarque()
{
var IDFormulario=gup(‘IDForm’);
var Estado=gup(‘Estado’);
var Gerente=gup(‘Gerente’);

if (Estado==’1′)
{
   Estado=”APROBADO”;
}
else if (Estado==’2′)
{
   Estado=”NO APROBADO”;
}

if (Gerente==’1′)
{
   Gerente=”AprobacionGerente1″;
}
else if (Gerente==’2′)
{
   Gerente=”AprobacionGerente2″;
}

var soapEnv = “<?xml version=\’1.0\’ encoding=\’utf-8\’?> \
<soap:Envelope xmlns:xsi=\’http://www.w3.org/2001/XMLSchema-instance\’ \
xmlns:xsd=\’http://www.w3.org/2001/XMLSchema\’ \
xmlns:soap=’http://schemas.xmlsoap.org/soap/envelope/\’> \
<soap:Body> \
<UpdateListItems xmlns=’http://schemas.microsoft.com/sharepoint/soap/’> \
<listName>Control de Embarques de Chatarra</listName> \
<updates> \
<Batch OnError=’Continue’> \
<Method ID=’1′ Cmd=’Update’> \
<Field Name=’ID’>”+IDFormulario+”</Field> \
<Field Name='”+Gerente+”‘>”+Estado+”</Field> \
</Method> \
</Batch> \
</updates> \
</UpdateListItems> \
</soap:Body> \
</soap:Envelope>”;
$.ajax({
url: “/_vti_bin/lists.asmx”,
beforeSend: function(xhr) { xhr.setRequestHeader(“SOAPAction”, “http://schemas.microsoft.com/sharepoint/soap/UpdateListItems“);
},
type: “POST”,
dataType: “xml”,
data: soapEnv,
complete: UpdateListItems,
contentType: “text/xml; charset=\”utf-8\””
});
}

function UpdateListItems(xData, status)
{
alert(“Aprobación: ” + status );
}

ActualizaEmbarque();
</script>

El archivo jquery.min.js lo pueden obtener de este sitio http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js.

La parte medular de este código es:

<UpdateListItems xmlns=’http://schemas.microsoft.com/sharepoint/soap/’> \
<listName>Control de Embarques de Chatarra</listName> \
<updates> \
<Batch OnError=’Continue’> \
<Method ID=’1′ Cmd=’Update’> \
<Field Name=’ID’>”+IDFormulario+”</Field> \
<Field Name='”+Gerente+”‘>”+Estado+”</Field> \
</Method> \
</Batch> \
</updates> \
</UpdateListItems> \

Este código es el que construye el cuerpo de la actualización del item utilizando el servicio web de SharePoint.

<listName>Control de Embarques de Chatarra</listName>: hace referencia al nombre de la lista en donde se harán las actualizaciones.

<Method ID=’1′ Cmd=’Update’> \: como es posible enviar varias actualizaciones en un mismo paso, aquí indicamos que existe uno solo (ID=’1′) y que sera de una operación de actualizacipón (Cmd=’Update’).

<Field Name=’ID’>”+IDFormulario+”</Field> \: utilizando el parámetro enviado en el URL, indicamos cual es el ID del item que vamos a actualizar.

<Field Name='”+Gerente+”‘>”+Estado+”</Field> \: aquí indicamos el campo del item que vamos a actualizar y el valor respectivo. Es importante mencionar que si el nombre del campo posee espacios en blanco debe ir en el formato: “Nombre_x0020_Campo”, la cadena “_x0020_” representa a un espacio en blanco.

ACTUALIZACIÓN: para visualizar el nombre de campo que se debe colocar en el XML Field Name se recomienda ingresar a la configuración de la lista y hacer clic en el campo, revisar en el URL el parámetro Field. Esto es de utilidad en el caso de que el campo contenga tildes o sea demasiado largo, por ejemplo Field=Aprobaci%5Fx00f3%5Fn%5Fx0020%5FAprobador. es necesario reemplazar %5F por un _, para este caso _x00f3_ representa a una ó.

Si se requiere actualizar más campos simplemente se deben agregar más secciones del tipo <Field Name='”+Gerente+”‘>”+Estado+”</Field> \.

 

Espero que esta serie de posts sean de su utilidad.

Sharepoint 2010 – Aprobación de workflows para dispositivos móviles – Parte 3: Código para envío de correo electrónico de notificación

A pesar de que un correo electrónico puede ser enviado utilizando una acción de SPD, en este caso particupar para la plantilla de formulario de InfoPath 2010 fue necesario incluir código C# dentro de las acciones de un botón para poder enviar el correo de notificación junto con el enlace adjunto de la página con los parámetros necesarios para poder hacer la aprobación de un item desde el correo electrónico.

El código C# ingresado es el siguiente:

 try
{
/*Recupera algunos campos para enviar por correo electrónico desde INFOPATH*/
XPathNavigator CamposFormulario = this.MainDataSource.CreateNavigator().SelectSingleNode(“//my:myFields/my:CAMPOS_APOYO/my:IDForm”, this.NamespaceManager);
String IDFormulario = CamposFormulario.Value;
XPathNavigator NombreF = this.MainDataSource.CreateNavigator().SelectSingleNode(“//my:myFields/my:GENERAL/my:NoOrdenCompra”, this.NamespaceManager);
String OrdenCompra = NombreF.Value;
XPathNavigator CorreoGerenteUno = this.MainDataSource.CreateNavigator().SelectSingleNode(“//my:myFields/my:APROBACION_METALICOS/my:CorreoGerente1”, this.NamespaceManager);
String CorreoGerente1 = CorreoGerenteUno.Value;
XPathNavigator CorreoGerenteDos = this.MainDataSource.CreateNavigator().SelectSingleNode(“//my:myFields/my:APROBACION_METALICOS/my:CorreoGerente2”, this.NamespaceManager);
String CorreoGerente2 = CorreoGerenteDos.Value;

/*Crea un document PDF con la vista actual*/
this.CurrentView.Export(@”c:\temp\” + OrdenCompra + “_MemoMetalicos.pdf”, ExportFormat.Pdf);

 

/*Importante detener al menos por 10 segundos mientras se crea el documento caso contrario genera un error*/
Thread
.Sleep(10000);

 

/*Crea un nuevo objeto del tipo mail*/
MailMessage
mail = new MailMessage();
SmtpClient SMTPServer = new SmtpClient(“<servidor de correo>”);
mail.From =
new MailAddress(“<dirección de correo del remitente>”);
mail.To.Add(CorreoGerente1);
mail.Subject =
“Aprobación de Orden de Compra – ” + OrdenCompra;

 

 

AlternateView av = AlternateView.CreateAlternateViewFromString(“Se ha generado una nueva Orden de Compra que requiere ser aprobada por usted. <br> En el documento adjunto encontrar los detalles de la Orden de Compra. <br><br> Para APROBAR la Orden de Compra hacer clic <a href=’http://<URL del servidor y la biblioteca>/paginaWebService.aspx?ID=” + IDFormulario + “&Gerente=1&Estado=1′>AQUÍ</a> <br><br> Para NO APROBAR la Orden de Compra hacer clic <a href=’http://<URL del servidor y la biblioteca>/paginaWebService.aspx?ID=” + IDFormulario + “&Gerente=1&Estado=2′>AQUÍ</a>”, null, “text/html”); Attachment adjunto;
adjunto =
new Attachment(@”c:\temp\” + OrdenCompra + “_MemoMetalicos.pdf”);
mail.Attachments.Add(adjunto);
SMTPServer.Send(mail);
MessageBox.Show(“Correo enviado exitosamente. El formulario se cerrar automticamente en 5 segundos.”);
}
catch (Exception ex)
{
MessageBox.Show(“Error: ” + ex.Message);
}
finally
{ 
Thread.Sleep(5000);
Application.Quit(
true);
}

mail.AlternateViews.Add(av);

La parte clave de este código es la creación del objeto AlternateView ya que el cuerpo del mensaje debe ser enviado en formato HTML para poder incluir los enlaces de aprobación, en el caso de que se requiera enviar únicamente texto plano se puede utilizar el método “mail.body(“cuerpo del mensaje”);.

El formato de los enlaces de aprobación es: <a href=’http://<URL del servidor y la biblioteca>/paginaWebService.aspx?ID=” + IDFormulario + “&Gerente=1&Estado=1′>AQUÍ</a> , en este enlace se hace referencia a la página de webparts “paginaWebService.aspx” en donde se encuentra incluido un CEW con el código javascript necesario para hacer la actualización del item de la biblioteca de formularios InfoPath.

Adicionalmente se envían los parámetros necesarios para hacer el llamado al servicio web de actualización de items.

 

En la siguiente parte revisaremos el código JavaScript incluido en el CEW que hace el llamado al servicio web para hacer la actualización del item de la biblioteca de documentos.

Sharepoint 2010 – Aprobación de workflows para dispositivos móviles – Parte 2: Solución

En la parte 1 de esta serie expliqué el problema de hacer una aprobación de un workflow basado en SharePoint Server 2010, SharePoint Designer 2010 e InfoPath 2010. Ahora es tiempo de explicar la solución al escenario.

– Al finalizar la creación de un nuevo item dentro de la biblioteca de formularios, utilizando InfoPath, automáticamente se dispara un correo electrónico de notificación a los aprobadores para que revisen la información y procedan  a “Aprobar” o “No Aprobar”.

– Este enlace adjunto al cuerpo del correo hace referencia a una página de webparts de SharePoint 2010 . Este enlace adjunto, además de la dirección URL de la página, debe contener al menos dos parámetros para poder actualizar un item de la biblioteca de formularios: ID del item, Estado de Aprobación, por ejemplo, 1 = Aprobado, 2 = No Aprobado.

– Esta página de webparts funcionará como una interfaz de comunicación para hacer el llamado al servicio web de actualización de items de una lista de SharePoint. Para lograr esto es necesario integrar código javascript dentro de un CEW. Este código debe ejecutar dos acciones:

   – Leer los parámetros del URL enviado por correo.

   – Invocar al web service y enviar los valores requeridos para que actualicen un item de la biblioteca de formularios de SharePoint.

– Una de las limitantes encontradas es que el servicio web no puede actualizar los valores de los campos de una biblioteca de formularios que fueron creados a partir de la plantilla de InfoPath. Siendo más específico, mi plantilla de formulario InfoPath posee un campo llamado “AprobacionCE”, el mismo que durante el proceso de publicación fue considerado para que se presente en la bilbioteca de formularios del sitio SharePoint.

– Este campo, durante el proceso de publicación, debió ser configurado para que pueda ser modificado externamente, es decir, sin necesidad de InfoPath.

– Debido a la limitante antes expuesta es necesario crear un campo de apoyo para poder colocar el estado de aprobación, Aprobado / No Aprobado, y luego por medio de un workflow de SPD hacer la actualización al campo respectivo del formulario de InfoPath.

 En la siguiente parte analizaremos el código C# incluído en la plantilla del formulario de InfoPath 2010 para el envío del correo electrónico de notificación de aprobación.

Sharepoint 2010 – Aprobación de workflows para dispositivos móviles – Parte 1: Escenario.

Este nuevo reto inició con un problema que se presentó en dispositivos BlackBerry al presenter una lista de SharePoint Server 2010. Puntualmente, cree una lista personalizada y junto con ella algunos formularios de mantenimiento de información también personalizados, es decir, formularios adicionales a: NewForm.aspx y EditForm.aspx.

La primera dificultad presentada es que estos formularios personalizados no tienen soporte para vista móvil, es necesario agregar el parámetro “…&mobile=0” en el enlace para que se pueda presentar sin problema, caso contrario se muestra así:

 Con el parámetro “…&mobile=0” lo que conseguimos es que se presente el formulario en un formato (tamaño) de PC. Al parecer estaba todo resuelto pero, al probar el zoom en el dispositivo se presentó brevemente la pantalla en un tamaño más grande, como era de esperarse, pero al instante se tornó todo en blanco. Nuevamente recalco que esto sucedió con dispositivos BlackBerry. Probamos con otro navegador instalado en el mismo equipo pero no funcionó. Probamos actualizando el software del teléfono y tampoco funcionó.  Busqué por un buen tiempo en internet por información sobre como resolver este problema sin tener suerte.

Una vez agotada toda altenativa viable propuse el utilizar los Web Services de SharePoint 2010 para poder incluir un enlace (link) dentro del correo electrónico de notificación de aprobación de un flujo y que el usuario del dispositivo móvil únicamente tenga que hacer “click” en el vínculo y el estado de aprobación del item de la lista de sharepoint sea actualizado con el estado de aprobación respectivo.

 Esta misma solución aplica para otro escenario en el cual el workflow se apoya en formularios de InfoPath para poder dar mantenimiento a la información, ya que no es possible abrir un formulario de InfoPath en un dispositivo BlackBerry.

El escenario es el siguiente:

– Existe una biblioteca de formularios en donde se encuentra publicada una plantilla de InfoPath 2010.

– Durante el proceso de publicación del formulario de InfoPath en la biblioteca de SharePoint se incluyeron algunos campos de información.

– En este formulario existen dos campos de aprobación que deben ser modificados por el aprobador respectivo. Como indicaba en un inicio, InfoPath no puede ser abierto en un dispositivo BlackBerry por lo que se debe plantear alguna otra opción de cambiar el estado de aprobación de “Seleccione uno …” a “Aprobado” o “No Aprobado”.

 En el siguiente post explicaré la solución planteada a este escenario.

Borrado de cache de Infopath

Trabajando con un formulario de InfoPath 2010 y probando las conexiones con servicios web me encontré con el problema que al publicar una versión nueva del formulario sin la conexión con el servicio web, al tratar de abrirlo desde una biblioteca de SharePoint mantenía la referencia la servicio web. Revisé completamente el formulario sin encontrar referencia alguna del servicio web. Finalmente y luego de “googlear” por algunos minutos encontré que puede deberse a la cache que mantiene InfoPath.

Luego de ejecutar el comando:

InfoPath.exe /cache clearall, intenté abrir nuevamente el formulario esta vez con éxito.

Controles para Sharepoint: Cascading Drop-Down List

Durante la ejecución de un proyecto en el que se involucra el diseño y desarrollo de flujos de trabajo me encontré con la necesidad de un campo de lista de Sharepoint que me permita seleccionar una opción en un campo padre y automáticamente las opciones que estan ligadas a ese valor puedan filtrarse en el siguiente campo de la lista. Luego de algunas búsquedas me encontré con que si existe un campo de Sharepoint que permite implementar esta funcionalidad, en el sitio de codeplex me encontré con el control Cascading Drop-Down List Field (http://cascddlistwithfilter.codeplex.com/), sin embargo la limitante es que está diseñado en teoría solo para Sharepoint 2007. En el mismo foro del control me encontré que si hay forma de instalarlo en Sharepoint 2010 (http://cascddlistwithfilter.codeplex.com/discussions/218850).