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