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