Обучаю битриксу программистов, интеграторов. Подробнee ⇒

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



статья про другие сущности crm
$factory = Bitrix\Crm\Service\Container::getInstance()->getFactory($smartTypeId); //сначала по типу получаем
создать элемент смарт-процесса
$newItem = $factory->createItem();
$newItem->setTitle('Тестовый элемент' );
$newItem->save();

создать с контекстом элемент смарт-процесса
$context = new Context();
$context -> setUserId($userId); // если добавление происходит в агенте например, то надо установить юзера
$item = $factory->createItem($data); 
$saveOperation = $factory->getAddOperation($item, $context); //для поддержки кастомизации операции добавления
$operationResult = $saveOperation->launch();
получить элемент смарт-процесса
$item = $factory->getItem($smartId); //по id смарт-процесса
$data = $item->getData();
//$data["#FIELD#"];
Получение списка элементов смарт-процесса
$items = $factory->getItems([
   'filter' => [
        '@ID' => $ids, 
        '=PARENT_ID_1'=>$otherSmartElementId
   ],
   'select' => ['ID', 'UF_CRM_2_POLE', 'TITLE'],
   'order' => ['UF_CRM_2_POLE' => 'ASC'],
   'limit'=>1000,
   'offset' =>0
]);
$items = $factory->getItems([
   "filter"=>["UF_CRM_5_1710857072973"=>10],
   "select"=>["ID","TITLE","STAGE_ID","ASSIGNED_BY_ID","UF_CRM_5_1710165256805"], //"id","title" - так тоже работает
]);

foreach($items as $item){
   echo $item->getTitle();
   echo $item->getUfCrm_5_1710165256805();
   echo $item->getAssignedById();
   echo $item->getStageId();
        //$item->getData();//как-то хреново работает, не все поля заполнены, тайтл кривой

}

Изменение элемента смарт-процесса
$item->set("#FIELD#",$value);
$item->save();
или так
$class = $factory -> getDataClass();
$saveResult = $class::update($id, $arUpdate);
Изменение элемента смарт-процесса с поддержкой кастомизации операции изменения
$saveOperation = $factory ->getUpdateOperation($item, $context); 
$operationResult = $saveOperation->launch();

Удаление элемента смарт-процесса
$saveOperation = $factory->getDeleteOperation($item, $context);
$operationResult = $saveOperation->launch();
получить все привязки компании к смарт процессам
в $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);
}
Подмена фабрики и контейнера
фабрика /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);
   }

}
можно в командной строке проdерить. что все ок, потом перенести в 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
);  


