Как найти и изменить результирующий запрос при формировании Расчетного листа в 1С:ЗУП 3.1

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом Управленческий учет IT и автоматизация бизнеса
← На главную

При работе с конфигурацией 1С:Зарплата и управление персоналом 3.1 программисты часто сталкиваются с необходимостью кастомизации стандартных отчетов. Одной из наиболее востребованных и одновременно сложных задач является модификация Расчетного листка. Типовая проблема заключается в том, что при установке отбора по конкретному подразделению система выводит данные только по основному месту работы сотрудника, игнорируя его внутреннее совместительство, если оно оформлено в другом отделе. В этой статье мы подробно разберем, где «прячется» итоговый запрос и как программно изменить логику формирования данных.

Архитектура механизма формирования отчетов по зарплате

Прежде всего, нам необходимо понять, что Расчетный листок в современных версиях ЗУП не является классическим отчетом на базе одной лишь схемы компоновки данных (СКД) с жестко прописанным текстом запроса. Он встроен в общую подсистему АнализНачисленийУдержаний.

Проанализируем структуру: данные собираются динамически из множества источников (регистры расчета, регистры накопления по взаиморасчетам и выплатам). Основная логика сборки текста запроса вынесена в общие модули, что позволяет системе гибко подстраиваться под настройки пользователя (группировки, отборы, выбранные поля).

Разберем основные точки входа, которые нам понадобятся для анализа:

  1. Модуль объекта отчета АнализНачисленийУдержаний — здесь в процедуре ПриКомпоновкеРезультата начинается инициализация процесса.
  2. Общий модуль ЗарплатаКадрыОтчеты — содержит специализированные процедуры для подготовки данных именно для расчетных листков.
  3. Общий модуль ЗарплатаКадрыОбщиеНаборыДанныхБазовый — именно здесь генерируется «скелет» запроса через функцию ПолучитьТекстОбщегоЗапроса.

Где найти результирующий запрос

Многие разработчики пытаются использовать Замер производительности, чтобы отловить текст запроса, но часто это не дает результата, так как запрос собирается из множества фрагментов. Чтобы увидеть финальный текст, который исполняется платформой, рассмотрим несколько способов.

Способ 1: Использование отладки в модуле ЗарплатаКадрыОтчеты

Наиболее близкая к финалу точка сборки находится в процедуре ПриКомпоновкеРезультатаРасчетныйЛистокПоФизическимЛицам. Проанализируем состояние объекта КомпоновщикМакета и коллекции ВнешниеНаборыДанных. Именно в этой коллекции содержатся таблицы, которые будут выведены в отчет. Если запрос выполняется внутри СКД, вы можете извлечь его из расшифровки компоновки.

Способ 2: Внешние консоли запросов (дамп данных)

Как упоминалось в обсуждении, для отладки сложных динамических запросов удобно использовать инструменты типа «Запросник» или консоли с возможностью выгрузки параметров в дамп. Порядок действий следующий:

  1. Устанавливаем точку останова в момент, когда Запрос уже инициализирован и все его параметры заполнены (обычно в общих модулях формирования наборов данных).
  2. Вычисляем выражение, которое записывает состояние запроса в файл (дамп).
  3. Загружаем этот файл в консоль запросов. Это позволит нам увидеть не только текст с «кракозябрами» временных таблиц, но и реальные данные, которыми они заполняются.

Решение задачи с внутренними совместителями

Вернемся к основной задаче: сделать так, чтобы при отборе по подразделению «А» в расчетный лист попадали данные сотрудника и по подразделению «Б», если он является там внутренним совместителем. Проблема в том, что стандартный отбор в СКД накладывается на поле Подразделение. Нам нужно изменить этот механизм на отбор по ФизическомуЛицу.

Рассмотрим алгоритм реализации этой логики в процедуре ПриКомпоновкеРезультата:

  1. Перехватываем установленные пользователем настройки отбора.
  2. Если в отборах присутствует поле Подразделение, мы программно определяем список всех сотрудников, работающих в этом подразделении в выбранном периоде.
  3. На основе списка сотрудников получаем список уникальных Физических лиц.
  4. Удаляем (или отключаем) исходный отбор по подразделению.
  5. Добавляем новый отбор по полю ФизическоеЛицо, используя наш сформированный список.

