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