В процессе разработки бизнес-логики часто возникает задача автоматического контроля сроков. Типичный пример: если после поступления товара прошло два дня, а ответственное лицо не заполнило определенные реквизиты (например, не прикрепило сертификат или паспорт изделия), система должна отправить уведомление менеджеру. Рассмотрим подробно, как реализовать такой механизм с помощью регламентного задания и запроса в 1С.
Предположим, у нас есть документ ХХХ_ПредварительныйЗаказПоставщику с табличной частью ОтметкиСклада. В этой табличной части присутствуют поля:
ДатаПоступления (тип Дата) — точка отсчета.Сертификат (тип Булево) — флаг готовности.ПаспортИзделия (тип Булево) — второй флаг готовности.Нам необходимо выявить строки, где оба флага имеют значение Ложь, а с момента ДатаПоступления прошло 2 и более дней. Основной вопрос заключается в том, как правильно рассчитать этот момент в запросе и как избежать повторной отправки писем (спама).
Для решения задачи мы воспользуемся механизмом запросов. Проанализируем два подхода к расчету разницы дат: использование функции РАЗНОСТЬДАТ и функции ДОБАВИТЬКДАТЕ.
Вариант 1: Использование функции РАЗНОСТЬДАТ
Этот способ интуитивно понятен. Мы вычисляем количество дней между текущей датой и датой из документа. Разберем пример кода:
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| ОтметкиСклада.Ссылка КАК Ссылка,
| ОтметкиСклада.Ссылка.Менеджер КАК Менеджер,
| ОтметкиСклада.ДатаПоступления КАК ДатаПоступления,
| РАЗНОСТЬДАТ(ОтметкиСклада.ДатаПоступления, &ТекДата, ДЕНЬ) КАК РазностьДат
|ИЗ
| Документ.ХХХ_ПредварительныйЗаказПоставщику.ОтметкиСклада КАК ОтметкиСклада
|ГДЕ
| ОтметкиСклада.Сертификат = ЛОЖЬ
| И ОтметкиСклада.ПаспортИзделия = ЛОЖЬ
| И РАЗНОСТЬДАТ(ОтметкиСклада.ДатаПоступления, &ТекДата, ДЕНЬ) >= 2";
Запрос.УстановитьПараметр("ТекДата", ТекущаяДата());
Вариант 2: Использование функции ДОБАВИТЬКДАТЕ (рекомендуемый)
С точки зрения производительности СУБД, более правильным считается использование функции ДОБАВИТЬКДАТЕ в условии сравнения. Это позволяет оптимизатору запросов более эффективно работать с индексами. Проанализируем ситуацию: мы прибавляем 2 дня к дате поступления и проверяем, не наступил ли этот момент уже сейчас.
Запрос.Текст = "
|ВЫБРАТЬ
| ОтметкиСклада.Ссылка КАК Ссылка,
| ОтметкиСклада.Ссылка.Номер КАК Номер,
| ОтметкиСклада.Менеджер КАК Менеджер
|ИЗ
| Документ.ХХХ_ПредварительныйЗаказПоставщику.ОтметкиСклада КАК ОтметкиСклада
|ГДЕ
| ОтметкиСклада.Сертификат = ЛОЖЬ
| И ОтметкиСклада.ПаспортИзделия = ЛОЖЬ
| И ДОБАВИТЬКДАТЕ(ОтметкиСклада.ДатаПоступления, ДЕНЬ, 2) <= &ТекДата";
Обратите внимание на знак сравнения: <= означает, что "контрольная точка" (дата поступления + 2 дня) уже находится в прошлом относительно текущего момента.
Если регламентное задание запускается ежедневно, то без фиксации факта отправки менеджер будет получать письмо по одному и тому же документу каждый день, пока не проставит нужные галочки. Выясним, как это предотвратить.
Способ А: Реквизит в табличной части
Можно добавить в табличную часть реквизит УведомлениеОтправлено (Булево). После успешной отправки письма программно устанавливаем этот флаг в документе.
Минусы: Изменение документа приводит к обновлению версии объекта, изменению даты изменения и может вызвать конфликты блокировок, если документ в этот момент редактирует пользователь.
Способ Б: Независимый регистр сведений (Архитектурно верный)
Рассмотрим создание регистра сведений СостоянияРассылкиУведомлений. В измерениях укажем Документ и КлючСтроки, а в ресурсах — ДатаОтправки.
Преимущества очевидны: мы не трогаем сам документ, не меняем его версию и не блокируем его для пользователей. В запрос тогда нужно добавить левое соединение с этим регистром и условие: ГДЕ СостоянияРассылкиУведомлений.Период ЕСТЬ NULL.
Рассмотрим еще несколько важных аспектов, которые помогут сделать решение профессиональным:
ДОБАВИТЬКДАТЕ использовать нельзя. В этом случае нужно использовать производственный календарь. В коде 1С (при наличии БСП) это делается через КалендарныеГрафики.ПолучитьДатуЗавершенияСрока(ДатаПоступления, 2). Полученную дату передаем в запрос как параметр.Разберем по шагам, как должен выглядеть код в модуле менеджера или общем модуле:
// 1. Подготовка параметров (например, расчет даты с учетом рабочих дней)
ГраничнаяДата = ТекущаяДата(); // Или расчет через календарь
// 2. Выполнение запроса
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ... (запрос с условиями на даты и флаги)";
Запрос.УстановитьПараметр("ТекДата", ГраничнаяДата);
Результат = Запрос.Выполнить();
// 3. Обход выборки и формирование писем
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь логика отправки почты или формирования таблицы для групповой отправки
// 4. Фиксация факта отправки в регистре или реквизите
ЗафиксироватьОтправку(Выборка.Ссылка);
КонецЦикла;
КонецЕсли;
Использование функции ДОБАВИТЬКДАТЕ совместно с надежным механизмом фиксации состояния (регистром сведений) обеспечит стабильную работу системы уведомлений и лояльность пользователей, которые не будут страдать от лишнего спама.