Битрикс24 работа с датами в бизнес процессах

Примеры работы с датами

Урок
52
из
244

Сложность урока:

3 уровень — средняя сложность. Необходимо внимание и немного подумать.


3 из 5

Дата изменения:
13.03.2023

Просмотров:
47023

Недоступно в лицензиях:

Текущую редакцию Вашего 1С-Битрикс можно просмотреть на странице Обновление платформы (Marketplace > Обновление платформы).


Старт, Стандарт, Малый бизнес

В уроке рассмотрим возможности работы с датами в бизнес-процессах. Результаты выведем с помощью действия

Сообщение соц.сети

Действие, которое позволяет отправить уведомление о событии указанному пользователю/группе пользователей через модуль социальной сети.
Подробнее…



.

  Перевод даты на русский язык

Для вывода даты используется функция

date

date — Форматирует вывод системной даты/времени




. В примере используем параметр F — полное наименование месяца. Список всех параметров функции смотрите в документации по PHP.

Текущий месяц - {{=date('F',{=System:Date})}}

В результате получим

уведомление




вида Текущий месяц - April.

Для получения названия месяца на русском языке понадобится создать Список соответствия для названий месяцев. Введем переменную бизнес-процесса типа Список:

В вариантах значений в квадратных скобках укажем ключ — номер месяца, а после — значение (название месяца на русском языке).

Вернемся к шаблону бизнес-процесса и перед сообщением соц.сети добавим действие

Изменение переменных




в котором укажем функцию {{=date('n')}}, где n — порядковый номер месяца без ведущего нуля (из документации по PHP).

В действии Уведомление соц. сети поменяем текст сообщения на вывод нашей переменной Variable1:

Текущий месяц - {=Variable:Variable1 > printable}

Результат:

Таким же образом можно выводить дни недели и др. подобные даты.

  Относительный формат даты

Задание: необходимо вывести дату — пятница следующей недели. Сделать это можно с помощью работы функции strtotime и относительных форматов PHP.

Создадим новую переменную

Дата




и снова воспользуемся действием Изменение переменных, как в примере выше. Укажем значение ='next week friday':

А в тексте сообщения соц. сети выведем переменную Дата.

Следующая пятница - {=Variable:Variable2 > printable}

Результат

  Добавление N дней из параметра

Сначала посмотрим на простой пример: прибавим к текущей дате точное количество дней.

Для этого понадобится функция dateadd:

Текущая дата + 2 дня: {{=dateadd({=System:Date}, '2d')}} // прибавим 2 дня к текущей дате

Теперь посмотрим, как правильно добавлять количество дней, которое хранится в параметре БП:

Текущая дата + N дней: {{=dateadd({=System:Date}, {=Template:Parameter1} & 'd')}} // прибавим дни из параметра к текущей дате

Важно! Для правильного указания количества дней из параметра применен оператор конкатенации, который возвращает строку, представляющую собой соединение левого и правого аргумента.

Результат (при запуске БП для параметра указано значение 10):

  Разница между двумя датами

Функция datediff() позволяет вычислять разницу между двумя датами.

Например, вычисление сколько дней прошло с момента создания элемента до текущего момента может выглядеть так:

{{=datediff({{Дата создания элемента}},{=System:NowLocal},"%d")}}

, где %d — значение параметра форматирования результата. Все значения параметра смотрите в документации PHP.

Для правильного использования функции, важно понимать, какой результат возвращает функция и как его использовать.

Возьмем две даты (с одинаковым днём):

  • Date1: 18.01.2022 12:15:25
  • Date2: 18.01.2022 18:31:00

Посчитаем разницу между этими датами:

{{=datediff({Date1},{Date2},"%h часов %i минут %s секунд")}}
// результат: 6 часов 15 минут 35 секунд

Если для этих же дат мы запишем функцию только со значением %i:

{{=datediff({Date1},{Date2},"%i")}}
// результат: 15

