Tarea I: Creando una oficina sin papeles

De Egeasy
Saltar a: navegación, buscar

Desarrollar con egeasy 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 almacenará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 el que almacenarlos.

[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 las 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 Subvenciones] 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 habitación 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 de 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 para solicitar una beca, el sistema de información generará un Expediente de beca único y se registrará la entrada, que además estará asociada al expediente mediante el campo vínculo [Solicitud]. A partir de este momento, toda la información que genere el proceso tendrá asociado un Expediente de beca, por lo que el maintarget del proceso Solicitud de beca es el expediente creado.

Por tanto, una vez lanzada la tarea raíz y empezada la ejecución el método RegistrarEntrada, habrá que crear un expediente de beca y registrar la entrada recibida lanzando las tareas correspondientes desde el método y definiéndolas:

metodo RegistrarEntrada();
    var
inicio
    $lanzar("Registrar expediente de beca");
    $lanzar("Registrar entrada");
fin
La función $lanzar, lanza una tarea cuyo nombre debemos 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 será creado por la propia tarea, aunque veremos que en posteriores definiciones sí tendremos que incluir un target como parámetro de entrada. Además, también es posible indicar la habitación en la cuál un usuario podrá realizar la tarea. En caso de no especificarla, se tomará como habitación la definida en la tarea raíz, 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 indicamos el objeto de 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].

Por tanto, al arrancar esta tarea se creará 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 una vez se finalice la tarea. En nuestro caso, se sellará el campo timbre que existe en el expediente y además se guardará el objeto. Para que entendamos bien las instrucciones empleadas en el atributo Al_finalizar.Codigo, es necesario conocer la propiedad [&Destino] de una tarea.

Esta propiedad permite acceder al target actual de una tarea, que en el caso de Registrar expediente de beca, es un Expediente de beca. Una vez accedido al target, 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 se realiza en nuestro caso. Con la función $sellar, sellamos el campo timbre, y con la función $guardar, guardamos el objeto.

Una vez registrado un nuevo expediente, procederemos a registrar la entrada de petición de beca mediante la tarea Registrar entrada. La diferencia que podemos observar respecto a la tarea anterior es la inclusión de los atributos destino.definicion y destino.valor.

¿Y por qué ahora sí están incluídos? Esto es debido a que esta tarea no va a registrar un Expediente de beca, sino que registrará una Entrada, aunque el objeto referencia de la tarea sí seguirá siendo el Expediente de beca creado anteriormente.

Además, al finalizar la tarea ejecutaremos el mismo código que la tarea anterior, con la diferencia de que, en esta ocasión, la propiedad [&Destino] accederá a un objeto de tipo Entrada, que es el target de esta tarea. ¿Y el atributo destino.valor?

Como ya explicamos en la definición de la tarea raíz Solicitud de beca, utilizaremos la función $crear en este atributo, para indicar la colección donde se va a guardar el objeto del tipo definido en el atributo destino.definicion, es decir, un objeto de tipo Entrada.


Una vez realizada esta primera fase, volvemos a fijarnos en el diagrama, y vemos que una vez la Entrada es recibida, registrada, y creado su Expediente de beca, 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 en el proceso, 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 introducidos, tanto en el contenedor Entrada como en el método, para comentarlos posteriormente:
[Sí o No] es enumerado
    valores
        "Sí",
        "No"
