wiki:WF/Tutorialdedesenvolvimentodeumprocessosimples

Version 5 (modified by cassiomaes, 17 years ago) (diff)

--

Neste documento, será abordada uma estratégia para desenvolvimento de um processo de Workflow. Utilizando esta estratégia, será desenvolvido um processo simples. Ao final de cada seção, esta será exemplificada no processo que está sendo desenvolvido.

Desenvolvimento de um Processo

O processo de desenvolvimento pode, grosseiramente, ser dividido em três etapas:

  1. Especificação
  2. Projeto
  3. Implementação

Especificação

Esta etapa é realizada através de reuniões como cliente que solicitou o processo de Workflow.Todos os dados relevantes ao processo devem ser documentados,conforme indicado no documento Documentação mínima do Projeto .Ao final desta etapa,o modo como o processo irá funcionar deve estar bem definido.

Exemplo

No nosso exemplo, devemos desenvolver um processo que gerencie "Solicitações". Antes de ser executada, a solicitação deve ser avaliada e aprovada por um distribuidor (pessoa que gerencia as solicitações). Dessa forma, temos dois caminhos distintos:

  1. Caso a solicitação seja aprovada, ela vai para execução de um técnico que descreve o procedimento que foi feito para solucionar o problema. Ao final da execução, o solicitante recebe um e-mail passando informações sobre sua solicitação;
  2. Caso a solicitação seja rejeitada, o solicitante recebe um e-mail informando sobre sua solicitação.

Projeto

Nesta etapa os dados obtidos na etapa de especificação são mapeados para a realidade do Workflow. E, é possível definir alguns dados sobre o processo, por exemplo: quantos perfis ele terá, o número de atividades, o relacionamento entre elas, etc.

Exemplo

No nosso exemplo podemos perceber claramente a existência de três perfis:

  1. Solicitante: grupo de pessoas que podem fazer solicitações;
  2. Distribuidor: grupo de pessoas que avaliam as solicitações;
  3. Técnico: grupo de pessoas que executam as solicitações aprovadas.

As atividades são quatro:

  1. Compor Solicitação: o perfil "solicitante" faz uma solicitação;
  2. Avaliar: o perfil "distribuidor" avalia a solicitação;
  3. Executar: o perfil "tecnico" executa as solicitações aprovadas;
  4. Informar Resultado: o perfil "solicitante" vê as informações referentes à sua solicitação.

Possíveis caminhos de execução:

  1. Compor Solicitação -> Avaliar (Aprovada) -> Executar -> Informar Resultado
  2. Compor Solicitação -> Avaliar (Rejeitada) -> Informar Resultado

Criação do Fluxo

Um dos passos mais importantes no desenvolvimento de um processo de Workflow é definir o fluxo do processo. O fluxo consiste no relacionamento das atividades através de transições. É importante também, quando retratar o fluxo, informar os perfis relacionados a cada atividade.

O resultado da criação do fluxo é um dos mais importantes documentos para o processo de Workflow e que por si só é capaz de demonstrar o funcionamento de todo o sistema.

Exemplo

No nosso exemplo, foi criado o seguinte fluxo:

http://doc.workflow.celepar.parana/wiki/tutorial_solicitacoes.png

Criação do Processo

Uma vez definido o fluxo do processo, é possível mapeá-lo para a engine do Workflow que estamos utilizando. Após esta etapa, cada uma das atividades que compõem o processo podem ser codificadas, dando funcionalidade às mesmas.

Exemplo

No nosso exemplo, vamos desenvolver esta etapa na seguinte ordem:

  1. Criar o Processo;
  2. Criar as Atividades / Transições / Perfis;
  3. Mapear os Perfis.

Criar o processo

Na interface de Administração de Processos, preenchemos:

Nome do processo: Solicitações

Descrição: Processo de gerenciamento de solicitações

Para os outros campos, utilizam-se os valores padrões.

Clicamos no botão "criar".

Criar as atividades / Transições / Perfis

Selecione a opção "Atividades".

Quando o processo é criado, duas atividades são criadas com ele: a atividade do tipo start e de nome "start" e a atividade do tipo end e de nome "end".

