При разработке документов в системе «1С:Предприятие 8.3» часто возникает задача автоматического расчета итоговых показателей внутри одной строки табличной части. Например, когда необходимо сложить различные статьи затрат (сырье, комплектующие, трудозатраты, топливо) и вывести их общую сумму в отдельную колонку «Фактическая себестоимость» в этой же строке.
В этой статье мы подробно разберем, как правильно реализовать такое сложение на управляемых формах, проанализируем типичные ошибки начинающих разработчиков, связанные с переходом от обычных форм к управляемым, и рассмотрим профессиональные методы оптимизации кода для динамического пересчета сумм.
Часто при переносе старого кода или использовании устаревших инструкций разработчики сталкиваются с ошибками компиляции кода на клиенте. Рассмотрим наиболее распространенную ошибку, которая прозвучала в обсуждении на форуме:
Переменная не определена (ЭлементыФормы)
Выясним причину этой ошибки. В старой технологической платформе «1С:Предприятие 8.2» (и в обычных формах 1С 8.3) для доступа к элементам интерфейса использовалась коллекция ЭлементыФормы. В современном управляемом приложении (Тонкий клиент, Веб-клиент) эта коллекция была упразднена. Вместо нее используется объект Элементы. Попытка вызвать старое свойство на управляемой форме неизбежно приводит к критической ошибке.
Вторая популярная ошибка — попытка обратиться к несуществующей переменной:
Переменная не определена (ТекущиеДанныеСтатейЗатрат)
Она возникает, когда разработчик пытается напрямую обратиться к данным строки, не получив предварительно саму строку из таблицы формы. Напрямую через имя таблицы обратиться к полям текущей строки невозможно. Сначала необходимо получить объект текущей строки через свойство таблицы ТекущиеДанные.
Рассмотрим, как правильно получить доступ к редактируемой строке таблицы в управляемой форме. Для этого мы обращаемся к таблице через коллекцию Элементы и извлекаем свойство ТекущиеДанные. Полученный объект имеет тип ДанныеФормыЭлементКоллекции, с которым можно работать как с обычной структурой или строкой таблицы значений.
Проанализируем базовый безопасный шаблон получения строки:
&НаКлиенте
Процедура СтатьиЗатратПриИзменении(Элемент)
// Получаем текущую строку таблицы «СтатьиЗатрат»
СтрокаТЧ = Элементы.СтатьиЗатрат.ТекущиеДанные;
// Обязательно проверяем, что строка действительно выбрана и не равна Неопределено
Если СтрокаТЧ <> Неопределено Тогда
// Здесь будет выполняться расчет
КонецЕсли;
КонецПроцедуры
Самый очевидный способ сложения — это прямое суммирование всех необходимых реквизитов через оператор «плюс». Если у вас фиксированный набор колонок, который гарантированно не изменится в будущем, можно использовать прямое присвоение.
Разберем пример такого кода:
&НаКлиенте
Процедура РассчитатьСуммуПростымСпособом()
СтрокаТЧ = Элементы.СтатьиЗатрат.ТекущиеДанные;
Если СтрокаТЧ = Неопределено Тогда
Возврат;
КонецЕсли;
// Складываем все числовые показатели строки напрямую
СтрокаТЧ.ФактическаяСебестоимость = СтрокаТЧ.СырьеИМатериалы
+ СтрокаТЧ.Комплектующие
+ СтрокаТЧ.ВозвратныеОтходы
+ СтрокаТЧ.ТопливоИЭнергия
+ СтрокаТЧ.ЗаработнаяПлата
+ СтрокаТЧ.НачисленияНаЗп
+ СтрокаТЧ.СодержаниеОборудования
+ СтрокаТЧ.ОбщехозяйственныеРасходы
+ СтрокаТЧ.ОбщепроизводственныеРасходы;
КонецПроцедуры
Важное примечание: Этот способ прост в написании, но имеет существенные недостатки. Во-первых, если в будущем в документ добавится новая статья затрат (например, «Амортизация»), вам придется вручную искать все подобные формулы в модуле формы и дописывать их. Во-вторых, длинные строки кода сложно читать и отлаживать.
Профессиональный подход к разработке в 1С подразумевает написание гибкого кода. Объект ДанныеФормыЭлементКоллекции позволяет обращаться к своим реквизитам динамически по их строковому имени, используя квадратные скобки: СтрокаТЧ[ИмяКолонки]. Это дает нам возможность перечислить все слагаемые колонки в массиве и сложить их в цикле.
Рассмотрим по шагам, как реализовать такую универсальную процедуру:
&НаКлиенте
Процедура ПересчитатьСебестоимостьСтроки()
СтрокаТЧ = Элементы.СтатьиЗатрат.ТекущиеДанные;
Если СтрокаТЧ = Неопределено Тогда
Возврат;
КонецЕсли;
// Инициализируем массив имен колонок, которые участвуют в расчете
МассивКолонок = Новый Массив;
МассивКолонок.Добавить("СырьеИМатериалы");
МассивКолонок.Добавить("Комплектующие");
МассивКолонок.Добавить("ВозвратныеОтходы");
МассивКолонок.Добавить("ТопливоИЭнергия");
МассивКолонок.Добавить("ЗаработнаяПлата");
МассивКолонок.Добавить("НачисленияНаЗп");
МассивКолонок.Добавить("СодержаниеОборудования");
МассивКолонок.Добавить("ОбщехозяйственныеРасходы");
МассивКолонок.Добавить("ОбщепроизводственныеРасходы");
ИтоговаяСумма = 0;
// Обходим массив и суммируем значения колонок
Для Каждого ИмяКолонки Из МассивКолонок Цикл
ЗначениеПоля = СтрокаТЧ[ИмяКолонки];
// Защищаем код от сложения с пустыми значениями (Неопределено)
ИтоговаяСумма = ИтоговаяСумма + ?(ЗначениеПоля = Неопределено, 0, ЗначениеПоля);
КонецЦикла;
// Записываем результат в итоговую колонку
СтрокаТЧ.ФактическаяСебестоимость = ИтоговаяСумма;
КонецПроцедуры
Этот подход значительно упрощает поддержку конфигурации. Если появится новое поле, достаточно будет добавить одну строчку в массив МассивКолонок, не меняя логику самого расчета.
Обратите особое внимание на конструкцию ?(ЗначениеПоля = Неопределено, 0, ЗначениеПоля). В платформе 1С на стороне клиента сложение числа со значением типа Неопределено или Null приведет к аварийному завершению работы программы с ошибкой несоответствия типов. Хотя числовые поля по умолчанию инициализируются нулями, при программном создании строк, импорте данных из Excel или некорректной очистке полей пользователем в ячейке может оказаться пустота. Данная тернарная проверка гарантирует стабильность работы вашего решения.
Важный архитектурный нюанс — в какой момент запускать пересчет. Автор темы на форуме предлагал использовать событие самой табличной части ПриИзменении (например, СтатьиЗатратПриИзменении).
Почему это неудобно для пользователя: Событие всей таблицы ПриИзменении срабатывает только тогда, когда пользователь полностью заканчивает редактирование текущей строки и переходит на другую строку или добавляет новую. Если пользователь меняет число в ячейке «Сырье и материалы», итоговая сумма в колонке «Фактическая себестоимость» не изменится до тех пор, пока он не выйдет из всей строки. Это выглядит неотзывчиво.
Как сделать правильно: Итог должен пересчитываться мгновенно («на лету») при изменении любого слагаемого показателя. Для этого необходимо сделать следующее:
СтатьиЗатратСырьеИМатериалы, СтатьиЗатратКомплектующие и т.д.), найдите в свойствах событие ПриИзменении.СтатьиЗатратКолонкаПриИзменении.Код обработчика будет предельно простым и лаконичным:
&НаКлиенте
Процедура СтатьиЗатратКолонкаПриИзменении(Элемент)
// Запускаем расчет при изменении любого слагаемого поля
ПересчитатьСебестоимостьСтроки();
КонецПроцедуры
Теперь, как только пользователь введет новое число в любую ячейку строки и нажмет Enter (или перейдет в соседнюю ячейку этой же строки), итоговое поле мгновенно обновится.
Помимо сложения по горизонтали внутри одной строки, пользователям почти всегда требуется видеть общую сумму себестоимости по всем строкам документа сразу. В управляемых формах 1С 8.3 вертикальные итоги настраиваются декларативно в конфигураторе без единой строчки программного кода.
Выполните следующие шаги для вывода общего итога в подвал таблицы:
СтатьиЗатрат.Истина. Под таблицей появится серая строка подвала.СтатьиЗатратФактическаяСебестоимость.Объект.СтатьиЗатрат.ИтогФактическаяСебестоимость (платформа автоматически предлагает готовые агрегатные итоги по всем числовым реквизитам табличных частей).После выполнения этих простых настроек платформа 1С возьмет на себя автоматический расчет суммы всей колонки по всем строкам и будет отображать актуальный сквозной итог в подвале таблицы в режиме реального времени.