Как заставить внешние печатные формы 1С запрашивать проведение документа перед печатью после обновления на 22 ветку?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с платформой 1С:Предприятие 8.3, особенно после обновления до так называемой "22 ветки" (или других актуальных версий, включающих последние изменения Библиотеки Стандартных Подсистем – БСП), многие разработчики и пользователи сталкиваются с изменением поведения внешних печатных форм (ВПФ). В частности, после обновления ВПФ, подключенные через механизм "Дополнительные отчеты и обработки", перестают запрашивать подтверждение проведения документа перед его печатью. Это приводит к тому, что непроведенные документы могут быть напечатаны без соответствующего предупреждения, что часто является нежелательным поведением.

Стандартный подход, заключающийся в установке свойства КомандаПечати.ПроверкаПроведенияПередПечатью = Истина в описании сведений о внешней обработке, к сожалению, перестает давать ожидаемый результат. Давайте рассмотрим, почему это происходит и как мы можем восстановить желаемое поведение.

Понимание корневой причины: изменения в подсистеме печати БСП

Чтобы эффективно решить проблему, мы должны сначала понять ее причину. Изменение поведения ВПФ, когда они перестают запрашивать проведение, скорее всего, связано с оптимизацией или изменением архитектуры подсистемы печати в БСП. Разработчики 1С постоянно работают над улучшением гибкости и унификации механизмов работы различных форм и обработок. Эти изменения, хотя и направлены на общее улучшение системы, иногда требуют от разработчиков внешних решений адаптации их кода к новым механизмам.

В более ранних версиях БСП, установка свойства ПроверкаПроведенияПередПечатью для команды печати часто было достаточным. Система автоматически перехватывала вызов печати непроведенного документа и выводила стандартный диалог с предложением провести документ. Однако в новых версиях этот механизм мог быть пересмотрен, особенно для внешних обработок, которые не являются частью основной конфигурации и подключаются динамически. Теперь для ВПФ может потребоваться более явное управление процессом печати.

Исходный подход и почему он перестал работать

Ранее мы привыкли, что для активации запроса на проведение перед печатью достаточно было в процедуре СведенияОВнешнейОбработке добавить или установить свойство для команды печати, например так:


Функция СведенияОВнешнейОбработке() Экспорт
    РегистрационныеДанные = Новый Структура;
    // ... другие параметры обработки
    
    КомандаПечати = РегистрационныеДанные.Команды.Добавить();
    КомандаПечати.Идентификатор = "МояПечатнаяФорма";
    КомандаПечати.Представление = "Печать моей формы";
    КомандаПечати.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода(); // Или другой тип
    КомандаПечати.ПроверкаПроведенияПередПечатью = Истина; // Это свойство перестало работать для ВПФ
    
    // ...
    
    Возврат РегистрационныеДанные;
КонецФункции

В "22 ветке" и последующих версиях для внешних печатных форм это свойство перестало влиять на появление диалога подтверждения проведения. Система теперь по-другому обрабатывает вызовы печати для ВПФ, часто игнорируя эту директиву или обрабатывая ее только для встроенных в конфигурацию форм.

Решение проблемы: комплексный подход на основе информации с багборда и доработка ВПФ

Как показывает опыт участников форума, решение было найдено благодаря информации, опубликованной на "багборде" (система отслеживания ошибок и предложений разработчиков 1С). Это решение подразумевает перехват вызова печати на стороне клиента внешней печатной формы и реализацию собственной логики проверки и запроса проведения. Давайте разберем этот процесс по шагам.

Шаг 1: Модификация процедуры СведенияОВнешнейОбработке

Первым шагом является изменение типа использования команды печати в процедуре СведенияОВнешнейОбработке вашего внешнего отчета или обработки. Вместо прямого вызова серверного метода или использования других типов, нам потребуется установить Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода(). Это позволит нам "перехватить" управление процессом печати на клиенте, прежде чем будут вызваны стандартные серверные процедуры.

  1. Откройте модуль объекта вашей внешней печатной формы.

  2. Найдите функцию СведенияОВнешнейОбработке(). В этой функции описываются метаданные вашей обработки, включая команды печати.

  3. Измените или добавьте команду печати так, чтобы ее свойство Использование было установлено в ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода(). Также важно указать уникальный Идентификатор для вашей команды.

