Как создать отчет по дням рождения сотрудников в 1С:ЗУП с учетом високосных годов и 29 февраля?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом Управленческий учет
← На главную

При формировании отчетов по дням рождения сотрудников в системе 1С:Зарплата и Управление Персоналом (ЗУП) часто возникает вопрос о корректности отображения дат рождения, приходящихся на 29 февраля. Основная проблема, как правило, заключается в том, что в невисокосные годы этой даты календарно не существует, и пользователи опасаются, что сотрудники, родившиеся 29 февраля, могут быть пропущены в отчетах или напоминаниях. Мы рассмотрим, как эта ситуация обрабатывается в типовых решениях 1С и как можно создать собственный запрос для максимально точного и надежного отчета.

Первоначально важно понимать, что современные версии 1С:ЗУП, как правило, уже обладают встроенными механизмами для корректной обработки таких дат. Однако, если требуется специфическая логика или тонкая настройка, нам придется углубиться в принципы работы с датами в языке запросов 1С.

Использование типового функционала 1С:ЗУП для отчетов по дням рождения

Прежде чем приступать к написанию собственного запроса, мы всегда рекомендуем рассмотреть возможности типовых отчетов, предоставляемых конфигурацией 1С:ЗУП. В большинстве случаев они уже содержат необходимый функционал и корректно обрабатывают специфические даты, такие как 29 февраля.

Отчет "Личные данные сотрудников"

Одним из наиболее подходящих типовых отчетов для получения информации о днях рождения является "Личные данные сотрудников". Давайте разберем, как его использовать и настроить:

  1. Открытие отчета: Перейдите в раздел "Кадры" или "Отчеты по персоналу" (в зависимости от версии конфигурации) и найдите отчет "Личные данные сотрудников". Откройте его.
  2. Настройка состава полей: Нажмите кнопку "Настройки" (обычно в правом верхнем углу отчета). В открывшейся форме настроек перейдите на вкладку "Поля и сортировки" или "Структура". Убедитесь, что в отчет включены следующие поля:
    • Сотрудник (или ФизическоеЛицо)
    • Дата рождения
    • Должность
    • Подразделение (если необходимо)
    • Любые другие реквизиты, которые вы хотите видеть в отчете.
  3. Установка отборов: Перейдите на вкладку "Отборы". Здесь вы можете установить условия, чтобы получить только нужных сотрудников или дни рождения за определенный период. Например, вы можете добавить отбор по Дате рождения. Однако для корректной обработки 29 февраля и вывода "ближайших" дней рождения, этот отбор может быть не совсем интуитивным.
  4. Группировки и сортировки: Настройте группировку по Подразделению или Должности, если это необходимо. Отсортируйте отчет по Дате рождения, чтобы видеть ближайшие события.
  5. Обработка 29 февраля типовым отчетом: Важно, что типовые отчеты 1С:ЗУП и система напоминаний, как правило, уже настроены так, чтобы не пропускать дни рождения 29 февраля. В невисокосный год, когда 29 февраля отсутствует, система чаще всего "переносит" такую дату на 28 февраля текущего года для целей напоминаний или включения в отчеты за этот период. Это стандартное поведение, которое предотвращает "потерю" информации о дне рождения. Мы убедились, что в стандартном ЗУП напоминания на 29 февраля срабатывают корректно.

Таким образом, для большинства пользователей и задач типового функционала "Личные данные сотрудников" будет достаточно, и нет необходимости изобретать велосипед.

Создание пользовательского запроса для отчета по дням рождения

Если же типовой отчет не подходит под ваши уникальные требования, например, нужна очень специфическая логика отбора или форматирования, мы можем создать свой запрос на языке 1С. Здесь ключевым моментом будет правильная работа с датами, особенно с 29 февраля.

Понимание логики обработки 29 февраля в 1С

Критически важно понимать, как система 1С работает с "несуществующими" датами. Если мы пытаемся создать дату, например, 29 февраля в невисокосный год (который имеет 365 дней), функции 1С автоматически скорректируют эту дату. В большинстве случаев ДОБАВИТЬКДАТЕ() или явное создание даты (например, ДАТА(Год, Месяц, День)) для 29 февраля невисокосного года приведет к результату 28 февраля того же года. Это происходит, потому что система "перематывает" дни и останавливается на последнем возможном дне месяца.

Этот механизм является нашим союзником. Нам не нужно писать сложные проверки на високосность для каждой даты рождения. Достаточно сформировать "виртуальную" дату дня рождения сотрудника в текущем (или интересующем нас) году, и система сама позаботится о коррекции 29 февраля.

Базовая структура запроса

Для создания запроса нам понадобятся данные о сотрудниках и их датах рождения. Эти данные обычно хранятся в регистре сведений РаботникиОрганизаций.СрезПоследних или КадроваяИсторияСотрудников.СрезПоследних и справочнике ФизическиеЛица.

