Как получить данные из справочника Номенклатура и заполнить ими табличную часть документа в 1С 8.3

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

В процессе разработки бизнес-приложений на платформе 1С:Предприятие одной из самых частых задач является автоматизация ввода данных. Типичный сценарий: пользователь заполняет табличную часть документа (например, добавляет товары в «Заказ покупателя»), выбирает определенную номенклатурную позицию, а система должна автоматически подтянуть сопутствующие сведения из карточки этой номенклатуры — единицу измерения, артикул, вес, ставку НДС или, как в нашем примере, количество штук на одной палете.

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

Разбор типичной методической ошибки при выборе события

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

Выясним причину, почему так делать нельзя:

  1. Событие ПриНачалеВыбора срабатывает в момент, когда пользователь только нажал на кнопку выбора (кнопку с тремя точками) или начал вводить наименование товара в ячейку.
  2. На данном этапе физический выбор объекта еще не произошел. Реквизит строки табличной части все еще пуст или содержит старое значение.
  3. Если пытаться получить данные на этом шаге, программа просто не сможет определить, какую именно номенклатуру выбрал пользователь.

Правильным событием для решения нашей задачи является ПриИзменении конкретного поля табличной части на форме (например, поля ТоварыНоменклатура). Оно срабатывает в тот момент, когда выбор в форме выбора или выпадающем списке уже завершен, новая ссылка на товар записалась в текущую строку табличной части, и данные готовы для обработки.

Способ 1. Отображение данных на форме без программирования (Путь к данным)

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

Разберем этот процесс по шагам в конфигураторе:

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

Платформа автоматически создаст новую колонку в таблице формы. В свойстве ПутьКДанным у этого элемента будет прописано: Объект.Товары.Номенклатура.КоличествоНаПалете. Теперь, когда пользователь будет выбирать товар в строке, платформа самостоятельно, используя оптимизированные внутренние механизмы СУБД, считает значение из справочника и выведет его на экран. Никаких серверных вызовов вручную писать не придется.

Способ 2. Программное заполнение реквизитов (Клиент-серверное взаимодействие)

Если бизнес-логика требует, чтобы значение «Количество на палете» не просто отображалось на форме, но и физически сохранялось в документе в момент его создания (чтобы зафиксировать исторические данные на случай изменения параметров номенклатуры в будущем), нам потребуется написать программный обработчик.

Поскольку управляемое приложение работает в клиент-серверном режиме, нам необходимо четко разделять контексты выполнения кода. На клиенте мы отслеживаем действия пользователя, а на сервере получаем данные из базы данных.

Для минимизации трафика между клиентом и сервером и ускорения работы интерфейса мы будем использовать внеконтекстный серверный вызов с директивой компиляции &НаСервереБезКонтекста. При таком вызове на сервер не передаются тяжелые данные всей формы, а уходят только те параметры, которые мы явно передаем в функцию.

Посмотрим на пример правильного шаблона кода на клиенте:


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

Теперь детально рассмотрим три различных варианта реализации серверной функции ПолучитьКоличествоНаПалете.

Вариант А. Получение данных через механизмы БСП (Самый оптимальный метод)

Если ваша конфигурация создана на основе типового решения фирмы «1С» (УТ, ERP, КА, УНФ, БП), в ней гарантированно установлена Библиотека стандартных подсистем (БСП). В составе БСП есть встроенный общий модуль ОбщегоНазначения, содержащий функции быстрого получения реквизитов объектов. Эти функции используют внутреннее кэширование платформы и работают быстрее, чем обычные запросы, написанные вручную.

Рассмотрим пример реализации серверной функции с использованием БСП:


&НаСервереБезКонтекста
Функция ПолучитьКоличествоНаПалете(НоменклатураСсылка)
    
    // Проверяем, заполнена ли ссылка (например, если пользователь очистил поле)
    Если Не ЗначениеЗаполнено(НоменклатураСсылка) Тогда
        Возврат 0;
    КонецЕсли;
    
    // Используем функцию БСП для быстрого получения одного реквизита
    Возврат ОбщегоНазначения.ЗначениеРеквизитаОбъекта(НоменклатураСсылка, "КоличествоНаПалете");
    
КонецФункции

Если вам требуется получить сразу несколько реквизитов (например, артикул, вес и единицу измерения), БСП позволяет сделать это за одно обращение к серверу базы данных:


&НаСервереБезКонтекста
Функция ПолучитьПараметрыНоменклатуры(НоменклатураСсылка)
    
    Результат = Новый Структура("КоличествоНаПалете, Артикул", 0, "");
    
    Если Не ЗначениеЗаполнено(НоменклатураСсылка) Тогда
        Возврат Результат;
    КонецЕсли;
    
    // Получаем структуру нужных реквизитов одним методом
    ЗначенияРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(НоменклатураСсылка, "КоличествоНаПалете, Артикул");
    ЗаполнитьЗначенияСвойств(Результат, ЗначенияРеквизитов);
    
    Возврат Результат;
    
КонецФункции

Вариант Б. Легковесный запрос к базе данных (Для самописных конфигураций)

Если вы разрабатываете конфигурацию с нуля и в вашей системе нет Библиотеки стандартных подсистем, наилучшим решением будет написание прямого и легковесного запроса к СУБД. Такой способ гарантирует, что система выберет из базы данных только необходимую информацию, не нагружая сервер чтением лишних полей.

Проанализируем пример кода с использованием объекта Запрос:


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

Вариант В. Прямое обращение «через точку» (Не рекомендуется для нагруженных систем)

Для начинающих разработчиков самым простым и очевидным кажется получение данных путем прямого обращения к реквизиту ссылки:


&НаСервереБезКонтекста
Функция ПолучитьКоличествоНаПалете(НоменклатураСсылка)
    
    Если Не ЗначениеЗаполнено(НоменклатураСсылка) Тогда
        Возврат 0;
    КонецЕсли;
    
    // Простой, но потенциально медленный способ получения данных
    Возврат НоменклатураСсылка.КоличествоНаПалете;
    
КонецФункции

Выясним причину, почему ведущие специалисты по технологическим вопросам 1С и стандарты разработки не рекомендуют использовать этот метод на высоконагруженных или крупных базах данных. Дело в том, что при обращении к реквизиту объекта «через точку» (НоменклатураСсылка.КоличествоНаПалете) платформа 1С неявно считывает из базы данных весь объект справочника целиком. Это означает, что система загрузит в оперативную память сервера все реквизиты элемента, включая табличные части, текстовые описания и присоединенные файлы, ради получения одного единственного числа.

Использовать обращение «через точку» допустимо только в небольших учебных базах, либо для простых плоских справочников, содержащих минимальное количество реквизитов.

Резюме

При автоматизации заполнения табличных частей документов всегда анализируйте бизнес-требования к хранению данных:

← На главную