Посмотрим на пример кода:


Функция СведенияОВнешнейОбработке() Экспорт
    РегистрационныеДанные = Новый Структура;
    РегистрационныеДанные.Вставить("Вид", "ДополнительнаяОбработка"); // Или "ДополнительныйОтчет"
    РегистрационныеДанные.Вставить("Наименование", "МояВПФ");
    РегистрационныеДанные.Вставить("Версия", "1.0");
    // ... другие необходимые параметры
    
    // Создаем или получаем коллекцию команд, если она уже есть
    Если Не РегистрационныеДанные.Свойство("Команды") Тогда
        РегистрационныеДанные.Вставить("Команды", Новый Массив);
    КонецЕсли;
    
    КомандаПечати = РегистрационныеДанные.Команды.Добавить();
    КомандаПечати.Идентификатор = "ПечатьМоейФормы"; // Уникальный идентификатор вашей команды печати
    КомандаПечати.Представление = "Моя печатная форма";
    КомандаПечати.Модификатор = "Печать"; // Стандартный модификатор для команд печати
    
    // *** Ключевое изменение: устанавливаем тип вызова клиентского метода ***
    КомандаПечати.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
    
    // Свойство ПроверкаПроведенияПередПечатью становится неэффективным при использовании клиентского метода
    // КомандаПечати.ПроверкаПроведенияПередПечатью = Истина; 
    
    // Возможно, вам также потребуется установить свойство для подавления стандартных оповещений
    КомандаПечати.ПоказыватьОповещениеПриПечати = Ложь;
    
    Возврат РегистрационныеДанные;
КонецФункции

Что дает ТипКомандыВызовКлиентскогоМетода()? Этот тип команды означает, что вместо автоматического вызова серверных процедур печати, система будет ожидать вызова клиентской процедуры с определенным именем в модуле вашей обработки или ее формы. Это дает нам полный контроль над поведением перед фактической печатью.

Шаг 2: Реализация клиентской процедуры Печать() в модуле формы ВПФ

После того как мы установили тип команды на клиентский вызов, нам необходимо реализовать соответствующую процедуру в модуле формы вашей внешней печатной формы. Эта процедура будет отвечать за всю логику: проверку проведения, запрос подтверждения у пользователя, возможное проведение документа и уже затем – вызов штатного механизма печати.

  1. Откройте модуль формы вашей внешней печатной формы (не модуль объекта).

  2. Реализуйте экспортную процедуру Печать(МассивОбъектов, ДополнительныеПараметрыПечати). Именно эта процедура будет вызываться системой при нажатии на вашу команду печати.

  3. Внутри этой процедуры мы выполним следующие шаги:

    • Получим ссылку на документ, который собираемся печатать, из параметра МассивОбъектов.
    • Проверим свойство Проведен у этого объекта.
    • Если документ не проведен, зададим вопрос пользователю, используя стандартный диалог Вопрос(), предлагая провести документ перед печатью.
    • В зависимости от ответа пользователя:
      • Если пользователь согласен (КодВозвратаДиалога.Да), попробуем провести документ (ОбъектДляПечати.Записать(РежимЗаписиДокумента.Проведение)). Важно обработать возможные ошибки проведения.
      • Если пользователь отказывается проводить, но хочет печатать (КодВозвратаДиалога.Нет), мы можем продолжить печать (если это допустимо для вашего бизнес-процесса) или предупредить пользователя о последствиях.
      • Если пользователь отменяет действие (КодВозвратаДиалога.Отмена), мы просто выходим из процедуры, прерывая печать.
    • После всех проверок и действий, вызовем штатный механизм печати, который обычно реализован в общих модулях и формах БСП (например, через общую форму ПечатьДокументов или специализированные серверные функции).

