Автосумма в 1С: как получить итоги столбцов автоматически

· 9 мин

Содержание

Отдельной кнопки «автосумма», как в Excel, в 1С нет. Итог по числовому столбцу собирается тремя путями: в подвале табличной части на управляемой форме, в ресурсах отчёта на СКД и в коде методом Итог(). Какой способ выбрать — зависит от того, где нужна сумма: в документе при вводе, в готовом отчёте или во время обработки данных.

Ниже — рабочие приёмы для платформы 8.3 с интерфейсом «Такси»: как вывести сумму в подвал столбца, пересчитывать её при изменении строк, считать итоги с отбором и строить многоуровневые итоги в отчётах. Код приведён целиком, без обрывов на комментарии.

Сумма по столбцу табличной части в подвале формы

Самый частый случай — показать итог по колонке Сумма прямо под таблицей документа. В управляемой форме это делается через подвал столбца.

Порядок действий:

  1. Откройте форму документа в конфигураторе.
  2. Выделите в дереве элементов нужный столбец таблицы (например, Сумма).
  3. В палитре свойств включите ПоказыватьВПодвале.
  4. Задайте ПутьКДаннымПодвала — укажите реквизит формы типа Число, в котором будет храниться итог.
  5. При желании заполните ТекстПодвала — тогда вместо числа покажется произвольная подпись.

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

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

Что проверить при настройке подвала
Выполнено: 0 / 5

Чтобы сумма менялась сразу после правки строки, повесьте обработчик на событие ПриИзменении редактируемой колонки и пересчитайте реквизит-итог.

Важная тонкость: на клиенте Объект.Товары — это ДанныеФормыКоллекция, и метода Итог() у неё нет. Поэтому на клиенте считаем простым обходом цикла:

&НаКлиенте
Процедура ТоварыСуммаПриИзменении(Элемент)
    ПересчитатьИтог();
КонецПроцедуры

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

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

Когда таблица большая и нужно сложить сразу несколько колонок, разовый пересчёт удобнее унести на сервер. Там табличную часть можно получить реальным объектом и применить Итог():

&НаСервере
Процедура ПересчитатьНаСервере()
    ТЗ = РеквизитФормыВЗначение("Объект").Товары.Выгрузить();
    ИтогоПоТоварам = ТЗ.Итог("Сумма");
    ИтогоКоличество  = ТЗ.Итог("Количество");
КонецПроцедуры

Выбор прост: правка одной ячейки — считайте циклом на клиенте; разовый пересчёт всей таблицы или сразу нескольких колонок — один вызов сервера.

Не считайте итог через обращение к серверу на каждое изменение ячейки — на больших таблицах это заметно тормозит ввод.

Метод Итог() в коде объекта

В модуле объекта (а не формы) Товары — это полноценная ТабличнаяЧасть, и у неё есть метод Итог(). Он возвращает сумму числового столбца одной строкой:

ВсегоПоДокументу = ЭтотОбъект.Товары.Итог("Сумма");

Тот же метод есть у ТаблицаЗначений и ДеревоЗначений. Это удобно при проведении документа, в обработках и при формировании печатных форм:

Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
// ... заполнение строк ...
Всего = Таблица.Итог("Сумма");
Сообщить("Итого: " + Формат(Всего, "ЧДЦ=2; ЧРД=,"));

Обратите внимание на Формат() при выводе: склеивать число со строкой напрямую нельзя — результат получится без нужного форматирования. Через Формат() или СтрШаблон() вы задаёте разделители и число знаков после запятой.

Если итог нужен по нескольким колонкам сразу, сверните таблицу методом Свернуть():

// группируем по номенклатуре, суммируем количество и сумму
Таблица.Свернуть("Номенклатура", "Количество, Сумма");

После свёртки в таблице останется по одной строке на каждую номенклатуру с готовыми суммами.

Итоги в отчёте на системе компоновки данных

Для отчётов итоги считает СКД — отдельный код для суммирования писать не нужно. Схема такая:

  1. В схеме компоновки на закладке Наборы данных задайте запрос или таблицу.
  2. Перейдите на закладку Ресурсы и добавьте числовое поле с выражением Сумма(Сумма), Сумма(Количество) и т. д.
  3. На закладке Настройки постройте структуру отчёта — добавьте группировки (например, по складу, по номенклатуре).

Дальше СКД сама выводит итог по каждой группировке и общий итог внизу. Ресурс — это и есть «автосумма»: платформа пересчитывает его при любом составе данных, при смене отбора и при перестановке группировок пользователем.

Расположением итогов тоже управляют настройки. В параметрах группировки есть выбор, где показать её итог — над строками или под ними, а общий итог отчёта можно вынести вверх или вниз. Для числовых ресурсов полезно сразу задать формат (ЧДЦ=2), чтобы суммы выводились с двумя знаками и разделителями разрядов.

Где настраиваетсяЧто даёт
Закладка «Ресурсы», выражение Сумма(...)общий и групповые итоги
Группировки в структурепромежуточные итоги по уровням
Отбор в настройкахитог только по отобранным данным

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

Итог с условием: фильтры и отборы

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

В таблице значений — сначала отберите строки, потом сложите:

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

В запросе — ограничьте выборку в ГДЕ до секции ИТОГИ:

ВЫБРАТЬ
    Продажи.Номенклатура КАК Номенклатура,
    Продажи.Сумма КАК Сумма
ИЗ
    РегистрНакопления.Продажи.Обороты КАК Продажи
ГДЕ
    Продажи.Склад = &Склад
ИТОГИ
    СУММА(Сумма)
ПО
    ОБЩИЕ,
    Номенклатура

