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

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

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

Анализ синтаксических ошибок при обращении к данным

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

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


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

Решение проблемы контекста: Клиент и Сервер

В современных управляемых формах код разделен на клиентский (выполняется на компьютере пользователя) и серверный (выполняется на сервере приложений). Рассмотрим ситуацию: реквизит Номенклатура — это ссылка. На клиенте мы видим только ее текстовое представление, но не можем «заглянуть внутрь» объекта, чтобы узнать его единицу измерения или другие свойства.

Чтобы получить данные из справочника, нам необходимо «сбегать» на сервер. Разберем по шагам, как это реализовать с помощью функции-помощника:


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

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

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

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

Работа с составными типами данных и проверка типа

Если в вашей конфигурации используется архитектура с несколькими справочниками (например, «ВходныеДвери», «МежкомнатныеДвери», «Ламинат»), и реквизит Номенклатура имеет составной тип, нам нужно научиться определять, к какому справочнику относится выбранный элемент. Рассмотрим, как это сделать с помощью функции ТипЗнч и метаданных.

Вместо перечисления наименований, проанализируем ситуацию с использованием типов:


&НаСервере
Функция ОпределитьЕдиницуПоТипу(Ссылка)
    // Проверяем тип объекта через функцию ТипЗнч
    Если ТипЗнч(Ссылка) = Тип("СправочникСсылка.ВхДвери") 
       ИЛИ ТипЗнч(Ссылка) = Тип("СправочникСсылка.МкДвери") Тогда
        Возврат Справочники.КлассификаторЕдиницИзмерения.НайтиПоНаименованию("шт");
    ИначеЕсли ТипЗнч(Ссылка) = Тип("СправочникСсылка.Ламинат") Тогда
        Возврат Справочники.КлассификаторЕдиницИзмерения.НайтиПоНаименованию("м2");
    КонецЕсли;
КонецФункции

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

Архитектурные рекомендации: как сделать правильно

Профессиональный подход к разработке в предполагает минимизацию условий Если...Тогда в пользу универсальных механизмов. Рассмотрим два способа оптимизации вашей базы данных:

  1. Единый справочник Номенклатура: Вместо создания пяти разных справочников, создайте один — Справочники.Номенклатура. Чтобы различать товары, используйте реквизит ВидНоменклатуры. Для каждого вида (Двери, Погонаж, Плитка) можно настроить свои наборы дополнительных реквизитов и свойств. В этом случае единица измерения будет просто одним из реквизитов карточки товара.
  2. Добавление реквизита в существующие справочники: Если вы решили оставить разные справочники, добавьте в каждый из них реквизит ЕдиницаИзмерения (тип — СправочникСсылка.КлассификаторЕдиницИзмерения). Тогда код станет максимально простым: ТекущаяСтрока.ЕдИзм = ТекущаяСтрока.Номенклатура.ЕдиницаИзмерения;.
  3. Использование Характеристик: Для дверей, где важны цвет, размер и открывание, идеально подходит механизм Характеристик. Это позволит не плодить сотни элементов в справочнике (например, «Дверь белая 800», «Дверь белая 900»), а иметь одну модель с разными свойствами.

Использование Библиотеки Стандартных Подсистем (БСП)

Если ваша конфигурация создана на основе современных типовых решений, в ней наверняка есть модуль ОбщегоНазначения. Он позволяет получать реквизиты объектов без написания собственных серверных функций. Посмотрим на пример:


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

Этот метод является стандартом де-факто в современной разработке, так как он автоматически обрабатывает кэширование и оптимизирует запросы к базе данных.

Подведем итог: для реализации автоматической подстановки единиц измерения всегда используйте событие ПриИзменении, работайте с коллекцией ТекущиеДанные и не забывайте разделять код на клиентскую и серверную части. Стремитесь к тому, чтобы данные (единицы измерения, цены) хранились внутри справочника номенклатуры, а не прописывались условиями в коде документа.

← На главную