我们如何在Bitrix24中为业务流程设置迁移

为了使他们的操作自动化,企业经常使用Bitrix24。 在本文中,我们讨论了更改业务流程时可能出现的一些问题以及我们如何解决它们。



Bitrix24是常见的CRM系统之一。 它包括用于构建业务流程图的可视设计器(设计师)。 重要的是要记住,在编辑这些过程时,可能会遇到困难-特别是在大型现有项目中,首先在本地和测试服务器上检查所有更改。 在这种情况下,当转移到生产中时,我们使用业务流程迁移机制(以下简称BP)。

通常,小公司可以不进行迁移而仅将特定的业务流程暂停2-3天。 大型企业通常买不起它,因此它使用测试服务器和部署。



Bitrix24关于业务流程模板如何工作

迁移工作有其自身的特点。 尤其是,由于涉及的对象和ID众多,因此变得很复杂。 此外,Bitrix24还不提供业务流程的迁移-通常通过导入和导出解决此问题,并且可能存在各种不一致之处。 让我们从开发的角度考虑哪些问题同时存在。

查找业务流程模板时遇到问题


创建业务流程时,只能为模板分配名称,而不能为唯一代码分配名称。 在这种情况下,更新业务流程时,必须按名称从数据库中获取它。 名称有时会更改,因为系统在启动时会使用它们显示在进程列表中。 因此,在升级过程中可能会找不到模板。 通常,按名称搜索并不是一个好主意。

解决方案:

系统中创建的所有业务流程模板都存储在b_bp_workflow_template表中。 打开表后,在字段中可以看到SYSTEM_CODE:有一个代码字段,它根本不会输出到接口。 我们可以使用模板ID自己设置代码-可以在流程编辑页面的url中看到它:



我们需要创建一个函数以获取模板和代码的ID,检查要更改的模板的重复性和字段的完整性,并设置其代码。

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; } 

来吧 例如,在列表上创建一个测试业务流程:



要将本地开发的流程转移到测试服务器(然后转移到生产),我们使用迁移机制。

Bitrix24允许您导出业务流程。 我们将利用这个机会。



传输方案如下:

  • 导出业务流程
  • 我们写迁移,附加文件
  • 在新的展台,我们备份了旧流程
  • 应用迁移

接下来,考虑该过程如何发生。

创建迁移


我们将使用来自市场的迁移模块: https : //marketplace.1c-bitrix.ru/solutions/ws.migrations/

我们项目中的迁移文件位于本地/迁移/方案中




打开流程模板页面并导出。 在迁移目录中,创建文件目录,并将导出的文件放在此处。 原来是这样的:

本地/迁移/方案/文件/ bp-94.bpt

创建迁移方案:

 class ws_m_1565783124_approve_task extends \WS\Migrations\ScriptScenario { 

定义业务流程模板的参数:

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

我们实现业务流程的导入功能:

 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']; } 

在这里,我们首先确定要为其应用流程的信息块的ID,然后使用给定的代码获取流程模板的ID。

如果找到模板,我们将对其进行更新。 如果找不到-添加。
该函数返回创建或更新的进程的ID以及所需的信息-我们将进一步说明。

我们定义了一个提交函数,它将添加/更新我们的业务流程:

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

因此,在此步骤中,我们已经能够通过迁移模块创建和更新特定的业务流程。

更新模板数据时出现问题


让我们回到业务流程并在其中添加操作-用户通知。



作为发送者,我们选择作者。 收件人将:

  • 人力资源用户组
  • 用户Svetlana Kuznetsova

现在让我们看看业务流程如何记录在数据库中。 为此,我们在管理面板的PHP控制台中获取并打印模板:



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


在过程参数数组中,我们看到了以下情况:



我们看一下group_g15行。 15是人力资源组ID。
我们看一行user_579。 579是用户ID。

这意味着,如果我们在另一个站点上导入该流程,则会产生持续的不一致。

T.O. 在将这些ID迁移到与我们要导入流程的网站相关的ID后,我们需要进行替换。

组通过符号代码标识,用户通过登录标识。

首先,在创建过程的站点上,我们获得了组的符号代码和用户登录名。 如果您没有设置符号组代码,最好编写迁移并先安装它们。

在我们的示例中:

  • 组代码-人力资源
  • 用户登录-svetlana.kuznetsova

接下来,我们编写迁移函数,通过代码和登录,将为我们提供组和用户的ID:

  • getUserId($登录名)
  • getGroupId($代码);

最后,更新模板中的适当值:

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


导入业务流程:

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


我们得到模板数据:

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


在业务流程中替换用户标识:

 $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); } 

在这里,开始迁移时,我们上传文件并使用importBP函数创建/更新过程。 接下来,我们将业务流程模板的结构放入一个数组中,替换ID并更新模板。

总结一下


在本文中,我们仅涉及了站点之间传输期间可能发生不一致的几种情况,并指出了要查找的内容。 通常,在我们的实践中,我们遇到了以下id绑定:

  • user_(绑定到用户)
  • group_(绑定到用户组)
  • iblock_(信息块绑定)
  • SequentialWorkflowActivity(从模板启动业务流程)
  • PROPERTY_(绑定到具有未定义字符代码的文档字段)

如果一切都正确完成,那么调试后的业务流程到生产的转移将迅速而顺利。

希望我们的经验对您有所帮助!

显示完整的例子
 <?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/zh-CN466823/


All Articles