В процессе разработки часто возникает задача не просто сформировать печатную форму, но и зафиксировать факт её реальной отправки на принтер. Это необходимо для ведения учета расхода бланков строгой отчетности, предотвращения дублирования печати или в целях безопасности. Однако стандартная платформа 1С имеет определенные ограничения: она легко фиксирует нажатие кнопки в интерфейсе, но «не видит», что происходит в системном диалоге печати Windows. В этой статье мы подробно разберем, как преодолеть эти ограничения, используя различные подходы — от встроенных средств 1С до системных инструментов Windows.
Давайте проанализируем ситуацию. Когда пользователь выбирает в меню Файл — Печать, управление передается операционной системе. 1С передает сформированный ТабличныйДокумент в распоряжение Windows Print Spooler (диспетчер очереди печати). С этого момента встроенный язык 1С по умолчанию не получает обратной связи о том, нажал ли пользователь «ОК» в диалоге выбора принтера или нажал «Отмена». Более того, даже если печать была запущена, бумага могла застрять, или пользователь мог выбрать виртуальный принтер для сохранения в PDF. Для решения этой задачи нам потребуется рассмотреть несколько уровней контроля.
Если в вашей конфигурации используется Библиотека стандартных подсистем (БСП), то первым делом нам стоит обратить внимание на механизмы формирования печатных форм. Это самый простой, но не самый точный метод, так как он фиксирует намерение напечатать, а не сам факт выхода бумаги.
Рассмотрим алгоритм действий в модуле менеджера объекта:
Печать в модуле менеджера документа.&ИзменениеИКонтроль или &После для встраивания своего кода.Пример реализации в модуле менеджера:
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// Стандартный код формирования печатных форм
// ...
// Наш код для фиксации события
Для Каждого СсылкаНаДокумент Из МассивОбъектов Цикл
ФиксироватьСобытиеПечати(СсылкаНаДокумент);
КонецЦикла;
КонецПроцедуры
Процедура ФиксироватьСобытиеПечати(ДокументСсылка)
НоваяЗапись = РегистрыСведений.ИсторияПечатиДокументов.СоздатьМенеджерЗаписи();
НоваяЗапись.Объект = ДокументСсылка;
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Пользователь = Пользователи.ТекущийПользователь();
НоваяЗапись.Записать();
КонецПроцедуры
Важный момент: этот код сработает в момент формирования табличного документа на сервере. Если пользователь закроет окно предпросмотра, не распечатав его, признак «Была печать» все равно будет проставлен. Для более точного контроля перейдем к следующему методу.
Чтобы исключить неопределенность системного диалога, мы можем программно управлять процессом вывода на принтер. Рассмотрим, как заставить 1С сразу отправлять документ на принтер, минуя стандартное окно выбора.
Для этого используется метод Напечатать() объекта ТабличныйДокумент с параметром РежимИспользованияДиалогаПечати.НеИспользовать. В этом случае, если код выполнился без ошибок, мы можем быть уверены, что задание ушло в очередь печати Windows.
ТабДок = СформироватьПечатнуюФорму(Ссылка);
// Устанавливаем принтер по умолчанию или программно выбираем нужный
ТабДок.ИмяПринтера = "HP LaserJet Pro M402";
// Отправляем на печать без вызова диалога
ТабДок.Напечатать(РежимИспользованияДиалогаПечати.НеИспользовать);
// Если выполнение дошло до этой строки, задание отправлено в спулер
ЗафиксироватьФактОтправкиВРегистр(Ссылка);
Этот способ позволяет избежать «человеческого фактора» при выборе принтера, но требует предварительной настройки имен принтеров в системе или в константах 1С.
Проанализируем более продвинутый способ, который позволяет отследить судьбу задания в самой операционной системе. Мы можем использовать COM-объект WbemScripting.SWbemLocator для подписки на события создания записей в системном классе Win32_PrintJob. Это позволит 1С «увидеть», появилось ли задание в очереди печати и с каким статусом оно завершилось.
Рассмотрим пример кода, который можно запустить в обработчике ожидания или фоновом задании:
Locator = Новый COMОбъект("WbemScripting.SWbemLocator");
Service = Locator.ConnectServer(".", "root\cimv2");
// Запрос к очереди печати
Jobs = Service.ExecQuery("SELECT * FROM Win32_PrintJob");
Для Каждого Job Из Jobs Цикл
// Job.Document содержит имя документа (заголовок окна в 1С)
// Job.JobStatus — текущий статус (Printing, Spooling, Error)
// Job.PagesPrinted — количество фактически напечатанных страниц
Если Найти(Job.Document, "Счет-фактура №123") > 0 Тогда
Сообщить("Документ в очереди. Статус: " + Job.JobStatus);
КонецЕсли;
КонецЦикла;
Этот метод является наиболее надежным с программной точки зрения, так как он работает напрямую с системным диспетчером печати. Мы можем получить информацию о количестве напечатанных страниц и даже об ошибках принтера (отсутствие бумаги или замятие).
Если нам нужно подтвердить факт печати постфактум, мы можем проанализировать журнал событий Windows. Система фиксирует успешное завершение заданий печати в журнале PrintService/Operational с событием ID 307.
Разберем, как считать эти данные из 1С с помощью PowerShell:
КомандаPS = "Get-WinEvent -LogName 'Microsoft-Windows-PrintService/Operational' | Where-Object {$_.Id -eq 307}";
ЗапуститьПриложение("powershell.exe -Command " + КомандаPS);
В логе содержится точное время, имя пользователя, имя принтера и количество страниц. Интегрировав парсинг этого лога в 1С, мы получим неопровержимое доказательство того, что документ вышел из принтера.
Выясним, как предотвратить ситуацию, когда пользователь вместо печати сохраняет документ в файл (например, PDF или Excel), обходя систему контроля. В 1С есть встроенное свойство табличного документа, которое позволяет запретить любые действия, кроме просмотра и печати.
Используйте свойство Защита:
ТабДок = СформироватьПечатнуюФорму(Ссылка);
ТабДок.Защита = Истина; // Запрещает редактирование и копирование
ТабДок.ТолькоПросмотр = Истина;
// Теперь пользователь сможет только отправить на принтер, но не сохранить как...
Дополнительно рекомендуется программно скрывать стандартное главное меню 1С через настройки прав доступа или интерфейса, чтобы исключить использование системной команды Файл — Сохранить как.
Подводя итог, можно выделить три уровня контроля печати, которые мы разобрали:
Win32_PrintJob. Позволяет точно знать, что задание ушло на конкретный принтер.Для большинства бизнес-задач оптимальным является сочетание Метода 2 (программная отправка без диалога) и Метода 5 (установка защиты табличного документа). Если же требуется строгий аудит, необходимо внедрять мониторинг через WMI.