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

Программист 1С v8.3 (Управляемые формы)
← На главную

При разработке в среде 1С:Предприятие 8.3 часто возникает задача отображения дополнительных данных в табличной части документа, которые не хранятся в самом документе, а извлекаются из регистров. Например, это может быть признак наличия товара в особом перечне, текущий остаток или актуальная цена. Рассмотрим подробнее, как реализовать такую задачу правильно, избегая типичных ошибок производительности.

Выбор способа реализации: Реквизит объекта или Реквизит формы

Прежде чем приступать к кодингу, проанализируем, нужно ли сохранять данные этой колонки в базе. Если информация носит чисто справочный характер (как «галочка» из регистра сведений в нашем примере), не следует добавлять новый реквизит в метаданные документа. Это излишне раздует базу данных. Правильным решением будет создание Реквизита формы.

Разберем по шагам, как это сделать:

  1. Откроем форму документа (в самом объекте или через расширение).
  2. На вкладке «Реквизиты» найдем таблицу Товары.
  3. Нажмем «Добавить реквизит формы», назовем его, например, ПризнакПеречня и укажем тип Булево.
  4. Перетащим созданный реквизит в элементы формы, внутрь элемента таблицы Товары.

Алгоритм эффективного заполнения данными

Основная ошибка начинающих разработчиков — выполнение запроса к регистру в цикле для каждой строки таблицы. Это приводит к критическому замедлению работы при открытии документов с большим количеством строк. Мы применим метод пакетной обработки через объект Соответствие.

Проанализируем алгоритм работы на сервере:

  1. Сформируем массив уникальных ссылок на Номенклатуру из всех строк табличной части.
  2. Одним запросом получим данные из регистра сведений для всех отобранных позиций.
  3. Выгрузим результат запроса в Соответствие (ключ — Номенклатура, значение — наш признак).
  4. Обойдем строки таблицы формы и заполним колонку, обращаясь к созданному соответствию.

Пример программной реализации

Рассмотрим код, который необходимо разместить в модуле формы. Оптимальное место для первоначального заполнения — процедура ПриЧтенииНаСервере или ПриСозданииНаСервере. Если вы используете расширение, применяйте аннотацию &После.


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

КонецПроцедуры

Обработка интерактивного изменения данных

Выясним важный нюанс: если пользователь в уже открытом документе выберет другой товар, значение в нашей колонке должно обновиться автоматически. Для этого нам необходимо создать обработчик события ПриИзменении для поля Номенклатура в табличной части.


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

&НаСервереБезКонтекста
Функция ПолучитьПризнакИзРегистра(ВыбраннаяНоменклатура)
    
    // Для одной строки запрос допустим, так как это интерактивное действие пользователя
    Возврат РегистрыСведений.СведенияОНоменклатуреГСВС.СрезПоследних(, Новый Структура("НоменклатураГСВС", ВыбраннаяНоменклатура))[0].ПризнакПеречняИзьятий;
    
КонецФункции

Особенности использования связей (Код ТН ВЭД)

Иногда связь между товаром и регистром идет не по прямой ссылке, а через дополнительные реквизиты, например, через Код ТН ВЭД. В этом случае в запросе необходимо использовать ЛЕВОЕ СОЕДИНЕНИЕ по строковому коду. Проанализируем пример такого запроса:


ВЫБРАТЬ
    ТоварыДокумента.Номенклатура,
    ЕСТЬNULL(РегистрСведений.ПризнакПеречняИзьятий, ЛОЖЬ) КАК Признак
ИЗ
    Документ.ПоступлениеТоваровУслуг.Товары КАК ТоварыДокумента
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОНоменклатуреГСВС.СрезПоследних КАК РегистрСведений
    ПО РегистрСведений.НоменклатураГСВС.КодГСВС = ТоварыДокумента.Номенклатура.КодТНВЭД
ГДЕ
    ТоварыДокумента.Ссылка = &Ссылка

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

Дополнительные рекомендации

Рассмотрим еще несколько приемов, которые сделают ваше решение более профессиональным:

Используя данный подход, вы обеспечите высокую скорость работы интерфейса и чистоту структуры метаданных конфигурации.

← На главную