Cómo configuramos migraciones para procesos empresariales en Bitrix24

Para automatizar sus operaciones, la empresa a menudo usa Bitrix24. En este artículo, hablamos sobre algunos de los posibles problemas al cambiar los procesos comerciales y cómo los solucionamos.



Bitrix24 es uno de los sistemas CRM comunes. Incluye un diseñador visual (diseñador) para construir diagramas de procesos de negocio. Es importante recordar que al editar estos procesos, las dificultades son posibles, especialmente en grandes proyectos existentes, donde cualquier cambio se verifica primero en los servidores locales y de prueba. En tales casos, cuando se transfiere a producción, utilizamos el mecanismo de migración de procesos de negocio (en adelante, BP).

Las pequeñas empresas, por regla general, pueden prescindir de la migración y simplemente suspender un proceso comercial en particular durante 2-3 días. Una gran empresa generalmente no puede permitírselo, por lo tanto, utiliza servidores de prueba e implementación.



Bitrix24 sobre cómo funciona una plantilla de proceso de negocio

El trabajo con migración tiene sus propias características. En particular, se complica por la gran cantidad de objetos involucrados e ID. Además, Bitrix24 tampoco proporciona la migración de los procesos comerciales como tal, a menudo este problema se resuelve a través de la importación y exportación, y puede haber varias inconsistencias. Consideremos qué problemas son posibles al mismo tiempo desde el punto de vista del desarrollo.

Problema para encontrar una plantilla de proceso empresarial


Al crear un proceso de negocio, solo puede asignar un nombre a la plantilla, no un código único. En este caso, al actualizar un proceso de negocio, deberá obtenerse de la base de datos por su nombre. Los nombres a veces cambian porque el sistema los usa para mostrar en la lista de procesos al inicio. En consecuencia, puede haber situaciones en las que durante la actualización será imposible encontrar una plantilla. Y en general, buscar por nombre no es una buena idea.

Solución:

Todas las plantillas de proceso de negocio creadas en el sistema se almacenan en la tabla b_bp_workflow_template. Una vez abierta la tabla, entre los campos vemos SYSTEM_CODE: hay un campo para el código, simplemente no se envía a la interfaz. Podemos configurar el código nosotros mismos usando la identificación de la plantilla; se puede ver en la URL de la página de edición del proceso:



Necesitamos crear una función para obtener la identificación de la plantilla y el código, realizar una verificación de duplicación y la integridad del campo para que se modifique la plantilla, y también establecer su 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; } 

Adelante Por ejemplo, cree un proceso comercial de prueba en las listas:



Para transferir un proceso desarrollado localmente a un servidor de prueba (y luego a producción), utilizamos el mecanismo de migración.

Bitrix24 le permite exportar un proceso de negocio. Aprovecharemos esta oportunidad.



El esquema de transferencia es el siguiente:

  • Exportar un proceso de negocio
  • Escribimos la migración, adjuntamos el archivo
  • En el nuevo stand, respaldamos el proceso anterior
  • Aplicar migración

Luego, considere cómo ocurre este proceso.

Crear migración


Utilizaremos el módulo de migración del mercado: https://marketplace.1c-bitrix.ru/solutions/ws.migrations/ .

Los archivos de migración en nuestro proyecto se encuentran en locales / migraciones / escenarios




Abra la página de plantilla de proceso y exporte. Dentro del directorio de migración, cree el directorio de archivos y coloque el archivo exportado allí. Resulta así:

local / migraciones / escenarios / archivos / bp-94.bpt

Crear un escenario de migración:

 class ws_m_1565783124_approve_task extends \WS\Migrations\ScriptScenario { 

Defina los parámetros de la plantilla de proceso de negocio:

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

Implementamos la función de importación del proceso de negocio:

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

Aquí, primero determinamos la ID del bloque de información para el que estamos aplicando el proceso, y obtenemos la identificación de la plantilla de proceso con el código dado.

Si se encuentra la plantilla, la actualizamos. Si no se encuentra, agregue.
La función devuelve la identificación del proceso creado o actualizado, y para lo que se necesita, le diremos más.

Definimos una función de compromiso que agregará / actualizará nuestro proceso comercial:

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

Entonces, en este paso ya podemos crear y actualizar un proceso comercial específico a través del módulo de migración.

Problema al actualizar los datos de la plantilla


Volvamos a nuestro proceso comercial y agreguemos una acción allí: notificación del usuario.



Como remitente seleccionamos el autor. Los destinatarios:

  • Grupo de usuarios de recursos humanos
  • Usuario Svetlana Kuznetsova

Ahora veamos cómo se registra el proceso de negocio en la base de datos. Para hacer esto, obtenemos e imprimimos la plantilla en la consola PHP en el panel de administración:



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


En la matriz de parámetros de proceso, vemos estos sucesos:



Nos fijamos en la línea group_g15. Aquí 15 es la identificación del grupo de recursos humanos.
Nos fijamos en la línea user_579. Aquí 579 es la identificación de usuario.

Esto significa que si importamos el proceso en otro sitio, tendremos inconsistencias continuas.

T.O. necesitamos hacer un reemplazo después de migrar estos ID a aquellos que son relevantes para el sitio donde estamos importando el proceso.

Los grupos se identifican por código simbólico, los usuarios por inicio de sesión.

Para comenzar, en el sitio donde se creó el proceso, obtenemos el código simbólico del grupo y el inicio de sesión del usuario. En el caso de que no tenga configurados códigos de grupo simbólicos, es mejor escribir la migración e instalarlos primero.

En nuestro ejemplo:

  • Código de grupo - HR
  • Inicio de sesión de usuario - svetlana.kuznetsova

A continuación, escribimos las funciones de migración que, por código e inicio de sesión, nos darán la identificación del grupo y usuario:

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

Finalmente, actualice los valores apropiados en la plantilla:

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


Importar un proceso de negocio:

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


Obtenemos los datos de la plantilla:

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


Reemplace la identificación de usuario dentro del proceso de negocio:

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

Aquí, al comenzar la migración, cargamos el archivo y creamos / actualizamos el proceso con la función importBP. A continuación, obtenemos la estructura de la plantilla de proceso de negocio en una matriz, reemplazamos la ID y actualizamos la plantilla.

Para resumir


En este artículo, tratamos solo algunos casos en los que pueden ocurrir inconsistencias durante la transferencia entre sitios, e indicamos qué buscar. En general, en nuestra práctica, nos encontramos con los siguientes enlaces de identificación:

  • usuario_ (enlace al usuario)
  • group_ (enlace al grupo de usuarios)
  • iblock_ (enlace de bloque de información)
  • SequentialWorkflowActivity (iniciar un proceso de negocio desde una plantilla)
  • PROPIEDAD_ (enlace a un campo de documento con un código de caracteres indefinido)

Si todo se hace correctamente, la transferencia de un proceso comercial depurado a producción es rápida y sin problemas.

¡Esperamos que nuestra experiencia le haya sido útil!

Mostrar ejemplo 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/466823/


All Articles