1С Длительная операция БСП 3.0
Содержание
В интернете очень много информации о таком коде, но вряд ли вы найдете ту, которая действительно бы работала как вам нужно. В БСП есть механизм использования длительной операции, но он работает для обработок, которые подключены к справочнику «ДополнительныеОтчетыИОбработки», при обращении к ним создается временный файл на сервере и уже в дальнейшем сервер работает именно с этим файлом, обращаясь к его модулю объекта.
Мы сделаем почти так же: Развернем копию обработки при открытии на сервере и будем обращаться к процедурам модуля этой копии.
Итак, приступим:
- Для начала создадим новую внешнюю обработку и дадим ей название, например, «НашаДлительнаяОперация»
- Создадим и назначим форму нашей обработке
- Сразу до начала написания кода распределим некоторые области для простоты работы и общей читаемости.
Модуль формы обработки: #Область ВЫПОЛЕННИЕ_БЕЗ_ДЛИТЕЛЬНОЙ_ОПЕРАЦИИ #КонецОбласти #Область ПОМЕЩЕНИЕ_ОБРАБОТКИ_НА_СЕРВЕР #КонецОбласти #Область ВЫПОЛНЕНИЕ_С_ДЛИТЕЛЬНОЙ_ОПЕРАЦИИ #КонецОбласти #Область ПРОЦЕДУРЫ_И_ФУНКЦИИ #КонецОбласти
Модуль объекта обработки: #Область ДЛИТЕЛЬНАЯ_ОПЕРАЦИЯ #КонецОбласти #Область ОБЩИЕ_ПРОЦЕДУРЫ_И_ФУНКЦИИ_МОДУЛЯ #КонецОбласти
- Создадим две команды на форме «ВыполнениеБезДлительнойОперации» и «ВыполнениеСДлительнойОперации»
- Разметим форму группами управления - это улучшит юзабилити для пользователя
- Приступим к реквизитам формы и обработки (Они зависят от вашей задачи и прочих факторов которые вам придется самостоятельно определить, в нашем примере мы рассматриваем тестовый вариант выполнения)
Это будут параметры для выполнения нашей длительной операции, которые мы будем передавать в процедуру модуля обработки - Разместим основные элементы управления на форме Должно получиться вот так, но это все формальности, вы можете настроить элементы управления как угодно вам
- Добавим реквизиты для отображения прогресса выполнения, некоторые реквизиты для хранения переменных длительной операции, а также команду отмены выполнения длительной операции
Общий вид обработки стал выглядеть так:
Итак, приступим к написанию программной части обработки. Для этого перейдем в модуль формы:
Первым делом определим процедуру «ПриСозданииНаСервере» если таковая нужна, мы же используем ее для примера в ознакомительных целях, она будет находится вне размеченных областей.
&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) //* Действия При создании на сервере. ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Запуск обработки."); КонецПроцедуры
Далее поработаем с областью «ВЫПОЛЕННИЕ_БЕЗ_ДЛИТЕЛЬНОЙ_ОПЕРАЦИИ», для этого зайдем на форму и назначим действие для команды «ВыполнениеБезДлительнойОперации»
Реализовывать их мы не будем, но здесь можно выполнять тот код, который захотим: например, в котором нам не нужно использовать механизмы длительной операции.
В модуле сформируется код, перенесем его в область «ВЫПОЛЕННИЕ_БЕЗ_ДЛИТЕЛЬНОЙ_ОПЕРАЦИИ»
Далее перейдем к области «ПОМЕЩЕНИЕ_ОБРАБОТКИ_НА_СЕРВЕР». Определим процедуру «ПриОткрытии» с директивой &НаКлиенте
В ней мы начнем помещать наш файл обработки на сервер во временное хранилище. Далее обработаем результат помещения и запишем адрес хранения в реквизит формы.
#Область ПОМЕЩЕНИЕ_ОБРАБОТКИ_НА_СЕРВЕР &НаКлиенте Процедура ПриОткрытии(Отказ) //Создаем описание файла для начала помещения. ОписаниеПередаваемогоФайла = Новый ОписаниеПередаваемогоФайла(ИспользуемоеИмяФайлаОбработки()); //Определяем массив для передачи описаний файлов. МассивФайлов = Новый Массив; МассивФайлов.Добавить(ОписаниеПередаваемогоФайла); //Проверяем внешняя ли это обработка или нет. Если ЭтоВнешняяОбработка() Тогда ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьПомещенияФайлаОбработкиВоВременноеХранилище", ЭтотОбъект); НачатьПомещениеФайлов(ОписаниеОповещения, МассивФайлов,, Ложь, УникальныйИдентификатор); КонецЕсли; КонецПроцедуры &НаКлиенте Процедура ОбработатьПомещенияФайлаОбработкиВоВременноеХранилище(МассивФайлов, ОбработчикЗавершения) Экспорт //Записываем копию текущией обработки во временном хранилище. Если МассивФайлов <> Неопределено Тогда ХранениеФайлаОбработки = ВрменныйФайлОбработкиНаСервере(МассивФайлов[0].Хранение); КонецЕсли; КонецПроцедуры &НаСервере Функция ВрменныйФайлОбработкиНаСервере(Хранение) Результат = ПолучитьИмяВременногоФайла(); ДвоичныеДанные = ПолучитьИзВременногоХранилища(Хранение); ДвоичныеДанные.Записать(Результат); Возврат Результат; КонецФункции &НаСервере Функция ИспользуемоеИмяФайлаОбработки() Возврат РеквизитФормыВЗначение("Объект").ИспользуемоеИмяФайла; КонецФункции &НаСервере Функция ЭтоВнешняяОбработка() НаборИменОбработки = СтрРазделить(РеквизитФормыВЗначение("Объект").Метаданные().ПолноеИмя(),"."); Возврат (ВРег(НаборИменОбработки[0]) = "ВНЕШНЯЯОБРАБОТКА") КонецФункции #КонецОбласти
Теперь заполним область «ВЫПОЛНЕНИЕ_С_ДЛИТЕЛЬНОЙ_ОПЕРАЦИИ» и для начала определим события для команды «ВыполнениеСДлительнойОперацией»
И помещаем полученный код в нашу область
В теле процедуры «ВыполнениеСДлительнойОперацией» напишем такой код:
ОчиститьСообщения(); ВремяНачалаДлительнойОперации = ТекущаяДата(); Элементы.ГруппаПрогрессДлительнойОперации.Видимость = Истина; СопровождающийТекст = НСтр("ru = 'Наша длительная операция'"); ОбработчикЗавершения = Новый ОписаниеОповещения("ПослеЗавершенияДлительнойОперации", ЭтотОбъект, СопровождающийТекст); ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ВыполнитьДействиеПрогрессВыполнения", ЭтотОбъект, СопровождающийТекст); НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтаФорма); НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина; НастройкиОжидания.ВыводитьОкноОжидания = Ложь; НастройкиОжидания.ВыводитьСообщения = Истина; НастройкиОжидания.ТекстСообщения = НСтр("ru = 'Выполнение длительно операции...'"); НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения; // Выполняемая команда общего модуля обработки // см. ОбщийМодуль.ОбработкаДанныхВФоне ВыполняемаяКоманда = Новый Структура("Идентификатор", "ОбработкаДанныхВФоне" ); ДлительнаяОперация = ВыполнениеСДлительнойОперациейНаСервере (ВыполняемаяКоманда, УникальныйИдентификатор); ИдентификаторФоновогоЗадания = ДлительнаяОперация.ИдентификаторЗадания; ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОбработчикЗавершения, НастройкиОжидания);
Далее в теле процедуры «ЗаполнитьВФонеНаСервере», переобозначим ее как функцию и определим 2 параметра для нее: ВыполняемаяКоманда, УникальныйИдентификатор
&НаСервере Функция ВыполнениеСДлительнойОперациейНаСервере(ВыполняемаяКоманда, УникальныйИдентификатор) // Структура для передачи параметров, в процедуру, выполняемую в модуле объкта // длительной операцией. ПараметрыВыполненияОбработки = Новый Структура(); ПараметрыВыполненияОбработки.Вставить("Параметр1", Объект.Параметр1); ПараметрыВыполненияОбработки.Вставить("Параметр2", Объект.Параметр2); ПараметрыВыполненияОбработки.Вставить("Параметр3", Объект.Параметр3); ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки"; ЭтоВнешняяОбработка = ЭтоВнешняяОбработка(); ИмяОбработки = ?(ЭтоВнешняяОбработка, ХранениеФайлаОбработки, РеквизитФормыВЗначение("Объект").Метаданные().ПолноеИмя()); ПараметрыЗадания = Новый Структура; ПараметрыЗадания.Вставить("БезопасныйРежим", Ложь); ПараметрыЗадания.Вставить("ИмяОбработки", ИмяОбработки); ПараметрыЗадания.Вставить("ИмяМетода", ВыполняемаяКоманда.Идентификатор); ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыВыполненияОбработки); ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", ЭтоВнешняяОбработка); ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", Справочники.ДополнительныеОтчетыИОбработки.ПустаяСсылка()); ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор); ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Имя фонового задания'"); ПараметрыВыполнения.ЗапуститьВФоне = Истина; ПараметрыВыполнения.Вставить("ИдентификаторФормы", УникальныйИдентификатор); ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор); Возврат ДлительныеОперации.ВыполнитьВФоне(ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения); КонецФункции
Так же определим обработчики оповещений, процедуры обработчиков обязательно должны быть экспортными
&НаКлиенте Процедура ПослеЗавершенияДлительнойОперации(Операция, СопровождающийТекст) Экспорт // Если отменено пользователем. Если Операция = Неопределено Тогда ПоказатьОповещениеПользователя(НСтр("ru = 'Отмена задания'"),, СопровождающийТекст, БиблиотекаКартинок.КрасныйКрестик); Возврат; КонецЕсли; Если Операция.Статус = "Выполнено" Тогда ПоказатьОповещениеПользователя(НСтр("ru = 'Успешное завершение'"),, СопровождающийТекст, БиблиотекаКартинок.Успешно32); //Если получаем данные сформировнаные длительной операцией. ОбработатьРезультатВыполнения(Операция.АдресРезультата); ОбработатьПоЗавершению(); ИначеЕсли Операция.Статус = "Ошибка" Тогда ПоказатьПредупреждение(, Операция.КраткоеПредставлениеОшибки); ОбработатьПоЗавершению(); КонецЕсли; КонецПроцедуры &НаКлиенте Процедура ВыполнитьДействиеПрогрессВыполнения(Прогресс, ДополнительныеПараметры) Экспорт ТекстУведомления = НСтр("ru = 'Пожалуйста, подождите...'"); Если Прогресс.Прогресс <> Неопределено Тогда Уведомление = Прогресс.Прогресс.Текст; ПроцентВыполнения = Прогресс.Прогресс.Процент; КонецЕсли; ТекстУведомления = ТекстУведомления + Символы.ПС + Уведомление; Элементы. ДекорацияТекстЗадания.Заголовок = ТекстУведомления; Если Прогресс.Сообщения <> Неопределено Тогда Для каждого СообщениеПользователю Из Прогресс.Сообщения Цикл СообщениеПользователю.Сообщить(); КонецЦикла; КонецЕсли; КонецПроцедуры
Для некоторых длительных операций нужно обработать результат уже у пользователя, поэтому мы можем получить его некоторыми процедурами, а опишем мы их в области «ПРОЦЕДУРЫ_И_ФУНКЦИИ_ДЛЯ_ФОНОВОГО_ЗАДАНИЯ»
&НаСервере Процедура ОбработатьРезультатВыполнения(АдресРезультата) Результат = ПолучитьИзВременногоХранилища(АдресРезультата); ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Результат.Сообщение); ВозвращаемыйРезультат = Результат.ВозвращаемыйРезультат; // Например: Загружаем данные полученной ТЗ, в ТЗ на форме обработки // ** Объект.ОбъектыИзменения.Очистить(); // ** Объект.ОбъектыИзменения.Загрузить(ВозвращаемыйРезультат); // Очищаем временное хранилище, для избежание его переполнения. УдалитьИзВременногоХранилища(АдресРезультата); КонецПроцедуры &НаКлиенте Процедура ОбработатьПоЗавершению() Элементы.ГруппаПрогрессЗадачи.Видимость = Ложь; Элементы.ТекстЗадания.Заголовок = ""; ПроцентВыполнения = 0; ОбщегоНазначенияКлиент.СообщитьПользователю("Обработка завершена. "); КонецПроцедуры
Вернемся к области «ВЫПОЛНЕНИЕ_С_ДЛИТЕЛЬНОЙ_ОПЕРАЦИИ» и допишем команды отмены задания, это делается очень легко, достаточно знать идентификатор фонового задания, который мы записали выше в коде запуска задания, он хранится в реквизите формы с одноименным наименованием ИдентификаторФоновогоЗадания
Определим события для команды «Отменить выполнение»
И в процедуре «ОтменитьВыполнениеДлительнойОперацииНаСервере» напишем одну строчку
&НаСервере Процедура ОтменитьВыполнениеДлительнойОперацииНаСервере() ДлительныеОперации.ОтменитьВыполнениеЗадания(ИдентификаторФоновогоЗадания); КонецПроцедуры
Наконец, мы переходим к модулю объекта, тут все предельно просто - заполняем следующим кодом:
// Отладка модуля обработки выполняется, // при параметрах запуска конфигурации: "/C РежимОтладки". // Для выполнения длительной операции требуется выключить данный параметр. #Область ДЛИТЕЛЬНАЯ_ОПЕРАЦИЯ Процедура ОбработкаДанныхВФоне(Параметры, АдресРезультата) Экспорт // Получаем результат обработки нашей процедурой и помещаем его в хранилище. Результат = ОбработкаДанныхДоговоров(Параметры, АдресРезультата); ПоместитьВоВременноеХранилище(Результат, АдресРезультата); КонецПроцедуры Функция ОбработкаДанныхДоговоров(Параметры, АдресРезультата) Параметр1 = Параметры.Параметр1; Параметр2 = Параметры.Параметр2; Параметр3 = Параметры.Параметр3; Результат = Новый Структура("Сообщение, ВозвращаемыйРезультат"); КоличествоОбработанных = Число(Параметр1); ВремяФиниша = ТекущаяДатаСеанса() + 100; Пока ТекущаяДатаСеанса()<ВремяФиниша Цикл Процент = 100 - (ВремяФиниша - ТекущаяДатаСеанса()); ТекстСобщения = СтрШаблон("Выполнено %1 процентов: Параметр1 - %2, Параметр2 - %3, Параметр3 - %4", Процент, Параметр1, Параметр2, Параметр3); Если НЕ (Процент % 10) Тогда ДлительныеОперации.СообщитьПрогресс(Процент, ТекстСобщения); КонецЕсли; КонецЦикла; Результат.Сообщение = "Сообщение для результата"; Результат.ВозвращаемыйРезультат = ВремяФиниша; Возврат Результат; КонецФункции #КонецОбласти #Область ОБЩИЕ_ПРОЦЕДУРЫ_И_ФУНКЦИИ_МОДУЛЯ // Здесь можно заполнить дополнительные процедуры/функции #КонецОбласти
Отладка модуля обработки может выполняться при параметре отладки конфигуратора «/C РежимОтладки»
Наглядно:Скачать внешнюю обработку
Откройте новые возможности для вашего бизнеса с Тарифами 1С:ИТС!