Рассмотрим шаги по формированию запроса:

  1. Выбор источника данных: Мы будем использовать срез последних по регистру сведений РаботникиОрганизаций.СрезПоследних, чтобы получить актуальные данные о работающих сотрудниках на определенную дату.
  2. Получение даты рождения: Дата рождения сотрудника хранится в справочнике ФизическиеЛица, на который ссылается регистр РаботникиОрганизаций.
  3. Расчет "виртуальной" даты дня рождения в текущем году: Это самый важный шаг. Мы берем год из параметра отчета (например, &ДатаОтчета), а месяц и день — из даты рождения физического лица.
  4. Фильтрация по периоду: Сравниваем полученную "виртуальную" дату дня рождения с заданным диапазоном дат отчета.

Давайте посмотрим на пример запроса. Мы будем использовать параметры &ДатаОтчета (обычно текущая дата или дата, на которую формируется отчет), &НачалоПериода и &КонецПериода (диапазон, за который мы хотим получить дни рождения, например, ближайшие 30 дней).

Пример запроса для отчета по дням рождения с учетом 29 февраля

Представим, что нам нужно получить список сотрудников, у которых день рождения выпадает в ближайшие 30 дней от текущей даты, и при этом корректно учесть 29 февраля.

Параметры запроса:

Важно: Запрос, который был приведен в сообщении 11, использует Период МЕЖДУ &ДатаНач И ДОБАВИТЬКДАТЕ(&ДатаКон, ДЕНЬ, 1) для регистра КадроваяИсторияСотрудников.СрезПоследних. Это неверно, так как поле Период в срезах регистров сведений, как правило, является датой записи или актуальности записи, а не датой рождения. Мы будем обращаться напрямую к ФизическоеЛицо.ДатаРождения.


ВЫБРАТЬ
    РаботникиОрганизацийСрезПоследних.Сотрудник.Наименование КАК Сотрудник,
    РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения КАК ДатаРожденияФизЛица,
    РаботникиОрганизацийСрезПоследних.Должность КАК Должность,
    РаботникиОрганизацийСрезПоследних.Подразделение КАК Подразделение,
    РаботникиОрганизацийСрезПоследних.ГоловнаяОрганизация КАК Организация,
    ВЫБОР
        КОГДА МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) = 2
             И ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) = 29
             И НЕ ГОДВИСОКОСНЫЙ(ГОД(&ДатаОтчета)) // Если год отчета не високосный
        ТОГДА ДОБАВИТЬКДАТЕ(
                ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&ДатаОтчета, ГОД), МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, МЕСЯЦ),
                ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 2, ДЕНЬ // Получаем 28 февраля
            )
        ИНАЧЕ ДОБАВИТЬКДАТЕ(
                ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&ДатаОтчета, ГОД), МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, МЕСЯЦ),
                ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, ДЕНЬ
            )
    КОНЕЦ КАК ДатаДняРожденияВГодуОтчета
ИЗ
    РегистрСведений.РаботникиОрганизаций.СрезПоследних(
        &ДатаОтчета,
        // Условие на активность сотрудника
        Активность = ИСТИНА
    ) КАК РаботникиОрганизацийСрезПоследних
ГДЕ
    // Фильтруем по дате дня рождения в текущем году отчета
    // Сравниваем полученную "виртуальную" дату дня рождения с заданным диапазоном.
    // Если день рождения уже прошел в текущем году, мы можем проверить его в следующем году
    // для корректного отображения "ближайших" дней рождения.
    (
        (ВЫБОР
            КОГДА МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) = 2
                 И ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) = 29
                 И НЕ ГОДВИСОКОСНЫЙ(ГОД(&ДатаОтчета))
            ТОГДА ДОБАВИТЬКДАТЕ(
                    ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&ДатаОтчета, ГОД), МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, МЕСЯЦ),
                    ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 2, ДЕНЬ
                )
            ИНАЧЕ ДОБАВИТЬКДАТЕ(
                    ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(&ДатаОтчета, ГОД), МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, МЕСЯЦ),
                    ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, ДЕНЬ
                )
        КОНЕЦ МЕЖДУ &НачалоПериода И &КонецПериода)
        ИЛИ
        // Учет дней рождения, которые уже прошли в текущем году, но наступят в следующем
        // если период &НачалоПериода - &КонецПериода пересекает конец/начало года.
        // Для простых "ближайших 30 дней" этот блок может быть излишним,
        // но для "всех дней рождения в текущем квартале" он может потребоваться,
        // если диапазон отчета начинается в одном году и заканчивается в следующем.
        // Для демонстрации "ближайших 30 дней" мы просто ищем в текущем году.
        (ДОБАВИТЬКДАТЕ(
             ВЫБОР
                КОГДА МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) = 2
                     И ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) = 29
                     И НЕ ГОДВИСОКОСНЫЙ(ГОД(ДОБАВИТЬКДАТЕ(&ДатаОтчета, ГОД, 1))) // Если СЛЕДУЮЩИЙ год не високосный
                ТОГДА ДОБАВИТЬКДАТЕ(
                        ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаОтчета, ГОД, 1), ГОД), МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, МЕСЯЦ),
                        ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 2, ДЕНЬ
                    )
                ИНАЧЕ ДОБАВИТЬКДАТЕ(
                        ДОБАВИТЬКДАТЕ(НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ДатаОтчета, ГОД, 1), ГОД), МЕСЯЦ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, МЕСЯЦ),
                        ДЕНЬ(РаботникиОрганизацийСрезПоследних.ФизическоеЛицо.ДатаРождения) - 1, ДЕНЬ
                    )
            КОНЕЦ,
            ДЕНЬ, 0
         ) МЕЖДУ &НачалоПериода И &КонецПериода И ГОД(ДОБАВИТЬКДАТЕ(&ДатаОтчета, ГОД, 1)) = ГОД(&КонецПериода))
    )
