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

Гибкие правила для настройки крайнего срока задач



Крайний срок не должен быть больше, чем значение поля типа дата (или дата/время).  
Возможность поставить интервал "-1ч", "0" "+10мин" к значению поля, что даст большую вариантивность функционалу
Можно выбрать подразделение сотрудников для правила, поставить исключение, указать его роль в задаче

use Bitrix\Main\SystemException; //если надо генерировать ошибку

AddEventHandler("tasks", "OnBeforeTaskAdd", "MyOnBeforeTaskAdd");
function MyOnBeforeTaskAdd(&$arTask){   
   if(!empty($arTask["UF_CRM_TASK"][0]) && CModule::IncludeModule("tasks") && CModule::IncludeModule("crm") && CModule::IncludeModule('intranet')){
      global $USER;
                 $arTaskForCheck = [
         "UF_CRM_TASK" => $arTask["UF_CRM_TASK"][0],
         "CREATED_BY" => $arTask["CREATED_BY"]?? $USER->GetID(),
         "RESPONSIBLE_ID" => $arTask["RESPONSIBLE_ID"]?? $USER->GetID(),
         "DEADLINE" => $arTask["DEADLINE"]
      ];   
      $arTask["DEADLINE"] = CheckTaskDeadLine($arTaskForCheck);   

      
   }

}
AddEventHandler("tasks", "OnBeforeTaskUpdate", "MyOnBeforeTaskUpdate");
function MyOnBeforeTaskUpdate($id, &$data, &$arTask){   
   if((!empty($data["UF_CRM_TASK"][0])||!empty($arTask["UF_CRM_TASK"][0])) && CModule::IncludeModule("tasks") && CModule::IncludeModule("crm") && CModule::IncludeModule('intranet')){
      $arTaskForCheck = [
         "UF_CRM_TASK" => $data["UF_CRM_TASK"][0] ?? $arTask["UF_CRM_TASK"][0],
         "CREATED_BY" => $data["CREATED_BY"] ?? $arTask["CREATED_BY"],
         "RESPONSIBLE_ID" => $data["RESPONSIBLE_ID"] ?? $arTask["RESPONSIBLE_ID"],
         "DEADLINE" => $data["DEADLINE"] ?? $arTask["DEADLINE"]
      ];   
      $data["DEADLINE"] = CheckTaskDeadLine($arTaskForCheck);      
   }   
}

