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