функция. которая из БП смарт-процесса запускается из блока пхп-код
function AddCommentsToMainDoc($arFields){//все комментарии визирующих в основной документ    
   if(!empty($arFields["type"]) && in_array($arFields["type"], ["dog","ks2","bill"])){
      $id = $arFields["id"] ?? "";
      $mainId = $arFields["mainId"] ?? "";
      $userId = $arFields["userId"] ?? "" ;

      if(!empty($id) && !empty($mainId) && CModule::IncludeModule("crm")){
         if($arFields["type"]=="dog"){
            $factory = \Bitrix\Crm\Service\Container::getInstance()->getFactory(132);
            $items = $factory->getItems([
               "filter"=>["UF_CRM_5_1710857072973"=>$mainId],
               "select"=>["ID","STAGE_ID","ASSIGNED_BY_ID","UF_CRM_5_1710165256805"],
            ]);
            $bAll = true; //все согласовали
            $arUserIds = [];
            foreach($items as $item){
               if($item->getStageId() == "DT132_10:NEW"){//не все
                  $bAll = false;
                  break;
               }
               $arUserIds[$item->getAssignedById()] = $item->getAssignedById();
               //$item->getUfCrm_5_1710165256805(); //коммент               
            }
            // AddMessage2Log($arUserIds);
            if($bAll && !empty($arUserIds)){//все согласовали
               // AddMessage2Log("все согласовали");
               $dbUsers = \Bitrix\Main\UserTable::getList([
                   'select' => ['ID','NAME','LAST_NAME'], 
                   'filter' => ["id"=>$arUserIds],
                   'order' => [],                       
               ]);
               $arUsers = [];
               while ($user = $dbUsers->fetchObject()) {
                  $arUsers[$user->getId()] = $user->getLastName()." ".$user->getName();
               }
               // AddMessage2Log($arUsers);
               $arComments = [];

               foreach($items as $item){
                  if(!empty($arUsers[$item->getAssignedById()])){
                     $arComments[] = $arUsers[$item->getAssignedById()].": ". $item->getUfCrm_5_1710165256805();
                  }
                  else{
                     $arComments[] = $item->getAssignedById().": ". $item->getUfCrm_5_1710165256805();
                  }
               }
               // AddMessage2Log($arComments);   
               if(!empty($arComments)){                  
                  $mainItem = $factory->getItem($mainId);
                  // AddMessage2Log($mainItem->getTitle());
                  // AddMessage2Log($mainItem->getId());
                  $mainItem ->setUfCrm_5_1710071876683($arComments);
                  $mainItem ->save();
                  $mainItem ->setStageId("DT132_8:UC_2PG7OF"); //корректировка договора      
                  $mainItem ->save();         
               }
            }
         }
         elseif($arFields["type"]=="ks2"){
            $factory = \Bitrix\Crm\Service\Container::getInstance()->getFactory(146);
            $item = $factory->getItem($id);
            
            $comment = $item->getUfCrm_3_1711132374160();
            $role = $item->getUfCrm_3_1711457858372();
            


            $mainItem = $factory->getItem($mainId);
            if($role == 194){//дир1
               $mainItem->setUfCrm_3_1711372268355($comment);
               if($item->getStageId() == "DT146_11:SUCCESS"){
                  $mainItem->setUfCrm_3_1711617100002(197);
               }
               elseif($item->getStageId() == "DT146_11:FAIL"){
                  $mainItem->setUfCrm_3_1711617100002(198);
               }
            }
            elseif($role == 195){//дир2
               $mainItem->setUfCrm_3_1711372325073($comment);   
               if($item->getStageId() == "DT146_11:SUCCESS"){
                  $mainItem->setUfCrm_3_1711617197261(199);
               }
               elseif($item->getStageId() == "DT146_11:FAIL"){
                  $mainItem->setUfCrm_3_1711617197261(200);
               }            
            }
            elseif($role == 196){//гл бух
               $mainItem->setUfCrm_3_1711372343816($comment);
               if($item->getStageId() == "DT146_11:SUCCESS"){
                  $mainItem->setUfCrm_3_1711617340871(201);
               }
               elseif($item->getStageId() == "DT146_11:FAIL"){
                  $mainItem->setUfCrm_3_1711617340871(202);
               }
            }   
            $mainItem ->save();
            $items = $factory->getItems([
               "filter"=>[
                  "STAGE_ID" => "DT146_11:NEW",
                  "UF_CRM_3_1711120055056"=>$mainId
               ],
               "select"=>["ID"],
            ]);
            
            if(empty($items)){//все согласовали                  
                                             
               $mainItem ->setStageId("DT146_6:UC_4VSMFT"); //бух экономист      
               $mainItem ->save();
               if(\CModule::IncludeModule("bizproc")){
                  $arErrors = Array();                  
                  CBPDocument::StartWorkflow(
                         139, //ID робота, смотреть через таблицы
                         array("crm", "Bitrix\Crm\Integration\BizProc\Document\Dynamic", "DYNAMIC_146_". $mainId),
                         array(),
                         $arErrorsTmp
                  );   
               }   
            }

         }
         elseif($arFields["type"]=="bill"){

         }
      }
   }
}
Если блог был полезным, можете угостить меня "чашечкой кофе" :)

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