Как программно создать прикрепленный файл из шаблона в 1С:Документооборот и заполнить его данными?

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

В процессе автоматизации бизнес-процессов часто возникает задача: в определенный момент, например, после согласования документа, необходимо автоматически создать прикрепленный к нему файл (например, Word-документ) на основе заранее подготовленного шаблона и заполнить его данными из этого документа. Рассмотрим пошагово, как реализовать этот механизм программно, проанализировав различные подходы и распространенные ошибки, с которыми сталкиваются разработчики. Если требуется настроить автоматическое добавление файлов на основе условий без изменения конфигурации, можно использовать расширение для настройки условий добавления шаблонов файлов в 1С:Документооборот 2.1.

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

Подход 1: Использование штатных процедур для получения списка файлов из шаблона

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

Давайте посмотрим на пример. Предположим, у нас есть переменная ШаблонДокумента, содержащая ссылку на нужный шаблон (например, Справочники.ШаблоныВнутреннихДокументов), и ДокументСсылка — ссылка на документ, к которому мы хотим прикрепить файлы.


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

// Заполняем таблицу данными о файлах из шаблона документа
ШаблоныДокументов.ЗаполнитьФайлыДокументаПоШаблону(ШаблонДокумента, ТаблицаФайлы, Ложь);

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

Теперь, когда у нас есть список шаблонов, нужно создать на их основе новые файлы. Самый очевидный способ — скопировать объект файла-шаблона.


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

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

Решение проблемы: Корректное копирование файла вместе с его версией

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

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

  1. Скопировать объект файла-шаблона.
  2. Получить объект его текущей версии.
  3. У скопированного объекта файла временно очистить ссылку на текущую версию. Это позволит нам сохранить его как "пустышку".
  4. Изменить владельца у объекта-версии, который мы получили на шаге 2. Новым владельцем станет наш новый, только что созданный файл.
  5. Записать измененную версию.
  6. Теперь снова получить объект нашего нового файла и присвоить ему в качестве текущей версии ту, которую мы только что перепривязали.
  7. После этого можно безопасно запускать автозаполнение.

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


// Предполагается, что ТаблицаФайлы уже заполнена, как в предыдущем примере

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

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

КонецЦикла;

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

Подход 3: Использование высокоуровневых функций БСП

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

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


// Предполагается, что переменная ФайлыШаблона содержит результат,
// аналогичный ТаблицаФайлы из прошлых примеров.
// ДокЗаявление - ссылка на документ, куда копируем файл.

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

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

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

← На главную