МЕТОДЫ
В обработку добавлены методы: загрузка файла с клиента на сервер, чтение Excel файла через построитель, процедура нересурсоемкого серверного ожидания в целях демонстрации на любой базе без требования к конкретным данным и приближенности примера к реальным задачам.
СРЕДА
Тестировалось на конфигурации Управление Торговлей 11.4.13.227, версия БСП 3.1.3.548, платформа 8.3.17.1549
ДЕМОНСТРАЦИЯ
Нажать на кнопку "Обзор" и выбрать любой файл Excel с клиента, версия формата 2007.
КОД
Модуль объекта
Функция СведенияОВнешнейОбработке() Экспорт
	
	ИмяОбработки = Метаданные().Имя;
	Синоним = Метаданные().Синоним;
	Синоним = ?(ПустаяСтрока(Синоним), ИмяОбработки, Синоним);
	
	ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке();
	ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
	ПараметрыРегистрации.Наименование = Синоним;
	ПараметрыРегистрации.Версия = "1.0";
	ПараметрыРегистрации.Информация = Синоним;
	ПараметрыРегистрации.БезопасныйРежим = Ложь;
	
	ТаблицаКоманд = ПараметрыРегистрации.Команды;
		
	Команда = ТаблицаКоманд.Добавить();
	Команда.Идентификатор = "ОткрытьОбработку";
	Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
	Команда.Представление = Синоним + " (открыть форму)";
	
	Возврат ПараметрыРегистрации;
	
КонецФункции
Процедура ЗагрузитьДанные(ПараметрыДлительнойОперации, АдресРезультата) Экспорт
	
	КоличествоСтрокВычисленияПрогресса = 1;
	ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
	
	ДлительныеОперации.СообщитьПрогресс(0, "Загрузка файла в систему...");
	
	ПараметрыДлительнойОперации.ДвоичныеДанные.Записать(ИмяВременногоФайла);
	ТабличныйДокумент.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
	ВысотаТаблицыБезЗаголовка = ТабличныйДокумент.ВысотаТаблицы - 1;
	
	ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличныйДокумент.Область(1, 1, ТабличныйДокумент.ВысотаТаблицы, ТабличныйДокумент.ШиринаТаблицы));
	ПостроительОтчетов = Новый ПостроительОтчета;
	ПостроительОтчетов.ИсточникДанных = ИсточникДанных;
	ПостроительОтчетов.Выполнить();
	
	ВыборкаДетальныеЗаписи = ПостроительОтчетов.Результат.Выбрать();
	ТекущаяСтрока = 0;
	СчетчикПрогресса = 0;
	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
	
		КакаяТоПроцедураОбработкиСтроки(ВыборкаДетальныеЗаписи);
		ТекущаяСтрока = ТекущаяСтрока + 1;
		СчетчикПрогресса = СчетчикПрогресса + 1;
		
		Если СчетчикПрогресса = КоличествоСтрокВычисленияПрогресса Тогда
			
			Процент = Формат(ТекущаяСтрока / ВысотаТаблицыБезЗаголовка * 100, "ЧДЦ=2");
			ДлительныеОперации.СообщитьПрогресс(Процент, СтрШаблон("Обработка %1 строки из %2", ТекущаяСтрока, ВысотаТаблицыБезЗаголовка));
			СчетчикПрогресса = 0;
			
		КонецЕсли;
		
	КонецЦикла;
	
	ДанныеРезультата = Новый Структура("ВсегоСтрок", ТекущаяСтрока);
	ПоместитьВоВременноеХранилище(ДанныеРезультата, АдресРезультата);
	
КонецПроцедуры
Процедура КакаяТоПроцедураОбработкиСтроки(ВыборкаДетальныеЗаписи)
	
	Ждать(1);
	
КонецПроцедуры
Процедура Ждать(КоличествоСекунд)
	
	Попытка
		
		Соединение = Новый HTTPСоединение("127.0.0.0",,,,,КоличествоСекунд);
		Соединение.Получить(Новый HTTPЗапрос());
		
	Исключение
	Конецпопытки;
	
