Как программно заполнить и записать документ без открытия его формы

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

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

Почему попытка открыть форму «невидимо» — это ошибка проектирования

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

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

Способ 1: Программное создание объекта на сервере

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


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

КонецПроцедуры

В данном примере мы работаем непосредственно с данными. Это происходит быстро, надежно и не требует открытия никаких окон. Пользователь даже не заметит процесса, пока не получит уведомление об успешном завершении.

Способ 2: Использование механизма «ОбработкаЗаполнения»

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

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

Шаг 1. В модуле объекта документа прописываем логику:


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

Шаг 2. Вызываем создание объекта из формы справочника:


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

Способ 3: Вынос логики в Модуль менеджера

Бывают случаи, когда алгоритм заполнения уже написан в модуле формы документа, и разработчику лень его переписывать. Однако, как мы выяснили, вызывать методы формы без её открытия нельзя. Правильным решением будет рефакторинг: вынесем общую логику в Модуль менеджера документа или в Общий модуль.

Рассмотрим пример организации кода:

  1. Создаем в модуле менеджера процедуру с ключевым словом Экспорт.
  2. Передаем в неё созданный объект или просто необходимые параметры.
  3. Вызываем эту процедуру как из формы (для интерактивной работы), так и из серверного кода (для автоматического создания).

Пример кода в модуле менеджера:


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

Теперь эту процедуру можно вызвать откуда угодно, передав туда ДокументОбъект, полученный через СоздатьДокумент().

Как правильно передать данные, если форму ВСЕ ЖЕ нужно открыть

Если задача стоит так: «Заполнить данные программно, НО показать их пользователю для проверки перед записью», то вместо открытия «пустой» формы и попыток её заполнить «снаружи», следует использовать параметры формы.

Посмотрим на пример правильного вызова формы с предварительным заполнением:


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

В этом случае платформа сама вызовет ОбработкаЗаполнения на сервере, создаст документ, заполнит его и откроет пользователю уже готовое, заполненное окно. Это исключает необходимость в невидимых формах и каскадных вызовах кода.

Подведение итогов

Подведем итог нашему анализу:

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

← На главную