При разработке документов и справочников в системе 1С:Предприятие 8.3 перед разработчиком часто возникает задача: автоматически рассчитывать и выводить итоговые показатели из табличной части в шапку или подвал формы. Чаще всего речь идет об общей сумме документа, общем весе, количестве позиций или сумме НДС.
В этой статье мы подробно разберем, как правильно реализовать данный механизм на управляемых формах. Мы проанализируем популярные ошибки начинающих разработчиков, рассмотрим ручной пересчет через события элементов формы и изучим наиболее элегантное решение — использование стандартных платформенных путей к данным.
Начинающие разработчики часто пытаются решить задачу простым сложением при изменении строки. Типичный пример некорректного кода выглядит так:
&НаКлиенте
Процедура СписокТоваровСуммаПриИзменении(Элемент)
Строка = Элементы.СписокТоваров.ТекущиеДанные;
Объект.Всего = Объект.Всего + Строка.Сумма;
КонецПроцедуры
Проанализируем ситуацию и выясним, почему этот код категорически **нельзя использовать** в реальных конфигурациях:
Объект.Всего. Сумма будет бесконечно увеличиваться при редактировании одной и той же строки.ПриИзменении конкретной колонки не сработает, и общий итог не уменьшится.Всего останется прежним.Другая частая ошибка — простое присвоение значения текущей строки:
Объект.Всего = Элементы.СписокТоваров.ТекущиеДанные.Сумма;
Такой код просто перезапишет реквизит Всего значением из активной строки. Если в документе несколько строк, то общая сумма станет равна сумме последней измененной строки, что полностью ломает логику учета.
Для корректного программного расчета суммы по всей табличной части в платформе 1С предусмотрен специальный метод Итог(). Он работает быстро, надежно и автоматически обходит все строки таблицы.
Разберем по шагам правильную программную реализацию расчета:
Шаг 1. Создаем общую процедуру расчета итогов на клиенте
Нам необходимо написать универсальную процедуру, которую мы сможем вызывать из разных обработчиков событий формы:
&НаКлиенте
Процедура РассчитатьИтогиДокумента()
// Метод Итог() суммирует значения по указанной колонке табличной части
Объект.Всего = Объект.СписокТоваров.Итог("Сумма");
КонецПроцедуры
Шаг 2. Подключаем обработчики событий для колонок
Если сумма в строке рассчитывается по формуле Цена * Количество, то значение суммы может поменяться при изменении любого из этих трех реквизитов. Следовательно, нам нужно вызывать процедуру пересчета в событиях ПриИзменении для каждого влияющего элемента на форме:
&НаКлиенте
Процедура СписокТоваровКоличествоПриИзменении(Элемент)
// Сначала рассчитываем сумму в текущей строке
СтрокаТЧ = Элементы.СписокТоваров.ТекущиеДанные;
СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
// Затем пересчитываем общий итог документа
РассчитатьИтогиДокумента();
КонецПроцедуры
&НаКлиенте
Процедура СписокТоваровЦенаПриИзменении(Элемент)
СтрокаТЧ = Элементы.СписокТоваров.ТекущиеДанные;
СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
РассчитатьИтогиДокумента();
КонецПроцедуры
&НаКлиенте
Процедура СписокТоваровСуммаПриИзменении(Элемент)
// Если пользователь вручную изменил сумму
РассчитатьИтогиДокумента();
КонецПроцедуры
Шаг 3. Обработка добавления и удаления строк
Чтобы сумма оставалась актуальной при добавлении новых или удалении старых строк, необходимо привязать расчет к событию ПриИзменении самой табличной части (а не ее отдельных колонок):
&НаКлиенте
Процедура СписокТоваровПриИзменении(Элемент)
РассчитатьИтогиДокумента();
КонецПроцедуры
Если вам требуется просто отобразить общую сумму табличной части на форме без необходимости записывать её в базу данных (или если запись будет происходить в модуле объекта перед записью), платформа 1С предлагает мощный встроенный механизм декларативной связи.
Рассмотрим, как настроить авторасчет вообще без написания кода:
ВсегоДекоративно).Объект -> СписокТоваров.ИтогСумма (или имя вашей колонки с префиксом Итог, например, ИтогСуммаСтроки). Выберите его.Важное преимущество: Платформа берет на себя все заботы по отслеживанию изменений. Сумма будет мгновенно пересчитываться при добавлении строк, удалении строк, очистке таблицы или изменении значений в ячейках на клиенте. При этом производительность системы остается максимальной, так как расчет оптимизирован на уровне платформы.
Важное ограничение: Поле ИтогСумма существует только на форме. Если реквизит Всего — это реальный реквизит документа в базе данных, то его значение не запишется автоматически при сохранении. Для записи в базу данных вам потребуется продублировать расчет в модуле объекта:
// В модуле документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Всего = СписокТоваров.Итог("Сумма");
КонецПроцедуры
Рассмотрим более сложную практическую задачу. Что делать, если пользователь воспользовался встроенным поиском по табличной части (отбором) и нам нужно показать сумму только тех строк, которые он сейчас видит на экране?
Стандартный метод Итог() и путь к данным ИтогСумма всегда рассчитывают сумму абсолютно по всем строкам, игнорируя любые фильтры. Чтобы рассчитать сумму только видимых строк, нам придется выполнить обход коллекции на клиенте с проверкой видимости через метод ПроверитьСтроку():
&НаКлиенте
Функция ПолучитьСуммуВидимыхСтрок()
РезультатСумма = 0;
Для Каждого СтрокаТЧ Из Объект.СписокТоваров Цикл
ИдентификаторСтроки = СтрокаТЧ.ПолучитьИдентификатор();
// Проверяем, отображается ли строка на форме с учетом фильтров
Если Элементы.СписокТоваров.ПроверитьСтроку(ИдентификаторСтроки) Тогда
РезультатСумма = РезультатСумма + СтрокаТЧ.Сумма;
КонецЕсли;
КонецЦикла;
Возврат РезультатСумма;
КонецФункции
При проектировании интерфейса вывода итоговых показателей настоятельно рекомендуется придерживаться официальных стандартов юзабилити системы 1С:Предприятие:
ИтогиФонГруппы.ТолькоПросмотр = Истина. Пользователь не должен иметь возможности вручную изменять автоматически вычисляемые значения, чтобы не нарушать целостность данных.