Как прервать выполнение функции в 1С и отменить печать внешних печатных форм без изменения типового кода

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

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

Часть 1. Прерывание выполнения вложенных функций

Разберем типичную ситуацию: у нас есть вызывающая функция Тест1, внутри которой вызывается вспомогательная функция Тест2. Если во второй функции происходит событие или не выполняется условие, требующее полной остановки алгоритма, нам нужно корректно прервать выполнение как самой функции Тест2, так и вызывающего метода Тест1. Обычный флаг отказа (например, параметр Отказ = Истина, который часто используется в процедурах-обработчиках событий) здесь использовать напрямую не получится, так как функции в 1С всегда требуют возврата значения через ключевое слово Возврат.

Проанализируем основные способы решения этой задачи:

  1. Трансляция булевого результата (Классический подход): последовательный возврат логического значения и его анализ на каждом уровне стека вызовов.
  2. Использование структуры результата (Стандарт БСП): передача наверх структуры, содержащей статус успешности и детальный текст возникшей ошибки.
  3. Использование механизма исключений: мгновенное прерывание выполнения всей цепочки функций с помощью оператора ВызватьИсключение в блоке попытки.
  4. Интерактивное прерывание: предоставление пользователю возможности остановить длительный цикл вычислений вручную.

Рассмотрим каждый из этих способов подробнее на практических примерах.

Способ 1. Трансляция булевого результата (Классический подход)

Самый простой и очевидный способ — это возврат логического значения Истина или Ложь из вложенной функции и последующий последовательный анализ этого результата во всех родительских методах. Посмотрим на пример реализации:


Функция Тест2()
    
    // Проверяем условие, при котором продолжать алгоритм нельзя
    Если Не НашеУсловие Тогда
        Возврат Ложь; // Прерываем выполнение текущей функции и возвращаем признак неудачи
    КонецЕсли;
    
    // Полезные действия функции Тест2, выполняемые при соблюдении условий
    // ...
    
    Возврат Истина; // Успешное завершение
    
КонецФункции

Функция Тест1()
    
    // Вызываем вложенную функцию и анализируем её результат
    Если Не Тест2() Тогда
        Возврат Ложь; // Прерываем выполнение родительской функции, так как дочерняя завершилась с ошибкой
    КонецЕсли;
    
    // Продолжаем выполнение алгоритма Тест1, если Тест2 вернул Истина
    // ...
    
    Возврат Истина;
    
КонецФункции

Этот способ отлично подходит для простых алгоритмов с небольшой глубиной вложенности (1-2 уровня). Однако, если цепочка вызовов состоит из 5-10 уровней, разработчику придется писать проверки вида Если Не... Тогда Возврат Ложь; КонецЕсли; на каждом уровне стека вызовов. Это загромождает код, снижает его читаемость и усложняет дальнейшую поддержку.

Способ 2. Использование структуры результата (Стандарт разработки БСП)

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

Разберем этот подход по шагам:


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

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

Использование структур делает код чрезвычайно гибким: если со временем вам потребуется возвращать из функции дополнительные аналитические показатели, вам не придется менять сигнатуру методов и переписывать все вызовы по всей конфигурации.

Способ 3. Использование механизма исключений (ВызватьИсключение)

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

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


Процедура ГлавныйВызовМетода()
    
    Попытка
        // Запускаем цепочку выполнения функций
        Тест1();
    Исключение
        // Сюда управление перейдет мгновенно из любой глубины вызова при возникновении исключения
        ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
        
        // Выводим пользователю понятное и дружелюбное сообщение
        ПоказатьПредупреждение(, "Выполнение операции прервано системой. Причина: " + ТекстОшибки);
    КонецПопытки;
    
    // Код после блока Попытка продолжит свое выполнение в штатном режиме
    
КонецПроцедуры

Процедура Тест1()
    
    // Выполняем предварительные действия
    Тест2(); // Если внутри Тест2 сработает исключение, этот метод также прервется автоматически
    
    // Этот код выполнится только в случае успешного прохождения Тест2
    // ...
    
КонецПроцедуры

