Как реализовать вывод напоминаний о днях рождения сотрудников при запуске 1С?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

Оповещение о предстоящих днях рождения коллег — одна из частых сервисных задач при доработке учетных систем. Пользователям удобно видеть список именинников на ближайшие 3–5 дней сразу при входе в программу. Рассмотрим, как правильно реализовать данный функционал, разберем возможные подводные камни алгоритмов и изучим примеры кода для различных версий платформы 1С.

Ключевые нюансы при расчете дат дней рождения

Прежде чем приступать к написанию кода, проанализируем неочевидные логические ошибки, с которыми часто сталкиваются разработчики:

  1. Переход через границу года (конец декабря — начало января). Если выполнять проверку простым сравнением дня и месяца в пределах одного года, алгоритм пропустит дни рождения первых чисел января при проверке 30 или 31 декабря. Требуется приводить дату рождения к текущему году, а если она уже прошла — к следующему году, после чего проверять вхождение в интервал.
  2. Високосные годы и дата 29 февраля. Прямое конструирование даты через функцию Дата(ТекущийГод, 2, 29) в невисокосный год приведет к критической ошибке выполнения («Недопустимая дата»). Для таких сотрудников необходимо программно предусматривать сдвиг на 28 февраля или 1 марта.
  3. Разделение физических лиц и действующих сотрудников. В типовых конфигурациях 1С дата рождения хранится в справочнике ФизическиеЛица, тогда как признак работы в организации определяется кадровыми срезами справочника Сотрудники или регистрами кадровой истории. Выборка напрямую из физических лиц без проверки статуса работы приведет к выводу уволенных сотрудников.

Реализация выборки с помощью запроса в 1С:Предприятие 8

Разберем наиболее производительный вариант для платформы 8.3 — использование языка запросов. Вместо перебора справочников в цикле мы вычисляем смещение года и получаем список сотрудников, чей день рождения попадает в интервал между текущей датой и датой через $N$ дней.

Рассмотрим пример формирования запроса с приведением даты к текущему и следующему годам:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Сотрудники.Ссылка КАК Сотрудник,
    |	Сотрудники.ФизическоеЛицо КАК ФизЛицо,
    |	Сотрудники.ФизическоеЛицо.ДатаРождения КАК ДатаРождения,
    |	ВЫБОР
    |		КОГДА ДОБАВИТЬКДАТЕ(Сотрудники.ФизическоеЛицо.ДатаРождения, ГОД, РАЗНОСТЬДАТ(Сотрудники.ФизическоеЛицо.ДатаРождения, &ТекущаяДата, ГОД)) < &ТекущаяДата
    |			ТОГДА ДОБАВИТЬКДАТЕ(Сотрудники.ФизическоеЛицо.ДатаРождения, ГОД, РАЗНОСТЬДАТ(Сотрудники.ФизическоеЛицо.ДатаРождения, &ТекущаяДата, ГОД) + 1)
    |		ИНАЧЕ ДОБАВИТЬКДАТЕ(Сотрудники.ФизическоеЛицо.ДатаРождения, ГОД, РАЗНОСТЬДАТ(Сотрудники.ФизическоеЛицо.ДатаРождения, &ТекущаяДата, ГОД))
    |	КОНЕЦ КАК БлижайшийДР
    |ПОМЕСТИТЬ ВТ_Именинники
    |ИЗ
    |	Справочник.Сотрудники КАК Сотрудники
    |ГДЕ
    |	НЕ Сотрудники.ВАрхиве
    |	И Сотрудники.ФизическоеЛицо.ДатаРождения <> ДАТАВРЕМЯ(1, 1, 1)
    |;
    |
    |ВЫБРАТЬ
    |	ВТ.Сотрудник,
    |	ВТ.ДатаРождения,
    |	ВТ.БлижайшийДР
    |ИЗ
    |	ВТ_Именинники КАК ВТ
    |ГДЕ
    |	ВТ.БлижайшийДР МЕЖДУ &ТекущаяДата И &ДатаКонцаПериода
    |УПОРЯДОЧИТЬ ПО
    |	ВТ.БлижайшийДР";

Запрос.УстановитьПараметр("ТекущаяДата", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ДатаКонцаПериода", КонецДня(ТекущаяДата() + 5 * 86400));

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    Сообщить("У сотрудника " + Строка(Выборка.Сотрудник) + " день рождения: " + Формат(Выборка.БлижайшийДР, "ДФ=dd.MM"));
КонецЦикла;

Способы вывода информации пользователю без изменения конфигурации

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

  1. Расширение конфигурации (Configuration Extension). Создаем расширение и перехватываем событие ПриНачалеРаботыСистемы с директивой &После. Конфигурация остается на полной поддержке.
  2. Информационная панель на начальной странице. Вместо всплывающих окон сообщений создаем виджет (форму) в рабочей области начальной страницы. Пользователь всегда видит актуальный список без блокировки интерфейса.
  3. Использование механизма напоминаний БСП. В конфигурациях на базе Библиотеки стандартных подсистем можно использовать подсистему напоминаний пользователя, программно создавая записи в регистре сведений НапоминанияПользователя.
  4. Регламентные задания и рассылки. Чтобы исключить замедление старта системы при большой базе сотрудников, формируем список именинников регламентным заданием в фоновом режиме (например, с отправкой уведомлений в корпоративную почту или мессенджер).

Реализация задачи в платформе 1С:Предприятие 7.7

Посмотрим на классические примеры решения данной задачи в версиях 7.7. Первый вариант строится на переборе элементов справочника в цикле с проверкой даты:


Спр = СоздатьОбъект("Справочник.Сотрудники");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
    Если Спр.ДатаУвольнения = Дата(0) Тогда
        ДатаДР = Дата(ДатаГод(РабочаяДата), ДатаМесяц(Спр.ДатаРождения), ДатаЧисло(Спр.ДатаРождения));
        Если (РабочаяДата >= ДатаДР - 5) и (РабочаяДата <= ДатаДР) Тогда
            Сообщить("Сотруднику " + Спр.Наименование + " исполняется " + (ДатаГод(РабочаяДата) - ДатаГод(Спр.ДатаРождения)) + " (" + Формат(Спр.ДатаРождения, "Д ДДММММГГГГ") + ")");
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Второй вариант для 7.7 использует встроенный объект Запрос, что позволяет фильтровать данные быстрее:


Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Обрабатывать НеПомеченныеНаУдаление;
|Без итогов;
|Сотрудник = Справочник.Сотрудники.ТекущийЭлемент;
|ДатаРождения = Справочник.Сотрудники.ДатаРождения;
|Группировка Сотрудник без групп;
|Условие((ДатаЧисло(ДатаРождения) >= ДатаЧисло(РабочаяДата)) и (ДатаЧисло(ДатаРождения) <= ДатаЧисло(РабочаяДата) + 5));
|Условие(ДатаМесяц(ДатаРождения) = ДатаМесяц(РабочаяДата));
|";

Если Запрос.Выполнить(ТекстЗапроса) <> 0 Тогда
    Пока Запрос.Группировка() = 1 Цикл
        Сообщить("У сотрудника " + Запрос.Сотрудник + " день рождения: " + Запрос.ДатаРождения);
    КонецЦикла;
КонецЕсли;

Таким образом, для современных систем 1С 8.3 оптимальным решением является использование запроса с обработкой смещения дат, внедренного через механизм расширений или панель начальной страницы.

← На главную