В процессе разработки автоматизированных систем на базе 1С часто возникает задача реализации регламентной печати. Типичный пример: регламентное задание должно собрать данные, сформировать накладные или этикетки и отправить их на принтер без участия пользователя. Однако программисты сразу сталкиваются с жестким ограничением платформы: метод ТабличныйДокумент.Напечатать() доступен только на клиенте. Попытка вызвать его на сервере приведет к ошибке, так как серверный контекст не имеет доступа к графической подсистеме и интерфейсу драйверов принтера в интерактивном режиме.
В этой статье мы подробно разберем, как обойти это ограничение, рассмотрим архитектурные подходы и выберем наиболее надежные инструменты для работы как в среде Windows, так и на Linux-серверах.
Прежде чем переходить к решениям, разберем причину проблемы. Объект ТабличныйДокумент на сервере — это лишь структура данных в памяти. Метод Напечатать() требует взаимодействия с очередью печати операционной системы (Print Spooler), выбора принтера через диалоговое окно или использования настроек по умолчанию из профиля пользователя. Служба сервера 1С (обычно usr1cv8) работает в так называемой «Сессии 0», которая изолирована от рабочего стола и пользовательского интерфейса. Именно поэтому нам требуются «обходные пути», которые позволят передать сформированный документ в операционную систему для вывода на печать.
Это самый популярный и стабильный метод. Общая схема выглядит так: формируем ТабличныйДокумент, сохраняем его во временный PDF-файл и вызываем внешнюю утилиту, которая умеет отправлять PDF на принтер в «тихом» режиме через командную строку.
Рассмотрим по шагам реализацию этого механизма. Сначала подготовим файл на сервере:
// Формируем табличный документ
ТабДок = Новый ТабличныйДокумент;
// ... заполнение документа данными ...
// Сохраняем во временный файл в формате PDF
ИмяФайла = ПолучитьИмяВременногоФайла("pdf");
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.PDF);
Теперь проанализируем инструменты для печати полученного PDF. Нам понадобятся бесплатные консольные утилиты, такие как PDFtoPrinter или SumatraPDF.
Вариант А: PDFtoPrinter. Эта крошечная программа специально создана для печати из командной строки. Она крайне проста в использовании. Пример вызова из 1С:
ПутьКУтилите = "C:\Utilities\PDFtoPrinter.exe";
ИмяПринтера = "\\Server\HP_LaserJet_400"; // Можно указать сетевое имя
КомандаЗапуска = СтрШаблон("%1 ""%2"" ""%3""", ПутьКУтилите, ИмяФайла, ИмяПринтера);
// Запускаем приложение на сервере
ЗапуститьПриложение(КомандаЗапуска, , Истина);
Вариант Б: SumatraPDF. Более универсальный просмотрщик, поддерживающий ключи командной строки. Команда будет выглядеть так: SumatraPDF.exe -print-to "ИмяПринтера" -silent "путь_к_файлу". Этот метод хорош тем, что SumatraPDF очень корректно обрабатывает сложные шрифты и масштабирование. Для пакетного вывода графических файлов в аналогичном консольном режиме можно использовать решение для пакетной печати с помощью утилиты IrfanView.
Если ваш сервер 1С работает под управлением Linux, использование Windows-утилит невозможно. Однако в Linux задача решается еще проще благодаря стандартной системе печати CUPS, а реализация инфраструктуры на базе Astra Linux позволит автоматизировать процесс. Мы воспользуемся встроенной командой lp или lpr.
Проанализируем пример кода для Linux-сервера:
// Сохраняем файл
ИмяФайла = "/tmp/doc_to_print.pdf";
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.PDF);
// Формируем команду для системы печати CUPS
// -d указывает на имя принтера
ИмяПринтера = "Zebra_Label_Printer";
Команда = СтрШаблон("lp -d %1 %2", ИмяПринтера, ИмяФайла);
// Выполняем команду через оболочку
ЗапуститьПриложение(Команда, , Истина);
Важный нюанс: Убедитесь, что пользователь usr1cv8, от имени которого запущен процесс rphost, имеет права на выполнение команд печати и принтер виден в системе через команду lpstat -p.
Если использование внешних утилит по каким-то причинам запрещено политикой безопасности, можно реализовать архитектуру с выделенным сеансом 1С. Выясним, как это работает:
ОчередьПечати) с ресурсом типа ХранилищеЗначения, куда будем сохранять ТабличныйДокумент, полученный через механизмы БСП.ОчередьПечати.ТабличныйДокумент и выполняет штатный метод ТабДок.Напечатать(Ложь).Этот способ является наиболее «нативным» для 1С, так как печать происходит в клиентском контексте, где доступны все установленные драйверы и настройки принтера по умолчанию, что позволяет реализовать полноценную групповую печать. Для автоматизации вывода стандартных форм подойдет обработка для печати любых печатных форм БСП.
Пример кода для клиентского «обработчика»:
&НаКлиенте
Процедура ПроверитьОчередьПечати()
ЗаписьОчереди = ПолучитьЗаписьИзРегистраНаСервере();
Если ЗаписьОчереди <> Неопределено Тогда
ТабДок = ЗаписьОчереди.Данные.Получить();
Если ТабДок <> Неопределено Тогда
ТабДок.Напечатать(Ложь); // Печать без диалога
УдалитьЗаписьИзОчередиНаСервере(ЗаписьОчереди.Ключ);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Рассмотрим ситуацию с печатью этикеток. Часто при конвертации в PDF качество штрихкодов падает. Чтобы избежать этого, можно использовать прямую отправку команд на языке принтера (например, ZPL для Zebra). В этом случае нам вообще не нужен ТабличныйДокумент.
Мы формируем текстовую строку с командами управления и отправляем её напрямую в порт принтера (обычно TCP 9100) или через обертку командной строки copy file.txt \\server\printer. Это гарантирует идеальную четкость печати, так как используются встроенные шрифты принтера.
При реализации серверной печати необходимо учитывать несколько критических факторов, без которых решение не заработает:
usr1cv8 должен обладать правами на запуск внешних приложений (настройка в консоли администрирования кластера — «Разрешить запуск внешних программ»).\\server\printer, иначе служба сервера 1С может его «не увидеть».ТабличныйДокумент при сохранении в PDF может сильно исказиться: колонки «поедут», а текст выйдет за границы ячеек.PDFtoPrinter.exe doc.pdf > log.txt 2>&1.Подведем итог. Наиболее универсальным и рекомендуемым способом для Windows-инфраструктуры является связка 1С + PDF + PDFtoPrinter. Для кроссплатформенных решений или при жестких ограничениях безопасности лучше выбрать метод с выделенным клиентским сеансом, который будет выполнять роль диспетчера печати.