function CheckTaskDeadLine($arTask){

   $iblockId = 369;
   $taskCreatedId = $arTask["CREATED_BY"];
   $taskResponsibleId = $arTask["RESPONSIBLE_ID"];
   $minDeadLine = $arTask["DEADLINE"];
   if(!empty($minDeadLine)){
      $minDeadLine = new DateTime($minDeadLine);
   }   
   
   if(substr($arTask["UF_CRM_TASK"], 0,2)=="L_"){ //lead
      $type = "lead";
      $leadId = substr($arTask["UF_CRM_TASK"], 2);
      $arFilter = [
           "ID"=>$leadId, 
           "CHECK_PERMISSIONS"=>"N" //не проверять права доступа текущего пользователя
      ];           
         
      $res = CCrmLead::GetList(Array(), $arFilter);
      if($arEntity = $res->Fetch()){

         $stageId = $arEntity["STATUS_ID"];          
      }
   }
   elseif(substr($arTask["UF_CRM_TASK"], 0,2)=="D_"){//deal
      $type = "deal";
      $dealId = substr($arTask["UF_CRM_TASK"], 2); 
      $arFilter = [
           "ID"=>$dealId, 
           "CHECK_PERMISSIONS"=>"N" //не проверять права доступа текущего пользователя
      ];            
        
      $res = CCrmDeal::GetList(Array(), $arFilter);
      if($arEntity = $res->Fetch()){
         
          $stageId = $arEntity["STAGE_ID"];
      }
   }
   echo $stageId;
   
   if(!empty($stageId) && CModule::IncludeModule("iblock")){
      //выбираем список значений свойств "стадия", "поле"
      $arIblockEnumProps = [];

      $propertyEnum = CIBlockPropertyEnum::GetList(Array("DEF"=>"DESC", "SORT"=>"ASC"), Array("IBLOCK_ID"=>$iblockId, "CODE"=>["STAGE","FIELD"]));      
      while($arProp = $propertyEnum->GetNext()){
        $arIblockEnumProps[$arProp["PROPERTY_CODE"]][$arProp["XML_ID"]] = $arProp["ID"];         
      }
        
      if(!empty($arIblockEnumProps["STAGE"][$stageId])){
         //выбираем правила
         $arFilter = Array(
           "IBLOCK_ID"=>$iblockId, 
            "ACTIVE"=>"Y",
            "PROPERTY_STAGE" => ($type=="lead") ? "L_".$arIblockEnumProps["STAGE"][$stageId] : $arIblockEnumProps["STAGE"][$stageId]
         );
         $arSelect = Array("ID", "IBLOCK_ID","PROPERTY_FIELD","PROPERTY_TIME","PROPERTY_USER_EXCEPTION");
         $res = CIBlockElement::GetList(Array("sort"=>"asc"), $arFilter, false, Array("nPageSize"=>100,"iNumPage"=>1), $arSelect);

         $arUserDepartments = [];
         while($arRule = $res->Fetch()){            
            $bRuleRight = false;//подходит ли правило
             
            //подразделения роли исключения для правила
            $arCodes = ["USER_GROUPS","ROLE","USER_EXCEPTION","FIELD"];
            $arElemEnumProps = [];
            foreach($arCodes as $code){
               $res = CIBlockElement::GetProperty($iblockId, $arRule["ID"], "sort", "asc", array("CODE" => $code));               
               
               while ($arValue = $res->GetNext()){ 
                  $arElemEnumProps[$arValue["CODE"]][$arValue["VALUE"]] = !empty($arValue["VALUE_XML_ID"])? $arValue["VALUE_XML_ID"] :$arValue["VALUE"];
               } 
            }            

            $arUserIds = [];

            //проверяем постановщика
            if(!empty($arElemEnumProps["ROLE"]) && in_array("CREATED_BY",$arElemEnumProps["ROLE"]) && !isset($arElemEnumProps["USER_EXCEPTION"][$taskCreatedId])) {
               $arUserIds[] = $taskCreatedId;
            }

            //проверяем ответственного
            if(!empty($arElemEnumProps["ROLE"]) && in_array("RESPONSIBLE_ID",$arElemEnumProps["ROLE"]) && !isset($arElemEnumProps["USER_EXCEPTION"][$taskResponsibleId])){
               
               $arUserIds[] = $taskResponsibleId;
            }

            foreach($arUserIds as $userId){
               if(empty($arUserDepartments[$userId])){
                  $arDepartments = CIntranetUtils::GetUserDepartments($userId);   
                  $arUserDepartments[$taskCreatedId] = $arDepartments;
               }
               else{
                  $arDepartments = $arUserDepartments[$userId];
               }
               
               foreach($arDepartments as $departmentId){                  
                  if(isset($arElemEnumProps["USER_GROUPS"][$departmentId])){
                     $bRuleRight = true;                     
                     break(2);
                  }
               }
            }
            if($bRuleRight){ //правило подходит, проверяем крайний срок               
               $crmFieldCode = $arElemEnumProps["FIELD"][$arRule["PROPERTY_FIELD_ENUM_ID"]] ?? "";
               if(!empty($crmFieldCode) && !empty($arEntity[$crmFieldCode])){
                  $deadline = new DateTime($arEntity[$crmFieldCode]);
                  if(!empty($arRule["PROPERTY_TIME_VALUE"])){
                                                       //вариант 1 генерировать ошибку 
                                                       if(CModule::IncludeModule("im")){
                        global $USER;
                        $arFields = array(
                            "NOTIFY_TITLE" => "Ошибка в крайнем сроке задачи", //заголовок                                
                            "MESSAGE" => "Крайний срок не может быть более ".$deadline->format("d.m.Y H:i:s"),
                           "MESSAGE_TYPE" => IM_MESSAGE_SYSTEM, // IM_MESSAGE_PRIVATE, IM_MESSAGE_CHAT, IM_MESSAGE_OPEN, IM_MESSAGE_SYSTEM, IM_MESSAGE_OPEN_LINE
                           "TO_USER_ID" => $USER->GetID(),
                           "FROM_USER_ID" => $USER->GetID(),
                           //"AUTHOR_ID" => $userIdOther, //может отличаться от FROM_USER_ID
                           
                           "NOTIFY_TYPE" => IM_NOTIFY_SYSTEM,  // IM_NOTIFY_CONFIRM, IM_NOTIFY_SYSTEM, IM_NOTIFY_FROM
                           "NOTIFY_MODULE" => "main", // module id sender (ex: xmpp, main, etc)
                           "NOTIFY_EVENT" => "manage",                                  
                        );
                         CIMMessenger::Add($arFields);
                     }
                     throw new SystemException("Error deadline");

                                                        //вариант 2. перезаписать    
                     //$deadline->modify($arRule["PROPERTY_TIME_VALUE"]);   
                  }
                  if(empty($minDeadLine) || ($deadline < $minDeadLine)){
                     $minDeadLine = clone $deadline;
                  }                  
               }
            }            

         }
      }

   }
      
   return !empty($minDeadLine) ? $minDeadLine->format("d.m.Y H:i:s") : "";   
}
добавить все стадии лидов и сделок в свойство стадия
CModule::IncludeModule('crm'); 
CModule::IncludeModule('iblock');

