Смарт-процессы - crm api коробка



общая статья про api d7 - добавить, получить, изменить смарт-процесс описано там
тут ниже дополнение для смарт-процессов

получить все привязки компании к смарт процессам
в $parents будет нужная, смотреть entityTypeId
use Bitrix\Crm\ItemIdentifier;
use Bitrix\Crm\Service\Container;
$parent = new ItemIdentifier(\CCrmOwnerType::Company, $companyId);
$parents = Container::getInstance()->getRelationManager()->getChildElements($parent); var_dump($parents);
получить привязанные смарт-процессы, к смарт-процессу
тоже самое, только
$parent = new ItemIdentifier($smartType, $smartItemId);
есть еще обратный метод
$parents = Container::getInstance()->getRelationManager()->getParentElements($parent);
простой обработчик ПОСЛЕ изменения смарт-процесса
AddEventHandler("crm","onCrmDynamicItemUpdate","MyOnCrmDynamicItemUpdate");
function MyOnCrmDynamicItemUpdate($item, $entityId){   
   //AddMessage2Log($item->getId()); // =$entityId
   //AddMessage2Log($entityId);
}

Если смарт-процесс привязан к другой сущности, например к сделке, то поле-связки можно заполнять как и любое поле сделки
$fields = ['PARENT_ID_171' => $smartProcessId]; //PARENT_ID_171 - поле связки
$entity = new CCrmDeal(false);
$result = $entity->Update($deal_id, $fields, true, true, array());

Подмена фабрики и контейнера
фабрика /local/php_interface/classes/sds/crm/factory.php
  • \CCrmFieldInfoAttr::Immutable - не позволяет изменять это поле через интерфейс пользователем.
  • \CCrmFieldInfoAttr::NotDisplayed - скроет поле из детальной карточки.
  • \CCrmFieldInfoAttr::Required - сделает поле обязательным независимо от настроек.
namespace sds\crm;

use \Bitrix\Main,
   \Bitrix\Crm,
   \Bitrix\Crm\Service,
   \Bitrix\Crm\Service\Factory\Dynamic,
   \Bitrix\Crm\Service\Operation,
   \Bitrix\Crm\Service\Context,
   \Bitrix\Main\Result,
   \Bitrix\Crm\Item,
   \Bitrix\Bizproc\Workflow\Type\GlobalConst;

Main\Loader::requireModule('crm');

class Factory extends Dynamic{

        //задача, чтобы только определенные пользователи могли редактировать определенные поля
   public function getUserFieldsInfo(): array
   {
      $fields = parent::getUserFieldsInfo();
                //список полей, которые только через апи можно изменить
      $arReadFields = [
         "UF_CRM_3_1711372268355", 
         "UF_CRM_3_1711372325073", 
         "UF_CRM_3_1711372343816", 
         "UF_CRM_3_1711617100002", 
         "UF_CRM_3_1711617197261", 
         "UF_CRM_3_1711617340871", 
      ]; 
      foreach ($arReadFields as $field) {
         if(isset($fields[$field])){
                   $fields[$field]['ATTRIBUTES'][] = \CCrmFieldInfoAttr::Immutable;
         }
      }
      
                //а тут или юзеры (через роли-константы), или админы (роль-константа)
      $userId = Service\Container::getInstance()->getContext()->getUserId();
      if(\CModule::IncludeModule("bizproc")){
         //кс-2
              $dir1 = str_replace("user_","",GlobalConst::getValue("Constant1709837236398")); 
                   $dir2 = str_replace("user_","",GlobalConst::getValue("Constant1709837193965"));
                   $glBuh = str_replace("user_","",GlobalConst::getValue("Constant1709837399990"));
              $buhEc = str_replace("user_","",GlobalConst::getValue("Constant1709837310294"));
                  $zamDirEcFin = str_replace("user_","",GlobalConst::getValue("Constant1709837367630"));
               $glInj = str_replace("user_","",GlobalConst::getValue("Constant1709837345998"));
         $injPto = str_replace("user_","",GlobalConst::getValue("Constant1712053287946"));

              $admins2 = GlobalConst::getValue("Constant1711462433918");
                $admins = [];
              foreach ($admins2 as $admin) {
              $admins[] = str_replace("user_","",$admin);
               }
           
           
                //замечания в согласовании  только директор 1, 2, только гл бух
           if(isset($fields["UF_CRM_3_1711132374160"]) && !in_array($userId, [$dir1,$dir2,$glBuh]) ){
                  $fields['UF_CRM_3_1711132374160']['ATTRIBUTES'][] = \CCrmFieldInfoAttr::Immutable;               
           }
           if(!in_array($userId, $admins)){
              $arFields = [
                 "UF_CRM_3_1709319836452" => [$buhEc], //субподрядная организация
                 "UF_CRM_3_1709319853364" => [$buhEc], //наименование объекта
                 "UF_CRM_3_1711708605142" => [$buhEc], //сумма                 
                 "UF_CRM_3_1711708531004" => [$buhEc], //комментарий
                 "UF_CRM_3_1709319932498" => [$buhEc], //дата акта
                 "UF_CRM_3_1709319908868" => [$buhEc], //номер акта в унф
                 "UF_CRM_3_1710079389817" => [$buhEc], //документ кс2
                 "UF_CRM_3_1710079558113" => [$buhEc], //поступления на объект
                 "UF_CRM_3_1710164767315" => [$buhEc], //возвраты с объекта
                 "UF_CRM_3_1711371018377" => [$buhEc], //комментарий к поступлениям
                 "UF_CRM_3_1711370249573" => [$buhEc, $zamDirEcFin],  //акт перерасхода финальный
                 "UF_CRM_3_1711370137171" => [$buhEc, $zamDirEcFin], //документы для подписания
                 "UF_CRM_3_1711975268246" => [$injPto], //согласовано или нет инж пто
                 "UF_CRM_3_1711975160397" => [$injPto], //коммент инж пто
                 "UF_CRM_3_1710079657466" => [$glInj]//акт перерасхода   
              ];           
              //AddMessage2Log($arFields);
              foreach ($arFields as $field => $arUsers) {
                 if(isset($fields[$field]) && !in_array($userId, $arUsers)){
                    $fields[$field]['ATTRIBUTES'][] = \CCrmFieldInfoAttr::Immutable;
                 }                                     
              }
         }           
        }   
      return $fields;
   }

