sábado, 29 de octubre de 2011

AWE: Application Workflow Engine

En está entrada vamos a ver el nuevo (Nuevo desde la versión 8.48) framework para incluir Workflows dentro de nuestras aplicaciones.  

La gran ventaja que presenta este framework frente a la anterior tecnología de workflow presente en PEOPLESOFT,  es que después de implantar el workflow dentro de nuestro aplicativo, no es necesario realizar trabajo técnico adicional, ya que todo el mantenimiento y parametrización adicional del workflow se puede realizar a través de la PIA. 

Lo primero que vamos a hacer son los pasos que se deben realizar por un técnico para poder incluir el worflow dentro del aplicativo.   

Para nuestro ejemplo necesitamos una página donde vamos a registrar los diferentes equipos deportivos, supongamos que ya tenemos la página y se ve de la siguiente forma:






Digamos que a este componente deseamos agregarle la funcionalidad del workflow, que para cada equipo que se adicione a la base de datos debe pasar por un proceso de aprobación. 


El primer paso es agregar al registro principal de nuestro componente (PE_EQUIPOS) un campo que represente el estado del equipo. El campo debe permitir 3 valores:


P: Pendiente
A: Aprobado
R: Rechazado


Adicionalmente debemos crear un registro derived que contendrá 4 campos:


- Un campo que representará el botón Enviar el que permitira iniciar el proceso de aprobación del registro


- Un segundo campo que representará el botón de Aprobar que permitirá al aprobador aprobar el registro. 

- Un tercer campo que representará el botón de rechazar que permitirá al aprobador rechazar el registro. 

- Y un último campo que permitirá ingresar comentarios al momento de aprobar o rechazar un registro. 

Después de agregar estos campos la página de nuestro componente debe lucir de la siguiente forma:





El siguiente paso es crear el registro que permitirá llevar el control de los procesos de aprobación de cada uno de los equipos,  en este record (de tipo SQL TABLE) se almacena el rastreo del workflow que estamos definiendo.  El registro debe ser construido de la siguiente forma:

1. Debe tener todos los campos llave del record principal de nuestro componente (en nuestro caso PE_EQUIPOS y la llave sería PE_ID_EQUIPO)

2. Debe incluir el subrecord EOAW_XREF_SBR.



Ahora debemos crear un Application Class que permita manejar el proceso del workflow.  Esta clase permite básicamente controlar la actualización del estado del registro, o sea permite actualizarlo a Pendiente, Aprobado o Rechazado según sea el caso. 


Está clase debe ser una clase derivada de la clase base EOAW_CORE:ApprovalEventHandler y debe implementar los siguientes métodos:


1. OnProcessLaunch: En este método se actualiza el estado del registro a P para indicar que el proceso acaba de iniciar y que el registro se encuentra pendiente de aprobación 


2. OnHeaderApprove: En este método se actualiza el estado del registro a A para indicar que el registro se encuentra aprobado

3. OnHeaderDeny: En este método se actualiza el estado del registro a R para indicar que el registro se encuentra rechazado

La clase padre posee una propiedad llamada &appInst que nos permite acceder a algunos métodos y propiedades para distintos procesos, en nuestra clase ejemplo utilizamos el método &appInst.thread.SetAppKeys para obtener la llaves del registro para el cual se está realizando el proceso de Workflow, en nuestro caso PE_EQUIPOS y la llave PE_ID_EQUIPO. 

Por último la clase tiene un método privado cuya finalidad es ejecutar el UPDATE sobre el campo estado del registro PE_EQUIPOS el cual es utilizado desde los otros 3 métodos. 

A continuación podemos ver el código completo de la clase:

import EOAW_CORE:*;
import EOAW_CORE:ENGINE:*;

class PE_APPROVAL_HANDLER extends EOAW_CORE:ApprovalEventHandler
   method PE_APPROVAL_HANDLER();
   method OnProcessLaunch(&appInst As EOAW_CORE:ENGINE:AppInst);
   method OnHeaderApprove(&appinst As EOAW_CORE:ENGINE:AppInst);
   method OnHeaderDeny(&userinst As EOAW_CORE:ENGINE:UserStepInst);
private
   method updateProcessFlag(&status As string);
   instance Record &RecordEquipo;
   Constant &APPROVED = "A";
   Constant &DENIED = "D";
   Constant &PENDING = "P";
end-class;

