Índice

 

Customização de Workflow

Propriedades Avançadas

As propriedades avançadas contêm informações especiais que podem alterar o comportamento padrão do processo em algum ponto. Elas devem ser utilizadas principalmente durante a fase de customização ou conter "flags" especiais que alterem alguma lógica interna (apenas em casos especiais).

Para cadastrar uma propriedade avançada em um processo

Eventos do Processo

Os eventos de um processo são um conjunto de scripts carregados pela API de workflow. Tais scripts são desenvolvidos com o uso da linguagem JavaScript e chamados ao longo da execução do processo em momentos pré-determinados, como por exemplo a criação de um processo ou a entrada em uma nova atividade.

AQUI VAI CONTEÚDO FANTANTE

Em todos os eventos do processo é possível obter informações da API de Workflow. Cada evento possui acesso ao handle da API de workflow através da variável global hAPI. Os seguintes métodos estão disponíveis através da hAPI:

MétodoEspecificação
getCardValue("nomeCampo")

Permite acessar o valor de um campo do formulário do processo, onde:

  • nomeCampo: nome do campo do formulário.
setCardValue("nomeCampo", "valor")

Permite definir o valor de um campo do formulário do processo, onde:

  • nomeCampo: nome do campo do formulário;
  • valor: valor a ser definido para o campo do formulário.
setAutomaticDecision(numAtiv, listaColab, "obs")

Permite definir o fluxo de saída de uma atividade de forma automática, onde:

  • numAtiv: número da atividade destino;
  • listaColab: lista (do tipo String) dos usuários que receberão a tarefa;
  • obs: observação da tarefa;
getActiveStates()Retorna uma lista das atividades ativas do processo.
getActualThread(numEmpresa, numProcesso, numAtiv)

Retorna a thread da atividade que está ativa, lembrando que em caso de atividades paralelas, retorna 0, 1, 2 e assim sucessivamente.

  • numEmpresa: número da empresa;
  • numProcesso: número da solicitação;
  • numAtiv: número da atividade.
setDueDate(numProcesso, numThread, "userId", dataConclusao, tempoSeg)

Permite alterar o prazo de conclusão para uma determinada atividade do processo, onde:

  • numProcesso: número da solicitação;
  • numThread: número da thread (normalmente 0, quando não se utiliza atividades paralelas);
  • userId: o usuário responsável pela tarefa;
  • dataConclusao: a nova data de conclusão;
  • tempoSeg: tempo que representa a nova hora de conclusão, calculado em segundos após a meia-noite.

Recomendamos a utilização deste método no evento afterTaskCreate, pois será executado logo após a criação da tarefa. Exemplo:

function afterTaskCreate(colleagueId) {
	var data = new Date();
	
	//seta o dia, mês (Janeiro é 0) e ano
	data.setDate(20);
	data.setMonth(10);
	data.setFullYear(2010);
	   
	// Recupera o numero da solicitação
	var processo = getValue("WKNumProces");
	
	// Seta o prazo para as 14:00
	hAPI.setDueDate(processo, 0, colleagueId, data, 50400);
}
transferTask(transferUsers, "obs", int numThread)

Transfere uma tarefa de um usuário para outro(s) usuário(s).

  • transferUsers: lista (do tipo String) de usuários;
  • obs: a observação;
  • numThread: sequência da thread, em caso de atividades paralelas.
transferTask(transferUsers, "obs")

Transfere uma tarefa de um usuário para outro(s) usuário(s). Este método não pode ser usado em processos com atividades paralelas:

  • transferUsers: lista (do tipo String) de usuários;
  • obs: a observação.
startProcess(processId, ativDest, listaColab, "obs", completarTarefa, valoresForm, modoGestor)

Inicia uma solicitação workflow, onde:

  • processId: código do processo;
  • ativDest: atividade de destino;
  • listaColab: lista (do tipo String) de usuários;
  • obs: texto da observação;
  • completarTarefa: indica se deve completar a tarefa (true) ou apenas salvar (false);
  • valoresForm: um Mapa com os valores do formulário do processo;
  • modoGestor: acesso como gestor do processo (true/false).

