Como configuramos migrações para processos de negócios no Bitrix24

Para automatizar suas operações, os negócios costumam usar o Bitrix24. Neste artigo, falamos sobre alguns dos possíveis problemas ao alterar processos de negócios e como os resolvemos.



O Bitrix24 é um dos sistemas comuns de CRM. Ele inclui um designer visual (designer) para criar diagramas de processos de negócios. É importante lembrar que, ao editar esses processos, são possíveis dificuldades - especialmente em grandes projetos existentes, onde as alterações são verificadas primeiro nos servidores local e de teste. Nesses casos, ao transferir para produção, usamos o mecanismo de migração de processos de negócios (daqui em diante - BP).

As pequenas empresas, como regra, podem ficar sem migração e simplesmente suspender um processo comercial específico por 2-3 dias. Uma grande empresa geralmente não pode pagar por isso, portanto, usa servidores de teste e implantação.



Bitrix24 sobre como um modelo de processo de negócios funciona

O trabalho com migração tem suas próprias características. Em particular, é complicado pelo grande número de objetos envolvidos e pelo ID. Além disso, o Bitrix24 também não fornece a migração de processos de negócios, como tal - geralmente esse problema é resolvido através de importação e exportação, e pode haver várias inconsistências. Vamos considerar quais problemas são possíveis ao mesmo tempo do ponto de vista do desenvolvimento.

Problema ao encontrar um modelo de processo de negócios


Ao criar um processo de negócios, você pode atribuir apenas um nome ao modelo, não um código exclusivo. Nesse caso, ao atualizar um processo de negócios, ele deverá ser obtido do banco de dados pelo nome. Às vezes, os nomes mudam porque o sistema os utiliza para serem exibidos na lista de processos na inicialização. Consequentemente, pode haver situações em que durante a atualização seja impossível encontrar um modelo. E, em geral, pesquisar pelo nome não é uma boa ideia.

Solução:

Todos os modelos de processos de negócios criados no sistema são armazenados na tabela b_bp_workflow_template. Tendo aberto a tabela, entre os campos que vemos SYSTEM_CODE: existe um campo para o código, ele simplesmente não é enviado para a interface. Podemos definir o código usando o ID do modelo - ele pode ser visto no URL na página de edição do processo:



Precisamos criar uma função para obter o ID do modelo e código, realizar uma verificação de duplicação e a integridade do campo para o modelo a ser alterado e também definir seu código.

use Bitrix\Main\Loader; Loader::includeModule("bizproc"); $BPloader = CBPWorkflowTemplateLoader::GetLoader(); // set template CODE field setTemplateCode ($BPloader, 'TEST', '94' ); function setTemplateCode($BPloader, $code, $tempalteId) { if (isCodeExists($BPloader, $code)) { die('   '); } if (!isCodeEmpty($BPloader, $tempalteId)) { die('     ') } $BPloader->UpdateTemplate($tempalteId, ['SYSTEM_CODE' => $code]); } // check if $code exists in DB function isCodeExists($BPloader, string $code) { $dbRes = $BPloader->GetTemplatesList( $arOrder = ['ID' => 'DESC'], $arFilter = ['CODE' => $code], $arGroupBy = false, $arNavStartParams = false, $arSelectFields = ['ID'] ); if (intval($dbRes->SelectedRowsCount()) > 0) { return true; } return false; } // check if the template code is not empty function isCodeEmpty($BPloader, $tempalteId) { $dbRes = $BPloader->GetTemplatesList( $arOrder = ['ID' => 'DESC'], $arFilter = ['CODE' => '', 'ID' => $tempalteId], $arGroupBy = false, $arNavStartParams = false, $arSelectFields = ['ID'] ); if (intval($dbRes->SelectedRowsCount()) > 0) { return false; } return true; } return true; } 

Vá em frente. Por exemplo, crie um processo de negócios de teste nas listas:



Para transferir um processo desenvolvido localmente para um servidor de teste (e depois para a produção), usamos o mecanismo de migração.

O Bitrix24 permite exportar um processo de negócios. Usaremos esta oportunidade.



O esquema de transferência é o seguinte:

  • Exportando um processo de negócios
  • Nós escrevemos a migração, anexamos o arquivo
  • No novo estande, fazemos backup do processo antigo
  • Aplicar migração

Em seguida, considere como esse processo ocorre.

Criar migração


Usaremos o módulo de migração do mercado: https://marketplace.1c-bitrix.ru/solutions/ws.migrations/ .

Os arquivos de migração em nosso projeto estão localizados em local / migrações / cenários




Abra a página do modelo de processo e exporte. Dentro do diretório de migração, crie o diretório de arquivos e coloque o arquivo exportado lá. Acontece assim:

local / migrações / cenários / arquivos / bp-94.bpt