method PE_APPROVAL_HANDLER
   %Super = create EOAW_CORE:ApprovalEventHandler();
   &RecordEquipo = CreateRecord(Record.PE_EQUIPOS);
end-method;

method updateProcessFlag
   /+ &status as String +/
   Local string &IdEquipo;
   
   &IdEquipo = &RecordEquipo.PE_ID_EQUIPO.Value;
   
   SQLExec(SQL.PE_EQUI_UPD_APPR_FLAG, &status, &IdEquipo);
   
end-method;

method OnProcessLaunch
   /+ &appInst as EOAW_CORE:ENGINE:AppInst +/
   /+ Extends/implements EOAW_CORE:ApprovalEventHandler.OnProcessLaunch +/
   
   &appInst.thread.SetAppKeys(&RecordEquipo);
   %This.updateProcessFlag(&PENDING);
end-method;

method OnHeaderApprove
   /+ &appinst as EOAW_CORE:ENGINE:AppInst +/
   /+ Extends/implements EOAW_CORE:ApprovalEventHandler.OnHeaderApprove +/
   
   &appinst.thread.SetAppKeys(&RecordEquipo);
   %This.updateProcessFlag(&APPROVED);
end-method;

method OnHeaderDeny
   /+ &userinst as EOAW_CORE:ENGINE:UserStepInst +/
   /+ Extends/implements EOAW_CORE:ApprovalEventHandler.OnHeaderDeny +/
   
   &userinst.thread.SetAppKeys(&RecordEquipo);
   %This.updateProcessFlag(&DENIED);
end-method;

El siguiente paso dentro de nuestra implantación del workflow es escribir el código que inicia los objetos necesarios para el proceso,  esto se debe realizar el el evento POSTBUILD del componente. Antes de eso vamos a escribir una clase que nos permite controlar la visualización de los botones de Aprobación, Rechazo y Envío del componente.  

Esta clase debe permitir a partir de una instancia de la clase EOAW_CORE:LaunchManager y otra de la clase EOAW_CORE:ApprovalManager determinar si el usuario que está accediendo al componente es aprobador, si es así habilitará los botones de aprobación y rechazo.  Si el proceso está pendiente de ser iniciado la clase habilitará el botón Enviar. 

Para determinar si un usuario está habilitado para aprobar o rechazar la transacción se utilizá la propiedad hasPending del objeto EOAW_CORE:ApprovalManager la cual indica si el usuario que ingreso al objeto tiene pendiente realizar una aprobación sobre el registro. 

Para determinar si el registro está pendiente de iniciar el proceso de Workflow se usa la propiedad submitEnabled del objeto  EOAW_CORE:LaunchManager.  

La clase quedaría de la siguiente forma:  

import EOAW_CORE:LaunchManager;
import EOAW_CORE:ApprovalManager;

class PE_UTILIDADES
   method PE_UTILIDADES();
   method pe_ActualizarWF(&rs0 As Rowset, &obj_launch As EOAW_CORE:LaunchManager, &obj_approval As EOAW_CORE:ApprovalManager);
private
end-class;

method PE_UTILIDADES
end-method;

method pe_ActualizarWF
   /+ &rs0 as Rowset, +/
   /+ &obj_launch as EOAW_CORE:LaunchManager, +/
   /+ &obj_approval as EOAW_CORE:ApprovalManager +/
   Local Row &row1 = &rs0.GetRow(1);
   Local Record &rec_approval = &row1.GetRecord(Record.PE_EQUIPOS_WRK);
   Local boolean &isApprover = False;
   
   If &obj_approval.hasAppInst Then
      &isApprover = &obj_approval.hasPending;
   End-If;
   &rec_approval.PE_ENVIAR_BTN.Visible = &obj_launch.submitEnabled;
   &rec_approval.PE_APROBAR_BTN.Visible = &isApprover;
   &rec_approval.PE_RECHAZAR_BTN.Visible = &isApprover;
end-method;

Ya habiendo construida está clase podemos escribir el código del evento postbuild del componente:

Importamos las clases propias del AWE que necesitamos

import EOAW_CORE:LaunchManager;
import EOAW_CORE:ApprovalManager;


Importamos la clase que acabamos de crear para habilitar los botones según el estado del proceso y el usuario que esté ingresando al registro:


import PE_WF_EJEMPLO:PE_UTILIDADES;


Declaramos las variables de componente que se utilizan durante todo el proceso de Workflow:

Component EOAW_CORE:LaunchManager &obj_launch;
Component EOAW_CORE:ApprovalManager &obj_approval;


Creamos la variable para almacenar el nombre del proceso que vamos a ejecutar. Este es el nombre con el cual se va a identificar el proceso y el que se debe parametrizar en las páginas de parametrización d workflow. 

Local string &str_process = "EQUIPOS";


Creamos la variable record para el cual se ejecutará el workflow.

Local Record &rec_equipos = GetRecord(Record.PE_EQUIPOS);



Inicializamos las variables de componente que se utilizan durante todo el proceso de Workflow, los parámetros identifican el proceso de workflow que se va a ejecutar para el registro y con que usuario se está ejecutando ese proceso. 

&obj_launch = create EOAW_CORE:LaunchManager(&str_process, &rec_equipos, %OperatorId);
&obj_approval = create EOAW_CORE:ApprovalManager(&str_process, &rec_equipos, %OperatorId);



Actualizamos el estado de los botones de aprobación, rechazo y envío. 

Local PE_WF_EJEMPLO:PE_UTILIDADES &obj_utilidades = create PE_WF_EJEMPLO:PE_UTILIDADES();;
&obj_utilidades.pe_ActualizarWF(GetLevel0(), &obj_launch, &obj_approval);

El siguiente paso es escribir el código que ejecutará cada uno de los botones. El código que se colocará directamente en los bonotes solo activará una bandera y salvará el componente,  esto con el fin de ejecutar el código principal en el evento SavePostChange del componente.

Botón Aprobar:

PE_EQUIPOS_WRK.PE_APROBAR_BTN.Value = "Y";

&XSTATUS = PE_EQUIPOS.PE_ESTADO_EQUIPO;
PE_EQUIPOS.PE_ESTADO_EQUIPO = "";
PE_EQUIPOS.PE_ESTADO_EQUIPO = &XSTATUS;
DoSaveNow();

Botón Rechazar:

PE_EQUIPOS_WRK.PE_APROBAR_BTN.Value = "Y";

&XSTATUS = PE_EQUIPOS.PE_ESTADO_EQUIPO;
PE_EQUIPOS.PE_ESTADO_EQUIPO = "";
PE_EQUIPOS.PE_ESTADO_EQUIPO = &XSTATUS;
DoSaveNow();


Botón Enviar:

PE_EQUIPOS_WRK.PE_ENVIAR_BTN.Value = "Y";

&XSTATUS = PE_EQUIPOS.PE_ESTADO_EQUIPO;
PE_EQUIPOS.PE_ESTADO_EQUIPO = "";
PE_EQUIPOS.PE_ESTADO_EQUIPO = &XSTATUS;
DoSaveNow();

Ahora si vamos a revisar el código que debemos colocar en el evento SavePostChange del Componente:


Importamos las clases propias del AWE que necesitamos


import EOAW_CORE:LaunchManager;
import EOAW_CORE:ApprovalManager;

Importamos la clase que acabamos de crear para habilitar los botones según el estado del proceso y el usuario que esté ingresando al registro:


import PE_WF_EJEMPLO:PE_UTILIDADES;


Declaramos las variables de componente que se utilizan durante todo el proceso de Workflow:

Component EOAW_CORE:LaunchManager &obj_launch;
Component EOAW_CORE:ApprovalManager &obj_approval;

Local PE_WF_EJEMPLO:PE_UTILIDADES &obj_utilidades = create PE_WF_EJEMPLO:PE_UTILIDADES();;



Creamos la variable record para el cual se ejecutará el workflow.


Local Record &rec_equipos = GetRecord(Record.PE_EQUIPOS);



Creamos la variable record donde se encuentran los campos referentes a los botones:


Local Record &rec_wrk = GetRecord(Record.PE_EQUIPOS_WRK);


Validamos si se oprimió el botón enviar y si es así inicializa el proceso de workflow utilizando el método  DoSubmit. Siempre que se inicie o se reinicie un proceso de workflow la variable EOAW_CORE:ApprobalManger debe ser reiniciada. La propiedad hasAppInst indica si el proceso fue iniciado correctamente. 

If &rec_wrk.PE_ENVIAR_BTN.Value = "Y" Then
   &obj_launch.DoSubmit();
   If &obj_launch.hasAppInst Then
      &obj_approval = create EOAW_CORE:ApprovalManager(&obj_launch.txn.awprcs_id, &rec_equipos, %OperatorId);
   End-If;
