Tarea I: Creando una oficina sin papeles

De Egeasy
Revisión del 14:27 11 mar 2009 de Irodriguez (Discusión | contribuciones) (Evolucionando el ''workflow'')

Saltar a: navegación, buscar

Construir una aplicación paso a paso

Procedimiento de concesión de becas


Hasta ahora, los usuarios del Registro utilizan el software sólo para introducir o consultar datos, sin realizar ningún trámite ni llevar a cabo un procedimiento administrativo.

Supongamos que la organización ofrece becas para la realización de estudios en el extranjero. Estas becas las gestiona el Servicio de Ayudas y Subvenciones. Los interesados deben presentar las solicitudes en el Registro de Entrada y Salida. Un auxiliar del Registro revisa la documentación y, en caso de faltar algo, elabora un requerimiento para el interesado. Este requerimiento debe firmarlo el jefe de servicio del Registro.

Una vez la documentación esté completa, se remite al Servicio de Ayudas y Subvenciones quien resuelve la beca por el procedimiento de concurrencia sin concurso; es decir, que todos aquellos interesados que cumplan con los requisitos recibirán la beca.

Al recibir la documentación, un técnico del Servicio de Ayudas y Subvenciones comprueba la documentación para ver si el interesado cumple con los requisitos. A continuación, procede a elaborar resolución positiva (o negativa). La resolución la deben firmar el jefe del Servicio de Ayudas y Subvenciones y el director de la organización.

Una vez firmada, la resolución se remite al Registro, donde un auxiliar se encarga de darle salida. El procedimiento se puede resumir en el siguiente diagrama.



¿Qué nos hace falta?

Para implementar este workflow, primero debemos identificar los ítems de información y, a continuación, definirlos en el sistema. Analizando, vemos que necesitamos cuatro objetos diferentes:

  • Entrada, para las tareas de Registrar entrada de documentación y Comprobar documentación. Este tipo ya lo tenemos definido.
  • Requerimiento, para las tareas de Elaborar requerimiento y Firmar requerimiento.
  • Resolución positiva y Resolución negativa, para las tareas de Elaborar resolución positiva/negativa, Firmar propuesta de resolución, Firmar resolución y Registrar salida de documentación.

Además, todos los documentos relacionados con una solicitud deben almacenarse en alguna parte. Para ello, definiremos también el tipo Expediente de beca.

Por último, debemos definir dos nuevas habitaciones, donde se enviarán sus tareas específicas: la Oficina de Ayudas y Subvenciones y la Oficina de dirección.

Definir los escritos

Definimos el requerimiento de documentación con dos componentes: una componente escrito, para la plantilla del documento, y una componente formulario, para los campos firma.

tipo [Requerimiento de documentación] es contenedor
    [Escrito] es documento
        -plantilla_documento = "Req 001.rtf";
    fin

    [Datos generales] es formulario
        [Firma del escrito] es firma
    fin
fin

Hacemos lo mismo para las resoluciones. En este caso, como las resoluciones la firman dos personas, debemos incluir dos campos firma, uno para la propuesta y otro para la resolución.

tipo [Resolución positiva] es contenedor
    [Escrito] es documento
        -plantilla_documento = "Res 001.rtf";
    fin

    [Datos generales] es formulario
        [Firma de la propuesta] es firma
        [Firma de la resolución] es firma
    fin
fin
tipo [Resolución negativa] es contenedor
    [Escrito] es documento
        -plantilla_documento = "Res 002.rtf";
    fin

    [Datos generales] es formulario
        [Firma de la propuesta] es firma
        [Firma de la resolución] es firma
    fin
fin

Definir el Expediente de beca

Cada vez que se inicie un trámite de beca, abriremos un expediente en el que se recogerá toda la documentación relacionada con el trámite. Este expediente tendrá un número (asignado automáticamente) que identificará el trámite y una fecha de alta que indicará la fecha en la que se inició el trámite. Asimismo, tendrá un vínculo a la Entrada que dio lugar al trámite.

Crearemos el expediente con dos componentes: una componente para el formulario de datos y otra para la colección en la que se almacerán todos los documentos.