КонецПроцедуры
Обратите внимание на переменную КоличествоСтрокВычисленияПрогресса, которая определяет интервал между вычислением и отправкой прогресса на клиент. Здесь намеренно значение равно 1 в целях демонстрации.
На рабочей задаче обязательно задайте максимальный интервал, который будет удовлетворять пользователя в целях оптимизации, например 100.
Используется чтение табличным документом из файла, т.к. на данный момент Excel читается только так. Если же вы работаете с форматами MXL, ODS, то используйте чтение из потока в целях оптимизации. В процедуре КакаяТоПроцедураОбработкиСтроки в целях демонстрации выполняется ожидание длиной в 1 секунду.
Модуль формы
#Область ОбработчикиСобытийФормы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	Если НЕ Параметры.Свойство("ДополнительнаяОбработкаСсылка") Тогда
		ПутьКВнешнейОбработке = РеквизитФормыВЗначение("Объект").ИспользуемоеИмяФайла;
	Иначе
		ДополнительнаяОбработкаСсылка = Параметры.ДополнительнаяОбработкаСсылка;
	КонецЕсли;
	
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	Если ЗначениеЗаполнено(ПутьКВнешнейОбработке) Тогда
		
		АдресВнешнейОбработки = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ПутьКВнешнейОбработке), УникальныйИдентификатор);
		ЗаписатьКопиюОбработки(АдресВнешнейОбработки, ПутьКопииОбработки);
		
	КонецЕсли;
	
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
	УдалитьКопиюОбработкиНаСервере(ПутьКопииОбработки);
КонецПроцедуры
#КонецОбласти
#Область ОбработчикиКомандФормы
&НаКлиенте
Процедура Обзор(Команда)
	
	ОписаниеОповещения = Новый ОписаниеОповещения("ОбзорПослеПомещенияФайла", ЭтотОбъект);
	ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
	ПараметрыЗагрузки.ИдентификаторФормы = УникальныйИдентификатор;
	ПараметрыЗагрузки.Диалог.Фильтр = "Табличный документ (*.xlsx *.xls)|*.xlsx;*.xls";
	ФайловаяСистемаКлиент.ЗагрузитьФайл(ОписаниеОповещения, ПараметрыЗагрузки);
	
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
&НаКлиенте
Процедура ОбзорПослеПомещенияФайла(ПомещенныйФайл, ДополнительныеПараметры) Экспорт
	Если Не ЗначениеЗаполнено(ПомещенныйФайл) Тогда
		Возврат;
	КонецЕсли;
	
	ДлительнаяОперация = ЗагрузитьСтатусыНаСервере(ПомещенныйФайл.Хранение);
	ОповещениеОЗавершении = Новый ОписаниеОповещения("ОбзорПослеПомещенияФайлаЗавершение", ЭтотОбъект);
	ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	ПараметрыОжидания.Вставить("ВыводитьПрогрессВыполнения", Истина);
	ПараметрыОжидания.Вставить("Интервал", 2);
	ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
	
КонецПроцедуры // ОбзорПослеПомещенияФайла()
&НаСервере
Функция ЗагрузитьСтатусыНаСервере(АдресПомещенногоФайла)
	
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресПомещенногоФайла);
	ОбъектОбработки = РеквизитФормыВЗначение("Объект");
	МетаданныеОбработки = ОбъектОбработки.Метаданные();
	
	ПараметрыДлительнойОперации = Новый Структура;
	ПараметрыДлительнойОперации.Вставить("ДвоичныеДанные", ДвоичныеДанные);
	
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = МетаданныеОбработки.Синоним;
	ПараметрыВыполнения.Вставить("ДополнительныйРезультат", Истина);
	ПараметрыВыполнения.Удалить("АдресРезультата");
	
	Если Отладка Тогда
		ПараметрыВыполнения.Вставить("ЗапуститьНеВФоне", Истина);
	КонецЕсли;
	
	ПараметрыЗадания = Новый Структура;
	ПараметрыЗадания.Вставить("ИмяМетода", "ЗагрузитьДанные");
	ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыДлительнойОперации);
	ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);
	
	Если ЗначениеЗаполнено(ДополнительнаяОбработкаСсылка) Тогда
		ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", ДополнительнаяОбработкаСсылка);
	Иначе
		ПараметрыЗадания.Вставить("ИмяОбработки", ПутьКопииОбработки);
	КонецЕсли;
	
	Возврат ДлительныеОперации.ВыполнитьПроцедуру(ПараметрыВыполнения, "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки", ПараметрыЗадания);
	