Секция ИТОГИ ... ПО строит иерархический результат: общий итог (ОБЩИЕ) и итоги по каждой номенклатуре. Читают его обходом по группировкам, где каждая строка выборки уже содержит готовую сумму своего уровня:

Выборка = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
Пока Выборка.Следующий() Цикл
    // здесь Выборка.Сумма — итог по текущей номенклатуре
    ВыборкаДетали = Выборка.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        // строки-детали внутри группировки
    КонецЦикла;
КонецЦикла;

Первый уровень обхода даёт групповые итоги, вложенный Выбрать() — детальные строки. Общий итог лежит в самой первой выборке при обходе с ОБЩИЕ.

В отчёте на СКД — задайте отбор в настройках либо используйте условное выражение прямо в ресурсе:

Сумма(ВЫБОР КОГДА СтавкаНДС = &Ставка ТОГДА Сумма ИНАЧЕ 0 КОНЕЦ)

Так в одном отчёте можно рядом вывести суммы по разным условиям — например, по каждой ставке НДС отдельной колонкой.

Многоуровневые итоги и группировки

Когда нужны итоги на нескольких уровнях — по складу, внутри него по номенклатуре, — опирайтесь на группировки.

В запросе перечислите уровни в секции ПО в порядке вложенности:

ИТОГИ
    СУММА(Сумма)
ПО
    Склад,
    Номенклатура

Платформа посчитает итог по каждому складу и по каждой номенклатуре внутри склада. В СКД то же самое задаётся вложенными группировками в структуре отчёта — порядок строк в структуре и есть порядок уровней. Переставить уровни местами можно прямо в пользовательских настройках отчёта, не меняя запрос, — итоги пересчитаются под новую структуру.

Для нарастающего итога (накопление сверху вниз) в СКД применяют вычисляемое поле на базе функции ВычислитьВыражение — её параметры задают диапазон строк, по которым накапливается сумма. В запросе нарастающий итог обычно получают соединением таблицы с самой собой по условию «дата меньше либо равна». Если такой итог нужен разово, проще досчитать его в коде обходом уже отсортированного результата.

Иерархическую номенклатуру суммируйте с учётом иерархии: в запросе — конструкцией с ИЕРАРХИЯ в секции ИТОГИ, иначе суммы групп-папок задвоятся с суммами их элементов.

Управляемые формы и обычный интерфейс

В платформе 8.3 с «Такси» основной вариант — управляемые формы, и подвал столбца там настраивается так, как описано выше. Обычные (неуправляемые) формы остались в толстом клиенте и считаются устаревшими; новые конфигурации на них не разрабатывают.

Отличия, которые стоит держать в голове:

  • В управляемой форме итог — это реквизит формы, привязанный через ПутьКДаннымПодвала, и пересчитывается он вашим кодом в обработчике события.
  • В обычной форме подвал колонки тоже есть, но модель данных и события другие, поэтому переносить код между формами напрямую нельзя.
  • ДанныеФормыКоллекция на клиенте управляемой формы не имеет метода Итог() — это первое, обо что спотыкаются при переходе со старого кода. Считайте циклом на клиенте либо берите реальную табличную часть на сервере.

Если разрабатываете с нуля — делайте управляемую форму. Если дорабатываете старую обычную — сумму удобнее считать в момент сохранения объекта через Итог() в модуле объекта, не завязываясь на подвал. Логика в модуле объекта работает одинаково для любой формы и даже при программном создании документа без формы — это самый надёжный вариант, когда итог критичен для проведения.

Вывод итогов во внешние системы

Когда сумму нужно передать дальше — в Excel, печатную форму или обмен, — считайте её в 1С методом Итог() или запросом, а затем выгружайте уже готовое число.

  • В табличный документ и Excel. Сформируйте ТабличныйДокумент, положите итог в ячейку области и сохраните методом Записать() в нужном формате. Складывать значения формулой на стороне Excel не нужно — отдавайте посчитанный результат.
  • В печатную форму. Итог по макету подставляется из того же реквизита или переменной, что и на форме, — отдельно пересчитывать не требуется.
  • В обмен или web-сервис. В выгружаемую структуру кладите итоговое число как отдельное поле, чтобы принимающая система не пересчитывала его сама и не разошлась с 1С на копейки округления.

Общее правило: источник истины по сумме — база 1С. Чем меньше систем считают итог заново, тем меньше расхождений.

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

Типичные ошибки

Короткая диагностика по симптомам — что проверить, если автосумма ведёт себя не так.

Диагностика: выберите симптом

Частые вопросы

Можно ли сделать автосумму без программирования?
В отчёте — да: заведите ресурс Сумма(...) на СКД, код не нужен. В подвале формы итог всё равно придётся класть в реквизит кодом — платформа сама столбец не складывает.
Почему итог в подвале правильный, а при открытии документа — ноль?
Пересчёт вызывается только при изменении строки. Добавьте вызов пересчёта в обработчик ПриОткрытии, тогда сумма появится сразу.
Как вывести сумму не всей колонки, а только по части строк?
Метод Итог() условий не принимает. Отберите строки через НайтиСтроки() и сложите циклом, либо ограничьте данные в запросе секцией ГДЕ до ИТОГИ.
Чем `Итог()` отличается от `Свернуть()`?
Итог() возвращает одно число по столбцу. Свернуть() группирует строки и суммирует внутри каждой группы — на выходе остаётся таблица с готовыми суммами.
Тормозит ввод при пересчёте суммы — что делать?
Считайте итог на клиенте обходом цикла, без вызова сервера на каждое изменение ячейки. Серверный вызов на каждый символ и есть причина задержек.