tipo [Expediente de beca] es contenedor
    [Datos generales] es formulario
        [Nº de expediente] es timbre
            -certificado.valor = [&Valor_secuencia];
            -certificado.secuencia.nombre = "STR$EXPEDIENTE"; 
            -certificado.secuencia.longitud = 5; 
        [Fecha de alta] es fecha
        [Solicitud] es vinculo
            -vinculo.definicion = [Entrada];
            -vinculo.etiqueta = [Datos generales].[Número] + " (" 
                                       + [Datos generales].[Remitente]->[Datos generales].[Nombre/Razón social] 
                                       + " " +  [Datos generales].[Remitente]->[Datos generales].[Apellidos] 
                                       + ")";
            -vinculo.valores = $matriz([Libro de entrada].[Contenido]);
    fin

    [Documentos] es coleccion
        -nombre_tabla = "TC$EXPEDIENTE_BECA";

        contiene [Requerimiento de documentación]
        contiene [Resolución positiva]
        contiene [Resolución negativa]

        columna [Nombre]
            -columna_bd.nombre = "DOCUMENTO";
            -origen = [&Nombre];
    fin
fin

Por último, necesitamos almacenar los expedientes en alguna parte. Para ello, crearemos un objeto del sistema en los que almacenarlo.

[Expedientes de beca] es contenedor
    [Contenido] es coleccion
        -nombre_tabla = "TC$EXPEDIENTES";

        contiene [Expediente de beca]

        columna [Nº de expediente]
            -columna_bd.nombre = "NUMERO";
            -origen = [Datos generales].[Nº de expediente];
        columna [Fecha de alta]
            -columna_bd.nombre = "FECHA_ALTA";
            -origen = [Datos generales].[Fecha de alta];
    fin
fin

Definir las oficinas

Tan sólo nos queda definir la oficinas y ubicar los recursos necesarios en cada una. En nuestro caso, se reduce sólo al estante de expedientes, ya que es el único recurso común a las tres oficinas.

[Oficina de Ayudas y Becas] es habitacion
    -publico = falso;

    ubicado [Expedientes de beca] 
        -lugar = "Estantes";
fin

[Oficina de la dirección] es habitacion
    -publico = falso;

    ubicado [Expedientes de beca] 
        -lugar = "Estantes";
fin

¿Cómo funciona el motor de workflow?

Hasta ahora nos hemos centrado en definir los ítems de información que nos iban a hacer falta para llevar a cabo el procedimiento de concesión de beca. En los próximos apartados veremos cómo implementar el flujo de trabajo, pero primero explicaremos cómo funciona el motor de workflow de la plataforma.

En egeasy, los procedimientos administrativos se definen en dos pasos. En primer lugar, debe definirse el flujo de tareas. Esta definición se hace en un fichero con extensión nmt. Los ficheros nmt son ficheros de texto plano que se crean en la carpeta Data del proyecto. Una vez definido el flujo de tareas, procederemos a definir los atributos de cada tarea: ítem de trabajo, código que se ejecuta al terminar la tareas, ... Estas definiciones se realizan en ficheros ndf, como hemos hecho con el resto de los recursos.

Comenzaremos con el flujo de tareas. Lo primero que debemos hacer es crear, en la carpeta Data, el fichero concesion_beca.nmt. A continuación, abrimos el fichero con el editplus.

Los ficheros nmt se componen de métodos. Por hacer un símil, un método sería equivalente a un procedimiento de PASCAL. Cada método lanza tareas, invoca a otros métodos y ejecuta sentencias en ODL. Adicionalmente, puede tener parámetros de E/S y variables locales.

Aquí tenemos un ejemplo.

metodo RegistrarEntrada();
    var
        TareaRegistro: tarea;
inicio
    TareaRegistro = $lanzar("Registrar entrada");
    TareaRegistro.[&Destino]->[Datos generales].[Asunto] = "Esto es una prueba";
    $guardar(TareaRegistro.[&Destino]);
fin

En este segmento de código hemos definido el método RegistrarEntrada. A continuación, hemos definido la variable TareaRegistro de tipo tarea. Después hemos definido la secuencia de tareas.

Cuando comienza la ejecución de un método, el motor de workflow posiciona el cursor en la primera línea del método que está justo después de inicio. Comienza a ejecutar línea por línea hasta que alguna de las sentencias lanza una tarea. Entonces, el sistema crea una nueva tarea, le asigna un ítem de trabajo y establece el estado de la tarea a pendiente. La ejecución del método queda detenida hasta que se finalice la tarea. En nuestro ejemplo, al iniciarse la ejecución del método se lanzaría la tarea Registrar entrada.

