lunes, 10 de marzo de 2014

SP Designer 2013: Bucle para recorrer todos los ítems de una lista.

Este post, es la continuación de un post anterior:
SP Designer 2013: Cómo usar la acción de "Call HTTP web service" para obtener los ítems de una lista de SharePoint, donde vimos cómo se podía utilizar el Call HTTP Web Service Action para obtener todos los ítems de una lista en una variable de tipo Dictionary, y cómo obtener la información de cada elemento de la lista. Hoy vamos a evolucionar el mismo ejemplo, partiendo de la misma base creada, para crear un bucle que vaya recorriendo todos los elementos de la lista y vaya realizando cambios en cada uno de ellos.

Para ello, partimos de la base del flujo que se creó en el post anterior, pues hay que tener en cuenta que la manera más sencilla y eficaz de recorrer todos los ítems de una lista va a ser a partir de un Web Service que nos retorne en una variable de tipo array (Dictionary) todos los ítems de dicha lista.



La idea es trabajar el siguiente ejemplo: A partir de un listado que contenga información de cada empleado, incluyendo sus días de vacaciones, hacer un flujo que al final del año permita:
  • Reiniciar los "Dias de vacaciones aprovados" a 0
  • Ver si quedan días pendientes, y notificarlos como días Extras para el nuevo año (si me han sobrado 3 días en 2013, voy a tener 3 días adicionales en 2014).
Puesto que en los flujos de SharePoint 2013, el valor que asume por defecto el "Workflow Status" es el del nombre de la etapa (Stage) donde se encuentra, no está de más que la primera acción del flujo sea un "Set Workflow Status" (en Core Actions), para poder mostrar un estado que al usuario no le parezca extraño (El nombre de la Stage no suele ser muy concreto).

También hay que tener en cuenta que vamos a necesitar una variable índice para recorrer el bucle, así que la creamos, de tipo Integer


Y luego añadimos una acción al principio del flujo (tras la modificación del Status), con la acción "Set Workflow Variable" (En Core Actions), que inicialice el índice a 0.

El siguiente paso es saber cuantas iteraciones vamos a tener que realizar en el bucle. Puesto que ya guardamos en una variable de tipo Dictionary todos los ítems devueltos por el WS ("Get d/results"), haremos uso de la acción "Count Items in a Dictionary" (en Core Actions) para contar de forma específica cuantos elementos contiene esa variable (que es lo mismo que saber cuantos ítems contiene esa lista). El Output de esta acción se guardará automáticamente en otra variable de tipo integer.

Ahora ya estamos listos para iniciar el bucle. En este punto, si se desea, se puede hacer un cambio de Workflow Status, o incluso de Step o Stage del flujo.

Para crear el bucle, iremos a la Ribbon y seleccionaremos "Loop" y en concreto "Loop n Times"


Y modificamos la variable para que coincida con la que nos devolvió el número de elementos del listado en la acción "Count Ítems in a Dictionary".


Este paso es opcional, pero importante si se quiere hacer que el flujo deje algún mensaje en el log que vaya informando de lo que va ocurriendo. Se trata de guardar información del ítem que actualmente está procesando el bucle, para irla mostrando en el log del Workflow. Para ello, volveremos a utilizar la Acción "Get an Item from a Dictionary" (Core Actions), pero esta vez especificando el ítem y el campo a retornar. En este caso la fórmula a utilizar sería la siguiente:
d/results([%Variable: Index%])/Title.

Como hemos inicializado Index a 0, la primera vez ejecutará: "d/results(0)/Title", de forma que retornará el Título del primer ítem del Array.


Podríamos repetir esta acción tantas veces como queramos para obtener diversos campos de cada elemento y luego componer una cadena con ellos en una acción "Log To History List".

Hay un campo que es necesario retornar, para luego poder modificar el ítem correctamente, y es el ID del ítem, que almacenaremos en una nueva variable de tipo Integer, ItemID :


Ahora, utilizando el ID del ítem retornado, podremos obtener, por ejemplo, cuantos días pendientes de vacaciones tiene ese empleado en concreto. Para ello usaremos una Acción del tipo "Set Workflow Variable" (Core Actions). En el campo "Data Source" haremos referencia al listado donde se contiene la información de los usuarios (el que hemos atacado con el WS), en "Field from source" especificaremos el nombre de la columna que almacena el dato que queremos recuperar (días pendientes de vacaciones), y en la segunda parte del formulario, especificaremos que se base en el ítem que contenga el Field ID, con el valor de la variable ÍtemID que inicializamos en el paso anterior. Al usar el campo ID, que es único para cada ítem, nos aseguramos de estar accediendo a un ítem concreto sin riesgo a duplicidad en la consulta. El resultado lo almacenaremos en una nueva variable de tipo Integer, NewExtraLeave.


 En este punto, y en mi caso, consideré oportuno usar una acción del tipo "Log to History List" (Core Actions) del siguiente tipo:


Una vez realizado esto, ya podemos actualizar el ítem en cuestión, modificando los campos de días aprobados (en mi caso "Approved Leave") a 0 y los de días extra (en mi caso "Extra Leave") al número de días que teníamos pendientes a final de año (recopilados en la variable "NewExtraLeave"). En mi caso, la lista también  contiene un campo donde se van justificando el por qué se añaden días extras (en mi caso "Extra Leave Reasons"), que también actualizo en esta acción mediante un string que explica el número de días sobrantes a final del año.

En la última parte del formulario de esta acción hay que especificar que el ítem de la lista que queremos cambiar es el que tiene el campo ID con el valor de la variable del flujo "ItemID" (proveniente del "Get d/results([%Variable:Index%])/ID).


Ahora ya solo nos queda incrementar el valor del índice del bucle. Para ello usaremos una acción del tipo "Do Calculation" (Core Actions), donde especificaremos un cálculo del tipo "Index plus 1". Esto se guardará en una nueva variable de tipo "Number".

Notad aquí una cosa "rara": Nuestra variable Index es de tipo "Integer", pero al realizar el cálculo, nos fuerza a guardarlo en un "Number". ¿Cómo lo hacemos compatible? Pues nos fuerza añadir una nueva acción del tipo "Set Workflow Variable", donde especificaremos que "Index" asume el valor del resultado del cálculo (simpatías de SharePoint Designer :-p)


Ya tenemos el flujo completo! Ahora ya estamos obteniendo los valores de una lista, recorriéndolos uno a uno y modificándolos al paso iterativo del bucle.

Podemos añadir algún paso adicional de cambio de estado al final del flujo, y por último marcar el "Transition to stage" final a "End of Workflow".

Así pues, nuestro flujo resultante ha de tener un aspecto similar al de la siguiente imagen:


¡Listo! Aquí un ejemplo de las nuevas capacidades de los flujos en SharePoint 2013, con llamadas a Web Services, bucles y uso de variables de tipo Dictionary.

Observad que todo el rato hemos utilizado acciones de tipo "Core Actions", por lo que podríamos haber definido este flujo como un "Site Workflow", ya que no hace uso de ninguna acción específica de lista. Con ello se consigue que un flujo delicado como este (añade días de vacaciones por nuevo año a todos los empleados) sólo se pudiera activar desde la Site Administration (que suele estar más restringida a administradores), y no desde una lista en concreto.

Eso es todo por hoy. ¡¡Un saludo!!

3 comentarios:

Anónimo dijo...

Eres un Maestro, muchas gracias por la ayuda!!!

Carmen Jimenez dijo...

Genial, Siempre explicas muy claro.
¡Muchas gracias por compartir!

Cesil Roa dijo...

Hola,excelente aporte.
pueden publicar el WorkFlow para reusarlo...