Crie um cenário de migração:

 class ws_m_1565783124_approve_task extends \WS\Migrations\ScriptScenario { 

Defina os parâmetros do modelo de processo de negócios:

 class ws_m_1565783124_approve_task extends \WS\Migrations\ScriptScenario { private $arBPFields = [ 'DOCUMENT_TYPE' => [ 'lists', 'BizprocDocument', 'iblock_' ], 'AUTO_EXECUTE' => 0, 'NAME' => ' ', 'CODE' => 'TEST', ]; 

Implementamos a função de importação do processo de negócios:

 private function importBP($path) { CModule::IncludeModule('bizproc'); CModule::IncludeModule('iblock'); //Get iBlock id for which BP is created $this->arBPFields['DOCUMENT_TYPE'][2] .= $this->getIblockId(); // Get BP id by the CODE $result = \CBPWorkflowTemplateLoader::GetList( [], [ 'CODE' => $this->arBPFields['CODE'], 'MODULE_ID' => 'lists' ] ); if ($arFields = $result->GetNext()) { $id = $arFields['ID']; } else { $id = 0; } //read file to a variable $f = fopen($path, 'rb'); $datum = fread($f, filesize($path)); fclose($f); //Update BP if id>0, otherwise add BP \CBPWorkflowTemplateLoader::ImportTemplate( $id, $this->arBPFields['DOCUMENT_TYPE'], $this->arBPFields['AUTO_EXECUTE'], $this->arBPFields['NAME'], '', $datum, $this->arBPFields['CODE'] ); return $arFields['ID']; } 

Aqui, primeiro determinamos o ID do bloco de informações para o qual estamos aplicando o processo e obtemos o ID do modelo de processo com o código fornecido.

Se o modelo for encontrado, nós o atualizamos. Se não for encontrado - adicione.
A função retorna o ID do processo criado ou atualizado e para o que é necessário - informaremos mais adiante.

Definimos uma função de confirmação que adicionará / atualizará nosso processo de negócios:

 public function commit() { $pathBPElement = __DIR__ . '/files/bp-94-approve-task.bpt'; $id = $this->importBP($pathBPElement); } 

Portanto, nesta etapa, já podemos criar e atualizar um processo de negócios específico por meio do módulo de migração.

Problema ao atualizar dados do modelo


Vamos voltar ao nosso processo comercial e adicionar uma ação lá - notificação do usuário.



Como remetente, selecionamos o autor. Os destinatários:

  • Grupo de usuários de RH
  • Usuário Svetlana Kuznetsova

Agora vamos ver como o processo de negócios é registrado no banco de dados. Para fazer isso, obtemos e imprimimos o modelo no console do PHP no painel de administração:



 $arFieldsTemplate = \CBPWorkflowTemplateLoader::GetList([], ['ID' => 94])->GetNext(); echo '<pre>'; var_dump($arFieldsTemplate); 


Na matriz de parâmetros do processo, vemos as seguintes ocorrências:



Nós olhamos para a linha group_g15. Aqui 15 é o ID do grupo de RH.
Nós olhamos para a linha user_579. Aqui 579 é o ID do usuário.

Isso significa que, se importarmos o processo em outro site, teremos inconsistências contínuas.

T.O. precisamos fazer uma substituição após migrar esses IDs para aqueles que são relevantes para o site em que estamos importando o processo.

Grupos são identificados por código simbólico, usuários por login.

Para começar, no site em que o processo foi criado, obtemos o código simbólico do grupo e o login do usuário. No caso de você não ter códigos de grupo simbólico definidos, é melhor gravar a migração e instalá-los primeiro.

No nosso exemplo:

  • Código do Grupo - HR
  • Login de usuário - svetlana.kuznetsova

Em seguida, escrevemos nas funções de migração que, por código e login, nos fornecerão o ID do grupo e do usuário:

  • getUserId ($ login)
  • getGroupId (código $);

Por fim, atualize os valores apropriados no modelo:

 /** * Write action by apply scenario. Use method `setData` for save need rollback data **/ public function commit() { 


Importe um processo de negócios:

 $pathBPElement = __DIR__ . '/files/bp-94-approve-task.bpt'; $id = $this->importBP($pathBPElement); 


Nós obtemos os dados do modelo:

 $arFieldsTemplate = \CBPWorkflowTemplateLoader::GetList([], ['ID' => $id])->GetNext(); $template = $arFieldsTemplate["TEMPLATE"]; 


Substitua o ID do usuário dentro do processo de negócios:

 $template[0]['Children'][0]['Properties']["MessageUserTo"][0] = 'group_g' . $this->getGroupId('HR'); $template[0]['Children'][0]['Properties']["MessageUserTo"][1] = 'user_' . $this->getUserId('svetlana.kuznetsova'); $arNewFields = [ “TEMPLATE” => $template, “VARIABLES” => $arFieldsTemplate["VARIABLES"] ]; $arNewFields["MODIFIER_USER"] = new \CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser); \CBPWorkflowTemplateLoader::Update($id, $arNewFields); } 

Aqui, ao iniciar a migração, carregamos o arquivo e criamos / atualizamos o processo com a função importBP. Em seguida, obtemos a estrutura do modelo de processo de negócios em uma matriz, substituímos o ID e atualizamos o modelo.

Resumir


Neste artigo, abordamos apenas alguns casos em que inconsistências podem ocorrer durante a transferência entre sites e indicamos o que procurar. Em geral, em nossa prática, encontramos as seguintes ligações de identificação:

  • user_ (ligação ao usuário)
  • group_ (ligação ao grupo de usuários)
  • iblock_ (ligação de infobloco)
  • SequentialWorkflowActivity (iniciando um processo de negócios a partir de um modelo)
  • PROPERTY_ (ligação a um campo de documento com um código de caractere indefinido)

Se tudo for feito corretamente, a transferência de um processo de negócios depurado para produção é rápida e suave.

Esperamos que nossa experiência tenha sido útil para você!

Mostrar exemplo completo
 <?php /** * Updates migration scenario actions **/ class ws_m_1565783124_approve_task extends \WS\Migrations\ScriptScenario { private $arBPFields = [ 'DOCUMENT_TYPE' => [ 'lists', 'BizprocDocument', 'iblock_' ], 'AUTO_EXECUTE' => 0, 'NAME' => ' ', 'CODE' => 'TEST', ]; private $codeIBlock = 'APPROVE_TASK'; /** * Name of scenario * @return string **/ public static function name() { return 'approve task process'; } /** * Description of scenario * @return string **/ public static function description() { return 'process to approve task and set task deadline +14 days after approving'; } /** * @return array First element is hash, second is owner name */ public function version() { return ['13ebf9abe69204014459b80a7036b7a0', '']; } /** * Return IBlock ID * @return int */ private function getIblockId() { $result = CIBlock::GetList( [], [ 'TYPE' => 'bitrix_processes', '=CODE' => $this->codeIBlock ], false, ['nTopCount' => 1] ); if ($arIBlock = $result->Fetch()) { return $arIBlock['ID']; } return 0; } /** * Start import BP * @param $path * @return mixed */ private function importBP($path) { CModule::IncludeModule('bizproc'); CModule::IncludeModule('iblock'); //Get iBlock id for which BP is created $this->arBPFields['DOCUMENT_TYPE'][2] .= $this->getIblockId(); // Get BP id by the CODE $result = \CBPWorkflowTemplateLoader::GetList( [], [ 'CODE' => $this->arBPFields['CODE'], 'MODULE_ID' => 'lists' ] ); if ($arFields = $result->GetNext()) { $id = $arFields['ID']; } else { $id = 0; } //read file to a variable $f = fopen($path, 'rb'); $datum = fread($f, filesize($path)); fclose($f); //Update BP if id>0, otherwise add BP \CBPWorkflowTemplateLoader::ImportTemplate( $id, $this->arBPFields['DOCUMENT_TYPE'], $this->arBPFields['AUTO_EXECUTE'], $this->arBPFields['NAME'], '', $datum, $this->arBPFields['CODE'] ); return $arFields['ID']; } /** * @param $login * @return mixed */ private function getUserId($login) { $rsUsers = Bitrix\Main\UserTable::getList([ "select" =>['ID'], "filter" => ['LOGIN' => $login], ]); $userFields = $rsUsers->fetch(); return $userFields['ID']; } /** * @param $code * @return mixed */ private function getGroupId($code) { $rsGroups = \Bitrix\Main\GroupTable::getList( [ 'filter' => ['STRING_ID'=> 'HR'], 'select' => ['ID'] ]); $arFields = $rsGroups->fetch(); return $arFields['ID']; } /** * Write action by apply scenario. Use method `setData` for save need rollback data **/ public function commit() { //make BP import $pathBPElement = _DIR_ . '/files/bp-94-approve-task.bpt'; $id = $this->importBP($pathBPElement); //get template data $arFieldsTemplate = \CBPWorkflowTemplateLoader::GetList([], ['ID' => $id])->GetNext(); $template = $arFieldsTemplate['TEMPLATE']; //replace id inside BP tempalte $template[0]['Children'][0]['Properties']['MessageUserTo'][0] = 'group_g' . $this->getGroupId('HR'); $template[0]['Children'][0]['Properties']['MessageUserTo'][1] = 'user_' . $this->getUserId('svetlana.kuznetsova'); $arNewFields = [ 'TEMPLATE' => $template, 'VARIABLES' => $arFieldsTemplate['VARIABLES'] ]; $arNewFields['MODIFIER_USER'] = new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser); \CBPWorkflowTemplateLoader::Update($id, $arNewFields); } /** * Write action by rollback scenario. Use method `getData` for getting commit saved data **/ public function rollback() { $pathBPElement = _DIR_ . '/files/bp-wt-old.bpt'; $id = $this->importBP($pathBPElement); $arFieldsTemplate = \CBPWorkflowTemplateLoader::GetList([], ['ID' => $id])->GetNext(); $template = $arFieldsTemplate['TEMPLATE']; $arNewFields = [ 'TEMPLATE' => $template, 'VARIABLES' => $arFieldsTemplate['VARIABLES'] ]; $arNewFields['MODIFIER_USER'] = new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser); \CBPWorkflowTemplateLoader::Update($id, $arNewFields); } } 

Source: https://habr.com/ru/post/pt466823/


All Articles