Cualquier usuario con los permisos suficientes puede ir a la bandeja de Tareas disponibles y comenzar la tarea. Cuando lo hace, la plataforma abre el ítem de trabajo asignado y cambia el estado de la tarea a realizándose.

Cuando el usuario finaliza la tarea, el sistema cambia el estado a terminada y retoma la ejecución del método que invocó a la tarea. En nuestro ejemplo, asignaría a la variable TareaRegistro la tarea que se acaba de terminar. A continuación ejecutaría las siguientes líneas de código, que modifican el ítem de trabajo de la tarea para después almacenarlo.

Un método termina de ejecutarse cuando el cursor alcanza la palabra fin.

¿Cómo comienza a ejecutarse un método?

Todo proceso tiene un punto de entrada que lanza a ejecutar la primera línea del primer método. Este punto de entrada es un tipo de tarea que se define como raíz en los ficheros de definiciones ndf.

Para cada proceso que exista en nuestro sistema de información, tendremos que definir una tarea, llamémosla inicializadora del proceso.

Veamos a continuación la definición de esta tarea, que se corresponde con el proceso Solicitud de beca:

tipo [Solicitud de beca] es tarea
    -descripcion = "Proceso que se encarga de realizar la resolución de una solicitud de beca";
    -fuente.definicion = [Registro de entrada y salida];
    -destino.definicion = [Expediente de beca];
    -destino.valor = $crear([Expedientes de beca].[Contenido]);
    -Al_Comenzar.Nombre = "Metodos\concesion_beca.RegistrarEntrada";
    -es_raiz = verdadero;
fin

La forma de indicar que la tarea Solicitud de beca inicia un proceso de nuestro sistema de información es mediante el atributo lógico es_raiz. Dicho atributo tiene asignado por defecto el valor falso, de forma que poniéndolo a verdadero, conseguiremos que dicha tarea inicie un proceso que será lanzado por un usuario.

Ahora bien, ¿sobre qué contenedor queremos que se lance la tarea?

Siempre que lanzamos una tarea, es necesario indicar sobre qué contenedor podremos lanzarla. Para ello, ODL proporciona un atributo llamado fuente.definicion. En el caso de una tarea raíz, se indicarán aquellas habitaciones a las que habrá que acceder para poder iniciar la tarea raíz. Por eso hemos indicado una habitacion en vez de un contenedor en la definición de Solicitud de beca.

Esto significa que el usuario podrá lanzar la tarea Solicitud de beca una vez haya accedido a la habitación Registro de entrada y salida. En posteriores definiciones de tareas, veremos que especificaremos un contenedor en vez de una habitación en el atributo fuente.definicion.

El método a ejecutar una vez se lance la tarea, lo indicaremos en el atributo Al_Comenzar.Nombre, que como vemos, tiene asignado el método creado anteriormente RegistrarEntrada. La manera de indicar el método es añadiendo la ruta del fichero donde está incluído a partir de la carpeta Data del modelo, seguido de un punto y el nombre del método.

Por último, indicaremos en el atributo destino.definicion lo que se conoce como maintarget de un proceso, es decir, aquel contenedor que se asociará al proceso durante su ejecución.

El maintarget de Solicitud de beca será un contenedor de tipo Expediente de beca. ¿Por qué? Porque las tareas que se lancen dentro de este proceso y la información que se genere se almacenará en un Expediente de beca.

Además, no sólo queremos indicar el maintarget del proceso Solicitud de beca, sino que también queremos crear el expediente una vez se inicie el proceso. Para ello, utilizaremos la función $crear definida en la librería de funciones de ODL, que nos permite crear un objeto, indicándole la colección donde se va a almacenar. El tipo de objeto será el definido en destino.definicion. El objeto devuelto por $crear se asignará al atributo destino.valor.

Interpretación del diagrama de flujo

Antes de meternos de lleno a desarrollar el workflow, vamos a estudiar el diagrama de flujo de información de concesión de becas facilitado al comienzo de este artículo.