, то получим результат: 15. Т.о. функция datediff не переводит разницу в одну единицу времени (в минуты или в секунды). Её результатом всегда является расчет в полном формате (сколько прошло лет, месяцев, дней, часов и т.д. между двумя датами). А при помощи третьего параметра функции мы указываем лишь какие данные из этого результата отобразить.

Исключением является вариант %a, который выводит общее количество дней между датами. Проверим на том же примере, только для первой даты изменим год на 2020:

  • Date1: 18.01.2020 12:15:25
  • Date2: 18.01.2022 18:31:00
{{=datediff({Date1},{Date2},"%d")}}
// %d - количество дней
// результат: 0
{{=datediff({Date1},{Date2},"%a")}}
// %a - общее количество дней
// результат: 731

Как видим, в первом варианте количество дней равно 0, т.к. прошло ровно 2 года и 0 дней. А во втором варианте результат 731 день, т.е. количество дней за 2 года.

  Проверка корректности времени

Выражение используется для полей документа, переменных или параметров шаблона.

	=if(and((intval(substr({=Template:Parameter1}, 0, 2)) >= 0), (intval(substr({=Template:Parameter1}, 0, 2)) < 25), (substr({=Template:Parameter1}, 2, 1) = ":"), (intval(substr({=Template:Parameter1}, 3, 2)) >= 0), (intval(substr({=Template:Parameter1}, 3, 2)) < 60)), {=Template:Parameter1}, "время указано неправильно")

Если в параметре {=Template:Parameter1} передается время (в 24 часовом формате ЧЧ:ММ, например 21:45), то возвращается его значение. Иначе вернется время указано неправильно.

Функция dateadd позволяет добавить к указанной дате определенное число времени (лет, месяцев, дней, часов, минут, секунд).

Выглядит она следующим образом:

=dateadd([начальная дата], [что добавлять])

В качестве даты можно установить переменные, параметры шаблона, а также поля документа, для которого создан бизнес-процесс. Кроме того можно просто ввести даты вручную или подставить текущее системное время {=System:Now}.

В [что добавлять] можно вводить значения y, m, d, h, i, s — года, месяца, дни, часы, минуты и секунды соответственно. При этом с помощью знаков + и — можно указать даты позднее или ранее начальной. Например:

=dateadd({=Document:DATE_CREATE}, «+1d») — получится значение, равное дате создания документа плюс 1 день.

=dateadd({=Document:DATE_CREATE}, «-21d») — получится значение, равное дате создания документа минус 21 день.

Dateadd не меняет саму дату, для которой она применяется. То есть, если в функции используется дата создания, то сама дата создания никак не меняется, мы просто берем ее значение и прибавляем к ней определенный срок. Поэтому, если важно именно сохранить новое значение, то тогда нужно записывать его отдельную в переменную или т.п.

Пример использования

Один из самых распространенных примеров использования dateadd — создать в бизнес-процессе задачу с крайним сроком, автоматически рассчитывающимся относительно даты начала.

Поставим задачу, на выполнение которой будет отведено 10 дней с момента ее создания.

Для этого в блоке задача в поле Крайний срок введем =dateadd({=System:Now}, «+10d»).

dateadd настройка действия.png

После запуска процесса будет создана задача, в которой крайний срок будет на 10 дней позже даты создания.

Поставленная задача dateadd.png

Для получения результатов функции в виде текста для уведомлений, задач, записей в живой ленте и т.п. нужно заключить ее в двойные фигурные скобки т.е. {{=dateadd({=Document:DATE_CREATE}, «+1d»)}}.

Рекомендую также прочитать:

  • Вычисление значений выражений в параметрах действий

Спасибо, помогло!

Спасибо :)


Это не то, что я ищу


Написано очень сложно и непонятно


Есть устаревшая информация


Слишком коротко, мне не хватает информации


Мне не нравится, как это работает

Document

Document – для обращения к произвольному полю документа, над которым запущен бизнес-процесс;

{=Document:DATE_CREATE}
{=Document:CREATED_BY} > User_1
{=Document:CREATED_BY > printable} > Иван Иванов [1]
{=Document:CREATED_BY > friendly} > Иван Иванов

