Всем привет!
В последнее время приходится программировать под Битрикс “Корпоративный
портал”. Впечатления весьма неоднозначные. Нет в этой системе той стройности и
упорядоченности, как например в
фреймворке Laravel, в коде компонентов редко используется ООП, часто шаблоны компонентов пестрят жуткой
смесью из PHP, JavaScript и html–кода. Как сказано в одной замечательной критичной к
Битрикс статье, "документация по Битрикс отстает от кода системы на 1 – 1.5
года”. Поэтому приходится залезать в дебри системных классов Битрикс и изучать
все самостоятельно.
Недавно мне поступило задание реализовать следующий алгоритм
на портале:
- Постановщик создает задачу для ответственного.
- Ответственный должен открыть карточку задачи и отредактировать крайний срок для исполнения
данной задачи
- Постановщику должно придти сообщение с указанием
данного крайнего срока и кнопками “Принять” и “Отменить”
- Если постановщик принимает крайний срок по
задаче, то данное поле блокируется для редактирования и ответственный начинает
решать задачу, иначе - ответственному
приходит сообщение о том, чтобы он предложил другой крайний срок

Алгоритм достаточно простой и понятный. Отсылка сообщений
должна происходить через веб-мессенджер портала.
Основная сложность здесь – это отсылка постановщику
сообщения для подтверждения или отмены и соответственно обработчик нажатия
кнопок “Принять” или “Отменить”. Погуглив, я понял, что не все так просто. Вот
эта статья от разработчика Битрикс
https://dev.1c-bitrix.ru/community/blogs/hazz/im-post-one.php
объясняет, как отсылать такое сообщение, требующее подтверждения. Однако в
качестве обработчика нажатия кнопок предлагается использовать код своего
самописного модуля. Модуль должен быть зарегистрирован следующей функцией.
RegisterModuleDependences("im", "OnBeforeConfirmNotify",
"yourmodule","CYourModuleEvents", "CYourModuleEventsIMCallback");
Как? Неужели для этого я должен писать свой собственный
модуль?
Однако выяснилось, что есть альтернатива – функция AddEventHandler,
которая регистрирует обработчик события. Отличие данного регистратора события
от RegisterModuleDependences в том, что последний сохраняется в базе данных и
работает с событиями в модулях.
Итак, вызов функции для отправки сообщения с подтверждением
в коде компонента bitrix:task.task.edit :
$mdeadline=ConvertDateTime($arFields["DEADLINE"], "DD.MM.YYYY", "ru");
$notify="Задача № {$arParams['TASK_ID']} будет выполнена до {$mdeadline} включительно. Прошу нажать 'Принять', если согласны, и мы приступим к решению данной задачи";
$buttons=Array(
Array('TITLE' => 'Принять', 'VALUE' => 'Y', 'TYPE' => 'accept' ),
Array('TITLE' => 'Отказаться', 'VALUE' => 'N', 'TYPE' => 'cancel' ),
);
CMessagesHelper::SendConfirmNotify($arTask['RESPONSIBLE_ID'],$arTask['CREATED_BY'],
'tasks',"tasks|CONFIRM_DEADLINE|{$arParams['TASK_ID']}|{$arTask['RESPONSIBLE_ID']}|{$arTask['CREATED_BY']}|{$task_path}",
$notify,'',$buttons,'');
Функция класса-хелпера для отсылки сообщения с подтверждением:
public static function SendConfirmNotify($from,$to,$module,$tag,$message,$message_email,$buttons,$email_template)
{
if (IsModuleInstalled("im") && CModule::IncludeModule("im"))
{
$arMessageFields = array(
"TO_USER_ID" => $to,
"FROM_USER_ID" => $from,
"NOTIFY_TYPE" => 1,
"NOTIFY_MODULE" => $module,
"NOTIFY_TAG" => $tag,
"NOTIFY_MESSAGE" => $message,
"NOTIFY_MESSAGE_OUT" => $message_email,
"NOTIFY_BUTTONS" => $buttons,
"NOTIFY_EMAIL_TEMPLATE" =>
$email_template,
);
return CIMNotify::Add($arMessageFields);
}
}
А вот необходимый обработчик нажатия кнопок в уведомлении, который располагается в файле
bitrix/php_interface/init.php:
AddEventHandler("im", "OnAfterConfirmNotify", "OnAnswerNotifyHandler");
function OnAnswerNotifyHandler($module,$tags,$value,$arRes,$resultMessages)
{
if (IsModuleInstalled("im") && CModule::IncludeModule("im") && CModule::IncludeModule("tasks"))
{
if($module=='tasks' && !empty($tags))
{
$tag_ar=explode ('|',$tags);
if($tag_ar && $tag_ar[1]=='CONFIRM_DEADLINE')
{
$task_id=$tag_ar[2];
if(!$task_id) return;
$responsible_id=$tag_ar[3];
if(!$responsible_id) return;
$author_id=$tag_ar[4];
if(!$author_id) return;
$task_path="/company/personal/user/{$responsible_id}/tasks/task/view/{$task_id}/";
function ChangeDeadLineCounter($val,$task_id)
{
global $USER;
$loggedInUserId = (int) $USER->getId();
$oTask = CTaskItem::getInstanceFromPool($task_id, $loggedInUserId);
if(!$oTask)
return false;
$arTask = $oTask->getData();
if(!$arTask)
return false;
if(!empty($arTask['UF_DEADLINE_COUNTER']))
$arTask['UF_DEADLINE_COUNTER']+=$val;
if($arTask['UF_DEADLINE_COUNTER']<0 artask="" otask-="">update(array('UF_DEADLINE_COUNTER'=>$arTask['UF_DEADLINE_COUNTER']));
return true;
}
if($value=='Y')
{
$arMessageFields = array(
"TO_USER_ID" => $responsible_id,
"FROM_USER_ID" => $author_id,
"NOTIFY_TYPE" => IM_NOTIFY_SYSTEM,
"NOTIFY_MODULE" => "tasks",
"NOTIFY_TAG" => "",
"NOTIFY_MESSAGE" => "Уважаемый сотрудник! Инициатор задачи № {$task_id} подтвердил установленный Вами крайний срок. Можете приступать к исполнению.",
"MESSAGE_TYPE" => "S"
);
ChangeDeadLineCounter(1,$task_id);
}
else
{
$arMessageFields = array(
"TO_USER_ID" => $responsible_id,
"FROM_USER_ID" => $author_id,
"NOTIFY_TYPE" => IM_NOTIFY_SYSTEM,
"NOTIFY_MODULE" => "tasks",
"NOTIFY_TAG" => "",
"NOTIFY_MESSAGE" => "Уважаемый сотрудник! Инициатор задачи № {$task_id} не подтверждает Ваш крайний срок по данной задаче.
Редактирование крайнего срока вновь доступно в карточке задачи. Скорректируйте крайний срок еще раз.",
"MESSAGE_TYPE" => "S"
);
ChangeDeadLineCounter(-1,$task_id);
}
$notifyID = CIMNotify::Add($arMessageFields);
}
}
}
В обработчике в зависимости от ответа постановщика задачи происходит изменение поля UF_DEADLINE_COUNTER указанной задачи и также отсылается уведомление ответственному по задаче.
Эту статью я решил написать, чтобы другим программистам было проще с реализацией подобных функций. Это необходимо, т.к. из-за скудости документации по Битриксу приходится много времени тратить на поиски решений подобных задач.