Как рассчитать итог в табличной части по реквизиту связанного справочника

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

В практике разработки на платформе 1С часто возникает ситуация, когда в табличной части документа или обработки нужно отобразить данные, которые физически не хранятся в этой таблице, а извлекаются «через точку» из связанного справочника. Типичный пример: колонка Цена, которая берется напрямую из справочника Номенклатура. Однако при попытке вывести итог по такой колонке в подвал формы разработчик сталкивается с тем, что стандартный механизм «Автосумма» не работает. Рассмотрим подробнее, почему так происходит, и разберем все способы решения этой задачи.

Почему не работает стандартный итог?

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

Способ 1: Программный перебор строк (универсальный метод)

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

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


&НаСервере
Процедура ПересчитатьИтогПоЦенамНаСервере()
    ЧисловойИтог = 0;
    // Обходим коллекцию строк табличной части
    Для Каждого СтрокаТЧ Из Объект.Товары Цикл
        // Обращаемся к реквизиту через точку. 
        // Внимание: это может вызвать обращение к базе данных!
        ЧисловойИтог = ЧисловойИтог + СтрокаТЧ.Номенклатура.Цена;
    КонецЦикла;
    ИтогЦен = ЧисловойИтог;
КонецПроцедуры

Чтобы итог всегда был актуальным, мы должны вызывать эту процедуру в событиях формы: ПриОткрытии, ПриИзменении номенклатуры в строке, а также после удаления строки. Это гарантирует, что пользователь всегда будет видеть верную сумму.

Способ 2: Оптимизация через запрос (решение проблемы производительности)

Выясним причину, по которой предыдущий способ может работать медленно. При обращении СтрокаТЧ.Номенклатура.Цена платформа выполняет неявный запрос к базе данных для каждой строки, если данные номенклатуры еще не кэшированы. Это классическая «проблема N+1». Если в документе сотни строк, форма будет «подтормаживать».

Проанализируем более эффективный подход — использование одного запроса ко всей табличной части. Мы выберем все уникальные ссылки на номенклатуру, получим их цены одним пакетом и просуммируем.


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

Способ 3: Использование «ПутьКДаннымПодвала» в управляемых формах

В управляемом приложении 1С 8.3 есть элегантный способ отображения итогов без привязки к «автоматическим» свойствам. Посмотрим на настройку элементов формы. У каждой колонки таблицы есть свойство ПутьКДаннымПодвала. Мы можем указать там наш реквизит формы ИтогЦен.

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

Способ 4: Архитектурно правильное решение (скрытый реквизит)

Рассмотрим ситуацию с точки зрения правильного проектирования систем. Опытные разработчики редко оставляют цену «только в справочнике». Если цена в справочнике изменится завтра, то во всех старых документах итог тоже изменится, что недопустимо для финансового учета.

Рекомендуемый алгоритм:

  1. Добавим в саму табличную часть реквизит Цена (тип Число).
  2. Сделаем его невидимым или доступным только для чтения, если бизнес-логика запрещает ручную правку.
  3. В событии ПриИзменении колонки Номенклатура пропишем копирование цены из справочника в этот реквизит.

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


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

Почему это лучше:

Подведение итогов

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

← На главную