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