Es recomendable que abramos el diagrama ampliado en una pestaña nueva del navegador y lo mantengamos hasta el final de este artículo, de manera que podamos ir fijándonos en él a medida que vamos avanzando en el desarrollo del workflow.

Fijándonos en el diagrama, vemos que el flujo de trabajo está dividido en tres secciones, donde cada una de ellas equivale a una oficina de la organización. Dentro de cada oficina existen una serie de estados, que equivalen a las diferentes tareas que se pueden lanzar. Por tanto, habrá que implementar una tarea por cada estado que aparece en el diagrama.

Si las tareas equivalen a los estados, el flujo de trabajo equivaldría a las líneas de transición que nos permiten cambiar de estado. En nuestro método RegistrarEntrada tendremos que implementar este flujo de trabajo.

Podemos ver que para lanzar ciertas tareas, habrá que evaluar una condición. Por ejemplo, para lanzar la tarea ComprobarDocumentacion será necesario evaluar si la documentación necesaria está completa. De no ser así, se lanzaría la tarea ElaborarRequerimiento.

Por tanto, en la implementación de nuestro método tendremos que plasmar el camino de datos que observamos en el diagrama.

Además, el diagrama nos indica a qué oficina debe acceder un usuario para realizar cada una de las tareas, teniendolo en cuenta a la hora de definir los roles.

Evolucionando el workflow

Antes de meternos de lleno en la elaboración del workflow, hagamos un resumen de aquellos ficheros y nuevas definiciones que hemos creado.

Por un lado, para poder desarrollar una concesión de beca, hemos definido un expediente de beca, un registro de expedientes de beca, un requerimiento de documentación y una resolución positiva y negativa de la concesión de una beca con la elaboración de sus respectivos documentos. Todas ellas son definiciones de tipo contenedor, y serán los ítems con los que trabajaremos a lo largo de todo el flujo de información. Además, hemos definido una oficina de ayudas y subvenciones y una oficina de dirección. Todas estas definiciones las hemos realizado en el fichero Main.ndf en la carpeta #Source.

En esta misma carpeta, se encuentra el fichero tareas.ndf donde ya hemos definido la tarea raíz Solicitud de beca y donde vamos a definir el resto de tareas.

Por último, en la carpeta Data\Metodos hemos creado el fichero concecion_beca.nmt donde hemos incluído un ejemplo del método RegistroEntrada.

Una vez hecho este resumen, ahora sí que vamos a desarrollar nuestro proceso Solicitud de beca. Mostraremos paso a paso el código a introducir siguiendo el diagrama de flujo de información. Iremos alternando la implementación del método y de las tareas según lo vayamos necesitando.


Cuando se produce una Entrada en una concesión de beca, se creará un Expediente de beca único y se registrará esa entrada que además estará asociada al expediente creado mediante el campo vínculo [Solicitud]. A partir de ese momento, toda la información que genere este proceso tendrá asociado un Expediente de beca, por ello el maintarget del proceso Solicitud de beca será el expediente creado. Por tanto, una vez lanzada la tarea Solicitud de beca y se empeciece a ejecutar el método RegistrarEntrada, habrá que crear un expediente de beca y registrar la entrada recibida:

metodo RegistrarEntrada();
    var
inicio
    $lanzar("Registrar expediente de beca");
    $lanzar("Registrar entrada");
fin
La función $lanzar, lanza una tarea cuyo nombre deberemos pasar por parámetro, como vemos en el código. En este caso, no pasamos por parámetro ningún ítem (target) a la tarea, ya que lo creará la propia tarea, pero veremos que en posteriores definiciones sí tendremos que hacerlo. Además también es posible indicar la habitación o habitaciones en la cuál un usuario podrá comenzar la tarea. En caso de no especificarla, se tomará como habitación la definida en la tarea raiz, que en nuestro caso es Registro de entrada y salida.

Definamos entonces dichas tareas en nuestro fichero tareas.ndf:

tipo [Registrar expediente de beca] es tarea
    -fuente.definicion = [Expediente de beca];
    -Al_finalizar.Codigo = "$sellar([&Destino]->[Datos generales].[Nº de expediente]); $guardar([&Destino]); ";
fin
tipo [Registrar entrada] es tarea
    -fuente.definicion = [Expediente de beca];
    -destino.definicion = [Entrada];
    -destino.valor = $crear([Libro de entrada].[Contenido]);
    -Al_finalizar.Codigo = "$sellar([&Destino]->[Datos generales].[Número]); $guardar([&Destino]); ";
