Как программно вызвать расчеты в табличной части 1С:УНФ при изменении строк?

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

При разработке обработок загрузки данных в конфигурацию 1С:Управление нашей фирмой (УНФ) программисты часто сталкиваются с проблемой: данные в табличную часть загружаются, но автоматические расчеты (цены, суммы, НДС, скидки), привязанные к событию ПриИзменении на форме, не срабатывают. Это происходит потому, что событие ПриИзменении является клиентским и интерактивным, а программная загрузка выполняется на сервере.

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

Причина проблемы: разделение контекстов

Рассмотрим ситуацию: в форме документа логика заполнения строки (например, подстановка цены при выборе номенклатуры) прописана непосредственно в обработчике НоменклатураПриИзменении. Когда пользователь выбирает товар руками, платформа вызывает этот код. Однако при программном заполнении коллекции Объект.Товары на сервере никакие события формы не генерируются.

Попытки «нажать на кнопку» программно или имитировать выбор строки через ТекущаяСтрока часто приводят к исключению «Ошибка изменения значения» или «Метод не доступен на сервере». Выясним, как решить эту задачу правильно.

Решение 1: Использование встроенных механизмов УНФ

Конфигурация УНФ достаточно технологична, и большинство расчетов в ней уже вынесено в общие модули. Вместо того чтобы пытаться вызвать событие формы, мы можем использовать серверные методы, которые делают ту же работу. Проанализируем состав конфигурации и выделим ключевые модули:

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

Рассмотрим пример программного заполнения строки на сервере с вызовом стандартной логики:


// Пример заполнения строки заказа покупателя на сервере
НоваяСтрока = Объект.Запасы.Добавить();
НоваяСтрока.Номенклатура = ВыбранныйТовар;

// Вызываем типовой механизм заполнения реквизитов по номенклатуре
ПараметрыЗаполнения = Новый Структура("ДокументОбъект, ИмяТабличнойЧасти", Объект, "Запасы");
ЗаполнениеДокументов.ЗаполнитьСтрокуТабличнойЧасти(Объект, НоваяСтрока, ПараметрыЗаполнения);

// Принудительно вызываем расчет цен и сумм, если это предусмотрено в модуле менеджера или объекта
Объект.РассчитатьЦеныИСуммы(НоваяСтрока); 

Решение 2: Рефакторинг и вынос логики в модуль объекта

Если в вашей форме УНФ в событии ПриИзменении действительно содержится «100500 строк кода», которые уникальны для этого документа, лучшим архитектурным решением будет рефакторинг. Нам нужно исключить дублирование кода (принцип DRY — Don't Repeat Yourself).

Разберем этот процесс по шагам:

  1. Перенесем основной код расчетов из процедуры формы в Модуль объекта документа. Создадим там экспортную процедуру, например, РассчитатьПараметрыСтроки(СтрокаТЧ).
  2. В обработчике события формы ПриИзменении заменим старый код на вызов этой новой процедуры.
  3. В вашей внешней обработке загрузки, работающей с объектом на сервере, просто вызывайте эту же процедуру после добавления строки.

Посмотрим на пример кода в модуле объекта:


// В модуле объекта
Процедура РассчитатьПараметрыСтроки(ТекущаяСтрока) Экспорт
    // Здесь размещаем всю логику: цены, скидки, НДС
    ТекущаяСтрока.Сумма = ТекущаяСтрока.Количество * ТекущаяСтрока.Цена;
    // ... и так далее
КонецПроцедуры

Теперь на форме вызов будет выглядеть крайне лаконично:


&НаКлиенте
Процедура ЗапасыНоменклатураПриИзменении(Элемент)
    СтрокаТЧ = Элементы.Запасы.ТекущиеДанные;
    // Вызываем серверный метод объекта для расчета
    РассчитатьПараметрыСтрокиНаСервере(СтрокаТЧ.ПолучитьИдентификатор());
КонецПроцедуры

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

Решение 3: Работа через идентификаторы (решение проблемы с ТекущейСтрокой)

Автор темы на форуме столкнулся с ошибкой при попытке программно менять текущую строку в форме. Важно помнить: в управляемом приложении ТекущаяСтрока — это не индекс массива и не сам объект данных, а Идентификатор строки (число).

Если вам все же необходимо программно «пройтись» по строкам в контексте формы и вызвать для каждой некий клиентский код, делайте это так:


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

Внимание: Этот метод работает только на клиенте. Однако помните, что вызывать ПриИзменении в цикле — это «костыль». Правильнее использовать подходы, описанные в первом и втором пунктах.

Решение 4: Преобразование «ДанныеФормы в Объект»

Если заполнение происходит внутри формы (например, по кнопке «Загрузить» в самой форме заказа), самым эффективным способом будет временная конвертация данных формы в прикладной объект. Это позволит использовать все методы модуля объекта, включая те, что отвечают за расчеты.

Проанализируем алгоритм:

  1. Конвертируем ДанныеФормыСтруктура в полноценный ДокументОбъект через РеквизитФормыВЗначение.
  2. Выполняем загрузку данных в табличную часть этого объекта.
  3. Для каждой новой строки вызываем необходимые процедуры пересчета, находящиеся в модуле объекта или общем модуле.
  4. Возвращаем измененный объект обратно в форму через ЗначениеВРеквизитФормы.

Этот подход гарантирует, что все связанные поля будут рассчитаны корректно, а пользователь сразу увидит результат на экране после завершения серверного вызова.

Подведем итоги

Для качественного решения задачи в 1С:УНФ следует придерживаться следующих правил:

Соблюдение этих принципов позволит вам создавать надежные механизмы загрузки данных, которые не ломаются при обновлении конфигурации и сохраняют всю бизнес-логику документа.

← На главную