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