fin
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 implementación de nuestro método, las cuales nos permitirán almacenar en ellas un recurso del mismo tipo que el definido para la variable. La variable lógica documentacion_incompleta, que inicializamos a "verdadero", la utilizaremos para controlar la salida del bucle que se ocupa de los requerimientos de documentación, y como consecuencia de nuevas entradas. Dicha salida se producirá cuando el campo [Documentación 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, la almacenamos en la variable de tipo tarea TareaRegistroEntrada. Esto nos va a permitir acceder al target de la tarea mediante la propiedad [&Destino] en cualquier momento del código, ya que la tarea quedará almacenada en la variable. En este caso, el objeto es de tipo Entrada, por lo que podremos acceder al campo [Documentación completa] y realizar la consulta.

Una vez la documentación esté completa, el usuario modificará el campo [Documentación completa] asignándole el valor "Sí", de manera que saldremos del bucle. En caso contrario, lanzaremos la tarea encargada de elaborar un requerimiento, que a su vez tendrá que ser firmada, lanzando la tarea correspondiente para dicha firma.

Respecto a las tareas Elaborar requerimiento y Firmar requerimiento, es necesario tener en cuenta lo siguiente:

Al igual que en el lanzamiento de las demás tareas, la tarea Elaborar requerimiento también es asignada a una variable, en este caso, llamada ElaborarRequerimiento. A continuación, se lanza la tarea Firmar requerimiento, pero esta vez con un nuevo parámetro. Este parámetro corresponde al target de la tarea anterior, y lo indicamos como parámetro utilizando la variable ElaborarRequerimiento para acceder a la tarea junto con la propiedad [&Destino] para acceder a su target. Esto lo realizamos porque la tarea Firmar requerimiento no va a crear ningún target, sino que firmará el campo firma que se encuentra en el objeto Requerimiento de documentación creado en la tarea anterior. Por tanto, este objeto o target tendrá que ser pasado como parámetro a la tarea Firmar requerimiento.

Hay dos instrucciones que no hemos comentado aún. Son exactamente las dos instrucciones anteriores a la consulta del campo [Documentación 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 último 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 cada 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];
    -localizacion = [Datos generales];
    -Al_finalizar.Codigo = "$firmar([&Destino]->[Datos generales].[Firma del escrito]); $guardar([&Destino]); ";
fin

Cabe comentar un atributo que hasta ahora no hemos tenido que utilizar. Se trata del atributo localizacion. En él indicaremos una componente que queramos activar al iniciar la tarea, en principio, para su edición. En este caso, activamos la componente [Datos generales] del contenedor Requerimiento de documentación, que es donde está incluído el campo firma que vamos a editar en esta tarea. En caso de no hacerlo, no podríamos realizar la firma al ejecutar el código {{STR|"$firmar([&Destino]->[Datos generales].[Firma del escrito]).

Una vez hemos analizado ya varias definiciones de tareas, nos damos cuenta que el aspecto más importante a la hora de definir una tarea es tener muy claro el target con el que va a trabajar. Es decir, saber si el target será creado por la propia tarea o si, por el contrario, trabajará con un target ya creado.

En caso de crear uno nuevo utilizaremos los atributos destino.definicion y destino.valor para especificar el tipo del objeto y el lugar donde se almacenará. En caso de utilizar uno creado por tareas anteriores, tendremos que incluir el target de la tarea anterior como parámetro de la nueva tarea. Esto lo conseguimos, como ya hemos visto, utilizando una variable en la cual almacenamos la tarea que nos interese, y con la propiedad [&Destino] referenciamos a su target.

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 hemos verificado que la documentación de una solicitud está completa, pasamos a lanzar la tarea Comprobar documentación. Esta tarea abrirá la última Entrada que referencia el campo vínculo [Solicitud] de un expediente concreto 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, 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 (Registro de entrada y salida), 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 Comprobar documentación:

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
        ...
        ...      //Bucle
        ...
    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 tratarían la elaboración de una resolución de beca, positiva o negativa, 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
        ...
        ...      //Bucle
        ...
    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
Consultamos 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, de forma que tendrán que ser pasados por parámetro en dichas tareas. Una vez realizadas las dos firmas del documento generado, se creará un objeto de tipo Salida que se registrará en el Registro de Entrada y 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
        ...
        ...      //Bucle
        ...
    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

Crear nuevos perfiles de usuario

Una vez tenemos implementado nuestro workflow, necesitamos definir nuevos roles puesto que los que teníamos definidos anteriormente han quedado desfasados.

Definiremos un tipo de rol por cada oficina de nuestra organización:

tipo [Permisos comunes] es rol
    accede [Libro de entrada]: abrir;
    accede [Libro de salida]: abrir;
    accede [Fichero de terceros]: abrir;
    accede [Registro de documentación]: abrir;
    accede [Expedientes de beca]: abrir;
    accede [Fichero de trabajadores]: abrir;
    accede [Oficina de recursos comunes]: entrar;
    accede [Registro de entrada y salida]: entrar;
fin
tipo [Usuario Oficina del Registro] es [Permisos comunes]
    accede [Entrada]: crear;
    accede [Expediente de beca]: crear;
    accede [Salida]: crear;
    accede [Tercero]: crear;
    accede [Trabajador]: crear;
    accede [Requerimiento de documentación]: crear;
    realiza [Registrar entrada]
    realiza [Elaborar requerimiento]
    realiza [Firmar requerimiento]
    realiza [Registrar salida de documentación]
    firma [Requerimiento de documentación]: [Datos generales].[Firma del escrito];
fin
tipo [Usuario Oficina de Servicio de Ayudas y Subvenciones] es [Permisos comunes]
    accede [Entrada]: modificar;
    accede [Expediente de beca]: abrir;
    accede [Tercero]: abrir;
    accede [Trabajador]: abrir;
    accede [Resolución positiva]: modificar;
    accede [Resolución negativa]: modificar;
    accede [Oficina de Ayudas y Becas]: entrar;
    realiza [Comprobar documentación]
    realiza [Elaborar resolución positiva]
    realiza [Elaborar resolución negativa]
    realiza [Firmar propuesta de resolución]
    firma [Resolución positiva]: [Datos generales].[Firma de la propuesta];
    firma [Resolución negativa]: [Datos generales].[Firma de la propuesta];
fin
tipo [Usuario Oficina de la Dirección] es rol
    accede [Resolución positiva]: modificar;
    accede [Resolución negativa]: modificar;
    accede [Oficina de la Dirección]: entrar;
    realiza [Firmar resolución]
    firma [Resolución positiva]: [Datos generales].[Firma de la resolución];
    firma [Resolución negativa]: [Datos generales].[Firma de la resolución];
fin

Una vez definidos, probaremos el proceso creado utilizando el egExplorer. Pero para ello, tendremos que crear los usuarios correspondientes para poder acceder al centro. Esto lo haremos mediante la herramienta egAdmin, cuyos pasos podemos seguir en el siguiente tutorial.

Cuando tengamos los usuarios creados, sería interesante crear un proceso Solicitud de beca e ir lanzando sus correspondientes tareas. En el momento que sea necesario cambiar de usuario para que una tarea pueda ser lanzada, cerraremos el egExplorer y accederemos nuevamente a él pero esta vez con un usuario que nos permita lanzar la siguiente tarea.

En caso de necesitar documentación sobre los roles, podemos acceder a la tarea F realizada anteriormente.

Siguiente tarea

Véase también