Примерный программный код (логика преобразования):


// В процедуре ПриКомпоновкеРезультата
Настройки = ЭтотОбъект.КомпоновщикНастроек.ПолучитьНастройки();
ОтборПодразделение = Неопределено;

// Ищем активный отбор по подразделению
Для Каждого ЭлементОтбора Из Настройки.Отбор.Элементы Цикл
    Если ТипЗнч(ЭлементОтбора) = Тип("ЭлементОтбораКомпоновкиДанных") 
        И ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Подразделение") 
        И ЭлементОтбора.Использование Тогда
        
        ОтборПодразделение = ЭлементОтбора;
        Прервать;
    КонецЕсли;
КонецЦикла;

Если ОтборПодразделение <> Неопределено Тогда
    // 1. Получаем список физлиц этого подразделения через запрос к срезу последних или ВТ
    СписокФизЛиц = ПолучитьСписокФизЛицПодразделения(ОтборПодразделение.ПравоеЗначение);
    
    // 2. Отключаем старый отбор
    ОтборПодразделение.Использование = Ложь;
    
    // 3. Добавляем новый отбор по физлицам
    НовыйОтбор = Настройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    НовыйОтбор.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ФизическоеЛицо");
    НовыйОтбор.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
    НовыйОтбор.ПравоеЗначение = СписокФизЛиц;
    НовыйОтбор.Использование = Истину;
КонецЕсли;

Где именно вносить изменения (Best Practice)

Выясним, в каком модуле лучше всего производить корректировки, чтобы не нарушить обновляемость конфигурации. Использование Расширений — самый правильный путь.

Нам нужно создать расширение и добавить в него общий модуль ЗарплатаКадрыОтчеты. Нас интересует метод ПриКомпоновкеРезультатаРасчетныйЛистокПоФизическимЛицам. Используйте аннотацию &Вместо или &Перед, чтобы внедрить логику подмены отборов.

Почему это работает? Когда отчет начинает формировать данные, он видит ограничение не по «комнате» (подразделению), а по «людям» (физическим лицам). Следовательно, запрос потянет все записи регистров, где фигурируют эти физические лица, независимо от того, в каком подразделении была сделана запись о начислении или выплате.

Важные нюансы итогового запроса

Проанализируем функцию ЗарплатаКадрыОбщиеНаборыДанныхБазовый.ПолучитьТекстОбщегоЗапроса. Вы увидите, что запрос строится на основе временных таблиц: ВТНачисленияУдержания, ВТВыплаты, ВТВзаиморасчеты.

Если ваша задача требует более глубокого изменения (например, добавления новых колонок), вам придется вмешаться в формирование именно этих временных таблиц. В ЗУП 3.1 для этого часто используется механизм ПакетЗапросов. Система последовательно дополняет текст запроса, вставляя куски SQL-кода в зависимости от флагов (например, нужно ли выводить НДФЛ или взаиморасчеты в разрезе документов-оснований).

Для отладки финального SQL, который уходит на сервер базы данных, рекомендуется также использовать Технологический журнал с настроенным сбором события DBMSSQL (для MS SQL Server), отфильтровав его по вашему сеансу. Это позволит увидеть «чистый» запрос без абстракций 1С.

Резюме

Для успешного решения задачи по модификации Расчетного листа выполним следующие шаги:

  1. Изучим точку входа в процедуре ПриКомпоновкеРезультата отчета АнализНачисленийУдержаний.
  2. Для поиска текста запроса используем отладку в модуле ЗарплатаКадрыОтчеты или внешнюю консоль с дампом параметров.
  3. Внедряем логику подмены отбора по подразделению на отбор по списку Физических лиц через расширение.
  4. Проверяем результат: теперь при выборе одного подразделения в отчет попадут и «хвосты» внутренних совместителей из других отделов, так как выборка будет идти по персоне в целом.

Такой подход сохраняет целостность типового механизма и позволяет добиться желаемого результата с минимальными правками кода.

← На главную