{=Document:DETAIL_PAGE_URL} — позволяет получить ссылку на страницу детального просмотра документа, при условии, что в настройках инфоблока корректно заполнен URL страницы детального просмотра.
Ссылка на страницу детального просмотра документа: [url]{=Document:DETAIL_PAGE_URL}[/url]

Workflow

{=Workflow:ID} — идентификатор бизнес-процесса; Ссылка на страницу с заданием: [url]http://[адрес_портала]/company/personal/bizproc/{=Workflow:ID}/[/url]

Template

Template – для обращения к входному параметру (свойству) бизнес-процесса (корневого действия);

{=Template:Creators}
{=Template:PathTemplate} . пример: Документ [url={=Template:PathTemplate}]{=Document:NAME}[/url] был одобрен
{=Template:TargetUser} — параметр, в котором содержится идентификатор пользователя, запустившего бизнес-процесс в формате user_[номер_пользователя_в_системе];

System

System – обращение к системным переменным, в настоящее время доступно только свойство Now – текущая дата в формате сайта;

{=System:Now} — текущая дата со временем на сервере;
{=System:NowLocal} — текущая дата со временем у клиента (учитывается часовой пояс);
{=System:Date} — текущая дата без времени;

User

User – для получения кода текущего пользователя (в качестве названия свойства должно быть указано » ID «);

{=User:ID} — идентификатор текущего пользователя в формате user_[номер_пользователя_в_системе];

Variable

Variable – для обращения к переменной бизнес-процесса;

Для параметров и переменных шаблона можно использовать модификатор _printable, который позволяет преобразовывать их значение в понятную пользователю строку. Если параметр/переменная не поддерживает этот модификатор, то она вернет такое же значение, как и без него.
Примеры использования модификатора для переменной типа пользователь:

{=Variable:user}
{=Variable:user_printable}

Результат, если значение переменной равно Автор:
author
Автор

Результат, если значение переменной равно [1]:
user_1
Иванов Иван [1]

Работа с датами

Установить дату события, можно использую следующее выражение:

Синтаксис: dateadd([начальная_дата], [что_добавлять]);

Варианты написания: y, year, years, m, month, months, d, day, days, h, hour, hours, i, min, minute, minutes, s, second, seconds.
При написании можно использовать верхний или нижний регистр.

Примеры: Dateadd({=Document:DATE_CREATE}, «-2d»), Dateadd({=Document:DATE_CREATE}, «2 days 3 minutes»)

Проверка корректности времен
=if(and((intval(substr({=Template:Parameter1}, 0, 2)) >= 0), (intval(substr({=Template:Parameter1}, 0, 2)) < 25), (substr({=Template:Parameter1}, 2, 1) = «:»), (intval(substr({=Template:Parameter1}, 3, 2)) >= 0), (intval(substr({=Template:Parameter1}, 3, 2)) < 60)), {=Template:Parameter1}, «время указано неправильно»)
Если в параметре {=Template:Parameter1} передается время (в 24 часовом формате чч:мм, например «21:45»), то будет возвращено его значение. Иначе вернется «время указано неправильно».
Данное выражение можно использовать для полей документа, переменных или параметров шаблона.

любое другое имя – обращение к свойству действия с этим именем.

Данное активити позволяет задавать повторение какого-либо процесса в определенный промежуток дня/времени с помощью возврата параметра день месяца/время либо другого указанного параметра. 

Сценарий работы активити бизнес-процесса

get_nearest_month_day_lab.gif


День месяца (условие):
Позволяет выбрать из выпадающего списка нужный день месяца. Выбрав 1: первое число месяца, 15: пятнадцатое число месяца.

Если вы выбрали день месяца, которого в этом месяце нет, то активити вернет ближайшую доступную дату. Т.е, если выбрали 31, а в месяце дней 28, то вернет 28.

Время: Указывается время к которому будет возвращено ближайшее значение ближайшего дня месяца, в формате ЧЧ:ММ.
Например: 11:00.
Если не корректно заполнить данное поле, то активити вернет в результатах не корректные данные.

