При разработке отчетов и печатных форм в конфигурациях 1С (в частности, в 1С:ЗУП 3.0 и других типовых решениях на базе БСП) разработчики часто сталкиваются с ситуацией, когда запрос к виртуальной таблице СрезПоследних регистра сведений ДокументыФизическихЛиц возвращает несколько строк по одному человеку вместо одной последней. Проанализируем причину такого поведения платформы 1С:Предприятие и рассмотрим практические способы получения актуального документа.
Разберем внутреннее устройство регистра сведений ДокументыФизическихЛиц. В отличие от простых регистров, где измерением выступает только Физлицо, в данном регистре измерениями являются:
Физлицо (ссылка на справочник ФизическиеЛица);ВидДокумента (ссылка на справочник ВидыДокументовФизическихЛиц).Виртуальная таблица СрезПоследних рассчитывает срез не по какому-то одному выбранному полю, а по уникальной комбинации всех измерений регистра. Если в параметрах виртуальной таблицы мы задаем отбор только по физлицу:
РегистрСведений.ДокументыФизическихЛиц.СрезПоследних(&Период, ФизЛицо = &ФизЛицо)
платформа добросовестно находит самую свежую запись для каждого вида документа, когда-либо зарегистрированного за этим человеком (например, наиболее свежий вид на жительство, наиболее свежий паспорт РФ, наиболее свежий загранпаспорт). В результате по сотруднику возвращается столько строк, сколько видов документов числится в его истории.
Рассмотрим, какими способами можно гарантированно получить именно один актуальный документ физлица как для одиночной выборки, так и для списка сотрудников.
Посмотрим на классический универсальный подход, который работает на любых версиях платформы. Сначала мы выбираем срез последних по физлицам, находим максимальную дату документа для каждого человека, а затем соединяем результат с основной таблицей регистра.
ВЫБРАТЬ
ПаспортныеДанные.ФизЛицо КАК ФизЛицо,
МАКСИМУМ(ПаспортныеДанные.Период) КАК Период
ПОМЕСТИТЬ ВТ_МаксимальныеПериоды
ИЗ
РегистрСведений.ДокументыФизическихЛиц.СрезПоследних(
&ДатаСреза,
ФизЛицо В (&СписокФизЛиц)
И ЯвляетсяДокументомУдостоверяющимЛичность = ИСТИНА) КАК ПаспортныеДанные
СГРУППИРОВАТЬ ПО
ПаспортныеДанные.ФизЛицо
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_МаксимальныеПериоды.ФизЛицо КАК ФизЛицо,
Документы.ВидДокумента КАК ВидДокумента,
Документы.Серия КАК Серия,
Документы.Номер КАК Номер,
Документы.ДатаВыдачи КАК ДатаВыдачи,
Документы.КемВыдан КАК КемВыдан,
Документы.КодПодразделения КАК КодПодразделения,
Документы.Представление КАК Представление
ИЗ
ВТ_МаксимальныеПериоды КАК ВТ_МаксимальныеПериоды
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ДокументыФизическихЛиц КАК Документы
ПО ВТ_МаксимальныеПериоды.ФизЛицо = Документы.ФизЛицо
И ВТ_МаксимальныеПериоды.Период = Документы.Период
И Документы.ЯвляетсяДокументомУдостоверяющимЛичность = ИСТИНА
Обратите внимание: если у физического лица в один и тот же день введены разные документы (например, при первоначальном переносе данных на техническую дату 01.01.1900), соединение только по периоду может снова вернуть дубли. В таких случаях во временной таблице рекомендуется дополнительно группировать по приоритетному виду документа или использовать максимальный идентификатор.
Если решение разворачивается на платформе 1С:Предприятие версии 8.3.20 и новее, мы можем применить оконную функцию ROW_NUMBER(). Это позволяет избежать срезов и лишних соединений, ранжируя документы прямо в запросе:
ВЫБРАТЬ
Документы.ФизЛицо КАК ФизЛицо,
Документы.ВидДокумента КАК ВидДокумента,
Документы.Серия КАК Серия,
Документы.Номер КАК Номер,
Документы.ДатаВыдачи КАК ДатаВыдачи,
Документы.КемВыдан КАК КемВыдан,
Документы.Представление КАК Представление,
ROW_NUMBER() OVER (
PARTITION BY Документы.ФизЛицо
ORDER BY Документы.Период УБЫВ, Документы.ДатаВыдачи УБЫВ
) КАК НомерСтроки
ПОМЕСТИТЬ ВТ_РанжированныеДокументы
ИЗ
РегистрСведений.ДокументыФизическихЛиц КАК Документы
ГДЕ
Документы.ФизЛицо В (&СписокФизЛиц)
И Документы.Период <= &ДатаСреза
И Документы.ЯвляетсяДокументомУдостоверяющимЛичность = ИСТИНА
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.ФизЛицо,
ВТ.ВидДокумента,
ВТ.Серия,
ВТ.Номер,
ВТ.ДатаВыдачи,
ВТ.КемВыдан,
ВТ.Представление
ИЗ
ВТ_РанжированныеДокументы КАК ВТ
ГДЕ
ВТ.НомерСтроки = 1
В типовой конфигурации «1С:Зарплата и управление персоналом» ручное написание запросов к регистру документов физических лиц обычно не требуется. В конфигурации реализован готовый программный интерфейс в общем модуле КадровыйУчет, который уже содержит алгоритмы обработки дублей, проверки флага удостоверения личности и ранжирования.
Разберем программное получение данных в коде:
КадровыеДанные = Новый Массив;
КадровыеДанные.Добавить("ДокументВид");
КадровыеДанные.Добавить("ДокументСерия");
КадровыеДанные.Добавить("ДокументНомер");
КадровыеДанные.Добавить("ДокументДатаВыдачи");
КадровыеДанные.Добавить("ДокументКемВыдан");
КадровыеДанные.Добавить("ДокументКодПодразделения");
КадровыеДанные.Добавить("ДокументПредставление");
ТаблицаДанных = КадровыйУчет.КадровыеДанныеФизическихЛиц(
Истина,
СписокФизЛиц,
КадровыеДанные,
ТекущаяДата()
);
Если же паспортные данные требуются внутри сложного пакетного запроса, воспользуемся методом создания временной таблицы:
КадровыйУчет.СоздатьВТКадровыеДанныеФизическихЛиц(
МенеджерВременныхТаблиц,
"ВТ_ПаспортныеДанные",
СписокФизЛиц,
КадровыеДанные,
ДатаСреза
);
Использование встроенных процедур БСП является наиболее надежным решением, так как оно полностью защищено от изменений структуры метаданных при последующих обновлениях конфигурации.