   public function getAddOperation(Item $item, Service\Context $context = null): Operation\Add        
   {

      $operation = parent::getAddOperation($item, $context);
      $operation->addAction(
          Operation::ACTION_BEFORE_SAVE,
          new class extends Operation\Action {
              public function process(Item $item): Result
              {

                  /*ваша функция ДО добавления*/
                  return new Result();
              }
          }
      );

      return $operation->addAction(
          Operation::ACTION_AFTER_SAVE,
          new class extends Operation\Action {
              public function process(Item $item): Result
              {

                 /*ваша функция ПОСЛЕ добавления*/
                  return new Result();
              }
          }
      );
    }

   public function getUpdateOperation(Item $item, Service\Context $context = null): Operation\Update
   {

      $operation = parent::getUpdateOperation($item, $context);
      $operation->addAction(
          Operation::ACTION_BEFORE_SAVE,
          new class extends Operation\Action {
              public function process(Item $item): Result
              {

                  /*ваша функция ДО изменения*/
                  return new Result();
              }
          }
      );
      return $operation->addAction(
          Operation::ACTION_AFTER_SAVE,
          new class extends Operation\Action {
              public function process(Item $item): Result
              {
                   /*ваша функция ПОСЛЕ изменения*/
                  return new Result();
              }
          }
      );
   }

   public function getDeleteOperation(Item $item, \Bitrix\Crm\Service\Context $context = null): Operation\Delete
        {

      $operation = parent::getDeleteOperation($item, $context);
      $operation->addAction(
          Operation::ACTION_BEFORE_SAVE,
          new class extends Operation\Action {
              public function process(Item $item): Result
              {

                  /*ваша функция ДО удаления*/
                  return new Result();
              }

          }
      );
      return $operation;
   }
}

методы item в Operation::ACTION_BEFORE_SAVE
// все старые значения полей
$fields = $item->getData(\Bitrix\Main\ORM\Objectify\Values::ACTUAL);

// все измененные значения полей
$fields = $item->getData(\Bitrix\Main\ORM\Objectify\Values::CURRENT);

// все старые значения полей, в формате как $arFields в \CCrmDeal
$fields = $item->getCompatibleData(\Bitrix\Main\ORM\Objectify\Values::ACTUAL);

// все измененные значения полей, в формате как $arFields в \CCrmDeal
$fields = $item->getCompatibleData(\Bitrix\Main\ORM\Objectify\Values::CURRENT);



контейнер /local/php_interface/classes/sds/crm/container.php
в котором фабрику нашу подцепляем
namespace sds\crm;use \Bitrix\Main,
   \Bitrix\Crm\Service;

Main\Loader::requireModule('crm');

class Container extends Service\Container
{public function getFactory(int $entityTypeId): ?Service\Factory
   {
      // Если наш тип - подменяем
       
      if ( $entityTypeId == 146 ) { //ks2
         // Сгенерируем название сервиса
         $identifier = static::getIdentifierByClassName(static::$dynamicFactoriesClassName, [$entityTypeId]);
         // если такой есть то вернем с ним
         if ( Main\DI\ServiceLocator::getInstance()->has($identifier) ){
            return Main\DI\ServiceLocator::getInstance()->get($identifier);
         }

         // Объекта нет. Получим 'объект смарт-процесса'
         $type = $this->getTypeByEntityTypeId($entityTypeId);
         if ( !$type ){// Не получилось, смарт-процесс удален            
            return null;
         }
         
         $factory = new \sds\crm\Factory($type); //нашу фабрику подцепляем
         Main\DI\ServiceLocator::getInstance()->addInstance(
            $identifier,
            $factory
         );
         
         return $factory;
      }
      // Если тип не наш - передаем в родительский метод
      return parent::getFactory($entityTypeId);
   }

}
можно в командной строке проверить. что все ок, потом перенести в init.php
require_once($_SERVER["DOCUMENT_ROOT"].'/local/php_interface/classes/sds/crm/container.php'); //класс с контейнером
require_once($_SERVER["DOCUMENT_ROOT"].'/local/php_interface/classes/sds/crm/factory.php'); //класс с фабрикой
\Bitrix\Main\DI\ServiceLocator::getInstance()->addInstanceLazy('crm.service.container', [
   'className' => '\\sds\\crm\\Container',
]);
проверить, что наши классы подцепились
echo get_class(\Bitrix\Crm\Service\Container::getInstance());
echo get_class(\Bitrix\Crm\Service\Container::getInstance()->getFactory( 146 ));


запустить БП роботов после изменения стадии смарт-процесса через апи
CBPDocument::StartWorkflow(
   139, //ID робота, смотреть через таблицу b_bp_workflow_template
   array("crm", "Bitrix\Crm\Integration\BizProc\Document\Dynamic", "DYNAMIC_146_". $id),
   array(),
   $arErrorsTmp
);  
 
Если блог был полезным, можете угостить меня "чашечкой кофе" :)

Сбер по номеру телефона +7 (953) 585-13-09 Вероника.
Спасибо!