Как заполнить колонку табличной части документа значением из дополнительного реквизита номенклатуры?

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

В процессе разработки в среде 1С:ERP 2.4 (и более поздних версиях) часто возникает задача автоматизации заполнения документов. Одной из типичных ситуаций является необходимость подставить данные в табличную часть документа на основе дополнительных реквизитов номенклатуры. Например, когда категория эксплуатации жестко связана с типом номенклатуры, прописанным в ее свойствах.

В этой статье мы подробно разберем, как правильно реализовать этот механизм, обсудим архитектурные особенности клиент-серверного взаимодействия и рассмотрим как простые решения, так и профессиональные подходы с использованием Библиотеки стандартных подсистем (БСП).

Постановка задачи и анализ ограничений

Рассмотрим ситуацию: у справочника Номенклатура создан дополнительный реквизит с типом "Дополнительное значение". В документе "Внутреннее потребление товаров" необходимо по нажатию кнопки заполнить колонку КатегорияЭксплуатации, основываясь на этом свойстве. Основная сложность заключается в том, что дополнительные реквизиты хранятся в подчиненной табличной части справочника, а не в его основных реквизитах. Следовательно, простым обращением через точку (ТекущаяСтрока.Номенклатура.ДопРеквизит) получить эти данные не получится, особенно на стороне клиента.

Важное ограничение: Получение данных через запросы или прямое обращение к базе данных возможно только в серверном контексте (&НаСервере). На клиенте (&НаКлиенте) мы оперируем только данными формы.

Способ 1: Реализация через прямой запрос (Простой вариант)

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

Сначала создадим серверную функцию для поиска значения:


&НаСервере
Функция ПолучитьКатегориюНаСервере(НоменклатураСсылка)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   НоменклатураДополнительныеРеквизиты.Значение КАК Значение
        |ИЗ
        |   Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
        |ГДЕ
        |   НоменклатураДополнительныеРеквизиты.Ссылка = &Ссылка
        |   И НоменклатураДополнительныеРеквизиты.Свойство = &Свойство";
    
    // Указываем ссылку на ПВХ ДополнительныеРеквизитыИСведения
    // В реальной задаче лучше использовать поиск по имени или предопределенный элемент
    СвойствоКатегория = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("Категория эксплуатации (Номенклатура)");
    
    Запрос.УстановитьПараметр("Ссылка", НоменклатураСсылка);
    Запрос.УстановитьПараметр("Свойство", СвойствоКатегория);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Если Не РезультатЗапроса.Пустой() Тогда
        Выборка = РезультатЗапроса.Выбрать();
        Выборка.Следующий();
        
        // Так как дополнительный реквизит — это справочник "Значения свойств объектов",
        // а нам нужна ссылка на справочник "Категории эксплуатации", выполняем поиск по наименованию.
        НаименованиеЗначения = Строка(Выборка.Значение);
        Возврат Справочники.КатегорииЭксплуатации.НайтиПоНаименованию(НаименованиеЗначения);
    КонецЕсли;
    
    Возврат Справочники.КатегорииЭксплуатации.ПустаяСсылка();
    
КонецФункции

Теперь вызовем эту функцию в процедуре обработки команды на клиенте:


&НаКлиенте
Процедура ЗаполнитьКатегориюЭксплуатации(Команда)
    
    Для Каждого ТекущаяСтрока Из Объект.Товары Цикл
        
        Если ЗначениеЗаполнено(ТекущаяСтрока.Номенклатура) Тогда
            РезультатПоиска = ПолучитьКатегориюНаСервере(ТекущаяСтрока.Номенклатура);
            
            Если ЗначениеЗаполнено(РезультатПоиска) Тогда
                ТекущаяСтрока.КатегорияЭксплуатации = РезультатПоиска;
            КонецЕсли;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Проанализируем этот код: Данный подход рабочий, но он обладает существенным недостатком — "запрос в цикле". Если в документе будет 100 строк, система совершит 100 вызовов сервера и выполнит 100 запросов к БД, что крайне негативно скажется на производительности.