Retorna um mapa com informações da solicitação criada. Entre elas, o iProcess que é o número da solicitação criada.

setColleagueReplacement(userId)

Seta um usuário substituto, onde:

  • userId: código do usuário substituto.
setTaskComments("userId", numProcesso,  numThread, "obs")

Define uma observação para uma determinada tarefa do processo, onde:

  • userId: usuário responsável pela tarefa;
  • numProcesso: número da solicitação de processo;
  • numThread: é o número da thread (normalmente 0, quando não se utiliza atividades paralelas);
  • obs: a observação.
getCardData(numProcesso)

Retorna um Mapa com todos os campos e valores do formulário da solicitação.

  • numProcesso: número da solicitação de processo.
getAdvancedProperty("propriedade")

Retorna o valor da propriedade avançada de um processo.

  • propriedade: nome da propriedade avançada. 
calculateDeadLineHours(data, segundos, prazo, periodId)

Calcula um prazo a partir de uma data com base no expediente e feriados cadastrados no produto passando o prazo em horas:

  • data: Data inicial (tipo Date);
  • segundos: Quantidade de segundos após a meia noite;
  • prazo: Prazo que será aplicado em horas (tipo int);
  • periodId: Código de Expediente.  

Retorno: Array de Objeto, onde a primeira posição do array é a data e a segunda a hora.

Exemplo:

function afterTaskCreate(colleagueId) {
   	var data = new Date();

   	//Calcula o prazo
   	var obj = hAPI.calculateDeadLineHours(data, 50000, 2, "Default");
	var dt = obj[0];
	var segundos = obj[1];

   	//Recupera o numero da solicitação
   	var processo = getValue("WKNumProces");

   	//Altera o prazo do processo
	hAPI.setDueDate(processo,0,colleagueId, dt, segundos);
}
calculateDeadLineTime(data, segundos, prazo, periodId)

Calcula um prazo a partir de uma data com base no expediente e feriados cadastrados no produto passando o prazo em minutos:

  • data: Data inicial (tipo Date);
  • segundos: Quantidade de segundos após a meia noite;
  • prazo: Prazo que será aplicado em minutos (tipo int).
  • periodId - Código de Expediente

Retorno: Array de Objeto, onde a primeira posição do array é a data e a segunda a hora.

 Exemplo:

function afterTaskCreate(colleagueId) {
	var data = new Date();
	//Calcula o prazo
	var obj = hAPI.calculateDeadLineTime(data, 50000, 120, "Default");
	var dt = obj[0];
	var segundos = obj[1];

	//Recupera o numero da solicitação
	var processo = getValue("WKNumProces");

	// Altera o prazo do processo
	hAPI.setDueDate(processo,0,colleagueId, dt, segundos);
}

Nos eventos existe a possibilidade de integração com serviços de dados. Tais serviços podem ser WebServices, AppServer Progress® e Dataset.

O acesso a WebServices ou AppServer Progress® deve ser previamente configurado no cadastro de Serviços. Para mais detalhes consulte em Integração Com Aplicativos Externos, no capítulo "Acessando WebServices a partir do Fluig".

Abaixo um exemplo de como executar o WebService de Colleague para criar um usuário no Fluig após executar uma tarefa:

function afterTaskComplete(colleagueId, nextSequenceId, userList) {
	
	if (nextSequenceId == 2) {
		//Busca o webservices de Colaborador
		var colleagueServiceProvider = ServiceManager.getServiceInstance("Colleague");
		var colleagueServiceLocator = colleagueServiceProvider.instantiate("com.totvs.technology.ecm.foundation.ws.ECMColleagueServiceService");
		var colleagueService = colleagueServiceLocator.getColleagueServicePort();
	
		//Cria o ColleagueDto – Verificar a lista de métodos na visualização do serviço
		var colleagueDto = colleagueServiceProvider.instantiate("com.totvs.technology.ecm.foundation.ws.ColleagueDto");
		colleagueDto.setCompanyId(1);
		colleagueDto.setColleagueId("teste");
		colleagueDto.setColleagueName("Usuario Teste");
		colleagueDto.setActive(true);
		colleagueDto.setVolumeId("Default");
		colleagueDto.setLogin("teste");
		colleagueDto.setMail("[email protected]");
		colleagueDto.setPasswd("teste");
		colleagueDto.setAdminUser(false);
		colleagueDto.setEmailHtml(true);
		colleagueDto.setDialectId("pt_BR");
		
		//Cria o colleagueDtoArray e adiciona
		var colleagueDtoArray = colleagueServiceProvider.instantiate("com.totvs.technology.ecm.foundation.ws.ColleagueDtoArray");
		colleagueDtoArray.getItem().add(colleagueDto);
	
		var result = colleagueService.createColleague("adm", "adm",  1, colleagueDtoArray);
		log.info("Result: " + result);
	}
}

Os seguintes eventos são disparados pela API de Workflow:

EventoDescriçãoParâmetros
afterCancelProcess

Ocorre após o cancelamento da solicitação.

  • Usuário corrente (String);
  • Número do processo (Integer).
afterProcessCreate

Ocorre logo após a criação de um novo processo.

Observação: Em caso de execução deste evento um em sub-processo, não será possível definir ou resgatar dados da ficha anexada ao sub-processo, pois nessa situação a ficha ainda não está criada.

  • Número do novo processo (Integer).
afterProcessFinish

Ocorre após finalizada a solicitação.

  • Número do processo (Integer).
afterReleaseVersion

Ocorre após a liberação de uma versão do processo.

  • XML com a definição do processo (String).
afterStateEntryOcorre após a entrada em uma nova atividade.
  • Sequência da atividade (Integer).
afterStateLeaveOcorre após a saída de uma atividade.
  • Sequência da atividade (Integer).
afterTaskComplete

Ocorre após o usuário completar uma tarefa, porém as informações de próxima tarefa e usuários destino já foram salvas.

  • Usuário corrente (String);
  • Sequência da próxima atividade (Integer);
  • Lista de usuários destino (List<String>).
afterTaskCreateOcorre após o usuário receber uma tarefa.
  • Matrícula do usuário (String).
afterTaskSave

Ocorre após salvar as informações selecionadas pelo usuário.

  • Usuário corrente (String);
  • Sequência da próxima atividade (Integer);
  • Lista de usuários destino (List<String>).
beforeCancelProcess

Ocorre antes do cancelamento da solicitação.

  • Usuário corrente (String);
  • Número do processo (Integer).
beforeStateEntryOcorre antes da entrada em uma nova atividade.
  • Sequência da atividade (Integer).
beforeStateLeaveOcorre antes da saída de uma atividade.
  • Sequência da atividade (Integer).
beforeTaskComplete

Ocorre antes que o usuário complete uma tarefa, porém as informações de próxima tarefa e usuários destino já foram salvas.

  • Usuário corrente (String);
  • Seqüência da próxima atividade (Integer);
  • Lista de usuários destino (List<String>).
beforeTaskCreateOcorre antes que o usuário receba uma tarefa.
  • Matrícula do usuário (String).
beforeTaskSave

Ocorre antes de salvar as informações selecionadas pelo usuário.

  • Usuário corrente (String);
  • Sequência da próxima atividade (Integer);
  • Lista de usuários destino (List<String>).
calculateAgreement

Ocorre após o cálculo do consenso (somente para atividades conjuntas) e permite alterar os dados do consenso de uma atividade.

Exemplo:

function calculateAgreement(currentState, agreementData) {
	log.info("Consenso Atual: " + agreementData.get("currentPercentage"));
	log.info("Atividade Destino Atual: " +  agreementData.get("currentDestState"));
	log.info("Usuario Destino Atual: " + agreementData.get("currentDestUsers"));
	
	//Altera o consenso
	agreementData.put("currentPercentage", 100);
	agreementData.put("currentDestState", 2);
	agreementData.put("currentDestUsers", "adm,teste,super");
}
  • currentState (Integer): atividade que terá o consenso alterado;
  • agreementData (Map<String, Object>): mapa de dados com o percentual calculado, a atividade destino e os usuários de destino. Para obter os valores, utilize o método "get" e para atribuir um valor, utilize o método "put".