Посмотрим на пример кода для процедуры Печать в модуле формы ВПФ:


// В модуле формы внешней печатной формы
// Название процедуры должно совпадать с Идентификатором команды, 
// если в СведенияОВнешнейОбработке не указано другое имя процедуры для вызова.
// По умолчанию, система ищет процедуру с именем команды или "Печать".
Процедура Печать(МассивОбъектов, ДополнительныеПараметрыПечати) Экспорт
    
    Если МассивОбъектов.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем первый объект из массива для анализа
    ОбъектДляПечатиСсылка = МассивОбъектов[0];
    ОбъектДляПечати = ОбъектДляПечатиСсылка.ПолучитьОбъект(); // Получаем сам объект
    
    Если ОбъектДляПечати = Неопределено Тогда
        ПоказатьПредупреждение(,"Не удалось получить объект для печати. Возможно, документ был удален.");
        Возврат;
    КонецЕсли;
    
    // *** 1. Проверяем проведение документа ***
    Если ОбъектДляПечати.Метаданные().Движения.Количество() > 0 И Не ОбъектДляПечати.Проведен Тогда
        // Документ имеет движения и не проведен
        
        Ответ = Вопрос("Документ " + ОбъектДляПечати.ПредставлениеОбъекта + " не проведен. Провести и напечатать?", 
                       РежимДиалогаВопрос.ДаНетОтмена, КодВозвратаДиалога.Да);
        
        Если Ответ = КодВозвратаДиалога.Да Тогда
            Попытка
                // Попытка провести документ
                ОбъектДляПечати.Записать(РежимЗаписиДокумента.Проведение);
                Если Не ОбъектДляПечати.Проведен Тогда
                    ПоказатьПредупреждение(,"Не удалось провести документ. Возможно, есть ошибки в данных. Печать отменена.");
                    Возврат;
                КонецЕсли;
            Исключение
                ПоказатьПредупреждение(,"Ошибка проведения документа: " + ОписаниеОшибки() + ". Печать отменена.");
                Возврат;
            КонецПопытки;
        ИначеЕсли Ответ = КодВозвратаДиалога.Нет Тогда
            // Пользователь отказался проводить, но хочет напечатать.
            // Здесь мы можем решить: продолжить печать без проведения,
            // или запретить ее. В данном примере продолжим с предупреждением.
            Сообщить("Документ будет напечатан без проведения.");
        Иначе // Ответ = КодВозвратаДиалога.Отмена
            Возврат; // Пользователь отменил действие, выходим из процедуры печати
        КонецЕсли;
    КонецЕсли;
    
    // *** 2. Вызываем штатный механизм печати ***
    // Теперь, когда документ либо проведен, либо пользователь согласился на печать без проведения,
    // мы можем вызвать стандартный механизм. Это часто делается через общие модули БСП.
    
    // Мы передаем параметры, необходимые для штатной печати.
    // Например, это может быть вызов серверной процедуры из общего модуля БСП.
    // Предполагаем, что есть такой метод, который умеет печатать по массиву объектов и идентификатору команды.
    
    ПараметрыВызоваСервернойПечати = Новый Структура;
    ПараметрыВызоваСервернойПечати.Вставить("МассивОбъектов", МассивОбъектов);
    
    // Идентификатор команды, переданный в ДополнительныеПараметрыПечати,
    // позволяет системе определить, какую конкретную команду печати использовать.
    Если ДополнительныеПараметрыПечати.Свойство("ИдентификаторКоманды") Тогда
        ПараметрыВызоваСервернойПечати.Вставить("ИдентификаторКоманды", ДополнительныеПараметрыПечати.ИдентификаторКоманды);
    Иначе
        // Если идентификатор не передан, то используем идентификатор команды,
        // который мы задали в СведенияОВнешнейОбработке (в нашем примере "ПечатьМоейФормы").
        ПараметрыВызоваСервернойПечати.Вставить("ИдентификаторКоманды", "ПечатьМоейФормы"); 
    КонецЕсли;
    
    // Дополнительные параметры печати, такие как настройки принтера, количество копий и т.д.
    // Если они нужны, их тоже можно передать.
    Если ДополнительныеПараметрыПечати.Свойство("ПараметрыПечати") Тогда
        ПараметрыВызоваСервернойПечати.Вставить("ПараметрыПечати", ДополнительныеПараметрыПечати.ПараметрыПечати);
    КонецЕсли;
    
    // Пример вызова серверного метода из общего модуля БСП
    // Название общего модуля и процедуры может варьироваться в зависимости от конфигурации и версии БСП.
    // Часто это что-то вроде "ПечатьКлиентСервер" или "ПечатьДокументовКлиентСервер".
    // Важно, чтобы вызываемая процедура на сервере была Экспортной и принимала нужные параметры.
    
    // Используем безопасный вызов серверной процедуры.
    // Здесь мы вызываем серверную процедуру, которая фактически сформирует и напечатает документ.
    // В реальной БСП это может быть вызов ПечатьМенеджер.НапечататьДокументы() или аналогичный.
    ОбщегоНазначенияКлиентСервер.ВыполнитьПроцедуруМодуляОбъекта("ОбщийМодуль.ПечатьКлиентСервер", "НапечататьДокументыПоКоманде", ПараметрыВызоваСервернойПечати);
    