УПОРЯДОЧИТЬ ПО
    ДатаДняРожденияВГодуОтчета

Разъяснение логики запроса:

  1. Источник данных: Мы используем РегистрСведений.РаботникиОрганизаций.СрезПоследних(&ДатаОтчета, Активность = ИСТИНА). Это позволяет нам получить список всех активных сотрудников на указанную дату отчета &ДатаОтчета. Важно передавать &ДатаОтчета как параметр в срез последних, чтобы данные были актуальны.
  2. Вычисляемое поле ДатаДняРожденияВГодуОтчета: Это ключевое поле. Мы конструируем дату дня рождения сотрудника, используя год из &ДатаОтчета, а месяц и день из ФизическоеЛицо.ДатаРождения.
    • НАЧАЛОПЕРИОДА(&ДатаОтчета, ГОД): Получаем 1 января года, в котором формируется отчет.
    • ДОБАВИТЬКДАТЕ(..., МЕСЯЦ(ДатаРождения) - 1, МЕСЯЦ): Прибавляем необходимое количество месяцев, чтобы получить 1-е число месяца рождения. Например, для марта (3-й месяц) прибавляем 2 месяца к 1 января.
    • ДОБАВИТЬКДАТЕ(..., ДЕНЬ(ДатаРождения) - 1, ДЕНЬ): Прибавляем необходимое количество дней, чтобы получить точный день рождения в этом месяце.

    Особый случай 29 февраля: Внутри ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ мы явно проверяем, является ли текущий год отчета невисокосным (НЕ ГОДВИСОКОСНЫЙ(ГОД(&ДатаОтчета))), и если да, то для дат 29 февраля мы принудительно устанавливаем день 28 (ДЕНЬ(ФизическоеЛицо.ДатаРождения) - 2, ДЕНЬ), что в конечном итоге даст 28 февраля. В противном случае (если год високосный или день рождения не 29 февраля), используется стандартная логика.

  3. Условие ГДЕ: Здесь мы фильтруем сотрудников. Основная часть условия ДатаДняРожденияВГодуОтчета МЕЖДУ &НачалоПериода И &КонецПериода выбирает всех, чья "виртуальная" дата дня рождения попадает в заданный нами интервал.

    Дополнительная секция ИЛИ, включающая в себя логику для дня рождения в следующем году, необходима, если диапазон отчета может охватывать границу годов. Например, если мы ищем дни рождения с 20 декабря текущего года по 20 января следующего года, то дни рождения, которые приходятся на январь следующего года, также должны быть учтены. Для простого отчета "ближайших X дней" такой усложненный вариант может быть избыточен, и достаточно первой части условия.

  4. Упорядочивание: Результат отчета упорядочивается по ДатаДняРожденияВГодуОтчета, что позволяет видеть предстоящие дни рождения в хронологическом порядке.

При использовании этого запроса в конструкторе запросов или в модуле вы должны будете передать значения для параметров &ДатаОтчета, &НачалоПериода и &КонецПериода.

Дополнительные рекомендации и советы

  1. Тестирование: Всегда тщательно тестируйте разработанный отчет с различными тестовыми данными, включая сотрудников с днем рождения 29 февраля, а также с датами, выходящими за рамки високосных и невисокосных годов.
  2. Производительность: Для больших баз данных убедитесь, что ваш запрос оптимален и не вызывает чрезмерной нагрузки на сервер. Использование срезов последних регистров сведений, как правило, эффективно.
  3. Интерфейс: Если вы создаете отчет для конечных пользователей, предусмотрите удобный интерфейс для ввода параметров (период отчета, дата отчета), чтобы пользователи могли легко настраивать его под свои нужды.
  4. Учет возраста: Если вам также необходимо выводить возраст сотрудника, используйте встроенные функции 1С для работы с датами, которые корректно рассчитывают возраст с учетом високосных лет. Например, можно вычесть годы из дат, а затем скорректировать результат, сравнивая месяцы и дни рождения с текущими месяцем и днем.

В заключение, проблема учета 29 февраля при формировании отчетов по дням рождения в 1С:ЗУП вполне решаема. В большинстве случаев достаточно использовать типовой функционал, который уже обрабатывает такие нюансы. Если же требуется индивидуальное решение, то, следуя принципам работы с датами в языке запросов 1С и используя описанную логику, вы сможете создать надежный и корректный отчет.

← На главную