Как убрать дубли строк в отчете СКД при получении контактной информации сотрудников?

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

При разработке отчетов на Системе Компоновки Данных (СКД) часто возникает задача вывести список сотрудников вместе с их контактными данными: телефонами, адресами электронной почты и т.д. Однако при простом соединении кадровых данных с регистром контактной информации можно столкнуться с неприятной проблемой — дублированием строк. Разберем, почему это происходит и как это исправить на примере отчета в 1С:Бухгалтерия 3.0.

Проанализируем исходную ситуацию. Есть запрос, который получает последние кадровые сведения о сотрудниках и соединяется с таблицей контактной информации физических лиц.

Исходный запрос с проблемой:


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

Причина дублей кроется в ЛЕВОЕ СОЕДИНЕНИЕ с табличной частью Справочник.ФизическиеЛица.КонтактнаяИнформация (или с регистром сведений КонтактнаяИнформация). Если у одного физического лица в системе заведено несколько видов контактов (например, рабочий телефон, личный телефон, email), то для каждой записи в таблице контактов будет создана отдельная строка в итоговом результате. В результате мы видим одного и того же сотрудника несколько раз.

Рассмотрим два основных способа решения этой проблемы.

Решение 1: Получение контактов через вычисляемое поле и общий модуль

Этот подход заключается в том, чтобы в основном запросе не соединяться с таблицей контактов, а получить их позже, на этапе вывода данных в СКД, для каждой строки отчета. Это позволяет избежать дублей на уровне запроса.

Шаг 1. Упрощаем основной запрос

Сначала уберем из запроса соединение с контактной информацией. Наш основной набор данных будет содержать уникальный список сотрудников без дублей.


ВЫБРАТЬ
    КадроваяИсторияСотрудниковСрезПоследних.ФизическоеЛицо,
    КадроваяИсторияСотрудниковСрезПоследних.Организация,
    КадроваяИсторияСотрудниковСрезПоследних.Подразделение,
    КадроваяИсторияСотрудниковСрезПоследних.Должность,
    КадроваяИсторияСотрудниковСрезПоследних.ФизическоеЛицо.ДатаРождения
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&НаДату, ) КАК КадроваяИсторияСотрудниковСрезПоследних

Шаг 2. Создаем вычисляемое поле в СКД

Теперь в схеме компоновки данных на вкладке "Вычисляемые поля" добавим новое поле, например, "ЭлектроннаяПочта". В колонке "Выражение" нужно указать, как его рассчитать. Первая мысль — использовать стандартную функцию для получения контактов:

УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(ФизическоеЛицо, Справочники.ВидыКонтактнойИнформации.EMailФизическиеЛица, ТекущаяДата())

Однако при попытке выполнить отчет мы получим ошибку "Поле не найдено: Справочники".

Важный момент: язык выражений СКД работает в ограниченном контексте. Он не имеет прямого доступа к объектам конфигурации, таким как Справочники, Перечисления и т.д., на клиенте. Эти выражения выполняются в специальной изолированной среде.

Шаг 3. Создаем "функцию-обертку" в общем модуле

Чтобы обойти это ограничение, создадим свою функцию в общем модуле. Эта функция будет выполняться на сервере, где есть доступ ко всем объектам конфигурации.

  1. Создайте новый общий модуль (например, мМоиОтчеты).
  2. Убедитесь, что у модуля установлены флаги "Сервер" и "Вызов сервера".
  3. Добавьте в него экспортную функцию:

Функция ПолучитьЭлектроннуюПочту(ФизЛицо) Экспорт
    // Получаем предопределенный элемент справочника ВидыКонтактнойИнформации
    // Название предопределенного элемента может отличаться в разных конфигурациях. 
    // Проверьте его точное имя в вашей базе.
    ВидКИ = Справочники.ВидыКонтактнойИнформации.EMailФизическиеЛица;

    // Вызываем стандартную функцию БСП
    ПредставлениеКонтакта = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(ФизЛицо, ВидКИ);
    
    Возврат ПредставлениеКонтакта;
КонецФункции

Шаг 4. Указываем вызов нашей функции в вычисляемом поле

Теперь вернемся в СКД и в выражении для нашего вычисляемого поля "ЭлектроннаяПочта" напишем вызов созданной нами функции:

мМоиОтчеты.ПолучитьЭлектроннуюПочту(ФизическоеЛицо)

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

Решение 2: Модификация запроса для исключения дублей

Этот способ является более производительным, так как вся обработка данных происходит на уровне СУБД в рамках одного запроса. Идея состоит в том, чтобы присоединять таблицу с контактами не один раз "в общем", а несколько раз — по одному для каждого нужного вида контакта.

Шаг 1. Используем несколько левых соединений

Мы будем использовать ЛЕВОЕ СОЕДИНЕНИЕ с регистром сведений КонтактнаяИнформация для каждого типа контакта (одно соединение для email, второе для телефона и т.д.). В условии соединения мы явно укажем, какой вид информации нас интересует.

Пример усовершенствованного запроса:


ВЫБРАТЬ
    КадроваяИстория.ФизическоеЛицо,
    КадроваяИстория.Организация,
    КадроваяИстория.Подразделение,
    КадроваяИстория.Должность,
    КадроваяИстория.ФизическоеЛицо.ДатаРождения,
    ЕСТЬNULL(ЭлектроннаяПочта.Представление, "") КАК АдресЭП,
    ЕСТЬNULL(Телефон.Представление, "") КАК НомерТелефона
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&НаДату, ) КАК КадроваяИстория

        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК ЭлектроннаяПочта
        ПО КадроваяИстория.ФизическоеЛицо = ЭлектроннаяПочта.Объект
        И (ЭлектроннаяПочта.Вид = &ВидЭлектроннаяПочта)

        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК Телефон
        ПО КадроваяИстория.ФизическоеЛицо = Телефон.Объект
        И (Телефон.Вид = &ВидТелефон)

Шаг 2. Настраиваем параметры в СКД

В этом запросе появились два новых параметра: &ВидЭлектроннаяПочта и &ВидТелефон. Их необходимо настроить в СКД:

  1. Перейдите на вкладку "Параметры" в схеме компоновки.
  2. Для параметра &ВидЭлектроннаяПочта в колонке "Выражение" укажите путь к предопределенному элементу справочника. Для этого нажмите кнопку выбора, перейдите в Справочники -> ВидыКонтактнойИнформации -> Предопределенные и выберите нужный элемент (например, EMailФизическиеЛица).
  3. Проделайте то же самое для параметра &ВидТелефон, выбрав соответствующий вид контакта.
  4. Снимите флажок "Включать в пользовательские настройки", чтобы эти параметры не отображались пользователю.

Функция ЕСТЬNULL(..., "") используется для того, чтобы в отчете выводилась пустая строка, а не значение NULL, если у сотрудника отсутствует тот или иной вид контакта.

Дополнительный совет: Отбор только работающих сотрудников

Часто в отчетах необходимо видеть только актуальных, работающих сотрудников. Виртуальная таблица СрезПоследних возвращает последнее состояние сотрудника, которое может быть и "Уволен". Чтобы исключить уволенных, добавьте в запрос условие ГДЕ.


ВЫБРАТЬ
    ...
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&НаДату, ) КАК КадроваяИстория
    ...
ГДЕ
    КадроваяИстория.ПричинаИзмененияСостояния <> ЗНАЧЕНИЕ(Перечисление.ПричиныИзмененияСостояния.Увольнение)

Таким образом, вы получите отчет только по сотрудникам, которые числятся работающими на указанную дату.

← На главную