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

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

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

Разбор типичной ошибки

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


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

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

Оптимальный подход к решению задачи

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

  1. Сбор данных: Соберите все товары из табличной части в массив или список значений на стороне клиента.
  2. Один серверный вызов: Передайте этот массив в функцию на сервере. Это значительно быстрее, чем дергать сервер для каждой строки.
  3. Фильтрация запросом: Используйте запрос к виртуальной таблице СрезПоследних, добавив условие ГДЕ Товар В (&МассивТоваров). Таким образом, вы получите цены сразу для всех позиций, которые есть в документе.
  4. Обход результата: Пройдите по результату запроса и для каждой записи найдите соответствующую строку в объекте Объект.Товары.

Реализация алгоритма

Давайте посмотрим, как это должно выглядеть в коде. Сначала на клиенте мы готовим данные для обработки:


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

Затем на сервере мы получаем все необходимые данные за один запрос и обновляем табличную часть:


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

Почему этот метод эффективен?

Мы проанализировали ситуацию и выяснили, что использование метода НайтиСтроки() вместе с массовым запросом дает два ключевых преимущества:

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

← На главную