При разработке внешних печатных форм (ВПФ) программисты часто сталкиваются с ситуацией, когда механизм печати используется не по прямому назначению. Например, необходимо по кнопке «Печать» не выводить бумажную форму, а выполнить какое-то действие: отправить данные в стороннюю систему, создать связанный документ или, как в нашем случае, открыть письмо в Outlook с заполненными данными о заказе. Однако при использовании стандартного шаблона ВПФ система 1С настойчиво открывает пустое окно предварительного просмотра, которое мешает пользователю. Разберем подробно, почему это происходит и как правильно реализовать задачу без лишних окон.
Проанализируем работу Библиотеки стандартных подсистем (БСП). Когда мы регистрируем внешнюю обработку с видом ПечатнаяФорма и указываем способ использования ВызовСерверногоМетода, система ожидает, что экспортная процедура Печать в модуле объекта заполнит коллекцию печатных форм хотя бы одним табличным документом.
Если мы просто выполняем код (например, запуск COM-объекта Outlook) и не возвращаем ТабличныйДокумент, БСП выдает исключение в общем модуле УправлениеПечатью. Если же мы возвращаем пустой ТабличныйДокумент, система считает свою работу выполненной и открывает стандартную форму предварительного просмотра, которая в данном случае оказывается пустой. Рассмотрим, как этого избежать.
Это самый правильный и архитектурно верный способ с точки зрения БСП. Если ваша задача — выполнить алгоритм без вывода макета на экран, то использование категории «Печатная форма» является семантической ошибкой. Нам следует изменить тип обработки на ЗаполнениеОбъекта. В этом случае кнопка появится не в подменю «Печать», а в меню «Изменить» или «Заполнение», и система не будет ожидать возврата печатных форм.
Рассмотрим, как изменить функцию СведенияОВнешнейОбработке:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.3.1.73");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта();
ПараметрыРегистрации.Назначение.Добавить("Документ.уатЗаказГрузоотправителя");
ПараметрыРегистрации.Наименование = "Отправка заказа в Outlook";
ПараметрыРегистрации.Версия = "1.2";
ПараметрыРегистрации.БезопасныйРежим = Ложь;
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Отправить инфо руководителю";
НоваяКоманда.Идентификатор = "ОтправитьOutlook";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
НоваяКоманда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
В этом случае в модуле объекта вместо процедуры Печать необходимо использовать процедуру ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив). После завершения этой процедуры никакие окна печати открываться не будут.
Если заказчик настаивает на том, чтобы кнопка находилась именно в меню Печать, нам придется обойти механизмы БСП. Для этого в параметрах регистрации команды укажем использование ВызовКлиентскогоМетода. Это позволит нам полностью контролировать процесс на стороне клиента и завершить выполнение кода до того, как в дело вступит типовое управление печатью.
Выполним следующие шаги:
СведенияОВнешнейОбработке укажем ТипКомандыВызовКлиентскогоМетода().Печать.Посмотрим на пример реализации в модуле формы:
&НаКлиенте
Процедура Печать(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
// Выполняем логику по запуску Outlook
Для Каждого СсылкаНаОбъект Из ОбъектыНазначенияМассив Цикл
Попытка
Outlook = Новый COMОбъект("Outlook.Application");
Письмо = Outlook.CreateItem(0);
Письмо.Subject = "Информация по заказу: " + СсылкаНаОбъект;
// Здесь можно вызвать серверный метод для получения данных заказа
Письмо.Body = ПолучитьТекстПисьмаНаСервере(СсылкаНаОбъект);
Письмо.Display(); // Отображаем письмо пользователю
Исключение
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка при запуске Outlook: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
// Важный момент: мы просто завершаем процедуру.
// Поскольку это клиентский вызов обработки, БСП не ждет возврата ТабДока.
КонецПроцедуры
Если вы все же используете ВызовСерверногоМетода в рамках Вид = ПечатнаяФорма, попробуйте проанализировать структуру ПараметрыВывода. В некоторых версиях БСП можно установить параметр ПараметрыВывода.ДополнительныеПараметрыПечати или попытаться очистить КоллекцияПечатныхФорм непосредственно перед выходом из процедуры, но это часто приводит к ошибке «В обработчике печати не был сформирован табличный документ», так как стандартный код БСП делает проверку:
Если ПечатнаяФорма.ТабличныйДокумент = Неопределено Тогда
// Вызов исключения, который мы видели в Сообщении 3
КонецЕсли;
Следовательно, если мы остаемся в рамках серверного вызова печатной формы, нам обязательно нужно вернуть ТабличныйДокумент, а значит, окно печати неизбежно откроется. Именно поэтому Решение №1 и Решение №2 являются единственно рабочими для того, чтобы убрать лишний макет.
Разберем важный нюанс, упомянутый в обсуждении. Использование Письмо.Display() открывает окно Outlook поверх 1С. Если ваша задача — отправить письмо мгновенно без участия пользователя, используйте Письмо.Send().
Важно: При работе в серверном контексте (ВызовСерверногоМетода) COM-объект будет пытаться создаться на сервере приложений 1С. Это сработает только если Outlook установлен непосредственно на сервере и у пользователя, под которым запущена служба 1С, есть соответствующие права. В 99% случаев запуск Outlook нужно делать на клиенте (через ВызовКлиентскогоМетода), так как почтовый клиент установлен на рабочем месте пользователя.
Проанализируем итоговый алгоритм действий для исправления вашей ситуации:
СведенияОВнешнейОбработке тип на ЗаполнениеОбъекта.Печать() в ВыполнитьКоманду() в модуле объекта.ТабличныйДокумент и его возврат.Использование правильных типов метаданных для внешних обработок — залог стабильной работы системы и отсутствия "костылей" в коде.