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

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

В практике разработчика 1С часто возникает ситуация, когда необходимо программно создать и заполнить документ, используя уже существующие механизмы типовой конфигурации (например, ЗУП 3.1, ERP 2.5 или КА 2). Однако при анализе кода выясняется, что основная логика заполнения вынесена в общие модули, но в качестве параметра они принимают не объект документа, а УправляемуюФорму. Попытка вызвать такую процедуру напрямую с сервера приводит к ошибкам "Интерактивные операции недоступны" или несоответствию типов. Рассмотрим подробнее, почему так происходит, и разберем эффективные способы решения этой задачи.

Почему 1С требует форму для заполнения данных?

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

Решение 1: Использование метода ПолучитьФорму на клиенте

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

  1. Создаем структуру параметров для открытия формы (например, передаем ссылку, если документ уже создан, или параметры заполнения).
  2. На клиенте вызываем функцию ПолучитьФорму.
  3. Вызываем экспортную процедуру формы, которая отвечает за заполнение.
  4. Записываем форму.

Разберем пример кода для тонкого клиента:


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

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

Решение 2: Использование расширений и имитация контекста

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

Рассмотрим ситуацию, когда процедура в общем модуле выглядит так:


Процедура ЗаполнитьТабель(Форма) Экспорт
    Объект = Форма.Объект;
    // ... логика заполнения ТЧ ...
КонецПроцедуры

В таком случае мы можем создать Структуру, которая имитирует форму. Это сработает, если внутри процедуры нет жесткой проверки типа через ТипЗнч(). Мы создаем структуру, добавляем в нее ключ Объект и передаем в процедуру. Однако в сложных документах, таких как "Табель" в ЗУП, этот номер часто не проходит из-за обращения к специфическим реквизитам формы.

Решение 3: Вынос логики в собственный модуль через расширение

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

Мы можем использовать расширение конфигурации:

  1. Создаем в расширении новый серверный общий модуль.
  2. Копируем в него код типовой процедуры заполнения.
  3. Заменяем все обращения к Форма.Объект на прямые обращения к ДокументОбъект.
  4. Все обращения к реквизитам формы заменяем на параметры, которые будем передавать в процедуру.

Пример преобразованного кода:


// Было (типовая в общем модуле):
Процедура ЗаполнитьСтроки(Форма)
    Данные = Форма.Объект.Сотрудники;
    Настройка = Форма.ПоказыватьТолькоЯвки; // Реквизит формы
    // ...
КонецПроцедуры

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

Использование временного хранилища для передачи данных

Если ваша задача — передать данные из обработки в документ, который "не хочет" заполняться без формы, можно использовать Временное хранилище. Рассмотрим схему:

1. В обработке собираем данные в ТаблицуЗначений или Структуру.
2. Помещаем данные во временное хранилище: Адрес = ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификатор);.
3. Передаем Адрес в форму документа через параметры открытия.
4. В модуле формы документа, в обработчике ПриСозданииНаСервере или через ПодключаемыйОбработчик, извлекаем данные и заполняем объект.

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

Особенности работы с документом "Табель" в ЗУП 3.1

В сообщении темы упоминался именно "Табель". Этот документ крайне сложен для программного заполнения, так как он использует механизм ДанныеФормыКоллекция для работы с динамическими колонками (дни месяца). Если вы столкнулись с необходимостью программного заполнения Табеля, рекомендуется использовать методы модуля менеджера или специализированные процедуры из модуля УчетРабочегоВремениРасширенный, предварительно изучив, как они работают с объектом без привязки к интерфейсу.

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

← На главную