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