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

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Торговля и дистрибуция
← На главную

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

Постановка задачи и разбор логики работы

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

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

Шаг 1: Создание функции получения цены через запрос

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

Рассмотрим следующий пример кода функции:


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

КонецФункции

Разберем важные детали этого кода. Во-первых, мы передаем условия Номенклатура = &Номенклатура непосредственно в параметры виртуальной таблицы СрезПоследних. Это критически важно для производительности: система сначала фильтрует записи, а потом ищет среди них последние. Если бы мы использовали ГДЕ, система сначала получила бы последние цены для всей номенклатуры, а потом отфильтровала нужную, что значительно медленнее.

Шаг 2: Вызов функции из табличной части

Теперь выясним, как правильно вызвать эту функцию. Основная ошибка здесь заключается в попытке передать "просто номенклатуру", когда программа не понимает, из какой именно строки её брать. В обычном приложении (как в примере из темы) для доступа к данным строки, которую редактирует пользователь, используется свойство ТекущиеДанные.

Проанализируем процедуру обработки изменения номенклатуры:


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

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

Обратите внимание на использование ЭлементыФормы.Товары.ТекущиеДанные. Это позволяет нам работать именно с той строкой, в которой пользователь только что выбрал товар. Если вы работаете в управляемом приложении, синтаксис изменится на Элементы.Товары.ТекущиеДанные, а вызов функции должен будет происходить на сервере.

Типичные ошибки разработчиков

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

Оптимизация: использование типовых механизмов

Если вы работаете в конфигурации "Бухгалтерия предприятия" или "Управление торговлей", писать прямые запросы к регистру цен в модуле формы не всегда целесообразно. В типовых решениях существуют общие модули (например, Ценообразование), которые содержат готовые функции получения цен.

Рассмотрим преимущества использования типовых функций:

Пример вызова типовой функции может выглядеть так (синтаксис зависит от версии конфигурации):


СтруктураПараметров = Новый Структура;
СтруктураПараметров.Вставить("Номенклатура", СтрокаТабличнойЧасти.Номенклатура);
СтруктураПараметров.Вставить("ТипЦен", Объект.ТипЦен);
// ... заполнение других параметров
Цена = Ценообразование.ПолучитьЦенуНоменклатуры(СтруктураПараметров);

Заключение

Мы проанализировали процесс получения цены номенклатуры: от написания функции запроса до её интеграции в интерфейс табличной части. Основной залог успеха — это использование ссылочных типов данных, правильная передача параметров в виртуальные таблицы и корректное обращение к текущим данным строки. Помните, что код должен быть защищен от пустых значений и учитывать специфику платформы (обычные или управляемые формы).

← На главную