$ibpenum = new \CIBlockPropertyEnum();
$sort = 10;

//лиды
$dbRow = CCrmStatus::GetList(['SORT'=>'asc'], ['ENTITY_ID'=>'STATUS']);
while ($row = $dbRow->fetch()) {

        $valueId = $ibpenum->Add([
       'PROPERTY_ID' => 4490,
       'VALUE' => "Лид. ".$row["NAME"],
       'XML_ID' => "L_".$row["STATUS_ID"],
            'SORT' => $sort
   ]);
         $sort = $sort + 5; 
    
}

//сделка основная воронка
$dbRow = CCrmStatus::GetList(['SORT'=>'asc'], ['ENTITY_ID'=>'DEAL_STAGE']); //DEAL_STAGE - основная

while ($row = $dbRow->fetch()) {

   $valueId = $ibpenum->Add([
       'PROPERTY_ID' => 4490, //id свойства стадия
       'VALUE' => "Сделка Общее. ".$row["NAME"],
       'XML_ID' => $row["STATUS_ID"],
            'SORT' => $sort
   ]);
        $sort = $sort + 5; 
    
}

//получаем остальные НЕосновные воронки
$arCategories = \Bitrix\Crm\Category\DealCategory::getList(
 ["select"=>["*"],]
)->fetchAll();

//добавляем стадии неосновных воронок
foreach($arCategories as $arCategory){
    $dbRow = CCrmStatus::GetList(['SORT'=>'asc'], ['ENTITY_ID'=>'DEAL_STAGE_'.$arCategory["ID"] ]); //DEAL_STAGE_i - i-id воронки

    while ($row = $dbRow->fetch()) {

   $valueId = $ibpenum->Add([
       'PROPERTY_ID' => 4490, //id свойства стадия
       'VALUE' => "Сделка ".$arCategory["NAME"].". ".$row["NAME"],
       'XML_ID' => $row["STATUS_ID"],
            'SORT' => $sort
   ]);
        $sort = $sort + 5; 
    
     }
   
}
добавить новую воронки
CModule::IncludeModule("crm");
CModule::IncludeModule("iblock");

$newTypeDeals = [140];
$sort = 3605; //сортировка

$ibpenum = new \CIBlockPropertyEnum();

//получаем НЕосновные воронки
$arCategories = \Bitrix\Crm\Category\DealCategory::getList(
 ["select"=>["*"],
  "filter" => ["ID"=>$newTypeDeals],
 ]
)->fetchAll();
echo "<pre>";

//добавляем стадии
foreach($arCategories as $arCategory){
   $dbRow = CCrmStatus::GetList(['SORT'=>'asc'], ['ENTITY_ID'=>'DEAL_STAGE_'.$arCategory["ID"] ]); //DEAL_STAGE_i - i-id воронки   
   while ($row = $dbRow->fetch()) {
   $arr = [
         'PROPERTY_ID' => 4490, //id свойства стадия
         'VALUE' => "Сделка ".$arCategory["NAME"].". ".$row["NAME"],
         'XML_ID' => $row["STATUS_ID"],
         'SORT' => $sort
   ];
        print_r($arr);
   $valueId = $ibpenum->Add($arr);
        $sort = $sort + 5; 
   }
}
echo "</pre>";
Если блог был полезным, можете угостить меня "чашечкой кофе" :)

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