Home

TOTVS | Plataformas e tecnologias

Árvore de páginas

Importante

Caro Cliente,

O TOTVS ECM 3.0 foi fundamentado na tecnologia de interface Flash, do qual a Adobe irá descontinuar seu suporte em 31/12/2020.

Recomendamos que nossos clientes avaliem a utilização do TOTVS Fluig Plataforma, que proporciona uma maior abrangência de recursos e importantes inovações tecnológicas. São inúmeras novidades não só em ECM e BPM que o Fluig entrega aos seus mais de 4 mil clientes, mas também conta com recursos de portais, social e identidade única.

Entre em contato com seu executivo de conta para saber mais detalhes desta oferta.

Índice


Customização 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 deve-se acessar a opção “Configuração de Processos” no menu Workflow.



    Selecione o processo desejado de acesse a opção “Editar”. A seguinte tela será apresentada:



    Clique sobre a aba “Avançado” e será apresentado o cadastro de “Propriedades Avançadas” do processo. A seguinte tela será apresentada:


    Use os botões Adicionar, Editar e Excluir para a manutenção dos eventos desejados. Uma propriedade avançada é representada por nome e valor. Onde o nome deve ser único. Abaixo o formulário para a criação de uma propriedade avançada.


    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 um momentos pré-determinados, como por exemplo a criação de um processo ou a entrada em uma nova atividade.



      Para criar a lista de eventos do processo deve-se acessar a opção “Configuração de Processos” no menu Workflow.



      Clique sobre a aba “Avançado” e posteriormente clique sobre a aba “Eventos”. A seguinte tela será apresentada.

      Importante

      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 da ficha do processo, onde:

      • nomeCampo: é o nome do campo da ficha.
      setCardValue(“nomeCampo”,”valor”)

      Permite definir o valor de um campo da ficha do processo, onde:

      • nomeCampo: é o nome do campo da ficha;
      • valor: é o valor a ser definido para o campo da ficha.
      setAutomaticDecision(numAtiv, listaColab, “obs”)

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

      • numAtiv: é o número da atividade destino;
      • listaColab: é a lista dos colaboradores que receberão a tarefa – do tipo String;
      • obs: é a 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: é o número da empresa;
      • numProcesso: é o número da solicitação;
      • numAtiv: é o 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: é o número da solicitação;
      • numThread: é o 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: é o 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: é uma lista de colaboradores – do tipo String.
      • 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, onde:

      • transferUsers: é uma lista colaboradores – do tipo String;
      • obs: a observação.
       startProcess(processId, ativDest, listaColab, “obs”, completarTarefa, valoresFicha, modoGestor )

      Inicia uma solicitação workflow, onde:

      • processId: Código do processo
      • ativDest: Atividade de destino
      • listaColab: é uma lista de colaboradores de destino – do tipo String;
      • obs: Texto da observação
      • completarTarefa: Indica se deve completar a tarefa (true) ou apenas salvar (false)
      • valoresFicha: Um Mapa com os valores da ficha do processo
      • modoGestor: Acesso como gestor do processo (true/false).

      Retorna um mapa com informações da solicitação criada. Entre eles 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;
      • 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.
       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 (Date)
      • segundos: Quantidade de segundos após a meia noite
      • prazo: Prazo que será aplicado em horas (Variável 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 (Date)
      • segundos: Quantidade de segundos após a meia noite
      • prazo: Prazo que será aplicado em minutos (Variável 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);
      }

       getParentInstance(processInstanceId)Retorna o número da solicitação pai, onde:

      processInstanceId : Número da solicitação filha.
      Exemplo:
      function beforeStateEntry(sequenceId) {
      if (sequenceId == 2) {
      var numProcess = getValue("WKNumProces");
      // Busca o número da solicitação pai
      var parentProcess = hAPI.getParentInstance(numProcess);
      // Busca os dados do formulário da solicitação pai

      var parentCardData = hAPI.getCardData(parentProcess);
      // Replica um dado do formulário da solicitação pai para o formulário da solicitação filha
      var cnpj = parentCardData.get("cnpj");
      hAPI.setCardValue("cnpj", cnpj);
      }
      }


      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 o Guia de Integração ECM, no capítulo “Acessando WebServices a partir do TOTVS | ECM“.
      Abaixo um exemplo de como executar o WebService de Colleague para criar um usuário 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.datasul.technology.webdesk.foundation.ws.ColleagueServiceServiceLocator");
      var colleagueService = colleagueServiceLocator.getColleagueServicePort();
      // Cria o ColleagueDto – Verificar a lista de métodos na visualização do serviço
      var colleagueDto = colleagueServiceProvider.instantiate("com.datasul.technology.webdesk.foundation.ws.ColleagueDto");
      colleagueDto.setCompanyId(1);
      colleagueDto.setColleagueId("teste1");
      colleagueDto.setColleagueName("Usuario Teste 1");
      colleagueDto.setActive(true);
      colleagueDto.setVolumeId("Default");
      colleagueDto.setLogin("teste1");
      colleagueDto.setMail("teste1@teste.com");
      colleagueDto.setPasswd("b09c600fddc573f117449b3723f23d64"); //String adm em MD5
      colleagueDto.setAdminUser(false);
      colleagueDto.setEmailHtml(true);
      colleagueDto.setDefaultLanguage("pt");
      colleagueDto.setDialectId("pt");
      // adiciona ao array
      var listColleague = new Array( );
      listColleague[0] = colleagueDto;
      // cria o colleagueDtoArray e adiciona
      var colleagueDtoArray = colleagueServiceProvider.instantiate("com.datasul.technology.webdesk.foundation.ws.

      ColleagueDtoArray");
      colleagueDtoArray.setItem(listColleague);
      var result = colleagueService.createColleague("adm", "admin", 1, colleagueDtoArray);
      log.info("Result: " + result);
      }
      }


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

      afterCancelProcess

      Ocorre após o cancelamento da solicitação.
      Parâmetros: Usuário corrente (CHARACTER) e Número do processo (INTEGER).
      Observação: Ao retornar a variável WKNumState quando o processo estar em atividades paralelas. Será retornado todas as atividades ativas separadas pelo carácter virgula.

      afterProcessCreate

      Ocorre logo após a criação de um novo processo. Parâmetros: Número do novo processo (INTEGER).
      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.

      afterProcessFinish

      Ocorre após finalizada a solicitação.
      Parâmetros: Número do processo (INTEGER).

      afterReleaseVersion

      Ocorre após a liberação de uma versão do processo workflow.
      Parâmetros: XML com a definição do processo (CHARACTER).

      afterStateEntryOcorre após a entrada em uma nova atividade. Parâmetros: Seqüência da atividade (INTEGER).
      afterStateLeaveOcorre após a saída de uma atividade. Parâmetros: Seqüência da atividade (INTEGER).
      afterTaskComplete

      Ocorre após o usuário completar uma tarefa, porém as informações de próxima tarefa e colaboradores destino já foram salvas.
      Parâmetros: Usuário corrente (CHARACTER), Seqüência da próxima atividade (INTEGER) e lista de usuários destino (CHARACTER).

      afterTaskCreateOcorre após o usuário receber uma tarefa. Parâmetros: Matrícula do usuário (CHARACTER).
      afterTaskSave

      Ocorre após salvar as informações selecionadas pelo usuário.
      Parâmetros: Usuário corrente (CHARACTER), Seqüência da próxima atividade (INTEGER) e lista de usuários destino (CHARACTER).

      beforeCancelProcess

      Ocorre antes do cancelamento da solicitação.
      Parâmetros: Usuário corrente (CHARACTER) e Número do processo (INTEGER).

      beforeStateEntryOcorre antes da entrada em uma nova atividade. Parâmetros: Seqüência da atividade (INTEGER).
      beforeStateLeave

      Ocorre antes da saída de uma atividade.

      Parâmetros: Seqüência da atividade (INTEGER).

      beforeTaskComplete

      Ocorre antes que o usuário complete uma tarefa, porém as informações de próxima tarefa e colaboradores destino já foram salvas.
      Parâmetros: Usuário corrente (CHARACTER), Seqüência da próxima atividade (INTEGER) e lista de usuários destino (CHARACTER).

      beforeTaskCreateOcorre antes que o usuário receba uma tarefa. Parâmetros: Matrícula do usuário (CHARACTER).
      beforeTaskSave

      Ocorre antes de salvar as informações selecionadas pelo usuário.
      Parâmetros: Usuário corrente (CHARACTER), Seqüência da próxima atividade (INTEGER) e lista de usuários destino (CHARACTER).

      calculateAgreement

      Ocorre após o cálculo do consenso (somente para atividades conjuntas) e permite alterar os dados do consenso de uma atividade.
      Parâmetros:
      currentState (INTEGER): atividade que terá o consenso alterado.
      AgreementData (ARRAYLIST): 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”. Para atribuir um valor, utilize o método “put”. Exemplo:
      function calculateAgreement (currentState, agreementData) {
      log.debug("Consenso Atual: " + agreementData.get("currentPercentage"));
      log.debug("Atividade Destino Atual: " + agreementData.get("currentDestState"));
      log.debug("Usuario Destino Atual: " + agreementData.get("currentDestUsers"));
      // Altera o consenso
      agreementData.put("currentPercentage", 100);
      agreementData.put("currentDestState", 2);
      agreementData.put("currentDestUsers", "adm,teste,super");
      }

      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” abaixo.
      Observação: Caso no Processo Workflow esteja cadastrado o evento "onNotify", o comportamento do produto também será de ignorar a validação de e-mails iguais para o remetente e destinatário.

      setProcess

      Ocorre quando um processo é “setado” na API.
      Parâmetros: Número do processo (INTEGER).
      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.

      subProcessCreatedOcorre quando um sub-processo é criado. Parâmetros: 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.

      Parâmetros: Seqüência da atividade atual (INTEGER) e input-output lista das seqüências das atividades (ARRAYLIST).

      Recomendações

      • 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 fichário na inicialização do processo. 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 de Processo


      Com o uso de eventos, o ECM permite que um processo seja customizado possibilitando a execução de ações definidas pelo usuário, tais como:

      • Validar o ato de completar uma atividade
      • Tomar decisões automaticamente

      Existem algumas propriedades que contém informações referentes à solicitação que podem ser utilizadas na customização do processo, são elas:

      WKDefCódigo do processo.
      WKVersDefVersão do processo.
      WKNumProcesNúmero do processo.
      WKNumStateNúmero da atividade.
      WKCompanyNúmero da Empresa.
      WKUserCommentComentário feito pelo usuário na atividade ou no cancelamento da solicitação.
      WKUserPasswordSenha do Usuário corrente em MD5
      WKCompletTaskSe a tarefa foi completada (true/false)
      WKNextStateNúmero da próxima atividade (destino).
      WKCardIdCódigo da ficha do processo.
      WKFormIdCódigo do fichário do processo.
      WKManagerModeSe quem está visualizando o processo é gestor do processo
      WKMobileSe a atividade está sendo inicializada via mobile (true/false).


      Além dessas propriedades já alimentadas pelo produto, é possível criar propriedades customizadas que podem ser utilizadas nos eventos.
      O produto disponibiliza a variável globalVars, que é um mapa de dados (HashMap<String, String>) e estará disponível em todos os eventos.
      Para adicionar uma propriedade e seu valor, utilize o método: globalVars.put("name", "value"). Onde name é o nome da propriedade e value o seu valor. Ex: globalVars.put("WDAprovador","adm");
      Para recuperar os valores da variável globalVars, utilize o método: globalVars.get("name");
      Onde "name" é o nome da propriedade a ser retornado o valor. Ex: globalVars.get("WDAprovador");

      Exemplo 1:
      Para validar se o usuário está completando uma atividade corretamente, basta utilizar o evento beforeTaskComplete e retornar alguma mensagem caso queira disparar um erro. Por exemplo, segue parte de um código de customização criado pelo ECM:

      function beforeTaskComplete(colleagueId,nextSequenceId,userList){
      var ativAtual = getValue("WKNumState");
      var users = new java.util.ArrayList();
      var usersTmp = new java.util.ArrayList();
      var cUsers;
      var process = parseInt(globalVars.get("process"));
      var User1 = hAPI.getCardValue("resp1_H");
      var eficacia1 = hAPI.getCardValue("eficaz1");
      var controle1 = hAPI.getCardValue("controle1");
      var eficaz = true;
      var codgrupo;
      log.info("ATIVIDADE---> " + ativAtual + " - " + nextSequenceId);
      if(ativAtual == 7 && nextSequenceId == 12){
      if(User1 != "" && eficacia1 != "1" && eficacia1 != "2"){
      if(verificaUsuario(users,User1)){
      users.add(User1);
      }
      }
      log.info("TAMANHO VETOR ----> " + users.size());
      hAPI.setAutomaticDecision(8, users, "Decisao tomada automaticamente pelo ECM.");
      } else if(ativAtual == 9 && nextSequenceId == 13){
      log.info("[1] Usuarios----> " + User1);
      log.info("[1] EFICACIA----> " + eficacia1);
      log.info("[1] CONTROLE----> " + controle1);
      if(User1 != "" && eficacia1 == "2" && controle1 == ""){
      eficaz = false;
      }
      log.info("EFICAZ " + eficaz);
      if(eficaz){
      log.info("[if1]");
      codGrupo = buscaGrupo(process,"Grupo-Qualidade");
      log.info("CODIGO GRUPO " + codGrupo);
      users.add("Pool:Group:" + codGrupo);
      hAPI.setAutomaticDecision(6, users , "Decisao tomada automaticamente pelo ECM.");
      }
      }
      }


      Exemplo 2:
      Para fazer com que uma decisão seja tomada automaticamente, os seguintes procedimentos devem ser executados:
      1. Configurar em Propriedades Avançadas a propriedade AutomaticTasks – conforme descrito anteriormente – com a lista de todas as atividades que terão decisão delegada via customização (Ex.: AutomaticTasks=3,6,10).
      2. Implementar o evento beforeStateEntry e executar e chamar a o método “setAutomaticDecision” da hAPI, passando como parâmetros o próximo estado, o próximo usuário (ou lista de usuários) e a observação.

      function beforeStateEntry(sequenceId) {
      var userList = new java.util.ArrayList();
      userList.add(“Administrator”);
      hAPI.setAutomaticDecision(new java.lang.Integer(8), userList, “Observação”);
      }

      ATENÇÃO: As atividades com decisão automática também podem ser criadas via editor de processos.
      Para mais informações consulte o Manual de Referência do ECM.


      Exemplo 3:
      Para iniciar uma nova solicitação de um outro processo ao finalizar uma solicitação devem ser executados os seguintes procedimentos:
      1. Criar um serviço no ECM em que a URL seja o webservice de WorkflowEngineService .
      (Ex.: http://localhost:8080/webdesk/WorkflowEngineService?wsdl )
      2. Implementar o evento afterProcessFinish utilizando o exemplo abaixo. Sendo ‘process2’ o novo processo a ser inicializado.

      function afterProcessFinish(processId){
      var func = { run: function(){
      a();
      }
      };
      var r = new java.lang.Runnable(func);
      var t = new java.lang.Thread(r);
      t.start();
      log.info("Iniciei a thread");
      return;
      }
      function a(){
      try {
      var atividade = getValue("WKNumState");
      var user = getValue("WKUser");
      var processo = getValue("WKNumProces");
      log.info("########## Atividade: " + atividade);
      log.info("########## inicio webservice workflow");
      var workflow = ServiceManager.getService("WorkflowEngineService");
      var serviceHelper = workflow.getBean();
      var serviceLocator = serviceHelper.instantiate("com.datasul.technology.webdesk.workflow.ws.WorkflowEngineServiceServiceLocator");
      var service = serviceLocator.getWorkflowEngineServicePort();
      log.info("########## carregou serviço workflow");
      log.info("########## Carrega Colaboradores do segundo processo");
      var stringArray = service.getAvailableUsersStart("adm", "adm", 1, "process2", 0, 0);
      var field1 = serviceHelper.instantiate("com.datasul.technology.webdesk.workflow.ws.KeyValueDto");
      field1.setKey("nome");
      field1.setValue("valorNome");
      var field2 = serviceHelper.instantiate("com.datasul.technology.webdesk.workflow.ws.KeyValueDto");
      field2.setKey("cid");
      field2.setValue("valorCidade");
      var resultArr = serviceHelper.instantiate("com.datasul.technology.webdesk.workflow.ws.KeyValueDtoArray");
      resultArr.setItem(new Array(field1, field2));
      log.info("########## Inicia StartProcess");
      var userArray = serviceHelper.instantiate("net.java.dev.jaxb.array.StringArray");
      userArray.setItem(new Array(user));
      log.info("########## Usuario: " + userArray.getItem(0));
      try {
      var ret = service.startProcessClassic("adm", "adm", 1, "process2", 2, userArray , "webservice chamada", "adm", false, null,resultArr, null, true);
      } catch(e) {
      log.info("########## Erro startProcess: " + e);
      }
      } catch(x) {
      log.info("########## Erro Process: " + x);
      }
      }


      Tratamento de Excessões


      As exceções podem ser tratadas nos seguintes eventos: beforeStateEntry, beforeTaskSave e beforeCancelProcess. O tratamento da exceção no evento beforeStateEntry pode ser utilizado somente na inicialização de solicitações, pois ele impede que a solicitação seja iniciada. O tratamento da exceção no evento beforeTaskSave pode ser utilizado somente se a solicitação já estiver inicializada. Abaixo segue 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 DA 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 DA EXCEÇÃO"
      }


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

      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 colaboradores 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 de start). 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.
      Na inicialização do ECM são criados alguns mecanismos automaticamente, conforme abaixo:

      AssociadoPermite compor lógicas complexas de atribuição por intermédio da associação de vários mecanismos.
      Campo FormulárioPermite atribuir tarefas ao colaborador informado em um campo do formulário do processo.
      Executor AtividadePermite selecionar os colaboradores que executaram uma atividade anterior.
      GrupoPermite filtrar apenas os colaboradores que façam parte de um determinado grupo.
      Grupos ColaboradorPermite filtrar apenas os colaboradores que pertençam a um dos grupos do colaborador corrente, ou do colaborador que iniciou o processo (solicitante). Também permite filtrar apenas os colaboradores cujo grupo de trabalho seja o mesmo do colaborador (corrente ou solicitante).
      PapelPermite filtrar apenas os colaboradores que possuam um determinado papel no Workflow.
      Pool GrupoPermite atribuir tarefas a um grupo de colaboradores e não apenas a um colaborador. Assim, qualquer um dos colaboradores deste grupo pode assumir as tarefas para completá-las.
      Pool PapelPermite atribuir tarefas a um papel e não apenas a um colaborador. Assim, qualquer um dos colaboradores neste papel pode assumir as tarefas para completá-las.
      UsuárioPermite atribuir tarefas a um colaborador específico.


      Como Criar Um Mecanismo de Atribuição


      O mecanismo de atribuição geralmente é composto de duas partes, a tela de configuração e o script de resolução do mecanismo de atribuição.


        Para criar um mecanismo de atribuição basta acessar o “Painel de Controle”, na opção “Workflow” e clicar sobre “Mecanismos de Atribuição”. A seguinte tela será apresentada:


        A tela apresenta todos os mecanismos de atribuição padrão do ECM e também os mecanismos customizados.



        Para criar um novo mecanismo de atribuição clique sobre o botão “Adicionar”, então a seguinte tela será apresentada:


        O mecanismo de atribuição deverá possuir obrigatoriamente seu código, o nome e a descrição da configuração. A tela de configuração é opcional, mas caso for utilizá-la, deve-se obrigatoriamente importar o componente “AssignmentSelectedEvent.swc” que fica dentro do diretório de instalação do ECM (Ex: <INSTALL_ECM>\server\default\deploy\Webdesk3EE.ear) dentro do pacote EAR existe um pacote “ecm-web.war”, abra o arquivo e copie o SWC para o seu projeto e importe como biblioteca.



        Após, sua tela deve estender o módulo WebdeskModule, veja um exemplo de tela abaixo:


        <?xml version="1.0" encoding="utf-8"?>
        <module:WebdeskModule xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:module="com.datasul.technology.webdesk.foundation.module.*"
        creationComplete="{init();}">
        <module:states> <mx:State name="blocked"> <mx:SetProperty target="{this}" name="enabled" value="false"/> </mx:State> </module:states>
        <mx:Script>
        <![CDATA[
        import com.datasul.technology.webdesk.workflow.assignment.event.AssignmentSelectedEvent;
        import com.datasul.technology.webdesk.dm.view.event.CloseWindowEvent;
        import mx.collections.ArrayCollection;
        [Bindable]
        private var arr:ArrayCollection = new ArrayCollection([
        {value:"asd1",label:"Informática"},
        {value:"asd2",label:"RH"},
        {value:"asd3",label:"Produto"}]);
        private function init():void {
        if (super.xmlFromDatabase != null) {
        var xml:XML = new XML(super.xmlFromDatabase);
        var area:String = String(xml.area);
        this.tiNome.text = String(xml.nome);
        for each (var current:Object in this.arr) {
        if (current.value == area) {
        this.cbArea.selectedItem = current;
        break;
        }
        }
        }
        }
        private function saveMecan():void {
        var event:AssignmentSelectedEvent = new AssignmentSelectedEvent();
        event.xmlString = "<Custom>" +
        " <nome>"+this.tiNome.text+"</nome>" +
        " <area>"+this.cbArea.selectedItem.value+"</area>" +
        "</Custom>";
        this.dispatchEvent(event);
        this.closeWindow();
        }
        private function closeWindow():void {
        this.dispatchEvent(new CloseWindowEvent());
        }
        ]]>
        </mx:Script>
        <mx:Form>
        <mx:FormItem label="Nome">
        <mx:TextInput id="tiNome" width="200"/>
        </mx:FormItem>
        <mx:FormItem label="Área">
        <mx:ComboBox id="cbArea" dataProvider="{arr}"></mx:ComboBox>
        </mx:FormItem>
        <mx:FormItem direction="horizontal" width="100%">
        <mx:Button label="Salvar" click="{saveMecan()}"/>
        <mx:Button label="Fechar" click="{closeWindow()}"/>
        </mx:FormItem>
        </mx:Form>
        </module:WebdeskModule>


        A tela de configuração deverá montar o XML que consiste da configuração do mecanismo de atribuição. Na resolução de uma atividade do processo o XML de configuração será enviado ao script de descrição da configuração – é o último campo da tela. Exemplo baseado na tela acima:


        function resolve(process,colleague,configXML){
        var newXML = new XML(configXML);
        var userList = new java.util.ArrayList();
         
        if (newXML.area.toString()=="asd1") { 
        userList.add('adm'); 
        } else if (newXML.area.toString()=="asd2") {
        userList.add('1'); 
        } else {
        userList.add('10'); 
        } 
        return userList;
        }

        OBS

        É possível acessar Datasets e WebServices apartir da função.

        Além do XML o script também recebe como parâmetros o código do processo e o usuário corrente. Por fim, o script de configuração retorna a lista de usuários e o fluxo de saída da atividade é selecionado.

        Para persistir o XML de configuração criado pela tela basta lançar o evento AssignmentSelectedEvent e atribuir o XML de configuração na propriedade “xmlString”.

        Dica: caso a compilação normal pela GUI de desenvolvimento não esteja efetuando as importações corretamente, segue sugestão de compilação do projeto:

        mxmlc -debug=false -optimize=true -warnings=false -load-config flex-config-mxmlc.xml -source-path=. <ARQUIVO>.mxml -output <ARQUIVO>.swf


        Arquivo FLEX-CONFIG-MXMLC.XML:

        <?xml version="1.0" encoding="utf-8"?>
        <flex-config xmlns="http://www.adobe.com/2006/flex-config">
        <metadata>
        <title>TOTVS | ECM</title>
        <language>EN</language>
        </metadata>
        <compiler>
        <fonts>
        <local-fonts-snapshot>C:/Arquivos de programas/Adobe/Flex Builder 3 Plug-in/sdks/2.0.1/frameworks/localFonts.ser</local-fonts-snapshot>
        </fonts>
        <!-- list of SWC files or directories that contain SWC files -->
        <library-path>
        <path-element>C:/Arquivos de programas/Adobe/Flex Builder 3 Plug-in/sdks/2.0.1/frameworks/libs</path-element>
        <path-element>C:/Arquivos de programas/Adobe/Flex Builder 3 Plug-in/sdks/2.0.1/frameworks/locale/en_US</path-element>
        <path-element>AssignmentSelectedEvent.swc</path-element>
        </library-path>
        <debug>true</debug>
        </compiler>
        <use-network>true</use-network>
        </flex-config>

        Por fim, o arquivo SWF do mecanismo de atribuição deve ser publicado no ECM como um documento. Para selecionar o documento no momento da publicação basta clicar sobre o ícone ao lado do campo “Tela de Configuração”.


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


        Para processos que possuem um fichário padrão definido são passados alguns parâmetros com informações sobre o processo para serem utilizados nas customizações do fichário, conforme abaixo:

        WKDefCódigo do processo.
        WKVersDefVersão do processo.
        Número do processo.Número do processo.
        WKNumStateNúmero da atividade.
        WKCompanyNúmero da Empresa.
        WKUserUsuário Corrente.

        Estas informações são passadas como parâmetros da URL do programa que permite o encaminhamento das atividades, portanto no programa de customização do fichá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 e alteração de e-mail padrão através do evento onNotify.
        • Envio de e-mail customizado em qualquer evento do Workflow.


        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 Workflow. 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:

        1. 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");
        2. Receivers: Lista de e-mails destinatários. Também é possível adicionar outros e-mails, de usuários que não participam do workflow. Inclusive, podem ser adicionados e-mails de usuários que não estão cadastrados no       ECM, caso seja necessário notificar uma pessoa que não tenho acesso ao sistema.
        3. Template: Permite 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.
        4. 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 ECM permite que o usuário cadastre templates customizados, através do ícone “Templates” na categoria GED ou Painel de Controle, na tela principal do sistema.

        Para incluir um novo Template, basta clicar no botão adicionar 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_USUARIO}

        Neste caso, será utilizado o identificador “NOME_USUARIO” 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 Workflow (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("MATRICULA-DESTINATARIO"); 
         
        //Envia e-mail 
        notifier.notify("MATRICULA-REMETENTE", "CODIGO-TEMPLATE", 
        parametros, destinatarios, "text/html"); 
         
        } catch(e){ 
        log.info(e); 
        }


        O primeiro parâmetro que a função notify recebe é o código/matrícula do usuário que irá enviar o e-mail (remetente).

        O segundo parâmetro é o código do template que foi cadastrado através do ícone de Templates.

        O terceiro parâmetro é um mapa de dados (java.util.HashMap) que contém os parâmetros que serão utilizados para preencher as variáveis do template.

        Por padrão, os parâmetros WDK_VirtualDir (diretório virtual) e WDK_AdviceUser (Nome do colaborador remetente) são adicionados ao mapa de parâmetros automaticamente e podem ser utilizados na template, sem que os valores sejam adicionados pela customização.

        O quarto parâmetro representa a lista de usuários que irão receber o e-mail (java.util.ArrayList). Esta lista de usuários consiste em uma lista de códigos/matrículas de colaboradores cadastrados no ECM.

        O quinto e último parâmetro especifica qual será o formato do e-mail enviado. Os valores aceitos são “text/html” e “text/plain”.

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

        notifier.notify("MATRICULA-REMETENTE", NÚMERO DA FICHA, "CODIGO-TEMPLATE", parametros, destinatarios, "text/html");

        Atenção

        Obrigatoriamente o valor informado deve ser uma ficha. 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 a lista de parâmetros e podem ser utilizados na template:

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



        • Sem rótulos