Как программно создать заполненный документ и открыть его пользователю во внешней обработке

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

При разработке внешних обработок в системе 1С:Предприятие 8.3 программисты часто сталкиваются с задачей: необходимо программно сформировать документ на основе каких-либо данных (например, результата запроса), но не записывать его в базу данных сразу, а предоставить пользователю возможность проверить заполнение, внести правки и самостоятельно нажать кнопку «Провести и закрыть». Рассмотрим, как правильно реализовать этот механизм, избегая типичных ошибок, таких как «Ошибка преобразования данных XDTO».

Почему возникает ошибка преобразования XDTO

Для начала проанализируем ситуацию, описанную автором темы. Попытка передать переменную типа ДокументОбъект напрямую с сервера на клиент всегда будет приводить к ошибке. В управляемом приложении действует строгое разделение: на стороне сервера мы работаем с объектами базы данных (ДокументОбъект, СправочникОбъект), а на стороне клиента таких типов не существует. Клиент оперирует ссылками (ДокументСсылка) или данными формы (ДанныеФормыСтруктура). Попытка передать «живой» объект через границу «сервер-клиент» вызывает сбой преобразования XDTO, так как система не знает, как сериализовать сложный серверный объект для передачи на сторону клиента.

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

Способ 1: Использование параметра «ЗначениеЗаполнения»

Этот метод считается наиболее стандартным и «чистым» с точки зрения архитектуры 1С. Мы не создаем сам объект документа вручную на сервере, а подготавливаем структуру данных, которую передаем в форму при ее открытии. Система сама инициирует создание нового объекта и заполняет его переданными значениями.

Рассмотрим алгоритм действий:

  1. На стороне клиента подготавливаем структуру параметров.
  2. Вызываем функцию ОткрытьФорму.
  3. В модуле объекта или менеджера документа обрабатываем эти данные в процедуре ОбработкаЗаполнения (если требуется сложная логика).

Пример программного кода на клиенте:


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

Важный нюанс: Чтобы табличная часть заполнилась автоматически через этот механизм, в документе (или в его модуле объекта) должна быть реализована логика обработки структуры ЗначениеЗаполнения. В типовых конфигурациях, таких как ERP 2.4, это часто уже реализовано для базовых реквизитов.

Способ 2: Использование функции «КопироватьДанныеФормы»

Если структура документа сложная, или если логика заполнения уже написана на сервере и возвращает готовый ДокументОбъект, мы можем программно создать форму и «вбросить» в нее данные нашего объекта. Этот метод позволяет обойти ограничение XDTO, так как мы копируем данные в структуру формы на сервере.

Выясним, как это реализовать пошагово:


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

&НаКлиенте
Процедура СоздатьИОткрытьФорму()
    
    // В управляемом приложении ПолучитьФорму можно вызвать и на сервере, 
    // но открывать ее нужно на клиенте.
    
    // Оптимальный вариант для данной задачи:
    Форма = ПолучитьФормуСервер(); 
    Форма.Открыть();
    
КонецПроцедуры

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

Преимущество метода: Пользователь видит перед собой документ со всеми заполненными полями, но при этом в базе данных записи еще нет. Ссылка документа будет пустой.

Способ 3: Массовое создание документов (Цикл на клиенте)

Если ваш запрос возвращает данные для нескольких документов (например, по разным Организациям или Складам), проанализируем ситуацию с точки зрения удобства пользователя. Не рекомендуется открывать сразу 50 окон. Правильнее будет вернуть массив структур с сервера и открывать формы в цикле на клиенте.

Разберем пример реализации:


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

Особенности для ERP Управление предприятием 2

При работе с ERP 2.4 важно учитывать специфику метаданных. Проанализируем обязательные поля для документа ВнутреннееПотреблениеТоваров:

Рекомендация по архитектуре

Чтобы выполнить требование «работать с самим объектом», которое озвучил руководитель в исходной теме, лучше всего инкапсулировать логику. Вынесите алгоритм заполнения в отдельную функцию серверного модуля вашей обработки. Эта функция должна принимать пустой ДокументОбъект, заполнять его и возвращать обратно. А вызывающая процедура на сервере будет использовать КопироватьДанныеФормы, чтобы перенести результат в интерфейс.

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

← На главную