Как программно создать и заполнить объект 1С, открыв его форму без записи в базу данных?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача: необходимо программно создать новый элемент справочника или документ, заполнить его реквизиты по определенному алгоритму и открыть его форму пользователю. При этом крайне важно не записывать объект в базу данных преждевременно — пользователь должен сам решить, сохранять этот объект или закрыть форму без записи.

Многие начинающие разработчики используют «наивный» подход: получают форму программно, вытаскивают из нее объект, заполняют его реквизиты на клиенте или сервере, копируют данные обратно в форму и открывают ее. Однако при таком подходе они сталкиваются со следующей проблемой: визуальные элементы формы (видимость полей, доступность кнопок, состав колонок табличных частей) настраиваются некорректно. Выясним причину этой проблемы и рассмотрим правильные архитектурные решения.

В чем причина некорректной настройки формы при простом копировании данных?

Давайте проанализируем жизненный цикл инициализации управляемой формы. Когда мы вызываем метод ПолучитьФорму или ОткрытьФорму, платформа немедленно запускает на сервере обработчик события формы ПриСозданииНаСервере. Именно в этом обработчике в типовых конфигурациях (например, ERP, Комплексная автоматизация, Управление торговлей) сосредоточена вся логика настройки интерфейса. Код анализирует текущие значения реквизитов объекта и на их основе скрывает или отображает нужные поля.

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

Рассмотрим три надежных и проверенных способа решения этой проблемы, которые позволяют передать данные в объект до момента настройки интерфейса управляемой формы.

Решение 1. Использование стандартного параметра «ЗначенияЗаполнения»

Это самый простой и изящный способ, заложенный в саму архитектуру платформы 1С. Мы можем передать структуру заполняемых реквизитов напрямую в параметры открываемой формы. Платформа обработает их автоматически еще до того, как начнется построение интерфейса.

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


ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("ТипНоменклатуры", ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Товар"));
ПараметрыЗаполнения.Вставить("СтавкаНДС", ПредопределенноеЗначение("Перечисление.СтавкаНДС.НДС20"));
ПараметрыЗаполнения.Вставить("Наименование", "Новый тестовый товар");

ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);

ОткрытьФорму("Справочник.Номенклатура.ФормаОбъекта", ПараметрыФормы);

При таком подходе платформа выполняет следующие действия:

  1. Инициализирует новый объект в памяти на сервере.
  2. Передает структуру из параметра ЗначенияЗаполнения в стандартный обработчик объекта ОбработкаЗаполнения.
  3. Если в свойствах реквизитов в конфигураторе взведен флаг «Заполнять из данных заполнения», платформа автоматически переносит туда соответствующие значения.
  4. И только после этого управление передается в обработчик формы ПриСозданииНаСервере. К этому моменту объект уже заполнен нашими значениями, и визуальная настройка интерфейса отрабатывает абсолютно корректно.

Решение 2. Перехват события «ОбработкаЗаполнения» через расширение (для сложных объектов)

Метод со стандартным заполнением реквизитов отлично подходит для простых сценариев. Однако, если логика заполнения нового объекта очень сложная (требует обращения к базам данных, расчетов или заполнения связанных табличных частей), простой передачи структуры может не хватить. В этом случае мы можем использовать механизм расширений конфигурации для перехвата модуля создаваемого объекта.

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

Шаг 1. На клиенте вызываем открытие формы и передаем структуру параметров с нашим уникальным идентификатором:


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

ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
ОткрытьФорму("Документ.ЭтапПроизводства2_2.ФормаОбъекта", ПараметрыФормы);

Шаг 2. В расширении для нужного объекта (например, документа «Этап производства») заимствуем процедуру ОбработкаЗаполнения и добавляем аннотацию &Перед:


&Перед("ОбработкаЗаполнения")
Процедура Расш_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") 
        И ДанныеЗаполнения.Свойство("КлючСобственногоЗаполнения") Тогда
        
        // Вызываем нашу собственную процедуру заполнения объекта на сервере
        ЗаполнитьНовыйДокументПоСвоимПравилам(ДанныеЗаполнения.ИсходныйДокумент);
        
        // Если стандартное заполнение платформы больше не требуется, можно отключить его
        // СтандартнаяОбработка = Ложь;
    КонецЕсли;
    