fin

En la tarea Registrar expediente de beca, el atributo fuente.definicion que hay definido ya lo conocemos. En él indicaremos la referencia de la tarea. En el atributo destino.definicion, que no aparece, deberíamos indicar el contenedor (target, ítem) con el que va a trabajar la tarea, pero este atributo, si no se especifica, asumirá como destino el contenedor definido en fuente.definicion. Equivaldría a poner destino.definicion = [Expediente de beca] en este caso.

Por tanto, al arrancar esta tarea, se abrirá un expediente nuevo. El atributo Al_finalizar.Codigo nos permite invocar un método o directamente asignarle instrucciones en forma de ristra, que se ejecutarán en tiempo de ejecución. En nuestro caso, hemos indicado que al finalizar la tarea, se selle el campo timbre que existe en el expediente y además se guarde el objeto. Para que entendamos bien las instrucciones que realizan estas operaciones, es necesario conocer la propiedad [&Destino] de una tarea.

Esta propiedad permite acceder al target actual de la tarea, que en la tarea que nos ocupa, es un Expediente de beca. Una vez en el contenedor, podremos acceder a otros componentes que estén definidos en él, como por ejemplo, a un campo timbre incluído en la definición de un formulario, que es exactamente lo que queremos realizar. Con la función $sellar, sellaremos el campo timbre, y con la función $guardar, guardaremos el objeto, accediendo a él una vez más mediante la propiedad [&Destino].

Una vez registrado un nuevo expediente, procederemos a registrar una entrada de petición de beca. Si nos fijamos en la tarea Registrar entrada vemos que ya hay varios atributos que nos suenan. La diferencia que podemos observar es la inclusión de los atributos destino.definicion y destino.valor. ¿Y por qué ahora sí están incluídos? Pues porque esta tarea no va a registrar un expediente de beca, sino que registrará una entrada, y por eso le asignamos ese tipo al destino de la tarea. En caso de no hacerlo, volvería a hacer lo mismo que la tarea anterior, ya que la referencia de esta tarea también es un Expediente de beca. Además, al finalizar la tarea, ejecutaremos el mismo código que acabamos de explicar. Pero esta vez, con la propiedad [&Destino] accederemos al contenedor con el que trabaja la tarea, que es una Entrada. ¿Y el atributo destino.valor? Como ya explicamos en la definición de la tarea raiz Solicitud de beca, utilizaremos la función $crear, a la que indicaremos la colección donde se va a guardar el objeto del tipo definido en el atributo destino.definicion. Son dos atributos dependientes uno del otro.


Una vez llegados a este punto, volvemos a fijarnos en el diagrama, y vemos que una vez la entrada es recibida, registrada, y creado su expediente, el siguiente paso, sería comprobar la documentación. Para ello, es necesario que la documentación entregada por la persona que realiza la petición de la beca esté completa. En caso de no ser así, se generará un documento de requerimiento, que deberá ser firmado, dando lugar a posibles nuevas entradas, pero con un expediente de beca ya creado. Esto se producirá tantas veces como requerimientos de documentación se puedan dar. Una vez no falte ningún tipo de documentación, se lanzará la tarea Comprobar documentación.

Pero, ¿y cómo podemos saber si en la solicitud de una beca falta documentación?

Para ello, hemos modificado la definición del contenedor Entrada, añadiendo simplemente un campo tabla para registrar la documentación y un campo de tipo texto llamado [Documentación completa?].

Veamos primero los cambios, tanto en el contenedor Entrada como en el método, para comentarlos posteriormente:
tipo [Entrada] es contenedor
    [Datos generales] es formulario
        ...
        ...
        ...
        [Documentación presentada] es tabla
            [Documento] es texto
        fin
        [Documentación completa?] es texto
            -apariencia.desplegable = verdadero;
            -edicion.seleccion = verdadero;
            -edicion.valores = $matriz([Sí o No]);
    fin
fin
metodo RegistrarEntrada();
    var
        TareaRegistroBeca: tarea;
        TareaRegistroEntrada: tarea;
        ElaborarRequerimiento: tarea;
        ElaborarResolucion: tarea;
        documentacion_incompleta: logico;