Else

Validamos si se oprimió el botón aprobar y si es así se llama el método DoApprove para realizar la aprobación del registro. Si el usuario que está aprobando no es el aprobador final y existen  otros usuario que deben aprobar antes de que el registro quede en estado aprobado, el métdo DoApprove dejará el estado en pendiente y remitirá la transacción al siguiente aprobador

   If &rec_wrk.PE_APROBAR_BTN.Value = "Y" Then
      &obj_approval.DoApprove(&rec_equipos);
   Else

Validamos si se oprimió el botón rechazar y si es así se llama el método DoDeny para realizar el rechazo del registro.

      If &rec_wrk.PE_RECHAZAR_BTN.Value = "Y" Then
         &obj_approval.DoDeny(&rec_equipos);
      Else


Si el proceso de workflow ya se ha iniciado pero alguien le hizo alguna modificación al registro, es necesario volver a iniciar el proceso de aprobación, para eso se utiliza el método DoResubmit el cual resetea el proceso y lo inicia nuevamente. 



         If &obj_approval.hasAppInst And
               &obj_launch.resubmitEnabled Then
            &obj_launch.DoResubmit();
         End-If;


      End-If;
   End-If;
End-If;

Por último actualizamos el estado de los botones de workflow:

&obj_utilidades.pe_ActualizarWF(GetLevel0(), &obj_launch, &obj_approval);
&rec_wrk.PE_ENVIAR_BTN.Value = "N";
&rec_wrk.PE_APROBAR_BTN.Value = "N";
&rec_wrk.PE_RECHAZAR_BTN.Value = "N";

Con lo anterior finalizamos los pasos técnicos que son necesarios para habilitar el workflow dentro de un componente especifico,  el siguiente paso es parametrizar el proceso dentro del aplicativo. 


Las parametrizaciones del AWE se realiza por el menú Inicio > Componentes de Empresa > Aprobaciones > Aprobaciones.  En esta ruta encontramos todas las opciones que nos permiten parametrizar el workflow.  


1. Primero se debe registrar la trasacción,  por la opción de Registro de Transacciones. El id de proceso que debemos registrar para nuestro ejemplo es EQUIPOS,  el cual es el que hemos estado utilizando dentro del PeopleCode. 


Lo principal que se debe parametrizar en este punto son:



  • El registro de referencia (El registro que creamos utilizando el subrecord EOAW_XREF_SBR).
  • La opción de Activar notificaciones, donde definimos si queremos informar a los interesados en el workflow (Solicitantes, aprobadores, etc.) por correo electrónico,  por lista de trabajo o por ambos. 
  • El menú y el componente donde se realizan las aprobaciones.  Hacia este menú y componente redireccionará el motor de workflow a los interesados (Aprobadores) para continuar con el proceso. 
  • Clase de Gestión de Aprobación,  acá seleccionamos la clase que administrará el estado de los registros que se encuentren en proceso de aprobación.  En nuestro caso será PE_APPROVAL_HANDLER
  • En Niveles de Aprobación seleccionamos el registro al que le vamos a realizar el proceso de aprobación. 
A continuación podemos visualizar como quedaría la definición del proceso EQUIPOS:



2. La segunda configuración que se debe hacer es la que se refiere a las notificaciones que se deben enviar cada vez que ocurra un evento dentro del proceso de workflow.  Para esto se debe definir:



  • La vista de usuarios que se va a utilizar (Usuarios Aprob): a menos que suceda algo extraordinario o que se necesite información adicional de los usuarios la vista que siempre se debe usar es PSOPRDEFN_VW
  • El evento para el cual se realizará la notificación: Básicamente se deben parametrizar 3 eventos: En Aprobación Final, En Rechazo Final y Ruta para Aprobación.
  • Luego se define el menú, componente y página al cual se debe dirigir el notificado para realizar el proceso de workflow (Aprobar, Rechazar o Revisar según el caso)
  • Por último se define el perfíl al cual se debe notificar: En el caso de Rechazo y Aprobación Final se debe informar al solicitante para que este revise por que se rechazo o por que se aprobó. En caso de Runta para Aprobación se le debe informar al usuario que debe aprobar o rechazar la transacción o sea a los aprobadores. 
A continuación se pueden visualizar las parametrizaciones que se realizaron para los 3 eventos dentro de nuestro ejemplo. 








