В процессе разработки в среде 1С:Предприятие 8.3 на управляемых формах часто возникает задача автоматического или полуавтоматического сохранения отчетов в файл формата PDF. Это может быть связано с необходимостью отправки прайс-листов клиентам, выгрузки актов сверки или архивации управленческой отчетности. Однако разработчики нередко сталкиваются со странной проблемой: код выполняется без ошибок, диалоговое окно сохранения отрабатывает штатно, но сформированный файл PDF оказывается абсолютно пустым.
В рамках этой статьи мы подробно разберем, почему возникает данная ошибка, в чем разница между элементами интерфейса и данными формы, а также рассмотрим универсальные механизмы сохранения отчетов как на клиенте, так и полностью на стороне сервера.
Проанализируем ситуацию, с которой часто сталкиваются начинающие программисты. Посмотрим на код, который изначально написал автор темы на форуме:
&НаКлиенте
Процедура СохранитьВФайл(Команда)
Режим = РежимДиалогаВыбораФайла.Сохранение;
ДиалогСохраненияФайла = Новый ДиалогВыбораФайла(Режим);
ДиалогСохраненияФайла.ПолноеИмяФайла = "Прайс";
Фильтр = "Документ PDF (*.pdf)|*.pdf";
ДиалогСохраненияФайла.Фильтр = Фильтр;
ДиалогСохраненияФайла.МножественныйВыбор = Ложь;
ДиалогСохраненияФайла.Заголовок = "Выберите файл";
Если ДиалогСохраненияФайла.Выбрать() Тогда
ТабДокумент = Новый ТабличныйДокумент();
ПутьКФайлу = ДиалогСохраненияФайла.ПолноеИмяФайла;
ТабДокумент.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
КонецЕсли;
КонецПроцедуры
Выясним причину, по которой этот код генерирует пустой файл. Обратите внимание на следующую строку:
ТабДокумент = Новый ТабличныйДокумент();
Этой инструкцией мы создаем в оперативной памяти абсолютно новый, чистый и незаполненный объект типа ТабличныйДокумент. Наша программа никак не связывает этот новый объект с тем отчетом СКД, который пользователь уже сформировал на экране. Далее метод Записать() честно переносит этот пустой документ в указанный файл PDF. Логично, что на выходе получается документ нулевого размера.
Пытаясь исправить ошибку, разработчики часто пробуют обратиться к элементам формы напрямую через коллекцию элементов:
ТабДокумент = Элементы.Результат;
После написания такой строки платформа выдает ошибку о том, что метод Записать() недоступен. Почему так происходит? Разберем разницу между реквизитами формы (данными) и элементами формы (визуальным представлением):
Элементы) — это элементы управления пользовательского интерфейса. Например, поле табличного документа на форме. У этого объекта нет метода для записи в файл, так как его задача — просто отображать данные на экране и реагировать на действия пользователя.Результат, который имеет тип ТабличныйДокумент. Именно в него СКД выводит результат компоновки данных.Поэтому обращаться нужно непосредственно к реквизиту формы Результат, минуя коллекцию Элементы.
Для того чтобы успешно сохранить уже сформированный на экране отчет, нам достаточно вызвать метод Записать() у реквизита Результат. Ниже приведен рабочий, протестированный код клиентской процедуры:
&НаКлиенте
Процедура СохранитьВФайл(Команда)
Режим = РежимДиалогаВыбораФайла.Сохранение;
ДиалогСохраненияФайла = Новый ДиалогВыбораФайла(Regim);
ДиалогСохраненияФайла.ПолноеИмяФайла = "Прайс-лист";
Фильтр = "Документ PDF (*.pdf)|*.pdf";
ДиалогСохраненияФайла.Фильтр = Фильтр;
ДиалогСохраненияФайла.МножественныйВыбор = Ложь;
ДиалогСохраненияФайла.Заголовок = "Выберите путь для сохранения отчета";
Если ДиалогСохраненияФайла.Выбрать() Тогда
ПутьКФайлу = ДиалогСохраненияФайла.ПолноеИмяФайла;
// Обращаемся напрямую к реквизиту формы "Результат"
Результат.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
ПоказатьПредупреждение(, "Отчет успешно сохранен в формат PDF!");
КонецЕсли;
КонецПроцедуры
На практике задача часто усложняется: нам требуется формировать отчет СКД и сохранять его в PDF автоматически, например, в фоновом задании по расписанию для последующей рассылки по электронной почте. В этом случае у нас нет открытой формы и реквизита Результат.
Рассмотрим подробнее, как программно сгенерировать отчет СКД "с нуля" на стороне сервера и сохранить его в файл:
&НаСервереБезКонтекста
Процедура СформироватьОтчетВPDFНаСервере(ИмяОтчета, ПутьКФайлу)
// 1. Получаем объект отчета и его схему компоновки
ОтчетОбъект = Отчеты[ИмяОтчета].Создать();
СхемаКомпоновкиДанных = ОтчетОбъект.СхемаКомпоновкиДанных;
// 2. Получаем настройки отчета по умолчанию
Настройки = ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки();
// 3. Создаем макет компоновки с помощью компоновщика макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, , , ТипГенератораМакетаКомпоновкиДанных.ВыводВТабличныйДокумент);
// 4. Инициализируем процессор компоновки данных для обработки бизнес-логики и запросов
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки);
// 5. Создаем результирующий табличный документ в памяти сервера
ТабДок = Новый ТабличныйДокумент;
// 6. Выводим результат компоновки в созданный табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
// Настраиваем параметры вывода для эстетичного отображения в PDF
ТабДок.АвтоМасштаб = Истина;
ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
// 7. Записываем табличный документ в файл на диске сервера
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
КонецПроцедуры
Просто сохранить отчет в PDF недостаточно. Если табличный документ содержит много колонок, он может хаотично разбиться на десятки страниц по ширине, превратив итоговый PDF в нечитаемый набор листов. Перед вызовом метода Записать() настоятельно рекомендуется программно управлять свойствами страницы:
АвтоМасштаб = Истина; принудительно масштабирует отчет по ширине страницы так, чтобы все колонки поместились на одном листе. Это избавляет от необходимости ручной настройки полей пользователем.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;.ПолеСверху, ПолеСнизу, ПолеСлева и ПолеСправа (значения указываются в миллиметрах).Пример подготовки параметров печати перед сохранением:
ТабДокумент.АвтоМасштаб = Истина;
ТабДокумент.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт;
ТабДокумент.ПолеСлева = 10; // отступ 10 мм слева
ТабДокумент.ПолеСправа = 10; // отступ 10 мм справа
ТабДокумент.ПолеСверху = 15; // отступ 15 мм сверху для заголовка
ТабДокумент.ПолеСнизу = 10; // отступ 10 мм снизу
Если ваша база 1С развернута в клиент-серверном варианте, а сервер функционирует под управлением операционной системы семейства Linux, при выгрузке отчетов в PDF на стороне сервера вы можете столкнуться со следующими проблемами:
Причина проблемы: Платформа 1С при формировании PDF на стороне сервера пытается использовать системные шрифты (например, Arial, Times New Roman, Calibri), прописанные в макете СКД. Если этих шрифтов нет в каталогах операционной системы Linux (по умолчанию они отсутствуют, так как защищены лицензиями Microsoft), платформа заменяет их на альтернативные или не может корректно обработать кодировку.
Решение:
sudo apt-get install ttf-mscorefonts-installer для дистрибутивов Debian/Ubuntu)./usr/share/fonts/truetype/ на сервере 1С.fc-cache -f -v.usr1cv8), чтобы платформа зафиксировала появление новых системных шрифтов.Начиная со средних релизов платформы 8.3, в 1С появилась поддержка расширенных форматов сохранения файлов PDF. Вместо стандартного типа ТипФайлаТабличногоДокумента.PDF вы можете использовать константы для архивного хранения:
ТипФайлаТабличногоДокумента.PDF_A_1 — гарантирует, что все используемые в отчете шрифты и цветовые профили будут жестко интегрированы (вшиты) внутрь самого PDF-файла. Такой документ откроется одинаково корректно на любом устройстве, даже если на нем не установлены исходные шрифты.ТипФайлаТабличногоДокумента.PDF_A_3 — современный стандарт, который помимо встраивания шрифтов позволяет прикреплять к PDF-документу другие файлы в виде вложений (например, XML-файл электронного первичного документа или счета).Использование стандартов PDF/A является хорошим тоном при проектировании систем автоматического документооборота и гарантирует долговечность отображения ваших отчетов СКД в неизменном виде.