inicio
    documentacion_incompleta = verdadero;
    TareaRegistroBeca = $lanzar("Registrar expediente de beca");
    mientras documentacion_incompleta
        TareaRegistroEntrada = $lanzar("Registrar entrada");
        TareaRegistroBeca.[&Destino]->[Datos generales].[Solicitud] = TareaRegistroEntrada.[&Destino];
        $guardar(TareaRegistroBeca.[&Destino]);
        si (TareaRegistroEntrada.[&Destino]->[Datos generales].[Documentación completa?] = "Sí")
            documentacion_incompleta = falso;
        sino
            ElaborarRequerimiento = $lanzar("Elaborar requerimiento");
            $lanzar("Firmar requerimiento", ElaborarRequerimiento.[&Destino]);
        fin
    fin
fin

Vemos que en la definición de Entrada hemos incluído los campos que comentamos para comprobar la documentación.

También podemos observar que hay una serie de variables declaradas en la definición de nuestro método, que nos permitirán almacenar un recurso del tipo de la variable. La variable lógica documentacion_incompleta, que inicializamos a "verdadero", la utilizaremos para controlar la salida del bucle. Dicha salida se producirá cuando el campo [Documentacion completa?] de la Entrada actual tenga valor "Sí", asignándole "falso" a documentacion_incompleta.

¿Y cómo consultamos dicho campo?

Al lanzar la tarea Registrar entrada, ésta la almacenamos en la variable de tipo tarea TareaRegistroEntrada. Esto nos va a permitir acceder al target de la tarea mediante la propiedad [&Destino], que en este caso, es un objeto de tipo Entrada, por lo que podremos acceder al campo [Documentacion completa?] y realizar la consulta. En caso de tener la documentación completa, saldremos del bucle. En caso contrario, lanzaremos la tarea encargada de elaborar un requerimiento, que a su vez tendrá que ser firmada, lanzando también su respectiva tarea.

Respecto a la ejecución de las tareas Elaborar requerimiento y Firmar requerimiento es necesario hacer un inciso. Al igual que en el lanzamiento de las demás tareas, la tarea Elaborar requerimiento es asignada a una variable de tipo tarea. Y al igual que en las anteriores, esto lo hacemos para poder acceder al objeto con el que trabaja la tarea, mediante la propiedad [&Destino]. A continuación, se lanza la tarea Firmar requerimiento, pero esta vez con un nuevo parámetro. Este parámetro corresponde al target con el que queremos que trabaje la tarea, que será el contenedor creado en la tarea Elaborar requerimiento, que será de tipo [Requerimiento de documentación]. Por tanto, la tarea Firmar requerimiento no creará ningún objeto, sino que lo obtendrá mediante la propiedad ElaborarRequerimiento.[&Destino].

Hay dos instrucciones que no hemos comentado aún. Son exactamente las dos instrucciones anteriores a la consulta del campo [Documentacion completa?].

Como ya sabemos, nuestra definición de tipo contenedor Expediente de beca tiene un campo vínculo, que referencia a la última Entrada que se haya almacenado en el expediente. Para que esto suceda, es necesario que después de registrar una nueva entrada se modifique este campo vínculo, para que referencie al nuevo objeto de tipo Entrada. Esto lo conseguimos utilizando dos variables de tipo tarea, una para la tarea Registrar expediente de beca y otra para Registrar entrada. En cada variable almacenamos una de las dos tareas, de manera que nos permitan acceder al target de cada una de ellas. Al campo vínculo TareaRegistroBeca.[&Destino]->[Datos generales].[Solicitud] le asignaremos el target de la tarea Registrar entrada, TareaRegistroEntrada.[&Destino]. Una vez asignada la Entrada al campo vínculo, se guardará el objeto para aplicar los cambios realizados en el objeto.

Es necesario realizar estas dos acciones dentro del bucle y antes de realizar la comprobación del campo [Documentación completa?] del objeto Entrada, ya que, en caso de no hacerlo, no se estará verificando el campo [Documentación completa?] de la nueva Entrada, sino de la anterior, o de ninguna, en caso de que estemos tratando una primera entrada.

Una vez analizado el nuevo código introducido en el método, veamos la definición de las nuevas tareas que aparecen; Elaborar requerimiento y Firmar requerimiento:

tipo [Elaborar requerimiento] es tarea
    -fuente.definicion = [Expediente de beca];
    -destino.definicion = [Requerimiento de documentación];
    -destino.valor = $crear([Documentos]);
fin
tipo [Firmar requerimiento] es tarea
    -fuente.definicion = [Expediente de beca];
    -destino.definicion = [Requerimiento de documentación];
    -destino.valor = $crear([Documentos]);
    -Al_finalizar.Codigo = "$firmar([&Destino]->[Datos generales].[Firma del escrito]); $guardar([&Destino]); ";
fin

La tarea Elaborar requerimiento creará un objeto de tipo [Requerimiento de documentación] que almacenará en la colección Documentos definida en el contenedor Expediente de beca. En la tarea Firmar requerimiento recibiremos el target de la tarea Elaborar requerimiento, es decir, un objeto de tipo Requerimiento de documentación, que evidentemente coincide con el valor del atributo destino.definicion. El campo firma de éste, será firmado al finalizar la tarea. Vemos además que la referencia de todas las tareas que estamos definiendo en el atributo fuente.definicion es el Expediente de beca creado en el proceso Solicitud de beca.

Finalizando el workflow

Siguiendo con el flujo de trabajo, pasamos ahora a la siguiente oficina de nuestra organización, Servicio de Ayudas y Subvenciones.

Una vez la documentación de una solicitud esté completa, pasaremos a lanzar la tarea Comprobar documentación. Esta tarea abrirá la última Entrada que referencia el campo vínculo [Solicitud] del expediente y analizará la documentación entregada para elaborar una resolución positiva, en caso de cumplir los requisitos, o negativa, en caso de no cumplirlos. El target de esta tarea, tendrá que ser pasado como parámetro de la tarea, que al ser la última Entrada registrada, podremos acceder a él utilizando la variable TareaRegistroEntrada. Pero, hay que tener en cuenta otro aspecto a la hora de lanzar esta tarea.

Hasta ahora, no nos hemos preocupado de la oficina en la cual podíamos realizar las tareas. Esto ha sido así debido a que las tareas hasta ahora lanzadas compartían la oficina de la tarea raíz, y por tanto, no se especificaba como parámetro al lanzar una tarea. Pero ahora sí es necesario especificarlo, ya que hemos cambiado de oficina. La sintaxis para hacerlo es la siguiente:
$lanzar("nombre",target,[oficina])

Veamos el código a añadir en nuestro método y la implementación de la tarea:

metodo RegistrarEntrada();
    var
        TareaRegistroBeca: tarea;
        TareaRegistroEntrada: tarea;
        ElaborarRequerimiento: tarea;
        ElaborarResolucion: tarea;
        DocumentacionComprobada: tarea;
        documentacion_incompleta: logico;
inicio
    documentacion_incompleta = verdadero;
    TareaRegistroBeca = $lanzar("Registrar expediente de beca");
    mientras documentacion_incompleta
        ...
        ...
        ...
    fin
    DocumentacionComprobada = $lanzar("Comprobar documentación",TareaRegistroEntrada.[&Destino],[Oficina de Ayudas y Becas]);
fin
tipo [Comprobar documentación] es tarea
    -fuente.definicion = [Expediente de beca];
    -destino.definicion = [Entrada];
fin
En este caso, el usuario de la Oficina de Ayudas y Subvenciones analizará la documentación presentada y dejará constancia de dicho análisis especificando si es un caso favorable o desfavorable para la concesión de una beca.

Pero, ¿dónde deja constancia?

Para ello, hemos definido otro campo de tipo texto en la definición de contenedor Entrada llamado [Cumple los requisitos?]. Este será el campo donde se concretará si un solicitante cumple los requisitos. Veamos el código a incluir en la definición de Entrada:
tipo [Entrada] es contenedor
    [Datos generales] es formulario
        ...
        ...
        ...
        [Cumple los requisitos?] es texto
            -apariencia.desplegable = verdadero;
            -edicion.seleccion = verdadero;
            -edicion.valores = $matriz([Sí o No]);
    fin
fin

Siguiendo con el flujo de trabajo del diagrama, las siguientes tareas a lanzar serían para elaborar una resolución de beca, positivo o negativo, en función del valor que contenga el campo [Cumple los requisitos?]. Por tanto, habrá que consultar dicho campo para saber cuál de las tareas lanzar:

metodo RegistrarEntrada();
    var
        TareaRegistroBeca: tarea;
        TareaRegistroEntrada: tarea;
        ElaborarRequerimiento: tarea;
        ElaborarResolucion: tarea;
        DocumentacionComprobada: tarea;
        documentacion_incompleta: logico;
inicio
    documentacion_incompleta = verdadero;
    TareaRegistroBeca = $lanzar("Registrar expediente de beca");
    mientras documentacion_incompleta
        ...
        ...
        ...
    fin
    DocumentacionComprobada = $lanzar("Comprobar documentación",TareaRegistroEntrada.[&Destino],[Oficina de Ayudas y Becas]);
    si (DocumentacionComprobada.[&Destino]->[Datos generales].[Cumple los requisitos?] = "Sí")	
        ElaborarResolucion = $lanzar("Elaborar resolución positiva",[Oficina de Ayudas y Subvenciones]);
    sino
        ElaborarResolucion = $lanzar("Elaborar resolución negativa",[Oficina de Ayudas y Subvenciones]);
    fin
fin
En el código se refleja lo que hemos comentado. Se consulta el campo [Cumple los requisitos?] y en función de su valor se lanzará o bien la tarea Elaborar resolución positiva o Elaborar resolución negativa.

Ambas tareas crearán un target nuevo, que será o bien un objeto de tipo Resolución positiva o Resolución negativa. Dicho objeto será posteriormente utilizado como target por las tareas Firmar propuesta de resolución y Firmar resolución. Una vez realizadas las dos firmas del documento generado, se realizará registrará dicha resolución en el registro de salida:

tipo [Elaborar resolución positiva] es tarea
    -fuente.definicion = [Expediente de beca];
    -destino.definicion = [Resolución positiva];
    -destino.valor = $crear([Documentos]);
fin
tipo [Elaborar resolución negativa] es tarea
    -fuente.definicion = [Expediente de beca];
    -destino.definicion = [Resolución negativa];
    -destino.valor = $crear([Documentos]);
fin


metodo RegistrarEntrada();
    var
        TareaRegistroBeca: tarea;
        TareaRegistroEntrada: tarea;
        ElaborarRequerimiento: tarea;
        ElaborarResolucion: tarea;
        DocumentacionComprobada: tarea;
        documentacion_incompleta: logico;
inicio
    documentacion_incompleta = verdadero;
    TareaRegistroBeca = $lanzar("Registrar expediente de beca");
    mientras documentacion_incompleta
        ...
        ...
        ...
    fin
    DocumentacionComprobada = $lanzar("Comprobar documentación",TareaRegistroEntrada.[&Destino],[Oficina de Ayudas y Becas]);
    si (DocumentacionComprobada.[&Destino]->[Datos generales].[Cumple los requisitos?] = "Sí")	
        ElaborarResolucion = $lanzar("Elaborar resolución positiva",[Oficina de Ayudas y Subvenciones]);
    sino
        ElaborarResolucion = $lanzar("Elaborar resolución negativa",[Oficina de Ayudas y Subvenciones]);
    fin
    $lanzar("Firmar propuesta de resolución",ElaborarResolucion.[&Destino],[Oficina de Ayudas y Subvenciones]);
    $lanzar("Firmar resolución",ElaborarResolucion.[&Destino],[Oficina de la dirección]);
    $lanzar("Registrar salida de documentación");
fin


tipo [Firmar propuesta de resolución] es tarea
    -fuente.definicion = [Expediente de beca];
    -localizacion = [Datos generales];
    -Al_finalizar.Codigo = "$firmar([&Destino]->[Datos generales].[Firma de la propuesta]); $guardar([&Destino]); ";
fin
tipo [Firmar resolución] es tarea
    -fuente.definicion = [Expediente de beca];
    -localizacion = [Datos generales];
    -Al_finalizar.Codigo = "$firmar([&Destino]->[Datos generales].[Firma de la resolución]); $guardar([&Destino]); ";
fin
tipo [Registrar salida de documentación] es tarea
    -fuente.definicion = [Libro de salida];
    -destino.definicion = [Salida];
    -destino.valor = $crear([Contenido]);	
fin

Siguiente tarea

Véase también