Способ 2: Оптимизированное заполнение (Пакетная обработка)

Чтобы избежать проблем с производительностью, мы должны минимизировать количество обращений к серверу. Правильный подход — собрать всю номенклатуру в массив, передать его на сервер, получить все соответствия одним запросом и вернуть результат на клиент.

Рассмотрим реализацию оптимизированного метода:


&НаСервере
Функция ПолучитьСоответствияКатегорий(МассивНоменклатуры)
    
    СоответствиеРезультат = Новый Соответствие;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ДопРеквизиты.Ссылка КАК Номенклатура,
        |   Категории.Ссылка КАК КатегорияСсылка
        |ИЗ
        |   Справочник.Номенклатура.ДополнительныеРеквизиты КАК ДопРеквизиты
        |       ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КатегорииЭксплуатации КАК Категории
        |       ПО (ВЫРАЗИТЬ(ДопРеквизиты.Значение КАК Справочник.ЗначенияСвойствОбъектов).Наименование = Категории.Наименование)
        |ГДЕ
        |   ДопРеквизиты.Ссылка В(&МассивНоменклатуры)
        |   И ДопРеквизиты.Свойство.Наименование ПОДОБНО ""Категория эксплуатации%""";
        
    Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        СоответствиеРезультат.Вставить(Выборка.Номенклатура, Выборка.КатегорияСсылка);
    КонецЦикла;
    
    Возврат СоответствиеРезультат;
    
КонецФункции

&НаКлиенте
Процедура ЗаполнитьОптимизировано(Команда)
    
    МассивНоменклатуры = Новый Массив;
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        МассивНоменклатуры.Добавить(СтрокаТЧ.Номенклатура);
    КонецЦикла;
    
    ДанныеКатегорий = ПолучитьСоответствияКатегорий(МассивНоменклатуры);
    
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        НайденнаяКатегория = ДанныеКатегорий.Получить(СтрокаТЧ.Номенклатура);
        Если НайденнаяКатегория <> Неопределено Тогда
            СтрокаТЧ.КатегорияЭксплуатации = НайденнаяКатегория;
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

В этом примере мы используем Соответствие для передачи данных. Это позволяет быстро сопоставить номенклатуру и найденную категорию прямо на клиенте без повторных запросов.

Способ 3: Использование механизмов БСП (Профессиональный подход)

В конфигурациях 1С:ERP и 1С:КА встроена мощная подсистема "Свойства". Программисту не обязательно писать запросы к табличным частям вручную. Можно воспользоваться методами общего модуля УправлениеСвойствами.

Разберем, как это работает. Метод УправлениеСвойствами.ЗначенияСвойств() позволяет получить таблицу всех дополнительных реквизитов объекта. Это более надежно, так как учитывает настройки видимости, доступности и другие внутренние механизмы 1С.

Пример использования БСП:


// Пример получения значения конкретного свойства через БСП
ЗначенияСвойств = УправлениеСвойствами.ЗначенияСвойств(ОбъектНоменклатура, Ложь);
Для Каждого СтрокаСвойство Из ЗначенияСвойств Цикл
    Если СтрокаСвойство.Свойство.Наименование = "Нужное нам свойство" Тогда
        // Обработка значения
    КонецЕсли;
КонецЦикла;

Важный совет: Если вы создаете внешнюю обработку заполнения, не забудьте правильно зарегистрировать ее в системе, используя функцию СведенияОВнешнейОбработке. Это позволит пользователям вызывать вашу команду прямо из меню "Заполнение" документа, не внося изменения в саму конфигурацию.

Типичные ошибки и способы их решения

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

Проанализировав вышеописанные методы, можно сделать вывод: для разовых и простых задач подходит прямой запрос на сервере с поиском по наименованию. Однако для качественной промышленной разработки в 1С:ERP следует использовать пакетную обработку данных и механизмы БСП, что обеспечит высокую скорость работы системы и стабильность кода.

← На главную