При разработке механизмов ввода документов на основании часто возникает задача не просто создать и открыть новый документ (например, Счет на оплату покупателю), но и сразу же вывести его печатную форму на экран или автоматически сохранить её в файл (PDF, Excel). При реализации этой логики программисты часто сталкиваются с неочевидными ошибками платформы «1С:Предприятие 8» и Библиотеки стандартных подсистем (БСП). К таким ошибкам относятся отсутствие метода Печать у объекта, блокировки изменения данных формы при передаче контекста на сервер, а также сложности с автоматическим сохранением сформированного печатного макета.
В этой статье мы подробно разберем, как правильно реализовать автоматический вывод печатной формы сразу после создания документа, выясним причины типичных ошибок работы с контекстом формы и БСП, а также рассмотрим полностью серверный вариант генерации и сохранения файлов без необходимости имитировать нажатие кнопок в пользовательском интерфейсе.
Начнем с разбора первой проблемы, с которой часто сталкиваются разработчики при попытке вызвать печать программно. Попытка получить объект документа из данных формы через функцию ДанныеФормыВЗначение и выполнить у него метод ДокОбъект.Печать(...) приводит к аварийному завершению работы кода:
// Ошибочный подход
ДокОбъект = ДанныеФормыВЗначение(Объект, Тип("ДокументОбъект.СчетНаОплатуПокупателю"));
ДокОбъект.Печать(МассивОбъектов, КоллекцияПечатныхФорм, ...); // Вызывает ошибку!
Выясним причину этого поведения. В современных типовых конфигурациях 1С (таких как Бухгалтерия предприятия, Управление торговлей, ERP и др.), построенных на базе Библиотеки стандартных подсистем (БСП), вся логика формирования печатных форм полностью отделена от объектного модуля документа ДокументОбъект.
Процедура Печать в БСП всегда располагается в модуле менеджера документа или в модуле менеджера специализированной обработки печати (например, Обработка.ПечатьСчетаНаОплату). Попытка вызвать этот метод у объекта документа всегда будет возвращать ошибку, так как в модуле объекта данной экспортной процедуры просто не существует.
Для правильного вызова процедур печати необходимо обращаться к менеджеру соответствующего объекта или использовать специализированные общие модули БСП, такие как УправлениеПечатью.
Вторая распространенная проблема возникает при передаче реквизита формы Объект на сервер для последующей обработки или получения ссылки. Рассмотрим ошибочный фрагмент кода:
&НаКлиенте
Процедура ВыполнитьКоманду()
// ... создание нового документа ...
_МассивОбъектов = ПолучитьСсылкуНаСервере(ФормаДок.Объект);
КонецПроцедуры
&НаСервере
Функция ПолучитьСсылкуНаСервере(_Объект)
ДокОбъект = ДанныеФормыВЗначение(_Объект, Тип("ДокументОбъект.СчетНаОплатуПокупателю"));
_МассивОбъектов = Новый Массив(1);
_МассивОбъектов[0] = ДокОбъект.Ссылка;
Возврат _МассивОбъектов;
КонецФункции
При выполнении этого кода платформа генерирует ошибку: «Ошибка при установке значения атрибута контекста (Объект) по причине: Нельзя изменять поле, содержащее объект данных формы». Выясним, почему это происходит.
Когда мы передаем переменную, содержащую ДанныеФормыСтруктура (в данном случае ФормаДок.Объект), в серверную функцию без явного указания способа передачи, платформа по умолчанию передает её по ссылке. В процессе выполнения функции ДанныеФормыВЗначение происходит обратная сериализация данных формы в прикладной объект. Платформа фиксирует попытку модификации или отслеживания состояния переменной контекста формы на сервере, из-за чего при возврате управления на клиент возникает конфликт блокировки данных формы.
Разберем два способа решения этой проблемы:
Знач: Если определить серверную функцию как Функция ПолучитьСсылкуНаСервере(Знач _Объект), то параметр будет передан по значению. Платформа создаст копию структуры данных формы, и исходный контекст формы на клиенте останется неизменяемым. Это решает проблему с ошибкой.ФормаДок.Записать(), у него гарантированно заполнилась ссылка. Гораздо правильнее передавать на сервер только готовую ссылку: ФормаДок.Объект.Ссылка. Передача ссылки типа ДокументСсылка вместо тяжелого объекта данных формы избавляет от ошибок и работает в разы быстрее.Если ваша задача — просто вывести печатную форму на экран пользователя так, как если бы он сам нажал кнопку «Печать» в интерфейсе формы, то наиболее правильным решением будет использование штатных клиентских методов БСП.
В модулях менеджеров документов БСП регистрирует команды печати. Для программного вызова готовой команды из кода формы воспользуемся методом УправлениеПечатьюКлиент.ВыполнитьКомандуПечати(). Рассмотрим пример реализации:
&НаКлиенте
Процедура ВыполнитьПечатьПослеСоздания(СсылкаНаДокумент, ФормаДокумента)
// Помещаем ссылку в массив, так как механизмы печати БСП всегда работают с массивами объектов
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СсылкаНаДокумент);
// Задаем параметры печати, если это необходимо (например, передаем организацию)
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("Организация", ФормаДокумента.Объект.Организация);
// Вызываем стандартную команду вывода печатной формы на экран
УправлениеПечатьюКлиент.ВыполнитьКомандуПечати(
"Обработка.ПечатьСчетаНаОплату", // Имя менеджера печати
"СчетЗаказ", // Идентификатор макета (команды печати)
МассивОбъектов, // Массив печатаемых документов
ФормаДокумента, // Владелец формы (откуда вызывается печать)
ПараметрыПечати // Дополнительные параметры
);
КонецПроцедуры
Этот способ идеален, если пользователю требуется визуально проконтролировать сформированный счет перед отправкой или печатью на принтере.
Часто в технических заданиях встречается требование: сформировать счет на оплату в фоновом режиме, автоматически преобразовать его в PDF (или другой формат) и сохранить в сетевую папку или прикрепить к электронному письму. При этом открывать форму предварительного просмотра на экране не нужно.
Попытки программно открыть форму табличного документа и имитировать интерактивное нажатие кнопки «Сохранить» — это грубая архитектурная ошибка. Платформа «1С:Предприятие» позволяет полностью сформировать макет, заполнить его данными и сохранить на диск исключительно серверными методами без привлечения клиентского интерфейса.
Рассмотрим детальный пример, как получить табличный документ печатной формы на сервере с помощью функций БСП и сохранить его на диск в формате PDF.
&НаСервере
Процедура СформироватьИСохранитьПечатнуюФормуНаСервере(СсылкаНаСчет, ПутьДляСохранения)
// Шаг 1. Подготавливаем параметры для БСП
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СсылкаНаСчет);
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("Организация", СсылкаНаСчет.Организация);
// Шаг 2. Формируем коллекцию печатных форм через серверный метод БСП.
// Функция возвращает структуру, содержащую таблицу сформированных макетов.
РезультатПечати = УправлениеПечатью.СформироватьПечатныеФормы(
"Обработка.ПечатьСчетаНаОплату", // Источник печати (менеджер или обработка)
"СчетЗаказ", // Идентификатор команды макета
МассивОбъектов, // Массив объектов назначения
ПараметрыПечати, // Параметры формирования
Новый СписокЗначений // Дополнительные параметры вывода
);
// Шаг 3. Извлекаем сформированный табличный документ
ТабличныйДокумент = Неопределено;
Для Каждого СтрокаКоллекции Из РезультатПечати.КоллекцияПечатныхФорм Цикл
Если СтрокаКоллекции.ИмяМакета = "СчетЗаказ" Тогда
ТабличныйДокумент = СтрокаКоллекции.ТабличныйДокумент;
Прервать;
КонецЕсли;
КонецЦикла;
// Шаг 4. Если табличный документ успешно получен, записываем его на диск
Если ТабличныйДокумент <> Неопределено Тогда
// Формируем уникальное имя файла, например, по номеру и дате документа
ИмяФайла = "Счет_№_" + СокрЛП(СсылкаНаСчет.Номер) + "_от_" + Формат(СсылкаНаСчет.Дата, "ДФ=ггггММдд") + ".pdf";
ПолныйПутьКФайлу = ОбъединитьПути(ПутьДляСохранения, ИмяФайла);
// Записываем файл в формате PDF на сервере
Попытка
ТабличныйДокумент.Записать(ПолныйПутьКФайлу, ТипФайлаТабличногоДокумента.PDF);
ЗаписьЖурналаРегистрации("ПечатьДокументов",
УровеньЖурналаРегистрации.Информация,
,
,
"Файл успешно сохранен: " + ПолныйПутьКФайлу);
Исключение
ВызватьИсключение "Не удалось сохранить печатную форму в файл! Ошибка: " + ОписаниеОшибки();
КонецПопытки;
Иначе
ВызватьИсключение "Не удалось сформировать табличный документ для макета СчетЗаказ.";
EndIf;
КонецПроцедуры
Если печатная форма «СчетЗаказ» реализована не в основной конфигурации, а подключена как внешняя печатная форма (ВПФ) через справочник «Дополнительные отчеты и обработки», стандартный вызов через общие модули БСП напрямую не сработает.
Для программного формирования внешних печатных форм на сервере в БСП предусмотрен специальный метод. Разберем, как его использовать:
&НаСервере
Функция СформироватьВнешнююПечатнуюФорму(СсылкаНаДокумент, СсылкаНаВнешнююОбработку)
// Подготавливаем структуру параметров для внешней обработки
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СсылкаНаДокумент);
ПараметрыИсточника = Новый Структура;
ПараметрыИсточника.Вставить("ИдентификаторКоманды", "СчетЗаказ"); // Идентификатор команды из ВПФ
ПараметрыИсточника.Вставить("ДополнительныеПараметры", Новый Структура);
// Вызываем экспортную функцию подсистемы ДополнительныеОтчетыИОбработки
Результат = ДополнительныеОтчетыИОбработки.ПечатьПоВнешнемуИсточнику(
СсылкаНаВнешнююОбработку, // Ссылка на элемент справочника дополнительных обработок
ПараметрыИсточника,
МассивОбъектов
);
// Возвращаем сформированный табличный документ из коллекции результатов
Если Результат.КоллекцияПечатныхФорм.Количество() > 0 Тогда
Возврат Результат.КоллекцияПечатныхФорм[0].ТабличныйДокумент;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Полученный таким образом табличный документ вы точно так же можете записать в любой необходимый формат с помощью метода Записать() на сервере или передать во временное хранилище для отправки клиенту.
Подведем итоги нашего разбора:
Печать напрямую у объекта документа ДокументОбъект — вся логика печати БСП инкапсулирована в модулях менеджеров.ДокументСсылка), а не весь объект данных формы (ДанныеФормыСтруктура). Если передача объекта неизбежна, обязательно используйте директиву передачи параметров Знач.УправлениеПечатьюClient.ВыполнитьКомандуПечати().УправлениеПечатью.СформироватьПечатныеФормы() и стандартный платформенный метод записи табличного документа ТабличныйДокумент.Записать(Путь, ТипФайла).