onNotify

Ocorre após a movimentação da solicitação e antes de enviar as notificações.

Para mais detalhes consulte o capítulo Customização de E-mail.
setProcess

Ocorre quando um processo é "setado" na API.

Observação: A propriedade WKCompletTask não deve ser utilizada neste evento, pois quando ele é executado o produto ainda não tem a informação se atividade foi ou não completada.

  • Número do processo (Integer).
subProcessCreatedOcorre quando um sub-processo é criado.
  • Número do sub-processo (Integer).
validateAvailableStates

Ocorre após montada a lista de tarefas disponíveis para o usuário a partir da tarefa atual.

  • Sequência da atividade atual (Integer);
  • Lista das sequências das atividades (List<Integer>).  
  • Não é necessário criar todos os eventos do processo – apenas aqueles que se estiver interessado.
  • Todos os eventos são executados de forma persistente.

Importante: Não é possível capturar (hAPI.getCardValue) ou adicionar (hAPI.setCardValue) dados no formulário na inicialização do processo, sendo possível somente a partir da segunda tarefa.

Para isso pode ser utilizado a seguinte lógica:

function beforeStateEntry(sequenceId) {
	if (sequenceId  != "NUMERO_DA_ATIVIDADE_INICIAL") {
		var campo = hAPI.getCardValue("campo1");
	}
}

Customização do Processo

 

Tratamento de Exceções

As exceções podem ser tratadas nos seguintes eventos: beforeStateEntry, beforeTaskSave e beforeCancelProcess. O tratamento de exceção no evento beforeStateEntry pode ser utilizado na inicialização de solicitações, pois ele impede que a solicitação seja iniciada. O tratamento de exceção no evento beforeTaskSave pode ser utilizado somente se a solicitação já estiver inicializada.

Abaixo é apresentado os modelos para utilização em cada um dos eventos:

function beforeStateEntry(sequenceId) {
	var activity = getValue("WKNumState");
	if (activity == 0 || activity == 1) {
		//Outra condição.
		throw "TRATAMENTO DE EXCEÇÃO";
	}
}

function beforeTaskSave(colleagueId, nextSequenceId, userList) {
	var activity = getValue("WKNumState");
	if (activity != 0 && activity != 1) {
		//Outra condição
		throw "TRATAMENTO DE EXCEÇÃO";
	}
}

function beforeCancelProcess(colleagueId, processId) {
	//Condição.
	throw "TRATAMENTO DE EXCEÇÃO";
}

É possível consultar o campo observação de uma solicitação de processo, verificando se ele foi preenchido ou não. Para isto, é necessário validar a propriedade WKUserComment no evento beforeTaskSave ou no evento beforeCancelProcess. Exemplo:

function beforeTaskSave(colleagueId, nextSequenceId, userList) {
	if (getValue("WKUserComment") == null || getValue("WKUserComment") == "") {
		throw "A observação deve ser preenchida";
	}	
}

function beforeCancelProcess(colleagueId, processId) {
	if (getValue("WKUserComment") == null || getValue("WKUserComment") == "") {
		throw "A observação deve ser preenchida";
	}	
}

Mecanismo de Atribuição

Os mecanismos de atribuição são instrumentos utilizados durante um processo de workflow que permitem criar, segundo um critério estabelecido pelo próprio mecanismo, uma lista de possíveis usuários para uma atividade. Esta lista pode ser utilizada em dois momentos:

  1. Na inicialização do processo, onde o sistema verifica se o usuário corrente faz parte desta lista e, portanto, pode iniciá-lo;
  2. No momento do encaminhamento de uma tarefa, quando esta lista é apresentada ao usuário corrente com opções de encaminhamento da solicitação.

No primeiro caso, a lista é gerada de acordo com o mecanismo de atribuição existente na primeira atividade do processo (que representa a atividade inicial). Nas demais atividades é adotado o segundo procedimento. Quando não houver um mecanismo de atribuição associado a uma atividade (seja ela inicial ou não), todos os usuários são considerados válidos.

