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