Не выводятся данные в печатную форму документа "Ведомость на выплату зарплаты в банк" в ЗУП 3.1: анализ ошибок и правильное решение

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

При разработке внешних печатных форм для конфигурации "1С:Зарплата и управление персоналом 3.1" (ЗУП) начинающие программисты часто сталкиваются с двумя проблемами: данные не попадают в макет (пустые поля) и форма формируется слишком долго. Разберем ситуацию, когда в документе ВедомостьНаВыплатуЗарплатыВБанк необходимо вывести данные о физическом лице, его ИНН, лицевом счете и дополнительных реквизитах.

Проанализируем типичные ошибки, допущенные в коде, и рассмотрим, как написать оптимизированный и рабочий алгоритм печати.

Ошибка №1: Запрос в цикле

Самая критичная ошибка, которую мы видим в исходном коде — использование запроса внутри цикла обхода строк документа. Рассмотрим, почему это недопустимо.

В приведенном примере разработчик получает выборку строк документа через Менеджер.ВыборкаДляПечатиТаблицы, затем запускает цикл Пока ВыборкаСтрок.Следующий() и внутри каждой итерации создает и выполняет Новый Запрос для получения лицевого счета и доп. реквизитов.

Почему так делать нельзя:

  1. Производительность: Если в ведомости 1000 сотрудников, платформа 1000 раз обратится к серверу баз данных. Это может "повесить" сеанс пользователя на несколько минут.
  2. Нагрузка: Такой подход создает избыточную нагрузку на сервер СУБД.

Правильный подход: Мы должны получить все необходимые данные (ссылки на сотрудников или физлиц) и выполнить один запрос ко всем данным сразу перед началом цикла вывода.

Ошибка №2: Неверная работа с параметрами и пустые поля

Вторая проблема — отсутствие данных (например, ИНН или номера лицевого счета). Это происходит по нескольким причинам:

Правильная архитектура функции печати

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

Алгоритм действий будет следующим:

  1. Получаем массив ссылок на печатаемые документы.
  2. Формируем единый пакетный запрос. В первой временной таблице собираем всех физлиц из всех ведомостей.
  3. Соединяем временную таблицу с регистром ЛицевыеСчетаСотрудниковПоЗарплатнымПроектам и справочником ФизическиеЛица.
  4. Выгружаем результат запроса в дерево или таблицу значений.
  5. Обходим результат и выводим области в макет.

Рассмотрим пример правильного запроса. Обратите внимание: мы не используем циклы для получения данных из БД.


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

КонецФункции

Разберем ключевые моменты решения

1. Получение ИНН.
В табличной части Зарплата документа ВедомостьНаВыплатуЗарплатыВБанк нет реквизита ИНН. Он хранится в справочнике ФизическиеЛица. Поэтому мы делаем ЛЕВОЕ СОЕДИНЕНИЕ с этим справочником в запросе. Это гарантирует, что ИНН будет получен быстро и для всех сразу.

2. Получение Лицевого счета.
Лицевые счета хранятся в регистре сведений ЛицевыеСчетаСотрудниковПоЗарплатнымПроектам. В запросе мы соединяем данные сотрудника из ведомости с этим регистром.
Важно: У сотрудника может быть несколько счетов. Чтобы избежать дублей строк, нужно либо накладывать дополнительные условия (например, на Зарплатный проект из шапки документа), либо использовать срез последних на дату документа, либо использовать конструкцию ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1 во вложенном запросе/временной таблице.

3. Дополнительные реквизиты.
Если вам нужно вывести дополнительный реквизит (свойство), например "ИнформацияПоОрганизации", не следует искать его в документе ПриемНаРаботу, так как документ приема мог быть давно. Дополнительные реквизиты обычно хранятся в табличных частях справочников (например, Сотрудники.ДополнительныеРеквизиты). Для их получения в запрос нужно добавить соединение с табличной частью справочника:


// Пример фрагмента запроса для доп. реквизита
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Сотрудники.ДополнительныеРеквизиты КАК ДопРеквизиты
    ПО ДанныеВедомости.Сотрудник = ДопРеквизиты.Ссылка
    И ДопРеквизиты.Свойство = &НужноеСвойствоПВХ

Как отлаживать внешние печатные формы

Чтобы не гадать, почему данные не выводятся, используйте эффективные методы отладки:

  1. Консоль запросов: Прежде чем писать код в модуле, откройте "Консоль запросов" в режиме 1С:Предприятие. Вставьте туда текст вашего запроса, задайте параметры (ссылку на конкретный документ) и выполните. Если колонка пустая — проблема в запросе (неверное соединение, условие), а не в макете.
  2. Внешняя обработка: Создайте форму для вашей внешней печатной формы, добавьте на нее поле выбора ссылки на документ и кнопку "Печать". В коде кнопки вызывайте функцию печати. Это позволит вам ставить "Точки останова" (Breakpoints) в конфигураторе и проверять значения переменных (ВыборкаСтрок.ИНН, РезультатЗапроса) в реальном времени.

Резюме

Проблема, когда данные не выходят на печатную форму, чаще всего связана с тем, что код пытается найти реквизиты там, где их нет (в табличной части документа, а не в справочнике), либо с ошибками в передаче параметров запроса. Использование запросов внутри цикла является грубой ошибкой. Переписав код на единый запрос с левыми соединениями, вы решите проблему производительности и обеспечите корректное заполнение всех полей макета.

← На главную