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