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