Как настроить автозаполнение итоговой суммы документа на управляемой форме 1С 8.3?

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

При разработке учетных документов в 1С часто возникает задача автоматического расчета итоговых показателей шапки на основании данных табличной части и дополнительных реквизитов. Начинающие разработчики нередко сталкиваются с ситуацией, когда итоговый реквизит либо не пересчитывается при редактировании строк, либо берет не те слагаемые, либо падает с ошибками контекста выполнения («Клиент/Сервер»).

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

Анализ проблемы и ошибок в кодовой базе

Рассмотрим типовой сценарий: в документе есть числовой реквизит шапки ЦенаРаботыБезУчетаМатериалов, табличная часть ПереченьМатериалов с колонкой ЦенаЗаЕдиницу и результирующий реквизит шапки ОбщаяСтоимостьРаботы.

Проанализируем исходный код, с которым возникли сложности:


&НаКлиенте
Процедура ЦенаРаботыБезУчетаМатериаловПриИзменении(Элемент)
    РасчетСуммы();
КонецПроцедуры

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

&НаКлиенте
Процедура РасчетСуммы()
    Объект.ОбщаяСтоимостьРаботы = Объект.СтоимостьМатериалов + Объект.ПереченьМатериалов.Итог("ЦенаЗаЕдиницу");
КонецПроцедуры

В данном фрагменте допущено сразу несколько критических ошибок:

  1. Неверные имена слагаемых: В процедуре расчета суммируется несуществующий или промежуточный реквизит Объект.СтоимостьМатериалов вместо реквизита шапки Объект.ЦенаРаботыБезУчетаМатериалов.
  2. Неправильная привязка событий: Обработчик ПереченьМатериаловИтогЦенаЗаЕдиницуПриИзменении был назначен не на колонку редактируемой строки, а на элемент подвала (итога) таблицы. Поля подвала в 1С служат для отображения и не генерируют событие ПриИзменении при пользовательском вводе в строках.
  3. Ошибочное понимание контекста метода Итог(): Существует заблуждение, что метод Итог() работает исключительно на сервере. Разберем этот нюанс подробнее.

Контекст выполнения: метод Итог() на клиенте и сервере

В платформе «1С:Предприятие 8.3» поведение метода зависит от типа объекта, к которому идет обращение:

  1. В объекте базы данных (ДокументОбъект): Табличная часть имеет тип ТабличнаяЧасть. Для нее метод Итог() доступен только на сервере, в толстом клиенте или внешнем соединении.
  2. В данных управляемой формы (Объект): Табличная часть представлена типом ДанныеФормыКоллекция. Для этого типа метод Итог("ИмяКолонки") полноценно доступен на тонком клиенте (&НаКлиенте).

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

Пошаговая настройка корректного пересчета на форме

Разберем реализацию правильного алгоритма.

Шаг 1. Создаем единую клиентскую процедуру расчета:


&НаКлиенте
Процедура РасчетСуммы()
    // Подсчитываем итог по табличной части ПереченьМатериалов
    СтоимостьМатериалов = Объект.ПереченьМатериалов.Итог("ЦенаЗаЕдиницу");
    
    // Если в шапке есть отдельное поле для стоимости материалов, заполняем его
    Объект.СтоимостьМатериалов = СтоимостьМатериалов;
    
    // Рассчитываем общую стоимость с учетом работы
    Объект.ОбщаяСтоимостьРаботы = Объект.ЦенаРаботыБезУчетаМатериалов + СтоимостьМатериалов;
КонецПроцедуры

