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