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

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

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

Анализ проблемы: почему нельзя заполнять реквизиты формы «в лоб» на клиенте

В сообщениях на форуме автору предлагают использовать метод ПолучитьФорму и напрямую присваивать значения реквизитам формы на клиенте:


Формадок = ПолучитьФорму("Документ.Соглашение.ФормаОбъекта");
Формадок.Объект.Контрагент = Результат.Контрагент;

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

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

Для решения этой задачи в платформе 1С предусмотрен штатный, быстрый и безопасный механизм заполнения через параметр ЗначенияЗаполнения и обработчик события ОбработкаЗаполнения на стороне сервера.

Решение 1: Стандартный механизм через параметр «ЗначенияЗаполнения» (Рекомендуется)

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

Шаг 1. Реализация на стороне клиента (в форме списка документов или обработке)

Сначала настроим открытие формы выбора шаблона и последующее открытие формы нового документа с передачей параметров. Разберем код:


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

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

Шаг 2. Заполнение данных на сервере в Модуле объекта документа

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


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

Преимущества данного метода: этот алгоритм работает на сервере в рамках единой транзакции создания объекта. Мы не дергаем базу данных по сети ради каждого реквизита. Функция ЗаполнитьЗначенияСвойств работает максимально быстро, автоматически сопоставляя имена и типы реквизитов источника и приемника.

Решение 2: Использование свойства «Заполнять из данных заполнения» для простых документов

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

Выполним следующие шаги:

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

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

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

При открытии формы платформа 1С автоматически проанализирует структуру ЗначенияЗаполнения, найдет реквизиты документа с включенным свойством «Заполнять из данных заполнения» и подставит туда переданные значения.

Решение 3: Заполнение через серверную структуру (без изменения модуля объекта)

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

Посмотрим, как реализовать этот обходной сценарий правильно и безопасно:


&НаКлиенте
Процедура ПослеВыбораШаблона(РезультатВыбора)
    
    Если РезультатВыбора = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Шаг 1: Получаем все необходимые данные шаблона с сервера за один вызов
    СтруктураДанных = ПолучитьВсеДанныеШаблона(РезультатВыбора);
    
    // Шаг 2: Получаем форму нового документа (она создается пустой)
    ФормаДокумента = ПолучитьФорму("Документ.Соглашение.ФормаОбъекта");
    
    // Шаг 3: Копируем данные из структуры в реквизиты формы на клиенте
    // Важно: Мы обращаемся к реквизитам структуры, а не к ссылке базы данных! Это быстро.
    ЗаполнитьЗначенияСвойств(ФормаДокумента.Объект, СтруктураДанных);
    
    // Шаг 4: Заполняем табличную часть на клиенте
    Для Каждого СтрокаТаблицы Из СтруктураДанных.ТаблицаТовары Цикл
        НоваяСтрокаФормы = ФормаДокумента.Объект.Товары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрокаФормы, СтрокаТаблицы);
    КонецЦикла;
    
    // Шаг 5: Открываем готовую и заполненную форму пользователю
    ФормаДокумента.Открыть();
    
КонецПроцедуры

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

Этот метод уступает первому варианту в изящности, однако он полностью решает проблему «треш-вызовов» сервера, так как все данные из базы считываются за одно серверное обращение ПолучитьВсеДанныеШаблона, а на клиенте происходит лишь заполнение локальных структур формы.

Резюме и правила хорошего тона в 1С

Подводя итоги, сформулируем основные правила создания документов по шаблонам на управляемых формах 1С:

← На главную