Шаг 2. Назначаем обработчики событий на элементы формы:

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

  1. У поля ввода ЦенаРаботыБезУчетаМатериалов в палитре свойств находим событие ПриИзменении и привязываем процедуру:
    
    &НаКлиенте
    Процедура ЦенаРаботыБезУчетаМатериаловПриИзменении(Элемент)
        РасчетСуммы();
    КонецПроцедуры
    
  2. В дереве элементов формы разворачиваем таблицу ПереченьМатериалов, находим колонку ЦенаЗаЕдиницу (и Количество, если оно участвует в сумме), переходим в ее свойства и в событии ПриИзменении указываем:
    
    &НаКлиенте
    Процедура ПереченьМатериаловЦенаЗаЕдиницуПриИзменении(Элемент)
        РасчетСуммы();
    КонецПроцедуры
    
  3. Для самой таблицы ПереченьМатериалов (не колонок, а корневого элемента таблицы формы) обязательно назначаем обработчик на событие ПослеУдаления. Если этого не сделать, при удалении пользователем строки сумма документа не пересчитается:
    
    &НаКлиенте
    Процедура ПереченьМатериаловПослеУдаления(Элемент)
        РасчетСуммы();
    КонецПроцедуры
    

Отображение стоимости материалов в форме списка документов

Выясним, как вывести рассчитанную стоимость в динамический список документов.

Вариант 1. Использование реквизита шапки (рекомендуемый):

Если в объекте метаданных создан реквизит документа СтоимостьМатериалов или ОбщаяСтоимостьРаботы, и он сохраняется при записи документа, достаточно открыть форму списка, найти в правом окне «Реквизиты» поле Список.СтоимостьМатериалов и перетащить его в элементы формы списка.

Вариант 2. Использование произвольного запроса в динамическом списке:

Если итоговая стоимость не хранится в шапке документа, а существует только в табличной части, отобразим ее динамически:

  1. Открываем форму списка документов.
  2. В реквизитах формы выбираем реквизит Список (тип ДинамическийСписок).
  3. В окне свойств устанавливаем флаг «Произвольный запрос» и нажимаем «Настройка списка».
  4. Формируем текст запроса, объединяющий шапку с итогами табличной части:
    
    ВЫБРАТЬ
        ДокументНаборкаРабот.Ссылка КАК Ссылка,
        ДокументНаборкаРабот.ПометкаУдаления КАК ПометкаУдаления,
        ДокументНаборкаРабот.Номер КАК Номер,
        ДокументНаборкаРабот.Дата КАК Дата,
        ДокументНаборкаРабот.Проведен КАК Проведен,
        ДокументНаборкаРабот.ЦенаРаботыБезУчетаМатериалов КАК ЦенаРаботыБезУчетаМатериалов,
        ЕСТЬNULL(ТаблицаИтогов.СуммаМатериалов, 0) КАК СтоимостьМатериалов,
        ДокументНаборкаРабот.ЦенаРаботыБезУчетаМатериалов + ЕСТЬNULL(ТаблицаИтогов.СуммаМатериалов, 0) КАК ОбщаяСтоимость
    ИЗ
        Документ.НаборкаРабот КАК ДокументНаборкаРабот
        ЛЕВОЕ СОЕДИНЕНИЕ (
            ВЫБРАТЬ
                ВложеннаяТЧ.Ссылка КАК Ссылка,
                СУММА(ВложеннаяТЧ.ЦенаЗаЕдиницу) КАК СуммаМатериалов
            ИЗ
                Документ.НаборкаРабот.ПереченьМатериалов КАК ВложеннаяТЧ
            СГРУППИРОВАТЬ ПО
                ВложеннаяТЧ.Ссылка
        ) КАК ТаблицаИтогов
        ПО ДокументНаборкаРабот.Ссылка = ТаблицаИтогов.Ссылка
    
  5. После настройки запроса добавленные поля (СтоимостьМатериалов, ОбщаяСтоимость) станут доступны для добавления в элементы формы списка.

Гарантия целостности данных: расчет в модуле объекта

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

Для надежности продублируем расчет итогов в модуле объекта в предопределенном событии ПередЗаписью:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    // Здесь мы работаем на сервере с типом ТабличнаяЧасть
    СтоимостьМатериалов = ПереченьМатериалов.Итог("ЦенаЗаЕдиницу");
    ОбщаяСтоимостьРаботы = ЦенаРаботыБезУчетаМатериалов + СтоимостьМатериалов;
КонецПроцедуры

Такой подход гарантирует корректность сумм в базе данных при любых сценариях записи и проведения документов.

← На главную