Часовой пояс: указывается часовой пояс, используемый в пункте «Время», в формате «+3»

Делать отладочные сообщения в журнал БП:варианты да/нет.
Позволяет выбрать, нужно ли создавать отладочные сообщения в журнал БП или нет.
Это поле нужно использовать только по необходимости из-за большого расхода запросов и уменьшенной скорости срабатывания активити.

Запускать от имени: данное поле необходимо для того, чтобы установить сотрудника, с правами которого выполнять действие данного активити. Если у сотрудника не будет прав на выполнение действия, то активити не сработает. Рекомендуем выбирать всегда сотрудника с правами администратора системы.

Устанавливать текст статуса: данное поле позволяет включать возможность установки статуса бизнес-процесса. Это необходимо для того, чтобы во время работы активити информировать пользователя в истории о том, что бизнес-процесс остановился на конкретном шаге. Это особенно важно в момент отладки и выяснения причин неполадок в работе механизма.

Текст статуса: в данном поле указывается текстовый вариант статуса, который Вы можете изменять.

Ожидать ответа: данное поле Вами не управляется. Оно необходимо для того, чтобы определить, нужно ли ожидать реакции от нашего активити после запуска.  

Период ожидания. Время ожидания ответа от приложения — Данная опция позволяет ограничить срок ожидания ответа от приложения. Технические особенности платформы Битрикс24 иногда создают ситуацию при которой создаётся очередь из огромного числа запросов. Это может помешать работе нашего активити и бизнес-процесс будет ожидать длительный период времени. Для того, чтобы не останавливать дальнейшие действия, вы можете установить своё время ожидания. Если время истекло и результат не получен, то бизнес-процесс будет двигаться далее по заложенной вами логике.

Сценарий работы робота

get_nearest_month_day_robot.gif


Возвращаемые параметры для данного активити:
— Найденная дата и время.
Отображает дату в формате DD.MM.YY. , а так же часы, минуты, секунды. 

Шпаргалка по работе с датой/временем в Битрикс

С самого начала работы с Битрикс меня порядком раздражало обилие методов и функций для работы с датой. Даже сейчас я заглядываю в хелп, чтобы узнать про тот или иной метод. И частенько смотрю в код, чтобы вспомнить, какие запросы есть/нет у той или иной функции. Пришло время покончить с этим и вынести в одно место все это дело.

Выставил функции в порядке частоты применения на практике. Еще раз подчеркну отличительную особенность всех стандартных функций — они учитывают формат текущего сайта и позволяют делать вам решения универсальными. Так же кое-где учитываются часовые пояса, что тоже порой важно.

Самые частые

$DB->FormatDate

— изменение формата даты на другой.
Применяется: когда надо изменить формат даты. Например, в шаблоне компонента, или для передачи в фильтр. На мой взгляд слишком громоздка, предпочитаю юзать простенькие свои обертки конкретно под задачи (например, стараюсь получить timestamp еще в запросе, а потом вывести нормальным date().

FormatDate

— это не метод, это отдельная функция. И на вход принимает timestamp. Имеет очень богатый набор параметров. За это, на мой взгляд, платим чересчур бОльшей нагрузкой.
Применяется: ну когда очень хочется вывести «

две минуты назад

«.

FormatDateFromDB

— обертка вышеописанной функции. Позволяет довольно хитро вертеть данными. На мой взгляд — экзотика. Приведу примеры:

echo FormatDateFromDB('01/23/2013', 'DD MMMM YYYY'); // вернет 23 Enero 2013, если язык сайта испанский
echo FormatDateFromDB('7 June 2012 12:00pm', 'SHORT'); // вернет 7 Июня 2012, если язык сайта русский и короткий формат языка - DD MMMM YYYY

С другой стороны может довольно гибко использоваться и в реально нужном контексте:

$arElem['ACTIVE_TO'] = FormatDateFromDB($arElem['ACTIVE_TO'], 'SHORT');//перегон из формата FULL в формат SHORT

MakeTimeStamp

— возвращает timestamp по дате.
Применяется: очевидно.

AddToTimeStamp — позволяет добавить период к timestamp. Например, +1 год и 1 месяц.
Применяется: кому как, мне проще перегнать в timestamp и добавить что хочу.

ParseDateTime

— вычленяет дни, месяцы, года, время из строки даты по формату.
Применяется: например, надо из даты формата FORMAT_DATETIME достать год. Мы же не знаем какой формат точно.

$DB->DateFormatToPHP

— простенькая функция, которая позволяет перегнать формат даты сайта (или другой) в формат PHP date. Например, YYYY-DD-MM превратит в Y-d-m.
Применяется: чаще всего применяется

для перегона формата сайта в php-формат

. Рекомендуется по причине совместимости (вы никогда не знаете какой именно формат сайта может быть на сайте). Очень

частое

применение — при формировании фильтра по датам в тех же

инфоблоках

. Даже вынесу сюда самый популярный копипаст (до сих пор за ним лезу в хелп :))

