При разработке в 1С часто возникает задача программно сформировать печатную форму (табличный документ), сохранить ее в формате PDF и прикрепить в качестве файла к какому-либо объекту системы, например, к элементу справочника Физические лица или Сотрудники — для автоматического формирования и отправки документов персоналу есть рассылка расчетных листков сотрудникам. Разберем по шагам, как правильно реализовать данный функционал, используя встроенные возможности платформы и Библиотеки стандартных подсистем (БСП).
Проанализируем классический подход, при котором табличный документ сначала сохраняется на диск во временный файл, а затем система считывает из него данные для помещения в базу. Это простой и надежный метод, который работает на большинстве версий платформы 1С:Предприятие.
Для начала рассмотрим, как получить двоичные данные из сформированного табличного документа — для быстрого создания макетов есть конструктор шаблонов печатных форм. Ошибка многих начинающих разработчиков заключается в попытке передать сам объект ТабличныйДокумент в функцию сохранения файла. Нам же необходимо преобразовать его в ДвоичныеДанные.
// Предполагается, что ТабличныйДокумент уже сформирован и заполнен
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".pdf");
// Записываем табличный документ в файл на диске
ТабличныйДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.PDF);
// Получаем двоичные данные из сохраненного файла
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
После того как мы получили двоичные данные, их необходимо поместить во временное хранилище и передать в функцию БСП. Посмотрим на пример кода, который прикрепляет этот файл к элементу справочника:
&НаСервере
Процедура ПрикрепитьФайлКФизЛицу(ВладелецФайла, ДвоичныеДанныеФайла)
// Формируем структуру с метаданными файла
СтруктураФайла = Новый Структура;
СтруктураФайла.Вставить("Автор", Пользователи.ТекущийПользователь());
СтруктураФайла.Вставить("ВладелецФайлов", ВладелецФайла);
СтруктураФайла.Вставить("ИмяБезРасширения", "ДокументСотрудника_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd"));
СтруктураФайла.Вставить("РасширениеБезТочки", "pdf");
СтруктураФайла.Вставить("ВремяИзмененияУниверсальное", ТекущаяУниверсальнаяДата());
СтруктураФайла.Вставить("ГруппаФайлов", Справочники.Файлы.ПустаяСсылка());
СтруктураФайла.Вставить("Служебный", Ложь);
// Помещаем данные во временное хранилище
АдресВременногоХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла);
// Вызываем стандартный метод БСП для добавления файла
ПрисоединенныйФайл = РаботаСФайлами.ДобавитьФайл(СтруктураФайла, АдресВременногоХранилища);
КонецПроцедуры
Важное замечание: При использовании метода ПолучитьИмяВременногоФайла() крайне важно после выполнения всех операций удалять созданный файл с жесткого диска. Если этого не сделать, на сервере 1С каталог временных файлов начнет быстро разрастаться, что со временем приведет к нехватке свободного места. Обязательно добавляйте вызов УдалитьФайлы(ИмяВременногоФайла) в конце процедуры!
Чтобы не собирать структуру файла вручную и не использовать временное хранилище, мы можем воспользоваться более высокоуровневыми функциями БСП. Если файл уже записан на диск, можно применить метод РаботаСФайлами.ДобавитьФайлСДиска(). Выясним, как это выглядит в коде:
// Сохраняем табличный документ
ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".pdf");
ТабличныйДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.PDF);
// БСП сама прочитает двоичные данные и создаст элемент справочника присоединенных файлов
ПрисоединенныйФайл = РаботаСФайлами.ДобавитьФайлСДиска(ВладелецФайла, ИмяВременногоФайла);
// Очищаем за собой временный каталог
УдалитьФайлы(ИмяВременногоФайла);
Современный и более производительный способ — сохранять табличный документ не на жесткий диск, а напрямую в оперативную память. Проанализируем, почему этот метод лучше: он исключает проблемы с правами пользователя ОС на запись файлов в каталоги и работает значительно быстрее из-за отсутствия операций дискового ввода-вывода (I/O). Для реализации мы будем использовать объект ПотокВПамяти.
// Создаем поток в оперативной памяти
Поток = Новый ПотокВПамяти();
// Записываем табличный документ прямо в поток
ТабличныйДокумент.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
// Закрываем поток и сразу получаем готовые двоичные данные
ДвоичныеДанные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
// Помещаем в хранилище для БСП
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
// Вызываем метод БСП (СтруктураФайла формируется как в Варианте 1)
РаботаСФайлами.ДобавитьФайл(СтруктураФайла, АдресВХранилище);
Разберем несколько важных нюансов, о которых должен знать разработчик при конвертации табличного документа в PDF:
ТабличныйДокумент.Записать() в формате PDF на сервере есть системные ограничения платформы. В частности, 1С не поддерживает сохранение в PDF картинок типа «Метафайл» (WMF/EMF). Если в вашем макете присутствуют логотипы, факсимиле подписей или печати в векторных форматах, они могут просто не отобразиться в итоговом файле — решить эту проблему поможет вывод факсимиле и картинок в печатные формы. Рекомендуем использовать графику исключительно в форматах PNG или JPG.ДокументPDF. Он позволяет не просто сформировать файл, но и защитить его паролем перед сохранением. Также с его помощью можно программно "склеить" несколько разных табличных документов в один многостраничный PDF-файл, прежде чем прикрепить его к карточке сотрудника.Рассмотрим применение этих знаний на практике. Использование потоков в памяти в связке со стандартными процедурами библиотеки БСП позволит вам создавать масштабируемые и отказоустойчивые решения для хранения любых печатных форм в базе данных 1С — для оптимизации объема базы данных подойдет модуль переноса присоединенных файлов на диск.