Как рассчитать сумму в табличной части 1С только по отфильтрованным строкам

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

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

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

Анализ исходной ситуации

Рассмотрим ситуацию, когда в документе «Заявка» реализована связь между тремя табличными частями через уникальный идентификатор (ИД). При активации строки в первой таблице, в двух других устанавливается фильтр через свойство ОтборСтрок. Проблема заключается в том, что когда мы пытаемся получить итоговую сумму материалов или технологий для конкретной продукции, стандартный функционал выдает общую сумму по всему документу.

Давайте проанализируем фрагмент исходного кода, где настраивается фильтрация:


Процедура ЗаявкаПриАктивизацииСтроки(Элемент)
    Данные = ЭлементыФормы.Заявка.ТекущаяСтрока;
    Если Данные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Установка фильтра в подчиненных ТЧ
    ЭлементыФормы.Материалы.ОтборСтрок.ИД.Значение = Данные.ИД;
    ЭлементыФормы.Материалы.ОтборСтрок.ИД.Использование = Истина;
    
    ЭлементыФормы.Технологии.ОтборСтрок.ИД.Значение = Данные.ИД;
    ЭлементыФормы.Технологии.ОтборСтрок.ИД.Использование = Истина;
    
    // Попытка получить итог (вернет сумму ВСЕХ строк ТЧ)
    М = Материалы.Итог("Сумма");
    Т = Технологии.Итог("Сумма");     
КонецПроцедуры

Как мы видим, методы Материалы.Итог("Сумма") обращаются к объекту коллекции данных, а не к элементам управления формы. Чтобы решить задачу, нам нужно использовать методы, которые умеют работать с условиями или выборками.

Решение №1: Использование ПостроителяЗапроса

Один из самых универсальных и корректных способов получить итоги по отфильтрованным строкам — это использование объекта ПостроительЗапроса. Его преимущество в том, что он может принимать в качестве источника данных табличную часть и учитывать те же самые объекты отбора, которые используются в визуальном интерфейсе ЭлементыФормы.

Разберем алгоритм реализации этого метода:

  1. Создаем новый объект ПостроительЗапроса.
  2. Назначаем источником данных нужную нам табличную часть через ОписаниеИсточникаДанных.
  3. Переносим настройки отбора из табличного поля формы в построитель.
  4. Выгружаем результат в таблицу значений и суммируем итог.

Пример программного кода для реализации этого подхода:


ПостроительЗапроса = Новый ПостроительЗапроса; 
// Заявка - это имя вашей табличной части
ПостроительЗапроса.ИсточникДанных = Новый ОписаниеИсточникаДанных(Материалы); 

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

// Получаем результат
ИтогТаблицаЗначений = ПостроительЗапроса.Результат.Выгрузить();
СуммаПоФильтру = ИтогТаблицаЗначений.Итог("Сумма");

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

Решение №2: Использование метода НайтиСтроки

Если связь между таблицами жестко задана через конкретный реквизит (в нашем случае ИД), то использование построителя запроса может быть избыточным. Более производительным и простым способом будет использование метода НайтиСтроки().

Рассмотрим, как это работает: метод НайтиСтроки() принимает структуру с параметрами поиска и возвращает массив строк, которые соответствуют условию. Мы можем просто перебрать этот массив и сложить значения в переменной-аккумуляторе.

Пример функции для расчета:


Функция ПолучитьСуммуПоИД(КоллекцияТЧ, ЗначениеИД)
    Отбор = Новый Структура("ИД", ЗначениеИД);
    МассивСтрок = КоллекцияТЧ.НайтиСтроки(Отбор);
    
    ИтогСумма = 0;
    Для Каждого СтрокаТЧ Из МассивСтрок Цикл
        ИтогСумма = ИтогСумма + СтрокаТЧ.Сумма;
    КонецЦикла;
    
    Возврат ИтогСумма;
КонецФункции

Этот код работает значительно быстрее на небольших и средних объемах данных, так как не создает тяжелых объектов метаданных.

Решение №3: Метод Вычислить таблицы значений

Существует еще один изящный способ, который позволяет избежать написания циклов. Если мы выгрузим табличную часть в объект ТаблицаЗначений, мы сможем воспользоваться встроенным методом Вычислить(), который поддерживает агрегатные функции и строковые фильтры.

Пример реализации:


ТЗ_Материалы = Материалы.Выгрузить();
// Формируем строку условия, например: "ИД = '5e2b...'"
СтрокаФильтра = "ИД = '" + ТекущийИД + "'";
Результат = ТЗ_Материалы.Вычислить("Сумма(Сумма)", СтрокаФильтра);

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

Где и когда вызывать расчет?

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

Отображение итогов в подвале таблицы

Чтобы результат вычислений выглядел профессионально, его стоит выводить в «подвал» (footer) табличного поля. Для этого выполните следующие действия:

  1. В свойствах табличного поля в конфигураторе установите флажок Подвал (Footer) в значение Истина.
  2. Для конкретной колонки (например, «Сумма») в коде установите значение текста:

// Устанавливаем текст в подвал конкретной колонки
ЭлементыФормы.Материалы.Колонки.Сумма.ТекстПодвала = Формат(РассчитаннаяСумма, "ЧДЦ=2");

Это позволит пользователю видеть итоговую сумму именно там, где он привык её видеть в стандартных отчетах и списках.

Рекомендация по хранению ИД

Обратите внимание на использование УникальныйИдентификатор. Если вы создаете его только в памяти при открытии формы, то при закрытии документа без записи или при последующем открытии связи между таблицами могут быть потеряны. Для надежной работы необходимо добавить реквизит ИД (тип: Строка или УникальныйИдентификатор) непосредственно в структуру табличных частей документа в конфигураторе. Только в этом случае данные о связи «Продукция — Материалы» будут сохранены в базе данных навсегда.

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

← На главную