'>DATE_ACTIVE_FROM' => date($DB->DateFormatToPHP(FORMAT_DATETIME), time()-86400*30),

(Фильтр для инфоблоков, приказывающий вывести элементы с датой активности менее месяца назад)

$DB->CompareDates

— сравнивает даты. Все бы хорошо, но использует запрос без кеширования к базе. Соответственно, применять следует по уму, без участия в циклах.
Применяется: если честно,

ни разу не было случая

, когда без этой функции никуда (чаще всего мешает именно запрос к БД). Обычно хватало фильтров на уровне БД, или перевода в time.

Ниже идут функции для применения в ваших запросах напрямую к БД. Как правило, это разработка модулей.

$DB->CharToDateFunction

— является оберткой $DB->FormatDate, переводит дату в формат БД (YYYY-MM-DD HH:MI:SS). То есть, фактически, это то же самое, что:

$DB->FormatDate($arGetFilter['date_payed_to'], FORMAT_DATETIME, 'YYYY-MM-DD HH:MI:SS');

Но! Использует внутри себя работу с часовыми поясами, добавляя

DATE_ADD

, если требуется.
Применяется: исключительно когда надо передать фильтр/сортировку по дате

в ваш запрос

(уже в безопасном виде). Для передачи в фильтр методов

не подходит

, так как обрамляет строку кавычками.

$DB->CurrentDateFunction

— возвращает CURRENT_DATE для MySQL и TRUNC(SYSDATE) для Oracle. Имеет напарницу

CurrentTimeFunction

, для времени.
Применяется: в ваших

запросах

, чтобы не греть голову о том, под Мускулом или под Ораклом вы работаете.

$DB->DateToCharFunction

— перегоняет дату из формата БД в формат текущего сайта. То есть, Query вам сразу вернет дату в формате сайта, каким бы хитрым он не был. Очень удобно.
Применяется: выше.

Пару слов о форматах времени.

Их есть всего два: FORMAT_DATETIME и FORMAT_DATE. Это константы и они определены всегда в публичной части. Но вообще, когда вы не уверены, где будет работать решение/скрипт, его желательно заменять на

CSite::GetDateFormat

(старая интерпретация

CLang

::GetDateFormat). Если константы выше определены, она сразу их и вернет. Нет — начнет копать дальше.

Заключение

Я не стал перечислять явные велосипеды, или обертки. Если что-то важное все же упустил — пожалуйста, в комменты.

Назад в раздел

Перейти к содержимому

Начинающие программисты, которые начинают свой профессиональный путь как правило с написания вебхуков, часто сталкиваются с ошибкой, пытаясь вставить в поля сущностей типа Даты текстовые значения.

fields' => [
          'ENTITY_ID' => $id,
          'ENTITY_TYPE' => 'deal',
          'CREATED' => '2020-06-16T16:08:32+03:00',
          'COMMENT' => $data
]

Такой подход ведет к только одному результату — реальная дата не добавляется, вместо нее подставляется системная, равная текущей дате и времени сервера.

