При разработке в конфигурации 1С:Зарплата и управление персоналом 3.1 программисты часто сталкиваются с необходимостью программного получения текущих плановых начислений сотрудника. Одной из самых эффективных функций для этого является КадровыйУчетРасширенный.ТекущиеНачисленияСотрудника. Однако результат, который она возвращает, представляет собой сложную многоуровневую структуру (Соответствие), «распаковка» которой может вызвать затруднения.
В этой статье мы подробно разберем, как устроены возвращаемые данные, и рассмотрим несколько способов извлечения из них конкретных показателей: вида начисления, суммы (размера) и процентных показателей.
Прежде чем приступать к написанию кода, проанализируем, что именно возвращает функция КадровыйУчетРасширенный.ТекущиеНачисленияСотрудника(Сотрудник, ТекущаяДата). Это знание критически важно для правильного обращения к объектам.
Функция возвращает объект типа Соответствие (Map), структура которого выглядит следующим образом:
ПланВидовРасчета.Начисления. Это конкретный вид расчета, например, «Оклад» или «Надбавка за вредность».ТаблицаЗначений. В этой таблице содержатся подробные сведения о начислении.Внутри ТаблицыЗначений (значения соответствия) обычно присутствуют следующие колонки:
Размер: Числовое значение (сумма начисления).Валюта: Ссылка на справочник Валюты.Показатели: Это еще одно вложенное Соответствие, где ключами являются ссылки на показатели расчета (например, показатель «Процент»), а значениями — их конкретные величины.Таким образом, мы имеем «матрешку»: Соответствие -> Таблица Значений -> Соответствие. Именно такая глубина вложенности часто сбивает с толку начинающих разработчиков.
Если нам нужно получить данные по конкретному начислению, и мы знаем его ссылку, мы можем обратиться к данным напрямую, минуя сложные циклы. Рассмотрим пример получения суммы и размера по конкретной надбавке.
// Определяем вид начисления, который нас интересует
КлючНачисления = ПланыВидовРасчета.Начисления.НайтиПоНаименованию("Надбавка за стаж");
// Получаем общие данные оплаты труда
ТекущиеДанныеОплатыТруда = КадровыйУчетРасширенный.ТекущиеНачисленияСотрудника(СотрудникСсылка, ТекущаяДата);
// Извлекаем таблицу значений для конкретного начисления
ТаблицаНачисления = ТекущиеДанныеОплатыТруда.Получить(КлючНачисления);
Если ТаблицаНачисления <> Неопределено И ТаблицаНачисления.Количество() > 0 Тогда
// Берем первую строку из таблицы (обычно начисление одно)
СтрокаДанных = ТаблицаНачисления[0];
// Получаем сумму из колонки "Размер"
СуммаНачисления = СтрокаДанных.Размер;
// Если нужно получить показатель (например, процент), лезем во вложенное соответствие "Показатели"
ПоказательПроцент = Справочники.ПоказателиРасчетаЗарплаты.НайтиПоНаименованию("Процент");
ЗначениеПроцента = 0;
СтрокаДанных.Показатели.Выяснить(ПоказательПроцент, ЗначениеПроцента);
Сообщить("Сумма: " + СуммаНачисления + ", Процент: " + ЗначениеПроцента);
КонецЕсли;
Если нам нужно обработать все начисления сотрудника и представить их, например, в отчете или форме, удобнее всего перегнать Соответствие в плоскую ТаблицуЗначений. Разберем, как это сделать с помощью цикла.
Функция ПреобразоватьДанныеНачисленийВТЗ(СоотвДанных)
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("ВидНачисления");
ТЗ.Колонки.Добавить("Сумма");
ТЗ.Колонки.Добавить("Процент");
Для Каждого ЭлементСоответствия Из СоотвДанных Цикл
ВидРасчета = ЭлементСоответствия.Ключ; // ПланВидовРасчетаСсылка.Начисления
ТаблицаПоказателей = ЭлементСоответствия.Значение; // ТаблицаЗначений
Для Каждого СтрокаТЗ Из ТаблицаПоказателей Цикл
НоваяСтр = ТЗ.Добавить();
НоваяСтр.ВидНачисления = ВидРасчета;
НоваяСтр.Сумма = СтрокаТЗ.Размер;
// Пытаемся найти процент в колонке "Показатели"
// В реальной задаче лучше передавать ссылку на показатель как параметр
Для Каждого ПоказательЭлемент Из СтрокаТЗ.Показатели Цикл
Если Найти(Строка(ПоказательЭлемент.Ключ), "Процент") > 0 Тогда
НоваяСтр.Процент = ПоказательЭлемент.Значение;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Возврат ТЗ;
КонецФункции
В некоторых случаях структура может быть еще более запутанной. Для универсального «вытаскивания» данных можно использовать рекурсивную процедуру. Проанализируем пример, предложенный на форуме, который позволяет обходить вложенные соответствия до тех пор, пока не будет найдено конечное значение.
Процедура РазобратьСоответствиеРекурсивно(ИсточникДанных, ИтоговаяТЗ)
Для Каждого Элемент Из ИсточникДанных Цикл
Если ТипЗнч(Элемент.Значение) = Тип("Соответствие") Тогда
// Если внутри опять соответствие - проваливаемся глубже
РазобратьСоответствиеРекурсивно(Элемент.Значение, ИтоговаяТЗ);
ИначеЕсли ТипЗнч(Элемент.Значение) = Тип("ТаблицаЗначений") Тогда
// Если внутри таблица значений - перебираем её строки
Для Каждого СтрокаИзТЗ Из Элемент.Значение Цикл
// Если в строке есть колонка-соответствие (как "Показатели"), обрабатываем и её
Для Каждого Колонка Из Элемент.Значение.Колонки Цикл
Если ТипЗнч(СтрокаИзТЗ[Колонка.Имя]) = Тип("Соответствие") Тогда
РазобратьСоответствиеРекурсивно(СтрокаИзТЗ[Колонка.Имя], ИтоговаяТЗ);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЕсли;
// Здесь можно добавить логику проверки Ключа и заполнения ИтоговойТЗ
// Например: Если Элемент.Ключ = СсылкаНаНужныйПоказатель Тогда ...
КонецЦикла;
КонецПроцедуры
Важное замечание: Рекурсия — мощный инструмент, но в случае с ТекущиеНачисленияСотрудника структура достаточно детерминирована (фиксирована). Поэтому чаще всего достаточно двойного цикла: по самому соответствию и по строкам вложенной таблицы значений.
Выясним, можно ли упростить задачу с помощью стандартных библиотек. В Библиотеке стандартных подсистем (БСП) существует метод ОбщегоНазначения.ВыгрузитьКолонку(). Хотя он не решает задачу «распаковки» вложенных ТЗ, он может быть полезен, если вам нужно быстро получить список всех Видов расчета (ключей соответствия) или всех Таблиц значений (значений соответствия) в массив для дальнейшей обработки.
Пример использования:
// Получаем массив всех Таблиц Значений из соответствия
МассивТЗ = ОбщегоНазначения.ВыгрузитьКолонку(ТекущиеДанныеОплатыТруда, "Значение");
Проанализируем несколько нюансов, которые помогут избежать ошибок при разработке:
ТекущиеНачисленияСотрудника на Неопределено или Количество() > 0. Если у сотрудника нет действующих начислений на указанную дату, попытка обращения к ключу вызовет ошибку.Показатели всегда является Ссылка на справочник ПоказателиРасчетаЗарплаты. Использование поиска по наименованию внутри цикла — плохая практика. Рекомендуется один раз получить нужные ссылки перед началом цикла.ПлановыеНачисления и др.) именно на ту дату, которую вы передаете в параметрах. Убедитесь, что дата указана корректно, особенно если начисления начинаются с первого числа месяца.Рассмотренные методы позволяют гибко извлекать любые данные об оплате труда сотрудников в ЗУП 3.1, превращая сложные вложенные объекты в понятные и удобные для использования структуры.