Процедура Тест2()
    
    Если Не ПроверитьКритическоеУсловие() Тогда
        // Прерываем весь стек вызовов и отправляем сообщение об ошибке напрямую в блок Исключение
        ВызватьИсключение "Обнаружено некорректное состояние объекта. Проведение невозможно.";
    КонецЕсли;
    
КонецПроцедуры

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

Способ 4. Интерактивное прерывание длительных циклов пользователем

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

Проанализируем пример использования этого метода в длительных операциях:


Процедура ВыполнитьДлительнуюОбработку(МассивДокументов)
    
    Для Каждого ДокументСсылка Из МассивДокументов Цикл
        
        // Позволяет платформе отслеживать нажатие комбинации клавиш Ctrl + Break
        ОбработкаПрерыванияПользователя();
        
        // Выполнение тяжелой бизнес-логики обработки документа
        ОбработатьДокумент(ДокументСсылка);
        
    КонецЦикла;
    
КонецПроцедуры

Если пользователь во время выполнения цикла нажмет сочетание клавиш Ctrl + Break, платформа мгновенно прервет выполнение кода и выдаст стандартное сообщение "Операция прервана пользователем".

Часть 2. Прерывание и отмена печати внешних печатных форм (ВПФ) без изменения типового кода

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

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

Метод 1. Использование общего модуля ДополнительныеОтчетыИОбработкиКлиентПереопределяемый

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

Рассмотрим по шагам программный код такого расширения:


&Вместо("ПередВыполнениемКомандыПечатиВнешнейПечатнойФормы")
Процедура Расш1_ПередВыполнениемКомандыПечатиВнешнейПечатнойФормы(ПечатаемыеОбъекты, СтандартнаяОбработка)
    
    // Анализируем массив объектов, отправленных на печать
    Для Каждого СсылкаИзСписка Из ПечатаемыеОбъекты Цикл
        
        // Пример условия: запретим печать внешних печатных форм для непроведенных документов
        Если ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаИзСписка, "Проведен") = Ложь Тогда
            
            // Устанавливаем СтандартнаяОбработка в Ложь для отмены стандартного алгоритма БСП
            СтандартнаяОбработка = Ложь;
            
            // Информируем пользователя о причине отмены печати
            ПоказатьПредупреждение(, "Печать отменена! Документ " + Строка(СсылкаИзСписка) + " должен быть предварительно проведен.");
            
            // Прерываем выполнение процедуры, не доходя до оригинального вызова БСП
            Возврат; 
            
        КонецЕсли;
        
    КонецЦикла;
    
    // Если все проверки пройдены успешно, вызываем оригинальный метод БСП
    ПродолжитьВызов(ПечатаемыеОбъекты, СтандартнаяОбработка);
    
КонецПроцедуры

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

Метод 2. Управление доступностью и видимостью команд печати ВПФ

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

Для реализации этого сценария мы можем переопределить процедуру ПередДобавлениемКомандПечати в общем модуле УправлениеПечатьюПереопределяемый с помощью расширения:


&После("ПередДобавлениемКомандПечати")
Процедура Расш1_ПередДобавлениемКомандПечати(ИмяФормы, КомандыПечати, СтандартнаяОбработка)
    
    // Проверяем форму конкретного документа
    Если ИмяФормы = "Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента" Тогда
        
        // Если текущий пользователь не обладает полными правами, скрываем команду печати ВПФ
        ИндексКоманды = КомандыПечати.Количество() - 1;
        Пока ИндексКоманды >= 0 Цикл
            КомандаПечати = КомандыПечати[ИндексКоманды];
            
            // Идентифицируем команду внешней печатной формы по ее идентификатору
            Если КомандаПечати.Идентификатор = "МояСпециальнаяВнешняяПечатнаяФорма" И Не РольДоступна("ПолныеПрава") Тогда
                // Удаляем команду из коллекции, и кнопка на форме просто не появится
                КомандыПечати.Удалить(ИндексКоманды);
            КонецЕсли;
            
            ИндексКоманды = ИндексКоманды - 1;
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Заключение

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

← На главную