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