Для вставки необходимой даты на практике необходимо использовать «обертку» из функций date и strtotime. Представим, что к нам приходит массив $ev с годом, месяцем и датой рождения клиента. Для вставки даты в поле «День рождения» мы будем писать в PHP:

$bdate = date("d-m-Y", strtotime($ev['birthday_day'].'-'.$ev['birthday_month'].'-'.$ev['birthday_year']));

Если у нас есть задача учесть переходы на летнее зимнее время, то можете дополнительно воспользоваться рекомендациями из данной статьи на этом сайте.

Наконец, последний совет связан с работой с датами исключительно в коробочной версии системы. В рамках Bitrix Framework существует встроенная функция работы с датой ConvertDateTime, которая очень помогает в задачах фильтрации больших списков данных. Представим, что имеем на входе дату в текстовом формате.

$datebeg = '01.03.2020';

Для того, чтобы отсечь по ней инфоблок или список сделок мы должны писать в массиве фильтра:

$arFilterc = array('>DATE_CREATE'=>ConvertDateTime($datebeg, "DD.MM.YYYY")." 00:00:00");

Итак, на основе списка требований нам нужно сохранять перечисленные данные в задаче. Для этого подойдут пользовательские поля. Они должны отображаться в списке. Это, так же как и возможность отключить отображение, является стандартным функционалом и проблем здесь возникнуть не должно.

У клиента есть ряд особенностей, которые нужно учесть при решении задачи:

  • На портале существуют задачи без крайнего срока
  • На портале много регулярных задач – эти задачи создаются на основе запуска агентов (на хитах или по cron)
  • Пользователи активно используют планировщик задач (расположенный в блоке управления рабочим днем)

Мне эта задача показалась интересной, поэтому я решил описать процесс решения и особенности с которыми столкнулся при этом. Возможно, кто-то из читателей захочет реализовать у себя на портале что-то подобное.

Задача решается с помощью обработчиков событий OnTaskAdd и OnTaskUpdate, но перед тем, как приступить к их разработке, нужно провести подготовительные процедуры.

Наша задача связана с вычислением дат (количества рабочих дней), поэтому нужно сохранить где-то все нерабочие и праздничные даты года. По идее можно воспользоваться API модуля «Календарь» для их получения из настроек. Это было бы правильно, но судя по событиям 2020 года, когда было большое количество незапланированных нерабочих дней (не учтённых в настройках календаря), лучше использовать альтернативный вариант. Я решил создать массив для хранения дат по годам и разместил его в файле settings.php. У этого подхода есть свой недостаток – в начале каждого года нужно добавлять даты в массив, но если за этим следить, то ничего страшного нет.

PHP

/*массив нерабочих дней по годам*/
$arHolidays = Array(
'2020' => Array(/*нерабочие дни за 2020 год*/),
'2021' => Array('2021-01-01', '2021-01-04', '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08', '2021-02-23', '2021-03-08', '2021-05-03', '2021-05-04', '2021-05-05', '2021-05-06', '2021-05-07', '2021-05-10',	'2021-06-14', '2021-02-23', '2021-11-04', '2021-11-05'));

Массив с датами по годам – это, конечно, хорошо, но еще как-то нужно вычислять количество рабочих дней при переносе крайних сроков. И снова воспользуемся сторонним решением, а именно функцией getWorkingDays, которая будет выполнять эту работу. По мимо этой функции нам понадобятся и другие вспомогательные функции для работы с датами. Поэтому я объединил их все в класс TasksHelper и разместил его в файле tasks.php.

PHP

