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