O Fluig possui alguns mecanismos de atribuição padrões, conforme abaixo:

Mecanismo de AtribuiçãoDescrição
Para um Papel (Pool)Permite atribuir tarefas a um papel e não apenas a um usuário. Assim, qualquer um dos usuários neste papel pode assumir as tarefas para completá-las.
Para um Grupo (Pool)Permite atribuir tarefas a um grupo e não apenas a um usuário. Assim, qualquer um dos usuários deste grupo pode assumir as tarefas para completá-las.
Por AssociaçãoPermite compor lógicas complexas de atribuição por intermédio da associação de vários mecanismos.
Por Campo de Formulário

Permite atribuir tarefas ao usuário informado em um campo do formulário do processo.

Por Executor de AtividadePermite selecionar os usuários que executaram uma atividade anterior.
Por GrupoPermite filtrar apenas os usuários que façam parte de um determinado grupo.
Por Grupos do Usuário

Permite filtrar apenas os usuários que pertençam a um dos grupos do usuário corrente, ou do usuário que iniciou o processo (solicitante). Também permite filtrar apenas os usuários cujo grupo de trabalho seja o mesmo do usuário (corrente ou solicitante).

Por PapelPermite filtrar apenas os usuários que possuam um determinado papel.
Por UsuárioPermite atribuir tarefas a um usuário específico.

Como criar um Mecanismo de Atribuição

Parâmetros Workflow para Customização de Formulários

Para processos que possuem uma definição de formulário definida são passados alguns parâmetros com informações sobre o processo para serem utilizados nos eventos da definição de formulário, conforme abaixo:

ParâmetroDescrição
WKDefCódigo do processo
WKVersDefVersão do processo
WKNumProcesNúmero da solicitação de processo
WKNumStateNúmero da atividade
WKCompanyNúmero da empresa
WKUserCódigo do usuário corrente
WKUserPasswordSenha do usuário corrente em MD5
WKCompletTaskSe a tarefa foi completada (true/false)
WKNextStateNúmero da próxima atividade (destino)
WKCardIdCódigo do formulário do processo
WKFormIdCódigo da definição de formulário do processo

Nos scripts dos eventos da definição de formulário basta recuperar as informações com o comando getValue, conforme exemplo:

var vCodProcess = getValue("WKDef");

Customização de E-mail

É possível incluir customizações de e-mail durante o andamento de um workflow. Existem duas modalidades de customização nessa categoria:

Envio de E-mail Padrão

Para interferir no envio de um e-mail padrão, deve ser utilizado o evento onNotify, que é disparado no exato momento em que qualquer um dos e-mails de processo é enviado. Nesse evento, podem ser feitas alterações, como por exemplo adicionar outros destinatários ao e-mail (além daqueles que estão participando do processo), modificar os valores dos parâmetros utilizados no template de e-mail, etc.

Abaixo se encontra um exemplo de como implementar esse evento:

function onNotify(subject, receivers, template, params) {
	if (template.match("tpl028") != null) {
		receivers.add("[email protected]");
	}
}

O evento onNotify está disponível na lista de eventos do processo. Portanto, ao selecionar esse evento na lista de eventos disponíveis, a assinatura da função acima já será preenchida automaticamente. Este evento disponibiliza os seguintes parâmetros:

ParâmetroDescrição
subjectÉ o assunto do e-mail. A alteração desta variável irá implicar que todos os usuários recebam o e-mail com o novo assunto configurado, inclusive aqueles que participam do processo. Exemplo de utilização: subject.add("ASSUNTO");
receiversLista de e-mails destinatários. Também é possível adicionar outros e-mails, de usuários que não participam do processo. Inclusive, podem ser adicionados e-mails de usuários que não estão cadastrados no Fluig, caso seja necessário notificar uma pessoa que não tenho acesso ao sistema.
templatePermite validar qual tipo de e-mail está sendo enviado (por exemplo, template de nova tarefa, notificação de gestor, etc). Com base nessa variável podemos distinguir quais e-mails queremos customizar. É recomendável que sempre seja verificado o código do template, para evitar que ocorram alterações em outros tipos de e-mail, que não necessitariam de customização.
paramsÉ um mapa de dados que permite alterar/incluir parâmetros para que sejam apresentados no e-mail. O nome dos parâmetros informados nesse mapa devem ser os mesmos que são utilizados dentro do arquivo de template.