КонецФункции
&НаКлиенте
Процедура ОбзорПослеПомещенияФайлаЗавершение(Результат, ДополнительныеПараметры) Экспорт
	
	Если ЗначениеЗаполнено(Результат) Тогда
		
		Если ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Результат, "Статус") = "Выполнено" Тогда
			
			РезультатСтруктура = ПолучитьИзВременногоХранилища(Результат.АдресДополнительногоРезультата);
			ТекстСообщения = СтрШаблон("Всего обработано строк: %1", РезультатСтруктура.ВсегоСтрок);
			
		Иначе
			ТекстСообщения = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Результат, "ПодробноеПредставлениеОшибки", "Неизвестная ошибка");
		КонецЕсли;
		
		Сообщение = Новый СообщениеПользователю;
		Сообщение.Текст = ТекстСообщения;
		Сообщение.Сообщить();
		
	КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаписатьКопиюОбработки(АдресВнешнейОбработки, ПутьКопииОбработки)
	
	ДвоичныеДанныеОбработки = ПолучитьИзВременногоХранилища(АдресВнешнейОбработки);
	ПутьКопииОбработки = ПолучитьИмяВременногоФайла("epf");
	ДвоичныеДанныеОбработки.Записать(ПутьКопииОбработки);
	
КонецПроцедуры
&НаСервереБезКонтекста
Процедура УдалитьКопиюОбработкиНаСервере(ПутьКопииОбработки)
	Если Не ЗначениеЗаполнено(ПутьКопииОбработки) Тогда
		Возврат;
	КонецЕсли;
		
	ФайлОбработки = Новый Файл(ПутьКопииОбработки);
	
	Если ФайлОбработки.Существует() Тогда
		УдалитьФайлы(ПутьКопииОбработки);
	КонецЕсли;
КонецПроцедуры // УдалитьКопиюОбработкиНаСервере(ПутьКопииОбработки)()
#КонецОбласти
При открытии формы происходит анализ места запуска и либо обработка сохраняется на сервере во временный файл, либо запоминается ссылка на справочник дополнительных обработок. В процедуре ОбзорПослеПомещенияФайла происходит вызов создания длительной операции и формирование параметров ожидания на клиенте.
В функции ЗагрузитьСтатусыНаСервере структура ПараметрыДлительнойОперации определяет параметры для основной процедуры из модуля объекта, в примере в параметрах передается полученный с клиента файл Excel в виде двоичных данных. Ключ ДополнительныйРезультат вместо АдресРезультата используется из-за безусловного алгоритма разработчиков БСП в вызове ДлительныеОперации.ВыполнитьПроцедуру.
Реквизит Отладка необходим для запуска алгоритма не в фоне для быстрой отладки на клиент-серверных базах без необходимости добавлять параметр запуска РежимОтладки в конфигураторе. На рабочей задаче необходимо скрыть данный реквизит на форме.
Именно процедура ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки позволяет запускать процедуры из модуля обработки. В зависимости от места запуска мы передаем либо ссылку, либо путь к временному файлу, куда скопирована обработка ранее. После завершения обработки в процедуре ОбзорПослеПомещенияФайлаЗавершение мы обращаемся именно к ключу АдресДополнительногоРезультата.
Форма и реквизиты

Известные проблемы
В процессе разработки можно получить следующую ошибку:

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