Comment nous configurons les migrations pour les processus métier dans Bitrix24

Pour automatiser leurs opérations, l'entreprise utilise souvent Bitrix24. Dans cet article, nous parlons de certains des problèmes possibles lors de la modification des processus métier et de la manière dont nous les avons résolus.



Bitrix24 est l'un des systèmes CRM les plus courants. Il comprend un concepteur visuel (concepteur) pour créer des diagrammes de processus métier. Il est important de se rappeler que lors de la modification de ces processus, des difficultés sont possibles - en particulier sur les grands projets existants, où les modifications sont d'abord vérifiées sur les serveurs locaux et de test. Dans de tels cas, lors du passage à la production, nous utilisons le mécanisme de migration des processus métier (ci-après - BP).

En règle générale, les petites entreprises peuvent se passer de migration et suspendre simplement un processus métier particulier pendant 2-3 jours. Une grande entreprise ne peut généralement pas se le permettre, elle utilise donc des serveurs de test et de déploiement.



Bitrix24 sur le fonctionnement d'un modèle de processus métier

Le travail avec la migration a ses propres caractéristiques. En particulier, il est compliqué par le grand nombre d'objets impliqués et d'ID. De plus, Bitrix24 ne prévoit pas non plus la migration des processus métier en tant que telle - souvent ce problème est résolu par l'importation et l'exportation, et il peut y avoir diverses incohérences. Voyons quels problèmes sont possibles en même temps du point de vue du développement.

Problème pour trouver un modèle de processus métier


Lors de la création d'un processus métier, vous ne pouvez attribuer qu'un nom au modèle, pas un code unique. Dans ce cas, lors de la mise à jour d'un processus métier, il devra être obtenu à partir de la base de données par son nom. Les noms changent parfois car le système les utilise pour s'afficher dans la liste des processus au démarrage. Par conséquent, il peut y avoir des situations où, lors de la mise à niveau, il sera impossible de trouver un modèle. Et en général, la recherche par nom n'est pas une si bonne idée.

Solution:

Tous les modèles de processus métier créés dans le système sont stockés dans la table b_bp_workflow_template. Après avoir ouvert la table, parmi les champs, nous voyons SYSTEM_CODE: il y a un champ pour le code, il n'est tout simplement pas sorti sur l'interface. Nous pouvons définir le code nous-mêmes en utilisant l'ID du modèle - il peut être vu dans l'url sur la page d'édition du processus:



Nous devons créer une fonction afin d'obtenir l'id du modèle et du code, effectuer une vérification de la duplication et de l'exhaustivité du champ pour le modèle à modifier, et également définir son code.

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

Allez-y. Par exemple, créez un processus métier de test sur les listes:



Pour transférer un processus développé localement vers un serveur de test (puis vers la production), nous utilisons le mécanisme de migration.

Bitrix24 vous permet d'exporter un processus métier. Nous utiliserons cette opportunité.



Le schéma de transfert est le suivant:

  • Exportation d'un processus métier
  • Nous écrivons la migration, joignons le fichier
  • Au nouveau stand, nous sauvegardons l'ancien processus
  • Appliquer la migration

Ensuite, considérez comment ce processus se produit.

Créer une migration


Nous utiliserons le module de migration depuis la place de marché: https://marketplace.1c-bitrix.ru/solutions/ws.migrations/ .

Les fichiers de migration de notre projet sont situés dans local / migrations / scenarios




Ouvrez la page du modèle de processus et exportez. Dans le répertoire de migration, créez le répertoire des fichiers et placez-y le fichier exporté. Il se présente comme ceci:

local / migrations / scénarios / fichiers / bp-94.bpt

Créez un scénario de migration:

 class ws_m_1565783124_approve_task extends \WS\Migrations\ScriptScenario { 

Définissez les paramètres du modèle de processus métier:

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

Nous implémentons la fonction d'importation du processus métier:

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

Ici, nous déterminons d'abord l'ID du bloc d'informations pour lequel nous appliquons le processus, et obtenons l'ID du modèle de processus avec le code donné.

Si le modèle est trouvé, nous le mettons à jour. S'il n'est pas trouvé - ajoutez.
La fonction renvoie l'id du processus créé ou mis à jour, et pour ce dont il a besoin - nous le dirons plus loin.

Nous définissons une fonction de validation qui ajoutera / mettra à jour notre processus métier:

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

Ainsi, à cette étape, nous sommes déjà en mesure de créer et de mettre à jour un processus métier spécifique via le module de migration.

Problème de mise à jour des données du modèle


Revenons à notre processus métier et y ajoutons une action - notification aux utilisateurs.



En tant qu'expéditeur, nous sélectionnons l'auteur. Les récipiendaires devront:

  • Groupe d'utilisateurs RH
  • User Svetlana Kuznetsova

Voyons maintenant comment le processus métier est enregistré dans la base de données. Pour ce faire, nous obtenons et imprimons le modèle dans la console PHP dans le panneau d'administration:



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


Dans le tableau des paramètres de processus, nous voyons ces occurrences:



Nous regardons la ligne group_g15. Voici 15 est l'ID du groupe RH.
Nous regardons la ligne user_579. Ici 579 est l'ID utilisateur.

Cela signifie que si nous importons le processus sur un autre site, nous aurons des incohérences continues.

T.O. nous devons effectuer un remplacement après la migration de ces identifiants vers ceux qui sont pertinents pour le site sur lequel nous importons le processus.

Les groupes sont identifiés par code symbolique, les utilisateurs par identifiant.

Pour commencer, sur le site où le processus a été créé, nous obtenons le code symbolique du groupe et la connexion utilisateur. Dans le cas où vous n'avez pas défini de codes de groupe symboliques, il est préférable d'écrire la migration et de les installer en premier.

Dans notre exemple:

  • Code de groupe - RH
  • Connexion utilisateur - svetlana.kuznetsova

Ensuite, nous écrivons dans les fonctions de migration qui, par code et login, nous donneront l'id du groupe et de l'utilisateur:

  • getUserId ($ login)
  • getGroupId ($ code);

Enfin, mettez à jour les valeurs appropriées dans le modèle:

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


Importer un processus métier:

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


Nous obtenons les données du modèle:

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


Remplacez l'ID utilisateur dans le processus métier:

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

Ici, lors du démarrage de la migration, nous téléchargeons le fichier et créons / mettons à jour le processus avec la fonction importBP. Ensuite, nous obtenons la structure du modèle de processus métier dans un tableau, remplaçons l'ID et mettons à jour le modèle.

Pour résumer


Dans cet article, nous n'avons abordé que quelques cas où des incohérences peuvent se produire lors du transfert entre les sites, et nous avons indiqué ce qu'il fallait rechercher. En général, dans notre pratique, nous sommes tombés sur les liaisons id suivantes:

  • user_ (liaison à l'utilisateur)
  • group_ (liaison au groupe d'utilisateurs)
  • iblock_ (liaison infoblock)
  • SequentialWorkflowActivity (démarrage d'un processus métier à partir d'un modèle)
  • PROPERTY_ (liaison à un champ de document avec un code de caractère non défini)

Si tout est fait correctement, le transfert d'un processus métier débogué vers la production est rapide et fluide.

Nous espérons que notre expérience vous a été utile!

Afficher l'exemple complet
 <?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/fr466823/


All Articles