Selecionamos a atividade "start" e, mudamos / preenchemos os seguintes campos:

   Nome: Compor Solicitação

   Descrição: Atividade para o solicitante compor uma solicitação

   Interativa: marcar opção

   Roteamento Automático: marcar opção

   '''Adicionar perfil'''

   Nome: solicitante

   Descrição: autorizados a compor solicitações

Clicamos em "salvar".

Selecionamos a atividade "end" e, mudamos / preenchemos os seguintes campos:

   Nome: Informar Resultado

   Descrição: Atividade para informar o solicitante sobre sua solicitação

   Interativa: marcar opção

   Roteamento Automático: marcar opção

   '''Usar perfis existentes'''

   Selecionar "solicitante"

   Clicamos em "salvar".

Clicamos em "novo".

Preenchemos os seguintes campos:

   Nome: Executar

   Descrição: Atividade para o técnico executar uma solicitação

   Tipo: activity

   Interativa: marcar opção

   Roteamento Automático: marcar opção

   '''Adicionar Transições'''

   Adicionar transições para: "Informar Resultado"

   '''Adicionar perfil'''

   Nome: tecnico

   Descrição: autorizados a executar solicitações

Clicamos em "salvar".

Clicamos em "novo".

Preenchemos os seguintes campos:

Nome: Avaliar

Descrição: Atividade para o distribuidor avaliar uma solicitação

Tipo: switch

Interativa: marcar opção

Roteamento Automático: marcar opção

Adicionar Transições

: Adicionar transições de: "Compor Solicitação"

: Adicionar transições para: "Executar" e "Informar Resultado"

Adicionar perfil

: Nome: distribuidor

: Descrição: autorizados a avaliar solicitações

Clicamos em "salvar".

Mapear os Perfis

Clicamos em "Perfis"

Na área "Mapear usuários/grupos a perfis", selecionamos um dos perfis (no lado direito) e adicionamos os usuários que pertencem a este perfil. Depois, clicamos em "Mapear".

Para finalizar, basta repetir este mesmo passo para os outros dois perfis.


Implementação

Nesta etapa é feita a codificação das atividades que foram criadas na etapa anterior.Será utilizada a arquitetura  http://pt.wikipedia.org/wiki/MVCMVC (Model-View-Controller). Consulte o documento Metodologia de Desenvolvimento? para saber mais detalhes de como a arquitetura MVC está implementada no WorkflowdoExpresso?.

Exemplo

Insiraoscódigos,listadosabaixo,nosrespectivosarquivos.Utilize,paraisso,oeditordecódigosPhpquejávemembutidonoWorkflow.(VejaodocumentoWF_Ediçãodecódigo)? .

Atividades

Avaliar.php

<?php

$application = new AvaliarController(new AvaliarModel($env), $env);
$application->run($_REQUEST['action']);

?>

Compor_Solicitao.php

<?php

$application = new ComporSolicitacaoController(new ComporSolicitacaoModel($env), $env);
$application->run($_REQUEST['action']);

?>

Executar.php

<?php

$application = new ExecutarController(new ExecutarModel($env), $env);
$application->run($_REQUEST['action']);

?>

Informar_Resultado.php

<?php

$application = new InformarResultadoController(new InformarResultadoModel($env), $env);
$application->run($_REQUEST['action']);

?>

Templates

templates/Avaliar.tpl

{include file="info_solicitacao.tpl"}

<br>
<input type="submit" name="action" value="Aprovar" />
<input type="submit" name="action" value="Rejeitar" />

templates/Compor_Solicitao.tpl

<table>
	<tr>
		<td><label>Título</label></td>
		<td><input type="text" name="titulo" value="{$titulo}" /></td>
	</tr>
	<tr>
		<td><label>Descrição</label></td>
		<td><textarea name="descricao">{$descricao}</textarea></td>
	</tr>
</table>

<input type="submit" name="action" value="Enviar" />

templates/Executar.tpl

{include file="info_solicitacao.tpl"}

<br/>

<strong>Procedimento Executado:</strong><br/>
<textarea name="procedimento" cols="50" rows="7"></textarea><br/>
<input type="submit" name="action" value="Finalizar" />

templates/Informar_Resultado.tpl

{include file="info_solicitacao.tpl"}
<br/>
<table>
	<tr>
		<td><strong>Mensagem</strong></td>
		<td>{$mensagem|nl2br}</td>
	<tr>
</table>

