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

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

При переносе данных или разработке внешних обработок часто возникает задача: сформировать новый документ, программно заполнить его реквизиты и табличные части значениями из внешнего источника (например, файла таблицы или макета), а затем открыть экранную форму документа для проверки пользователем, не записывая его предварительно в базу данных.

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

Причина возникновения ошибки «Поле объекта не обнаружено (Объект)»

Проанализируем ситуацию: разработчики, начинающие работать на платформе 1С 8.3, часто сталкиваются с путаницей между обычным интерфейсом (обычные формы) и управляемым интерфейсом (управляемые формы).

  1. В управляемых формах (УФ) основным реквизитом формы по умолчанию является Объект (тип ДанныеФормыСтруктура). Обращение к полям документа происходит через конструкцию вида Форма.Объект.Дата.
  2. В обычных формах (ОФ), которые используются в конфигурациях вроде УПП 1.3 или УТ 10.3, основной реквизит формы документа называется ДокументОбъект. Попытка обратиться к свойству Форма.Объект приводит к ошибке, так как такого реквизита на обычной форме не существует.

Основной реквизит формы всегда выделяется жирным шрифтом в дереве реквизитов редактора формы конфигуратора.

Способ 1. Заполнение и открытие через объект документа (для обычных форм)

В обычном приложении наиболее простым и лаконичным способом является создание объекта в памяти, полное его заполнение и последующее получение связанной с ним формы. Разберем этот вариант на примере:


// Создаем экземпляр объекта документа в оперативной памяти
НовыйДокумент = Документы.ЗаказПокупателя.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();

// Заполняем реквизиты шапки
НовыйДокумент.Контрагент = ВыбранныйКонтрагент;

// Заполняем строки табличной части
Для Строка_ = 19 По ТабДок.ВысотаТаблицы Цикл
    КодНоменклатуры = СокрЛП(ТабДок.Область(Строка_, 44).Текст);
    Если ЗначениеЗаполнено(КодНоменклатуры) Тогда
        СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоКоду(КодНоменклатуры);
        Если ЗначениеЗаполнено(СсылкаНоменклатура) Тогда
            НоваяСтрока = НовыйДокумент.Товары.Добавить();
            НоваяСтрока.Номенклатура = СсылкаНоменклатура;
            НоваяСтрока.Количество = 10;
            НоваяСтрока.Цена = 55;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

// Получаем форму, привязанную к заполненному объекту, и открываем ее
ФормаДокумента = НовыйДокумент.ПолучитьФорму();
ФормаДокумента.Модифицированность = Истина;
ФормаДокумента.Открыть();

Обратите внимание: установка флага ФормаДокумента.Модифицированность = Истина; позволяет платформе зафиксировать, что в форме есть несохраненные данные. Если пользователь попытается закрыть окно, система выдаст стандартное предупреждение с предложением сохранить документ.

Способ 2. Заполнение через форму объекта (для обычных форм)

Если требуется сначала получить пустую форму и сразу работать с ее элементами данных, обращение выполняется через реквизит ДокументОбъект:


Форма_ = ПолучитьФорму("Документ.ЗаказПокупателя.ФормаОбъекта");
Форма_.ДокументОбъект.Дата = ТекущаяДата();

Для Строка_ = 19 По ТабДок.ВысотаТаблицы Цикл
    Код_ = СокрЛП(ТабДок.Область(Строка_, 44).Текст);
    Если ЗначениеЗаполнено(Код_) Тогда
        ЭлементСсылка = Справочники.Номенклатура.НайтиПоКоду(Код_);
        Если ЗначениеЗаполнено(ЭлементСсылка) Тогда
            НоваяСтрок = Форма_.ДокументОбъект.Товары.Добавить();
            НоваяСтрок.Номенклатура = ЭлементСсылка;
            НоваяСтрок.Количество = 10;
            НоваяСтрок.Цена = 55;
        КонецЕсли;
    КонецЕсли;
КонецЦикла;

Форма_.Открыть();

Способ 3. Использование механизма параметров заполнения (стандартный подход для управляемых и обычных форм)

Платформа 1С предоставляет механизм передачи данных через структуру ЗначенияЗаполнения при вызове функции ОткрытьФорму. Это позволяет передавать готовые данные шапки и таблицы значений в открываемую форму.

Рассмотрим вызов со стороны клиентского кода:


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

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

Если в структуру передаются простые реквизиты шапки с именами, в точности совпадающими с именами реквизитов документа, платформа заполнит их автоматически. Если же требуется заполнить сложную табличную часть, в модуле объекта документа в процедуре ОбработкаЗаполнения реализуется соответствующая логика:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
        ЗаполнитьЗначенияСвойств(ЭтотОбъект, ДанныеЗаполнения);
        
        Если ДанныеЗаполнения.Свойство("ТаблицаТоваров") И ТипЗнч(ДанныеЗаполнения.ТаблицаТоваров) = Тип("ТаблицаЗначений") Тогда
            Товары.Загрузить(ДанныеЗаполнения.ТаблицаТоваров);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Способ 4. Универсальный подход для управляемых форм (на клиенте и сервере)

В управляемом приложении объект ДокументОбъект не может передаваться на сторону клиента, а метод ПолучитьФорму() у объекта недоступен. Поэтому для сложного заполнения объекта на сервере с последующим отображением на клиенте используется следующий шаблон:


&НаКлиенте
Процедура ОткрытьФормуНаКлиенте()
    // Получаем экземпляр формы
    Форма = ПолучитьФорму("Документ.ЗаказПокупателя.Форма.ФормаДокумента");
    
    // Заполняем данные формы на сервере
    ДанныеФормы = Форма.Объект;
    ЗаполнитьДокументНаСервере(ДанныеФормы);
    КопироватьДанныеФормы(ДанныеФормы, Форма.Объект);
    
    // Открываем форму пользователю
    Форма.Открыть();
КонецПроцедуры

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

Практические рекомендации по оптимизации

  1. Отказ от поиска в цикле: Вызов методов НайтиПоКоду() или НайтиПоНаименованию() внутри цикла обхода строк выполняет отдельный запрос к СУБД на каждом шаге. Если строк много, рекомендуется предварительно собрать все коды в массив, выполнить один общий запрос к справочнику, выгрузить результат в Соответствие и быстро получать ссылки в памяти.
  2. Использование метода «Загрузить»: Если данные для табличной части уже собраны в Таблицу Значений с колонками, повторяющими имена реквизитов табличной части, используйте пакетную вставку ДокументОбъект.Товары.Загрузить(ТЗ) вместо построчного добавления методом Добавить().
← На главную