При разработке или модификации печатных форм в системе 1С часто возникает задача: вывести в область шапки данные, которые физически расположены не в реквизитах самого документа, а в его табличной части. Классический пример — печатная форма ТОРГ-12 для документа «Возврат товаров от покупателя», где в поле «Основание» нужно указать номер и дату документа партии (поступления), взятого из первой строки списка товаров.
В этой статье мы подробно разберем, как правильно реализовать этот механизм, проанализируем типичные ошибки начинающих разработчиков и рассмотрим несколько способов решения задачи: от прямого обращения к объектной технике до использования языка запросов.
Рассмотрим типичную ситуацию: программист пытается получить данные через запрос, но при заполнении параметров макета система выдает ошибку Поле объекта не обнаружено. Проанализируем причину на примере кода из обсуждения:
Запрос.Текст = "ВЫБРАТЬ ВозвратТоваровОтПокупателя.Товары.(ДокументПартии.Номер, ДокументПартии.Дата) ...";
// ...
ОбластьМакета.Параметры.ПартияНомер = ДокументПартии.ДокументПартииНомер;
Почему это не работает?
Товары.(...), запрос возвращает внутри основной строки выборки специальный объект типа РезультатЗапроса (вложенную таблицу). К ней нельзя обращаться просто через точку для получения номера документа.ДокументПартии.Номер, то в структуре результата поле будет называться либо Номер, либо иметь псевдоним, который вы назначили. Поля ДокументПартииНомер в выборке не существует, если оно не задано явно словом КАК.Если вы уже находитесь в контексте модуля печати и у вас есть доступ к ссылке на документ (СсылкаНаОбъект), проще всего обратиться к табличной части напрямую. Это избавит вас от написания лишних запросов и сделает код более читаемым. В 1С табличные части ведут себя как коллекции, к элементам которых можно обращаться по индексу.
Разберем реализацию этого метода. Поскольку нам нужна информация только из первой строки, мы обратимся к индексу 0.
// Проверяем, что табличная часть "Товары" не пуста
Если СсылкаНаОбъект.Товары.Количество() > 0 Тогда
// Получаем первую строку (индексация начинается с нуля)
ПерваяСтрока = СсылкаНаОбъект.Товары[0];
// Проверяем, заполнено ли поле "ДокументПартии"
Если ЗначениеЗаполнено(ПерваяСтрока.ДокументПартии) Тогда
// Заполняем параметры макета
// Обратите внимание: Номер и Дата берутся через точку от ссылки на документ партии
ОбластьМакета.Параметры.ПартияНомер = ПерваяСтрока.ДокументПартии.Номер;
ОбластьМакета.Параметры.ПартияДата = ПерваяСтрока.ДокументПартии.Дата;
КонецЕсли;
КонецЕсли;
Преимущества: Высокая скорость написания кода и простота отладки. Недостатки: Если документ партии — это ссылка, обращение ДокументПартии.Номер вызовет дополнительное неявное обращение к базе данных (разыменование ссылки). Для формирования одной печатной формы это не критично, но в массовой печати может снизить производительность.
Если ваша печатная форма строится на сложном запросе, или вам нужно выводить данные, которых нет в текущем объекте, правильнее всего будет получить данные из ТЧ отдельным запросом или соединением. Выясним, как правильно составить запрос к табличной части.
Рассмотрим вариант запроса, который вернет данные только первой строки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Т.ДокументПартии.Номер КАК НомерПартии,
| Т.ДокументПартии.Дата КАК ДатаПартии
|ИЗ
| Документ.ВозвратТоваровОтПокупателя.Товары КАК Т
|ГДЕ
| Т.Ссылка = &СсылкаНаОбъект
|УПОРЯДОЧИТЬ ПО
| Т.НомерСтроки";
Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ОбластьМакета.Параметры.ПартияНомер = Выборка.НомерПартии;
ОбластьМакета.Параметры.ПартияДата = Выборка.ДатаПартии;
КонецЕсли;
Важные моменты в запросе:
ВЫБРАТЬ ПЕРВЫЕ 1 гарантирует, что мы получим только одну запись, даже если в ТЧ много строк.Документ.ВозвратТоваровОтПокупателя.Товары — это физическая таблица ТЧ в базе данных.УПОРЯДОЧИТЬ ПО Т.НомерСтроки важна, чтобы "первой" оказалась именно та строка, которую пользователь видит в форме первой.Зачастую в печатных формах (особенно в ТОРГ-12) требуется вывести не просто номер и дату в разные ячейки, а сформировать красивую строку вида "Возврат по накладной № 123 от 01.01.2023". Для этого в типовых конфигурациях 1С рекомендуется использовать встроенные функции общих модулей.
Проанализируем пример формирования такой строки:
Если ЗначениеЗаполнено(ПерваяСтрока.ДокументПартии) Тогда
// Используем типовой механизм для формирования представления документа
ТекстОснования = "Возврат по документу " + ОбщегоНазначения.СформироватьЗаголовокДокумента(ПерваяСтрока.ДокументПартии, "№");
ОбластьМакета.Параметры.Основание = ТекстОснования;
КонецЕсли;
Если вы работаете в конфигурации, где такой функции нет, можно собрать строку вручную, используя Формат() для даты:
ПредставлениеДаты = Формат(ПерваяСтрока.ДокументПартии.Дата, "ДФ=dd.MM.yyyy");
ТекстОснования = СтрШаблон("№ %1 от %2", ПерваяСтрока.ДокументПартии.Номер, ПредставлениеДаты);
В ходе обсуждения возник вопрос о том, как получить номер последней строки. Это часто требуется для заполнения итоговых показателей в подвалах или шапках (например, "Всего наименований").
Рассмотрим решение:
КоличествоСтрок = СсылкаНаОбъект.Товары.Количество();. Последняя строка будет иметь индекс КоличествоСтрок - 1.МАКСИМУМ(НомерСтроки) или КОЛИЧЕСТВО(*).Пример получения номера последней строки для шапки:
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ОбластьШапка.Параметры.ВсегоНаименований = СсылкаНаОбъект.Товары.Количество();
ТабДок.Вывести(ОбластьШапка);
Мы выяснили, что для корректного вывода данных из табличной части в шапку необходимо:
[0], не забывая о проверке на пустоту ТЧ.ВЫБРАТЬ ПЕРВЫЕ 1.ЗначениеЗаполнено), чтобы избежать пустых строк в печатной форме.Использование этих подходов позволит вам создавать гибкие и отказоустойчивые печатные формы, которые корректно отображают информацию из любой части документа.