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