class TasksHelper{
	/*Вычисляем количество рабочих дней в указанном диапазоне*/
	public static function getWorkingDays($startDate, $endDate, $holidays){
	   $endDate = strtotime($endDate);
	   $startDate = strtotime($startDate);
	   $days = ($endDate - $startDate) / 86400 + 1;
	   $no_full_weeks = floor($days / 7);
	   $no_remaining_days = fmod($days, 7);
	   $the_first_day_of_week = date("N", $startDate);
	   $the_last_day_of_week = date("N", $endDate);

	   if ($the_first_day_of_week <= $the_last_day_of_week) {
		   if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
		   if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
	   } else {
		   if ($the_first_day_of_week == 7) {
			   $no_remaining_days--;
			   if ($the_last_day_of_week == 6) {
				   $no_remaining_days--;
			   }
		   } else {
			   $no_remaining_days -= 2;
		   }
	   }
	   $workingDays = $no_full_weeks * 5;

	   if ($no_remaining_days > 0)
	   {
		   $workingDays += $no_remaining_days;
	   }
	   foreach($holidays as $holiday){
		   $time_stamp=strtotime($holiday);
		   if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)
			   $workingDays--;
	   }
	   return $workingDays;
}

Обычно обработчики событий в Битриксе хранятся в файле 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

EventManager::getInstance()->addEventHandler('tasks', 'OnTaskAdd', 'OnTaskAddHandler');

Им является функция OnTaskAddHandler. В качестве аргументов ей передаются: идентификатор задачи $idTask и массив полей $arTask. Код функции несложный, но важно учесть следующие моменты:

  • Созданная задача может быть без крайнего срока
  • При добавлении задачи из планировщика отсутствует элемент массива $arTask[‘DEADLINE’]

В первом случае мы выходим из обработчика:

PHP

if(array_key_exists('DEADLINE', $arTask) && empty($arTask['DEADLINE'])){
	return true;
}

Во втором формируем DEADLINE из элемента массива $arTask[‘CREATED_DATE‘]. На мой взгляд это правильный подход, так как подразумевается, что задачи которые создаются в планировщике должны быть выполнены в тот же день.

PHP

if(!isset($arTask['DEADLINE'])){
	$cd = explode(' ', $arTask['CREATED_DATE'])[0]; //22.01.2021 13:49:43 => 22.01.2021
	$arTask['DEADLINE'] = $cd.' 19:00:00'; //22.01.2021 => 22.01.2021 19:00:00
}

Далее подключаем модули sale и highloadblock. Так как основной задачей обработчика является запись первоначального крайнего срока в поле UF_PRIMARY_DL задачи, я приведу фрагмент кода, который выполняет это действие:

PHP

$obTask = new CTasks;
$arTaskFields = Array('UF_PRIMARY_DL' => $arTask['DEADLINE']);
$tskres = $obTask->Update($arTask['ID'], $arTaskFields);

Если все проходит без ошибок, то нужно сформировать сообщение об этом для последующей записи в лог. Сообщение об ошибке также формируем. В итоге записываем в файл лога с помощью функции file_put_contents(). В коде мы используем метод CTasks::Update(), а это как известно запускает обработчик события OnTaskUpdate. Поэтому при создании задачи срабатывают оба наших обработчика. Это также нужно запомнить.

По желанию вы можете сохранять информацию об изменениях в задачах в HL-блок для того, чтобы потом сформировать на основе нее какой-нибудь отчет.

PHP

// выбираем информацию о сущности из базы данных
$arHLBlock = BitrixHighloadblockHighloadBlockTable::getById(TASK_DEADLINES_HL_ID)->fetch();
//затем инициализируем класс сущности
$obEntity = BitrixHighloadblockHighloadBlockTable::compileEntity($arHLBlock);
$strEntityDataClass = $obEntity->getDataClass();
$arTaskItemArray =  Array();
$arTaskItemArray['UF_TASK_ID'] = $arTask['ID'];
$arTaskItemArray['UF_TASK_TITLE'] = $arTask['TITLE'];
$arTaskItemArray['UF_CUR_DEADLINE'] = $arTask['DEADLINE'];	
//записываем данные в элемент HL-блока
$obResult = $strEntityDataClass::add($arTaskItemArray);
$hlres = $obResult->isSuccess();

На этом код обработчика OnTaskAddHandler заканчивается.

Выше я писал, что на портале создается много регулярных задач и что нужно это учесть. Обращаю внимание, обработчики событий при этом срабатывают и наш код будет выполняться. Главное, чтобы был корректно настроен запуск агентов, если они выполняются на cron’е.

Переходим к обработчику события OnTaskUpdate.

