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