Итак, на основе списка требований нам нужно сохранять перечисленные данные в задаче. Для этого подойдут пользовательские поля. Они должны отображаться в списке. Это, так же как и возможность отключить отображение, является стандартным функционалом и проблем здесь возникнуть не должно.
У клиента есть ряд особенностей, которые нужно учесть при решении задачи:
- На портале существуют задачи без крайнего срока
- На портале много регулярных задач – эти задачи создаются на основе запуска агентов (на хитах или по cron)
- Пользователи активно используют планировщик задач (расположенный в блоке управления рабочим днем)
Мне эта задача показалась интересной, поэтому я решил описать процесс решения и особенности с которыми столкнулся при этом. Возможно, кто-то из читателей захочет реализовать у себя на портале что-то подобное.
Задача решается с помощью обработчиков событий OnTaskAdd и OnTaskUpdate, но перед тем, как приступить к их разработке, нужно провести подготовительные процедуры.
Наша задача связана с вычислением дат (количества рабочих дней), поэтому нужно сохранить где-то все нерабочие и праздничные даты года. По идее можно воспользоваться API модуля «Календарь» для их получения из настроек. Это было бы правильно, но судя по событиям 2020 года, когда было большое количество незапланированных нерабочих дней (не учтённых в настройках календаря), лучше использовать альтернативный вариант. Я решил создать массив для хранения дат по годам и разместил его в файле settings.php. У этого подхода есть свой недостаток – в начале каждого года нужно добавлять даты в массив, но если за этим следить, то ничего страшного нет.
PHP
Массив с датами по годам – это, конечно, хорошо, но еще как-то нужно вычислять количество рабочих дней при переносе крайних сроков. И снова воспользуемся сторонним решением, а именно функцией getWorkingDays, которая будет выполнять эту работу. По мимо этой функции нам понадобятся и другие вспомогательные функции для работы с датами. Поэтому я объединил их все в класс TasksHelper и разместил его в файле tasks.php.
PHP
Обычно обработчики событий в Битриксе хранятся в файле init.php, расположенном в папке php_interface. Правильным решением будет разместить файлы settings.php и tasks.php в папке php_interface/include/tasks. После этого не забудем подключить указанные файлы в init.php.
Далее переходим к созданию пользовательских полей. Я, например, добавил следующие:
- UF_PRIMARY_DL – поле для хранения первоначального крайнего срока (тип – дата)
- UF_POSTPONEMENTS_NUM – поле для хранения количества переносов крайних сроков (тип - число)
- UF_WORKDAYS_NUM – поле для хранения количества рабочих дней от первоначального крайнего срока до текущего (тип - число)
Делал это со стороны административной части портала, так как при этом есть возможность дать им свои имена, а не те которые сгенерирует Битрикс.
Приступаем к основной части задачи – написанию кода функций-обработчиков событий, которые мы разместим непосредственно в файле init.php.
Начнем с обработчика события OnTaskAdd.
PHP
Им является функция OnTaskAddHandler. В качестве аргументов ей передаются: идентификатор задачи $idTask и массив полей $arTask. Код функции несложный, но важно учесть следующие моменты:
- Созданная задача может быть без крайнего срока
- При добавлении задачи из планировщика отсутствует элемент массива $arTask['DEADLINE']
В первом случае мы выходим из обработчика:
PHP
Во втором формируем DEADLINE из элемента массива $arTask['CREATED_DATE']. На мой взгляд это правильный подход, так как подразумевается, что задачи которые создаются в планировщике должны быть выполнены в тот же день.
PHP
Далее подключаем модули sale и highloadblock. Так как основной задачей обработчика является запись первоначального крайнего срока в поле UF_PRIMARY_DL задачи, я приведу фрагмент кода, который выполняет это действие:
PHP
Если все проходит без ошибок, то нужно сформировать сообщение об этом для последующей записи в лог. Сообщение об ошибке также формируем. В итоге записываем в файл лога с помощью функции file_put_contents(). В коде мы используем метод CTasks::Update(), а это как известно запускает обработчик события OnTaskUpdate. Поэтому при создании задачи срабатывают оба наших обработчика. Это также нужно запомнить.
По желанию вы можете сохранять информацию об изменениях в задачах в HL-блок для того, чтобы потом сформировать на основе нее какой-нибудь отчет.
PHP
На этом код обработчика OnTaskAddHandler заканчивается.
Выше я писал, что на портале создается много регулярных задач и что нужно это учесть. Обращаю внимание, обработчики событий при этом срабатывают и наш код будет выполняться. Главное, чтобы был корректно настроен запуск агентов, если они выполняются на cron’е.
Переходим к обработчику события OnTaskUpdate.
PHP
В качестве аргументов ей передаются: идентификатор задачи $id, массив полей $arFields и копию массива $arTaskCopy.
В самом начале также подключаем модули sale и highloadblock. Обращаю внимание на то, что при обновлении может не существовать $arFields['DEADLINE'] и $arFields['UF_PRIMARY_DL'], зато есть $arFields['META:PREV_FIELDS']['DEADLINE'] и $arFields['META:PREV_FIELDS']['UF_PRIMARY_DL']. Массив $arFields['META:PREV_FIELDS'] в данном случае является очень полезным, потому что в нем сохранены значения полей, которые были до изменения задачи.
В самом начале функции нужно удостовериться, что выполняется условие:
PHP
Далее снова проверка задачи – есть ли у нее крайний срок. Если его нет, то обработчик завершается.
Если до добавления обработчика на портале уже существовали задачи, а такое может быть очень вероятно, в коде нужно добавить одну условную конструкцию. Она заключается в том, что нужно проверить заполнено ли поле Первоначальный крайний срок (UF_PRIMARY_DL). Если UF_PRIMARY_DL не заполнено, то заполняем его текущим крайним сроком и обнуляем счетчики (значения полей UF_POSTPONEMENTS_NUM и UF_WORKDAYS_NUM).
PHP
Далее: если условие
PHP
вернет true, значит изменился именно крайний срок. В этом случае выполняем основные задачи обработчика.
- Преобразуем даты в определенный формат, который подходит для сохранения их в HL-блоке. Для этого используем метод TasksHelper::tranformDate()
- Объединяем все праздники в 1 массив и вычисляем кол-во рабочих дней. Используем методы TasksHelper::getAllHolidaysList() и TasksHelper::getWorkingDays().Увеличиваем кол-во переносов крайнего срока на 1.
- Обновляем данные в задаче
Вычисленное количество рабочих дней и актуальное количество переносов крайних сроков сохраняем в переменных $workDaysQuant и $ppNum соответственно. Затем используем их в массиве для обновления задачи.
PHP
Вы можете записать информацию об обновлении крайнего срока в HL-блок. Как это было в случае с обработчиком OnTaskAdd. Код будет выглядеть также как и приведенный выше, поэтому я не буду повторяться.
Обращу внимание читателя на то, что в конце файла init.php не нужно ставить закрывающий тег PHP ?>. Это может привести к некорректной работе кода обработчиков событий. В частности это касается тех случаев, когда регулярные задачи запускаются по cron, а также ошибки могут возникнут и в других случаях.
На этом статья с описанием создания инструмента по контролю за крайними сроками в задачах подходит к концу. В ней мы рассмотрели код 2 обработчиков событий, настройки и вспомогательные функции, а также способ хранения информации о крайних сроках задач в HL-блоке.
Надеюсь, статья была полезна для вас.