КонецПроцедуры

При такой реализации весь сложный код инициализации объекта отработает в модуле самого объекта непосредственно перед созданием формы. Форма откроется полностью готовой, а все ее элементы интерфейса перестроятся в соответствии со значениями, которые мы записали в объект.

Решение 3. Передача сложных структур данных через Временное хранилище

При передаче данных через параметры формы мы можем столкнуться с ограничением платформы: таблицы значений и сложные объекты, не поддерживающие XML-сериализацию, невозможно напрямую передать в параметрах с клиента на сервер. Если нам нужно передать в форму нового незаписанного объекта сложную структуру (например, готовую таблицу с десятками строк для табличной части), на помощь приходит Временное хранилище.

Рассмотрим подробнее этот паттерн проектирования:

Шаг 1. Формируем структуру данных на сервере в вызывающем коде, помещаем ее во временное хранилище и получаем уникальный адрес:


// Выполняется на сервере в модуле нашей внешней обработки или вызова
&НаСервере
Функция ПодготовитьДанныеВоВременномХранилище()
    
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("ОсновнойСклад", Справочники.Склады.НайтиПоКоду("00001"));
    
    // Создаем и заполняем таблицу товаров
    ТаблицаТоваров = Новый ТаблицаЗначений;
    ТаблицаТоваров.Колонки.Добавить("Номенклатура");
    TaблицаТоваров.Колонки.Добавить("Количество");
    
    НоваяСтрока = ТаблицаТоваров.Добавить();
    НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоРеквизиту("Артикул", "ART-001");
    НоваяСтрока.Количество = 10;
    
    СтруктураДанных.Вставить("ТаблицаТоваров", ТаблицаТоваров);
    
    // Помещаем структуру во временное хранилище
    АдресХранилища = ПоместитьВоВременноеХранилище(СтруктураДанных, Новый УникальныйИдентификатор);
    Возврат АдресХранилища;
    
КонецФункции

Шаг 2. На клиенте передаем полученный адрес хранилища в качестве параметра при открытии формы:


&НаКлиенте
Процедура СоздатьИОткрытьНовыйДокумент()
    
    АдресДанных = ПодготовитьДанныеВоВременномХранилище();
    
    ПараметрыЗаполнения = Новый Структура;
    ПараметрыЗаполнения.Вставить("АдресДанныхЗаполнения", АдресДанных);
    
    ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
    ОткрытьФорму("Документ.ЗаказКлиента.ФормаОбъекта", ПараметрыФормы);
    
КонецПроцедуры

Шаг 3. В расширении модуля объекта перехватываем ОбработкаЗаполнения, считываем данные из временного хранилища по переданному адресу и переносим их в создаваемый объект:


&Перед("ОбработкаЗаполнения")
Процедура Расш_ОбработкаЗаполненияИзХранилища(ДанныеЗаполнения, СтандартнаяОбработка)
    
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") 
        И ДанныеЗаполнения.Свойство("АдресДанныхЗаполнения") Тогда
        
        Адрес = ДанныеЗаполнения.АдресДанныхЗаполнения;
        Если ЭтоАдресВременногоХранилища(Адрес) Тогда
            
            // Извлекаем структуру из памяти сервера
            ДанныеОбъекта = ПолучитьИзВременногоХранилище(Адрес);
            
            // Заполняем реквизиты объекта
            ЭтотОбъект.Склад = ДанныеОбъекта.ОсновнойСклад;
            
            // Заполняем табличную часть документа
            ЭтотОбъект.Товары.Очистить();
            Для Каждого СтрокаТЧ Из ДанныеОбъекта.ТаблицаТоваров Цикл
                НоваяСтрока = ЭтотОбъект.Товары.Добавить();
                ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТЧ);
            КонецЦикла;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Важные нюансы платформы 1С, о которых необходимо помнить

При реализации вышеописанных подходов обратите внимание на следующие важные архитектурные особенности:

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

← На главную