3. El siguiente paso es definir las listas de usuarios que realizarán aprobaciones dentro del workflow. Estás listas se pueden definir con base en un App Package, un Objeto SQL, un Rol   o una consulta realizada por el gestor de consultas.  Las listas de usuarios se definen por la opción Definición Lista Usuarios.  

Para nuestro ejemplo definiremos 3 listas de usuarios, cada una apuntando a un rol diferente. Utilizaremos 3 listas de usuarios por que tendremos 3 niveles de aprobación, o sea que un registro debe ser aprobado por 3 usuarios antes de cambiar de estado a Aprobado. 

A continuación podemos ver la primer lista de usuarios que se parametrizó (En entradas posteriores revisaremos los diferentes tipos de listas de usuario, y la forma de usar el control ruta para las listas de usuarios definidas como roles.):






4. El último paso a la hora de definir un workflow es definir el proceso de aprobación. Cada proceso consta de:

  • Fases: Todas las fases se deben ejecutar dentro de un proceso y  son secuenciales una detrás de otra. 
  • Las fases están compuestas por Rutas:  dentro de una fase las diferentes rutas son paralelas. A diferencia de las fases las rutas no necesariamente deben ser ejecutadas. Para que una ruta sea ejecutada debe cumplir los criterios definidos sino será ignorada. 
  • Por último las rutas están compuestos por pasos que deben ser ejecutados de forma secuencial y que a su vez pueden ser ignorados si no cumplen los criterios definidos para el paso. Dentro del paso se define la lista de usuarios que debe realizar la aprobación del paso. 
Para nuestro ejemplo se debe ingresar en cada uno de los criterios de las rutas, los pasos y el proceso y definirlo como se ve en la siguiente imagen:




La definición del proceso de nuestro ejemplo debe quedar como la siguiente figura:



5. Se me olvidaba, si deseamos poder hacer seguimiento a cada una de nuestras transacciones dentro del proceso de aprobación utilizando la opción Control de Aprobaciones, debemos agregar nuestro Id de Proceso a la opción Configuración del Monitor y debe quedar de la siguiente forma:



Listo ahora solo nos queda probar nuestro workflow, para lo anterior debemos crear los siguientes usuarios:

  • Solicitante: Usuario con permisos sobre el componente de equipos. 
  • Aprobador 1: Usuario con permisos sobre el componente de equipos y adicionalmente con el rol asociado a la lista de usuarios PE_EQUIPOS_UNO
  • Aprobador 2: Usuario con permisos sobre el componente de equipos y adicionalmente con el rol asociado a la lista de usuarios PE_EQUIPOS_DOS
  • Aprobador 3: Usuario con permisos sobre el componente de equipos y adicionalmente con el rol asociado a la lista de usuarios PE_EQUIPOS_TRES. 
1. El primer paso de nuestra prueba es ingresar un registro en el componente de equipos,  para eso ingresamos con el usuario Solicitante y creamos un equpo:




Como podemos ver al usuario solicitante se le habilita el botón enviar. Al dar clic en el botón enviar se iniciará el proceso de aprobación y se le ocultará el botón enviar para el usuario Solicitante.

Si vamos a la opción Inicio > Componentes de Empresa > Aprobaciones > Aprobaciones > Control de aprobaciones y buscamos por el Proceso "EQUIPOS" podemos ver que el equipo se encuentra en estado pendiente. Si ingresamos al registro podremos ver graficamente como va el proceso de aprobación,  incluso los pasos que faltan antes de la aprobación final. 

2. El segundo paso en nuestro ejemplo es ingresar al aplicativo con el usuario Aprobador 1 e ir a revisar nuestra lista de trabajo. Como podemos ver en la imagen tenemos pendiente una aprobación. 




3. Mediante el link que aparece en la lista de trabajo nos dirigimos hacia el componente de equipos al registro pendiente por aprobación. En la imagen se ve que ahora se encuentran habilitados el botón Aprobar y Rechazar.




4. El siguiente paso es aprobar la transacción e ingresar con los usuarios Aprobador 2 y Aprobador 3 y terminar el proceso completo hasta que el estado del registro quede aprobado. 

Con esto hemos terminado nuestra entraba básica sobre el manejo del AWE. En futuras entradas estaremos estudiando características adicionales de está tecnología, como son:

  • Control Ruta
  • Criterios de Selección de Rutas y Pasos
Bueno espero que les sea de utilidad está información y nos vemos en futuras publicaciones.