No exemplo que foi apresentado acima está sendo validado se o template é o TPL028 (que corresponde a Notificação do Gestor), em caso positivo, um novo e-mail será adicionado na lista de destinatários. Ou seja, além do gestor do processo, outra pessoa será notificada, recebendo uma cópia do e-mail que o gestor irá receber. Como está sendo validado o código do template, os demais tipos de e-mail não serão afetados.

Os templates podem ser consultados dentro do diretório do volume, em: <VOLUME>\templates\tplmail. Se for necessário adicionar algum parâmetro no e-mail padrão, os templates podem ser editados diretamente nesse diretório.


Envio de E-mail Customizado

Caso seja necessário incluir um novo tipo de e-mail, além daqueles que são disponibilizados pelo produto, o Fluig permite que o usuário cadastre templates de e-mails customizados, através da opção Templates de Emails presente na aba Gerais do Painel de Controle.

Para incluir um novo Template, basta acionar a opção Adicionar no menu e preencher os dados solicitados. Nesta etapa também deve ser feito upload do arquivo de template.

Para adicionar parâmetros dentro de um arquivo de template (TXT ou HTML), deve-se utilizar a seguinte notação:

${NOME_DO_PARAMETRO}

Neste caso, será utilizado o identificador "NOME_DO_PARAMETRO" durante a customização para atribuir um valor a este parâmetro. Os templates disponíveis no volume da empresa (<VOLUME>\templates\tplmail) podem ser consultados para mais exemplos de utilização de parâmetros. 

 Após cadastrar um novo template, é possível utilizá-lo para enviar e-mail a partir de qualquer um dos eventos do processo (exceto no onNotify – ver "Envio de E-mail Padrão"). Para efetuar um envio de e-mail, em base de um template customizado, é utilizado o objeto notifier, chamando a função "notify", conforme o código abaixo:

try{
	//Monta mapa com parâmetros do template 
	var parametros = new java.util.HashMap();
	parametros.put("NOME_USUARIO", "JOAO");
	parametros.put("CODIGO_USUARIO", "01");

	//Este parâmetro é obrigatório e representa o assunto do e-mail
	parametros.put("subject", "ASSUNTO");

	//Monta lista de destinatários
	var destinatarios = new java.util.ArrayList();
	destinatarios.add("CODIGO-DESTINATARIO");

	//Envia e-mail
	notifier.notify("MATRICULA-REMETENTE", "CODIGO-TEMPLATE", parametros, destinatarios, "text/html");

} catch(e){
	log.info(e);
}

Onde:

 

Outra forma de executar o método de envio de email é informando o número da ficha, conforme exemplo:

notifier.notify("MATRICULA-REMETENTE", NUMERO DO FORMULARIO, "CODIGO-TEMPLATE", parametros, destinatarios, "text/html");

Atenção: Obrigatoriamente o valor informado deve ser um formulário. Outros tipos de documentos não serão tratados e ocorrerá erro na execução do evento.

 

Ao executar este método, automaticamente os parâmetros abaixo serão adicionados na lista de parâmetros e podem ser utilizados no template:

ParâmetroDescrição
WDK_CardContentConteúdo HTML do formulário (simula a visualização)
WDK_DocumentAuthorNome do Autor
WDK_DocumentCommentsComentário adicional
WDK_DocumentDescriptionDescrição do formulário
WDK_DocumentIconImageImagem do ícone do formulário
WDK_DocumentNumberNúmero do formulário
WDK_DocumentUpdatedDateData de atualização do formulário
WDK_DocumentVersionVersão do formulário
WDK_DocumentViewLinkLink para acesso ao formulário