При разработке внешних обработок, написании тестов или интеграционных сценариев часто возникает задача: получить управляемую форму объекта, программно установить значение реквизита (например, Организация или Контрагент) и инициировать выполнение связанных с этим реквизитом событий (ПриИзменении, пересчет сумм, заполнение договоров и т. д.).
Проанализируем особенности работы событийной модели платформы 1С:Предприятие 8.3, выясним причину, по которой простое присвоение значения не вызывает код интерфейсных обработчиков, и рассмотрим рабочие способы решения этой задачи.
В платформе 1С:Предприятие существует четкое разделение между интерактивными действиями пользователя и программной модификацией данных:
ПриИзменении, АвтоПодбор, Очистка, Нажатие, вызываются клиентом платформы исключительно в ответ на физические действия пользователя в интерфейсе (ввод с клавиатуры, выбор мышью из списка). Простая установка значения свойства объекта или реквизита формы через код вида Форма.Реквизит = Значение или Форма.Объект.Организация = НоваяОрганизация меняет данные в памяти, но не генерирует пользовательские события.Экспорт. Они являются локальными для модуля конкретной формы и недоступны для вызова извне (из внешней обработки или другого клиентского контекста).Если главная цель — проверить работоспособность событий и поведение интерфейса в конфигурации, находящейся на поддержке (без изменения метаданных и без добавления расширений), штатным инструментом платформы является механизм автоматизированного тестирования.
Разберем по шагам, как устроен этот механизм:
/TestClient./TestManager.ТестируемоеПриложение, ТестируемаяФорма, ТестируемоеПолеФормы.Посмотрим на пример кода в менеджере тестирования, который полноценно эмулирует действия пользователя и вызывает все привязанные обработчики:
ТестируемоеПриложение = Новый ТестируемоеПриложение;
ТестируемоеПриложение.УстановитьСоединение();
// Открываем форму документа
ТестируемоеПриложение.ВыполнитьКоманду("Документ.РеализацияТоваровУслуг.Создать");
ФормаДокумента = ТестируемоеПриложение.ПолучитьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента");
// Получаем элемент управления и эмулируем интерактивный ввод
ПолеОрганизация = ФормаДокумента.ПолучитьЭлемент("Организация");
ПолеОрганизация.ВвестиТекст("Основная организация");
// Платформа генерирует событие ПриИзменении и отрабатывает всю цепочку алгоритмов
Если необходимо программно дергать обработчик из внешней обработки без использования менеджера тестирования, но типовую конфигурацию менять нельзя, воспользуемся механизмом расширений.
Рассмотрим порядок действий:
Посмотрим, как выглядит вызов такой процедуры из внешней обработки:
ПараметрыФормы = Новый Структура;
Форма = ПолучитьФорму("Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);
Форма.Открыть();
// Устанавливаем значение реквизита
Форма.Объект.Организация = НужнаяОрганизация;
// Вызываем экспортную процедуру формы, инициирующую пересчет
Форма.ОрганизацияПриИзмененииЭкспорт();
Если задача заключается в начальной инициализации реквизитов и срабатывании алгоритмов заполнения при создании формы, используем штатную структуру ЗначенияЗаполнения.
Разберем пример передачи параметров:
ЗначенияЗаполнения = Новый Структура;
ЗначенияЗаполнения.Вставить("Организация", ВыбраннаяОрганизация);
ЗначенияЗаполнения.Вставить("Контрагент", ВыбранныйКонтрагент);
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("ЗначенияЗаполнения", ЗначенияЗаполнения);
// Открываем форму с автоматической инициализацией зависимых данных
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта", ПараметрыОткрытия);
В этом случае платформа автоматически передает управление в процедуру ОбработкаЗаполнения модуля объекта и в серверные обработчики формы ПриСозданииНаСервере, что позволяет штатно заполнить взаимосвязанные реквизиты объекта без прямого вызова клиентских событий элементов управления.
В большинстве типовых решений логика, завязанная на реквизиты шапки (выбор валюты, заполнение счетов учета, подстановка договоров), выносится в модуль объекта или в экспортные процедуры общих модулей. Если интерфейсная часть не критична, проверку логики эффективнее выполнять напрямую на уровне данных:
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Организация = ВыбраннаяОрганизация;
// Вызываем типовые методы заполнения объекта
НовыйДокумент.Заполнить(Неопределено);
// Либо вызываем специализированные методы пересчета из общих модулей
// Например: ОбработкаТабличнойЧастиКлиентСервер.ПересчитатьСумму(НовыйДокумент);