<input type="submit" name="action" value="Encerrar" />

templates/info_solicitacao.tpl

Por padrão, o Workflow cria um arquivo tpl para cada atividade interativa do processo. O arquivo info_solicitacao.tpl não corresponde a uma atividade, mas sim a um trecho de código que será incluído em outros arquivos tpl. Por isso, não estará na lista de arquivos já existentes, e deverá ser criado através da interface de código, aba templates, da seguinte maneira:

1 - Clique no botão 'Novo template';

2 - Escolha a opção 'em_branco.tpl';

3 - Informe o nome do arquivo e clique em OK

4 - Inclua o código abaixo

<table>
	<tr>
		<td><strong>Solicitante</strong></td>
		<td>{$solicitante_desc}</td>
	</tr>
	<tr>
		<td><strong>Data</strong></td>
		<td>{$data}</td>
	</tr>
	<tr>
		<td><strong>Título</strong></td>
		<td>{$titulo}</td>
	</tr>
	<tr>
		<td><strong>Descrição</strong></td>
		<td>{$descricao|nl2br}</td>
	</tr>
</table>

Includes

Os próximos arquivos devem ser incluídos de forma semelhante como foi feito para o arquivo info_solicitação.tpl anteriormente, só que desta vez será usada a aba includes, da interface de código. Para cada arquivo a ser incluído, execute:

1 - Clique no botão 'Novo Include'; 2 - Escolha a opção 'em_branco.php'; 3 - Informe o nome do arquivo e clique em OK 4 - Inclua o código correspondente

class.avaliar.controller.inc.php

<?php

class AvaliarController extends Controller

{
	function __default ()
	{
		$this->model->defaultAction();
		$this->loadViewVars();
		$this->showForm($this->AVALIAR);
	}

	function aprovar()
	{
		$this->model->aprovarAction();
	}

	function rejeitar()
	{
		$this->model->rejeitarAction();
	}

        function run($action)
	{
		$this->dispatch($action);
	}

}

?>

class.avaliar.model.inc.php

<?php
class AvaliarModel extends Model
{
	function defaultAction()
	{
		$this->updateAttributes();
		$this->addViewVar('titulo', $this->_titulo);
		$this->addViewVar('descricao', $this->_descricao);
		$this->addViewVar('data', $this->_data);
		$this->addViewVar('solicitante_desc', $this->_solicitante_desc);

		return true;

	}

	function aprovarAction()
	{
		$this->instance->setNextActivity('Executar');
		$this->commitInstance();

		return true;

	}

	function rejeitarAction()
	{
		$this->updateAttributes();
		$this->instance->setNextActivity('Informar Resultado');
		$this->instance->setNextUser($this->_solicitante); /* devolve a instância para o solicitante */
		$this->_mensagem = "Sua solicitação foi rejeitada";
		$this->updateInstance();
		$this->commitInstance();

		return true;

	}

}

?>

class.compor.solicitacao.controller.inc.php

<?php

class ComporSolicitacaoController extends Controller
{
	function __default ()
	{
		$this->model->defaultAction();
		$this->loadViewVars();
		$this->showForm($this->COMPOR_SOLICITACAO);
	}

	function enviar()
	{
		$this->model->enviarAction();
		$this->loadViewVars();
	}


	function run($action)
	{
		$this->dispatch($action);
	}

}

?>

class.compor.solicitacao.model.inc.php

<?php
class ComporSolicitacaoModel extends Model
{
	function defaultAction()
	{
		return true;
	}

	function inputValidate($form)
	{
		$msgerro = Array();

		/* título não pode ser vazio */

		if (isset($form['titulo']) && !empty($form['titulo']))
			$this->_titulo = $form['titulo'];
		else
			$msgerro[] = 'É necessário fornecer um título';


		if (isset($form['descricao']) && !empty($form['descricao']))
			$this->_descricao = $form['descricao'];
		else
			$msgerro[] = 'É necessário fornecer uma descrição';

		return $msgerro;

	}


	function enviarAction()
	{
		/* se não houve erros */
		if (count($this->activity->error = $this->inputValidate($this->request)) == 0)
		{

			$this->_solicitante = $this->getWfProperty('wf_user_id');
			$this->_solicitante_desc = $this->getWfProperty('wf_user_cnname');
			$this->_data = date('d/m/Y H\hi');
			$this->updateInstance();
			$this->commitInstance();

		return true;
		}
		else

		{
			$this->addViewVar('titulo', $this->_titulo);
			$this->addViewVar('descricao', $this->_descricao);
			return false;

		}

	}

}