КонецПроцедуры

Обратите внимание на вызов ОбщегоНазначенияКлиентСервер.ВыполнитьПроцедуруМодуляОбъекта. Это обобщенный способ вызвать серверную процедуру из клиентского кода. В вашем конкретном случае, название общего модуля ("ОбщийМодуль.ПечатьКлиентСервер") и процедуры ("НапечататьДокументыПоКоманде") может отличаться. Вам потребуется проанализировать код вашей типовой конфигурации или БСП, чтобы найти актуальный метод для вызова стандартной печати, который принимает массив объектов и идентификатор команды.

Шаг 3: Дополнительные соображения и обходные пути

Параметры формы для печати

Для корректной работы такой схемы нам могут потребоваться дополнительные ключевые параметры формы для печати, чтобы передать информацию о необходимости проведения или другие специфические данные. Это включает передачу ссылки на документ, идентификатора команды и других данных в процедуру печати. Параметр ДополнительныеПараметрыПечати в нашей процедуре Печать() как раз предназначен для этого.

Отладка и тестирование

При возникновении подобных проблем всегда рекомендуется использовать отладчик для пошагового анализа выполнения кода. Это позволит нам точно понять, на каком этапе теряется управление или почему не срабатывает проверка проведения. Запускайте 1С в режиме отладки и устанавливайте точки останова в вашей процедуре Печать и в функции СведенияОВнешнейОбработке.

Альтернативный подход (ручная проверка)

Как было предложено в сообщении 3, теоретически можно было бы просто проверить свойство Проведен в процедуре Печать и вывести сообщение, если документ не проведен. Однако, такой подход не дает стандартного диалога с предложением провести, а лишь информирует пользователя. Наш комплексный подход с клиентской процедурой позволяет полностью эмулировать стандартное поведение.

Важность тестирования

После реализации предложенных изменений обязательно проведите тщательное тестирование вашей внешней печатной формы в различных сценариях:

  1. Печать проведенного документа.
  2. Печать непроведенного документа с согласием на проведение.
  3. Печать непроведенного документа с отказом от проведения (если ваша логика это допускает).
  4. Печать непроведенного документа с отменой действия.
  5. Проверьте, что печать работает корректно, и сформированный макет соответствует ожиданиям.

Таким образом, хотя изменения в БСП и могут вызвать временные трудности, мы всегда можем адаптировать наши внешние обработки, используя механизмы, предоставляемые платформой 1С:Предприятие, для обеспечения желаемого поведения.

← На главную