При разработке внешних печатных форм (ВПФ) или доработке нетиповых документов в современных конфигурациях 1С (таких как «Комплексная автоматизация 2.0», ERP или «Управление торговлей 11») разработчики часто сталкиваются с неочевидным поведением системы: при нажатии на кнопку «Печать» открываются сразу две идентичные формы с табличным документом. При этом печать из формы списка работает корректно (одно окно).
В этой статье мы подробно разберем, почему возникает такая ситуация, как отличить дублирование экземпляров от дублирования вызовов, и где искать ошибку в программном коде управляемой формы.
Рассмотрим типичную ситуацию, описанную разработчиком:
Первое, что приходит в голову — ошибка в цикле вывода областей макета или неверные настройки принтера. Однако, если бы ошибка была в коде формирования (например, двойной вывод областей), мы бы получили одно окно, в котором содержимое продублировано (например, две накладные на одной странице или на двух страницах одного документа).
Если же открываются два независимых окна 1С с печатными формами — это означает, что команда «Печать» была вызвана системой дважды.
Прежде чем лезть в дебри механизмов БСП (Библиотеки Стандартных Подсистем), исключим самую простую причину. У объекта ТабличныйДокумент есть свойство КоличествоЭкземпляров. Оно отвечает за то, сколько копий будет отправлено на принтер при нажатии кнопки печати, но не должно влиять на количество открываемых окон предварительного просмотра.
Тем не менее, стоит убедиться, что мы явно не задаем это свойство, или задаем его равным 1:
ТабличныйДокумент.КоличествоЭкземпляров = 1;
Однако, как показывает практика и обсуждение проблемы, установка этого свойства не решает проблему открытия двух окон. Это подтверждает гипотезу о том, что проблема кроется в интерфейсной части, а именно в модуле формы документа.
В конфигурациях на базе БСП (КА, ERP, УТ, ЗУП) механизм печати стандартизирован. Кнопки печати обычно не добавляются вручную на форму в конфигураторе. Вместо этого они генерируются программно при открытии формы.
Давайте проанализируем, что происходит в модуле формы документа. Самая частая причина «двойной печати» — это конфликт между стандартным механизмом БСП и «ручной» самодеятельностью разработчика.
В процедуре ПриСозданииНаСервере модуля формы обычно присутствует вызов:
// Стандартный вызов БСП для подключения команд печати
УправлениеПечатью.ПриСозданииНаСервере(ЭтаФорма, Элементы.ГруппаКоманднаяПанель);
Этот код автоматически ищет все доступные команды печати (в том числе внешние печатные формы) и добавляет соответствующие кнопки в подменю «Печать».
Ошибка возникает, если разработчик, создавая нетиповой документ или модифицируя форму, сделал следующее:
УправлениеПечатью.ПриСозданииНаСервере.В результате на форме могут оказаться два механизма, реагирующие на одно действие, либо (что чаще бывает с ВПФ) при нажатии срабатывает и платформенный механизм расширений, и код, прописанный в модуле формы.
В модуле формы документов, использующих БСП, обязательно присутствует процедура для обработки нажатий на кнопки, подключенные программно. Обычно она называется Подключаемый_ВыполнитьКоманду или Подключаемый_ВыполнитьКомандуПечати.
Посмотрим на потенциально ошибочный код:
// ОШИБОЧНЫЙ ВАРИАНТ
&НаКлиенте
Процедура Подключаемый_ВыполнитьКоманду(Команда)
// Стандартный обработчик БСП
УправлениеПечатьюКлиент.ВыполнитьПодключаемуюКоманду(Команда, ЭтаФорма, Объект);
// ЛИШНИЙ КОД РАЗРАБОТЧИКА
// Если разработчик добавил сюда явный вызов своей печати, думая, что БСП не сработает
Если Команда.Имя = "ПечатьРеестра" Тогда
ОткрытьФормуПечатиМоя();
КонецЕсли;
КонецПроцедуры
Если в этом обработчике присутствует и вызов УправлениеПечатьюКлиент, и ваш собственный код открытия формы — произойдет дублирование. БСП откроет форму сама, и ваш код откроет её второй раз.
Еще одна тонкая причина связана с передачей контекста формы. Когда мы печатаем из списка, владельцем формы печати является список. Когда из документа — сам документ.
Если вы вызываете печать программно (не через БСП), обратите внимание, как вы формируете параметры открытия формы. Если вы используете метод УправлениеПечатьюКлиент.ВыполнитьКомандуПечати, убедитесь, что корректно передаете ЭтаФорма.
Если система «подумает», что один вызов идет в контексте текущего окна, а второй — создает новый контекст (из-за неверного КлючУникальности или УникальныйИдентификатор), она откроет два окна.
Чтобы устранить дублирование печати, выполним следующие действия в модуле формы документа:
ПриСозданииНаСервере.
Убедитесь, что там есть только один вызов подсистемы печати:
УправлениеПечатью.ПриСозданииНаСервере(ЭтаФорма);
Если вы вручную добавляли команды в коллекцию команд формы, проверьте, не дублируют ли они те, что подтягивает БСП.
Найдите процедуру Подключаемый_ВыполнитьКоманду. В ней должен быть только делегат в БСП. Уберите любые попытки «помочь» системе и вызвать печать явно, если там уже есть вызов УправлениеПечатьюКлиент.
&НаКлиенте
Процедура Подключаемый_ВыполнитьКоманду(Команда)
УправлениеПечатьюКлиент.ВыполнитьПодключаемуюКоманду(Команда, ЭтаФорма, Объект);
КонецПроцедуры
Иногда разработчики встраивают логику: «Если нажата кнопка Печать -> Записать документ -> Печатать». Если не сбросить флаг печати, то механизм БСП может сработать после записи еще раз.
Для полноты картины убедимся, что процедура печати в модуле менеджера (или модуля объекта ВПФ) написана корректно. Код, приведенный в исходной проблеме, в целом верен, но требует внимательного использования вызова УправлениеПечатью:
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
ПараметрыПечати = Новый Структура;
// Проверяем, нужно ли формировать именно этот макет
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "Реестр") Тогда
// Формируем табличный документ
ТабДок = СформироватьПечатнуюФормуРеестра(МассивОбъектов, ОбъектыПечати, ПараметрыПечати);
// ОДИН РАЗ добавляем его в коллекцию.
// БСП сама позаботится о том, чтобы показать его пользователю.
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"Реестр",
"Реестр почтовых отправлений",
ТабДок
);
КонецЕсли;
КонецПроцедуры
Важно: Никогда не вызывайте методы ТабДок.Показать() внутри функции печати, если вы работаете через БСП. Библиотека сама получит табличный документ из коллекции и покажет его. Если вы напишете Показать() внутри функции, вы получите первое окно от вашего кода, а второе — от БСП.
Если печать дублируется окнами (а не копиями на бумаге), проблема всегда лежит в плоскости вызова команды. В 99% случаев это конфликт ручного кода на форме и стандартных механизмов БСП. Удалите лишний код из модуля формы, доверьтесь УправлениеПечатьюКлиент, и проблема исчезнет.