?>

class.controller.inc.php

<?php

class Controller extends BaseController

{

	var $COMPOR_SOLICITACAO = 'Compor_Solicitao.tpl';
	var $AVALIAR = 'Avaliar.tpl';
	var $EXECUTAR = 'Executar.tpl';
	var $INFORMAR_RESULTADO = 'Informar_Resultado.tpl';

	function Controller(&$model , &$env)
	{

		$this->super(&$model , &$env);

	}

}

?>

class.executar.controller.inc.php

<?php

class ExecutarController extends Controller
{
	function __default ()
	{
		$this->model->defaultAction();
		$this->loadViewVars();
		$this->showForm($this->EXECUTAR);

	}



	function finalizar()
	{
		$this->model->finalizarAction();

	}



	function run($action)

	{
		$this->dispatch($action);

	}

}

?>

class.executar.model.inc.php

<?php

class ExecutarModel extends Model

{
	function defaultAction()
	{
		$this->updateAttributes();
		$this->addViewVar('titulo', $this->_titulo);
		$this->addViewVar('descricao', $this->_descricao);
		$this->addViewVar('data', $this->_data);
		$this->addViewVar('solicitante_desc', $this->_solicitante_desc);


		return true;

	}


	function finalizarAction()
	{
		$this->updateAttributes();
		$this->_mensagem = "Sua solicitação foi atendida pelo técnico "
			. $this->getWfProperty('wf_user_cnname')
			. ".\n<strong>Procedimento executado:</strong>\n" . $this->request['procedimento'];
		$this->updateInstance();
        	$this->instance->setNextUser($this->_solicitante); /* devolve a instância para o solicitante */
		$this->commitInstance();

		return true;

	}

}

?>

class.informar.resultado.controller.inc.php

<?php

class InformarResultadoController extends Controller
{
	function __default ()

	{
		$this->model->defaultAction();
		$this->loadViewVars();
		$this->showForm($this->INFORMAR_RESULTADO);
	}

	function encerrar()
	{
		$this->model->encerrarAction();
	}

	function run($action)
	{
		$this->dispatch($action);
	}

}

?>

class.informar.resultado.model.inc.php

<?php
class InformarResultadoModel extends Model
{
	function defaultAction()
	{
		$this->updateAttributes();
		$this->addViewVar('titulo', $this->_titulo);
		$this->addViewVar('descricao', $this->_descricao);
		$this->addViewVar('data', $this->_data);
		$this->addViewVar('solicitante_desc', $this->_solicitante_desc);
		$this->addViewVar('mensagem', $this->_mensagem);

		return true;
	}

	function encerrarAction()
	{
		$this->commitInstance();
		return true;
	}

}

?>

class.model.inc.php

<?php
class Model extends BaseModel
{
	var $_titulo;
	var $_descricao;
	var $_solicitante;
	var $_solicitante_desc;
	var $_data;
	var $_mensagem;

	function Model(&$env)
        {
		$this->super(&$env);

	}

}

?>

shared.php

<?php

//camada de controle do processo

wf_include('class.controller.inc.php');
wf_include('class.compor.solicitacao.controller.inc.php');
wf_include('class.avaliar.controller.inc.php');
wf_include('class.executar.controller.inc.php');
wf_include('class.informar.resultado.controller.inc.php');



//camada da lógica de negócios

wf_include('class.model.inc.php');
wf_include('class.compor.solicitacao.model.inc.php');
wf_include('class.avaliar.model.inc.php');
wf_include('class.executar.model.inc.php');
wf_include('class.informar.resultado.model.inc.php');

?>

Finalização

Para finalizar o processo,é necessário compilá-lo e ativá-lo.Para isto,acessamos a interface de Administração de Processos ,abrimos o nosso processo e clicamos em "Compilação" e depoi sem "ativar".Uma vez feito isso,o processo estará disponível aquem tem direito(os que estão nos perfis do processo).

Para colocar um ícone que representa o processo, basta inserir uma imagem de 32x32 pixels de nome "icon.png" no diretório resources do processo.