PHP

EventManager::getInstance()->addEventHandler('tasks', 'OnTaskUpdate', 'OnTaskUpdateHandler');

В качестве аргументов ей передаются: идентификатор задачи $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

if(is_array($arFields['META:PREV_FIELDS']) && count($arFields['META:PREV_FIELDS']) > 0){ }

Далее снова проверка задачи – есть ли у нее крайний срок. Если его нет, то обработчик завершается.

Если до добавления обработчика на портале уже существовали задачи, а такое может быть очень вероятно, в коде нужно добавить одну условную конструкцию. Она заключается в том, что нужно проверить заполнено ли поле Первоначальный крайний срок (UF_PRIMARY_DL). Если UF_PRIMARY_DL не заполнено, то заполняем его текущим крайним сроком и обнуляем счетчики (значения полей UF_POSTPONEMENTS_NUM и UF_WORKDAYS_NUM).

PHP

if(array_key_exists('UF_PRIMARY_DL', $arCurTsk) && empty($arCurTsk['UF_PRIMARY_DL'])){
    // если поле не заполнено, то заполняем его текущим крайним сроком и обнулим счетчики
   $obCurTask = new CTasks;
   $arCurTaskFields = Array(
	'UF_PRIMARY_DL' => $arCurTsk['DEADLINE'],
	'UF_POSTPONEMENTS_NUM' => "0", 
	'UF_WORKDAYS_NUM' => "0"
   );
  $tskres = $obCurTask->Update($arCurTsk['ID'], $arCurTaskFields);
  $arFields['META:PREV_FIELDS']['UF_PRIMARY_DL'] = $arCurTsk['DEADLINE'];			
}

Далее: если условие

PHP

if(isset($arFields['DEADLINE']) && $arFields['DEADLINE'] !== $arFields['META:PREV_FIELDS']['DEADLINE']){}

вернет true, значит изменился именно крайний срок. В этом случае выполняем основные задачи обработчика.

  • Преобразуем даты в определенный формат, который подходит для сохранения их в HL-блоке. Для этого используем метод TasksHelper::tranformDate()
  • Объединяем все праздники в 1 массив и вычисляем кол-во рабочих дней. Используем методы TasksHelper::getAllHolidaysList() и TasksHelper::getWorkingDays().Увеличиваем кол-во переносов крайнего срока на 1.
  • Обновляем данные в задаче

Вычисленное количество рабочих дней и актуальное количество переносов крайних сроков сохраняем в переменных $workDaysQuant и $ppNum соответственно. Затем используем их в массиве для обновления задачи.

PHP

// обновляем данные в задаче
$obTask = new CTasks;
$arTaskFields = Array('UF_POSTPONEMENTS_NUM' => $ppNum, 'UF_WORKDAYS_NUM' => $workDaysQuant);
$tskres = $obTask->Update($arFields['ID'], $arTaskFields);

Вы можете записать информацию об обновлении крайнего срока в HL-блок. Как это было в случае с обработчиком OnTaskAdd. Код будет выглядеть также как и приведенный выше, поэтому я не буду повторяться.

Обращу внимание читателя на то, что в конце файла init.php не нужно ставить закрывающий тег PHP ?>. Это может привести к некорректной работе кода обработчиков событий. В частности это касается тех случаев, когда регулярные задачи запускаются по cron, а также ошибки могут возникнут и в других случаях.

На этом статья с описанием создания инструмента по контролю за крайними сроками в задачах подходит к концу. В ней мы рассмотрели код 2 обработчиков событий, настройки и вспомогательные функции, а также способ хранения информации о крайних сроках задач в HL-блоке.

Надеюсь, статья была полезна для вас.

Скачать архив с кодом из статьи

Понравилась статья? Поделить с друзьями:
  • Бизнес центр трехгорная мануфактура парковка
  • Благотворительный фонд сердце есть реквизиты
  • Бизнес центр тринити санкт петербург газпром
  • Бланк организации с реквизитами образец ворд
  • Броско молл в хабаровске часы работы сегодня