При разработке внешних печатных форм в современных конфигурациях на базе 1С:Управление торговлей 11 (ERP, КА) часто возникает задача вывода данных, которые хранятся не в основных реквизитах объектов, а в дополнительных свойствах. Например, нам может понадобиться вывести «Техническое задание» или «Код позиции КТРУ» для каждой строки номенклатуры в документе «Коммерческое предложение». Разберем подробно, как это сделать правильно, избежав типичных ошибок производительности и логических сбоев.
Проанализируем сначала ситуацию, с которой часто сталкиваются начинающие разработчики. При попытке установить параметры для двух разных свойств в одном запросе, программисты иногда пишут следующий код:
Запрос.УстановитьПараметр("Свойство", ДопРеквизитТЗ);
Запрос.УстановитьПараметр("Свойство", ДопРеквизитКод);
В этом случае в структуру параметров запроса сначала записывается ссылка на первое свойство, а следующей строкой она полностью заменяется ссылкой на второе свойство. В итоге запрос всегда будет искать только «Код позиции КТРУ», а первое свойство просто «исчезнет» из выборки. Для решения нужно использовать разные имена параметров, например, Свойство1 и Свойство2.
Рассмотрим самый простой и понятный способ — использование нескольких левых соединений к таблице дополнительных реквизитов в основном запросе. Это решение хорошо подходит, когда вам нужно вытащить 2–3 конкретных реквизита.
Посмотрим на пример запроса, который собирает данные из табличной части документа и присоединяет к ним значения двух свойств номенклатуры:
ВЫБРАТЬ
КПТовары.НомерСтроки КАК ПорядковыйНомер,
КПТовары.Номенклатура.Наименование КАК НаименованиеНоменклатуры,
ЕСТЬNULL(ТехЗадание.Значение, "") КАК ТехническоеЗадание,
ЕСТЬNULL(КодКТРУ.Значение, "") КАК КодПозицииКТРУ,
КПТовары.Количество КАК Количество,
КПТовары.Ссылка КАК Ссылка
ИЗ
Документ.КоммерческоеПредложениеКлиенту.Товары КАК КПТовары
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК ТехЗадание
ПО КПТовары.Номенклатура = ТехЗадание.Ссылка
И ТехЗадание.Свойство = &СвойствоТЗ
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК КодКТРУ
ПО КПТовары.Номенклатура = КодКТРУ.Ссылка
И КодКТРУ.Свойство = &СвойствоКод
ГДЕ
КПТовары.Ссылка В(&МассивОбъектов)
Важный нюанс: Обратите внимание, что условие по свойству (Свойство = &СвойствоТЗ) вынесено в секцию ПО левого соединения. Если вы вынесете это условие в секцию ГДЕ, то при отсутствии заполненного реквизита у номенклатуры, вся строка товара пропадет из результата запроса. Использование ЕСТЬNULL позволяет корректно выводить пустые строки, если значение реквизита не задано.
Если свойств становится много (более 3–5), использование множества левых соединений может негативно сказаться на производительности. Проанализируем ситуацию: каждое соединение заставляет СУБД заново просматривать таблицу доп. реквизитов. В этом случае лучше применить метод «свертки» через агрегатные функции. Разберем, как это работает:
ВЫБОР КОГДА... ТОГДА... ИНАЧЕ NULL КОНЕЦ распределяем значения по колонкам.МАКСИМУМ.Пример реализации такого подхода:
ВЫБРАТЬ
ДопРеквизиты.Ссылка КАК Номенклатура,
МАКСИМУМ(ВЫБОР КОГДА ДопРеквизиты.Свойство = &Свойство1 ТОГДА ДопРеквизиты.Значение ИНАЧЕ NULL КОНЕЦ) КАК Значение1,
МАКСИМУМ(ВЫБОР КОГДА ДопРеквизиты.Свойство = &Свойство2 ТОГДА ДопРеквизиты.Значение ИНАЧЕ NULL КОНЕЦ) КАК Значение2
ПОМЕСТИТЬ ВТ_ДопСвойства
ИЗ
Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
ГДЕ
ДопРеквизиты.Свойство В(&СписокСвойств)
И ДопРеквизиты.Ссылка В (ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура ИЗ ВТ_ТоварыДокумента)
СГРУППИРОВАТЬ ПО
ДопРеквизиты.Ссылка
Такой подход позволяет выполнить всего одно соединение с основной таблицей товаров, сколько бы свойств вам ни потребовалось вывести.
В типовых конфигурациях на базе БСП (Библиотека стандартных подсистем) существует готовый механизм для получения значений свойств. Это наиболее «правильный» путь с точки зрения архитектуры 1С, так как он учитывает все особенности хранения данных (реквизиты или сведения) и права доступа.
Для получения данных воспользуемся методом УправлениеСвойствами.ЗначенияСвойствДляОбъектов. Разберем алгоритм работы:
Пример кода:
// Получаем таблицу всех свойств для массива номенклатуры
ТаблицаСвойств = УправлениеСвойствами.ЗначенияСвойствДляОбъектов(МассивНоменклатуры);
ТаблицаСвойств.Индексировать("Объект, Свойство");
// При обходе строк документа находим значение
Отбор = Новый Структура("Объект, Свойство", ТекущаяНоменклатура, СсылкаНаСвойствоТЗ);
СтрокиСвойств = ТаблицаСвойств.НайтиСтроки(Отбор);
ЗначениеТЗ = ?(СтрокиСвойств.Количество() > 0, СтрокиСвойств[0].Значение, "");
Преимущество этого метода в том, что он универсален. Если завтра структура хранения дополнительных реквизитов в платформе изменится, ваш код останется рабочим, так как БСП возьмет обновление логики на себя.
Выясним еще одну важную деталь. Часто программисты ищут свойства по наименованию: ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Техническое задание"). Это крайне ненадежно, так как пользователь может переименовать свойство в интерфейсе, и печатная форма перестанет работать.
В современных конфигурациях УТ 11/ERP рекомендуется использовать реквизит Имя (Имя для формул). Это уникальный строковый идентификатор, который заполняется при создании свойства и не меняется пользователем. В коде лучше искать свойство именно по этому полю:
СвойствоТЗ = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоРеквизиту("Имя", "Номенклатура_ТехническоеЗадание");
Подведем итог: для простых задач используйте левые соединения с условием в секции ПО, для сложных и высоконагруженных — Pivot-запросы или штатные механизмы БСП. Это обеспечит стабильную работу вашей печатной формы и упростит её дальнейшую поддержку.