Выполнение внешней обработки по расписанию для управляемого и обычного приложения

06.08.20

Разработка - Универсальные функции

Использование БСП для выполнения внешних обработок в управляемом и обычном приложении

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

Если сказать в общем, то данные функционал реализовывать мы будем при помощи подсистемы БСП "Дополнительные отчеты и обработки" . Рекомендую для начала ознакомиться с возможностями подсистемы https://its.1c.ru/db/bsp21doc#content:22:1

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

создать внешнюю обработку (в моем примере даже не буду создавать форму),

в модуле внешней обработки разместить следующую процедуру:

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

далее идут процедуры и функции, необходимые для выполнения вашего алгоритма:

Функция ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыКоманды) Экспорт
	
	Если ИдентификаторКоманды = "Синхронизация" Тогда
		Синхронизировать();
	КонецЕсли;
	
КонецФункции

//процедура выполняемой команды
Процедура Синхронизировать()
	
	Обработка = Обработки.УниверсальныйОбменДаннымиXML.Создать();
	Обработка.РежимОбмена = "Выгрузка";	
	Обработка.ДатаНачала	 = ТекущаяДата()- 86400 * 3;
	Обработка.ДатаОкончания   = КонецМесяца(ТекущаяДата());
	Обработка.ИмяФайлаОбмена  = "C:\1сbase\Обмен БП - УТ XML\Файл выгрузки.xml";
	Обработка.ИмяФайлаПравилОбмена  = "C:\1сbase\Обмен БП - УТ XML\ПравилаОбменаБП-УТ.xml";
	Обработка.ЗагрузитьПравилаОбмена();
	Обработка.ВыполнитьВыгрузку();	
		
КонецПроцедуры

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

проверяем журнал регистрации, чтобы убедиться в выполнении нашей обработки:

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

Возьмем какую-нибудь типовую конфигурацию на обычных формах, например УПП.

Для справочника ВнешниеОбработки, добавим табличную часть Команды со следующей структурой (все реквизиты строкового типа):

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

Процедура КомандыПередНачаломДобавления(Элемент, Отказ, Копирование)
	Отказ = Истина;
КонецПроцедуры

Процедура КомандыПередУдалением(Элемент, Отказ)
	Отказ = Истина;
КонецПроцедуры

Процедура ЗаполнитьКоманды()
	
	КомандыОбработки.Очистить();
	
	Для Каждого ЭлементКоманда Из Команды Цикл
		РегламентноеЗаданиеЗадано = Ложь;
		НоваяКоманда = КомандыОбработки.Добавить();
		
		НоваяКоманда.Представление = ЭлементКоманда.Представление;
		НоваяКоманда.Идентификатор = ЭлементКоманда.Идентификатор;
		
		РегламентноеЗаданиеGUID = ЭлементКоманда.РегламентноеЗаданиеGUID;
		Если ЗначениеЗаполнено(РегламентноеЗаданиеGUID) Тогда
			
			РегламентноеЗадание = ДополнительныеОтчетыИОбработки.НайтиРегламентноеЗадание(РегламентноеЗаданиеGUID);
			
			Если РегламентноеЗадание = Неопределено Тогда
				
				ЭлементКоманда.РегламентноеЗаданиеGUID = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000");
				
			Иначе
				
				ЭлементКоманда.РегламентноеЗаданиеGUID = РегламентноеЗаданиеGUID;
				
				НоваяКоманда.РасписаниеПредставление = Строка(РегламентноеЗадание.Расписание);
				НоваяКоманда.Расписание.Добавить(РегламентноеЗадание.Расписание);
				
				РегламентноеЗаданиеЗадано = Истина;
			КонецЕсли;
			
		КонецЕсли;
		
		Если НЕ РегламентноеЗаданиеЗадано Тогда
			НоваяКоманда.РасписаниеПредставление = стрРасписаниеНеЗадано();
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция стрРасписаниеНеЗадано()
	
	Возврат НСтр("ru = 'Расписание не задано'");
	
КонецФункции

Функция ПредставлениеПустогоРасписания()
	
	Возврат Строка(Новый РасписаниеРегламентногоЗадания);
	
КонецФункции

Функция РедактированиеРасписанияРегламентногоЗадания(Расписание)
	
	Если Расписание = Неопределено Тогда
		
		Расписание = Новый РасписаниеРегламентногоЗадания;
		
	КонецЕсли;
	
	Диалог = Новый ДиалогРасписанияРегламентногоЗадания(Расписание);
	
	// открываем диалог для редактирования Расписания
	Если Диалог.ОткрытьМодально() Тогда
		
		Расписание = Диалог.Расписание;
		
	КонецЕсли;
	
	Возврат Расписание;
	
КонецФункции

Процедура УстановитьРасписание(ТекущиеДанные, Отказ = Ложь)
	
	Если ТекущиеДанные.Расписание.Количество() > 0 Тогда
		Расписание = ТекущиеДанные.Расписание.Получить(0).Значение;
	Иначе
		Расписание = Неопределено;
	КонецЕсли;
	
	Расписание = РедактированиеРасписанияРегламентногоЗадания(Расписание);
	
	ТекущиеДанные.Расписание.Очистить();
	ТекущиеДанные.Расписание.Добавить(Расписание);
	
	ТекущиеДанные.РасписаниеПредставление = Строка(Расписание);
	
	Если ТекущиеДанные.РасписаниеПредставление = ПредставлениеПустогоРасписания() Тогда
		ТекущиеДанные.РасписаниеПредставление = стрРасписаниеНеЗадано();
		ТекущиеДанные.Использование = Ложь;
		Отказ = Истина;
	КонецЕсли;
	
КонецПроцедуры

Процедура КомандыОбработкиРасписаниеПредставлениеНачалоВыбора(Элемент, СтандартнаяОбработка)
	
	СтандартнаяОбработка = Ложь;
	
	ТекущиеДанные = ЭлементыФормы.КомандыОбработки.ТекущиеДанные;
	
	Если ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	УстановитьРасписание(ТекущиеДанные);

КонецПроцедуры

Процедура УстановитьВидимостьЭлементов()

	Если ФормированиеФоновогоЗадания Тогда
		ЭлементыФормы.Панель.Доступность = Истина;
	КонецЕсли;	
	ЭлементыФормы.Панель1.Страницы.СтраницаКоманды.Видимость = ФормированиеФоновогоЗадания;
	ЭлементыФормы.Панель1.Страницы.СтраницаПринадлежность.Видимость = Не ФормированиеФоновогоЗадания;

КонецПроцедуры

Теперь касаемо БСП, берем за основу подсистему дополнительных отчетов и обработок, и адаптируем ее под обычное приложение, поместим в общий модуль ДополнительныеОтчетыИОбработки, рабочий код выглядит следующим образом:

////////////////////////////////////////////////////////////////////////////////
// Подсистема "Дополнительные отчеты и обработки"
// 
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// ПРОГРАММНЫЙ ИНТЕРФЕЙС

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

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

////////////////////////////////////////////////////////////////////////////////
// Изменение регламентных заданий

// Для внутреннего использования
// 
Процедура ОбновитьСведенияПоРасписанию(ДополнительнаяОбработка, Команда, Расписание, Использование, Отказ) Экспорт
	
	// получаем регламентное задание по идентификатору, если объект не находим, то создаем новый
	РегламентноеЗаданиеОбъект = ПолучитьРегламентноеЗадание(Команда.РегламентноеЗаданиеGUID);
	
	// обновляем свойства РЗ
	УстановитьПараметрыРегламентногоЗадания(РегламентноеЗаданиеОбъект, Расписание, Использование, ДополнительнаяОбработка.Ссылка, Команда);
	
	// записываем измененное задание
	ЗаписатьРегламентноеЗадание(Отказ, РегламентноеЗаданиеОбъект);
	
	//запоминаем GUID регл. задания в реквизите объекта
	Команда.РегламентноеЗаданиеGUID = РегламентноеЗаданиеОбъект.УникальныйИдентификатор;
	
КонецПроцедуры

// Выполняет удаление регламентного задания по GUID
// Параметры
//  РегламентноеЗаданиеGUID - УникальныйИдентификатор - уникальный идентификатор регламентного задания
//
Процедура УдалитьРегламентноеЗадание(РегламентноеЗаданиеGUID) Экспорт
	
	РегламентноеЗаданиеОбъект = НайтиРегламентноеЗадание(РегламентноеЗаданиеGUID);
	
	Если РегламентноеЗаданиеОбъект <> Неопределено Тогда
		УстановитьПривилегированныйРежим(Истина);
		РегламентноеЗаданиеОбъект.Удалить();
	КонецЕсли;
	
КонецПроцедуры

// Выполняет поиск регламентного задания по GUID
// Параметры
//  РегламентноеЗаданиеGUID - УникальныйИдентификатор - уникальный идентификатор регламентного задания
// Возвращаемое значение
//  РегламентноеЗадание - если найдено
//  Неопределено - если не найдено
//
Функция НайтиРегламентноеЗадание(РегламентноеЗаданиеGUID) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Попытка
		ТекущееРегламентноеЗадание = РегламентныеЗадания.НайтиПоУникальномуИдентификатору(РегламентноеЗаданиеGUID);
	Исключение
		ТекущееРегламентноеЗадание = Неопределено;
	КонецПопытки;
	
	Возврат ТекущееРегламентноеЗадание;
	
КонецФункции


////////////////////////////////////////////////////////////////////////////////
// Выполнение регламентных заданий

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

////////////////////////////////////////////////////////////////////////////////
// Экспортные служебные процедуры и функции

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


////////////////////////////////////////////////////////////////////////////////
// Локальные служебные процедуры и функции

// Для внутреннего использования
// 
Процедура УстановитьПараметрыРегламентногоЗадания(РегламентноеЗаданиеОбъект, Расписание, Использование, Ссылка, Команда)
	
	ПараметрыРЗ = Новый Массив;
	ПараметрыРЗ.Добавить(Ссылка);
	ПараметрыРЗ.Добавить(Команда.Идентификатор);
	
	НаименованиеРегламентногоЗадания = НСтр("ru = 'Запуск обработок: " + СокрЛП(Команда.Представление) + "'");
	
	РегламентноеЗаданиеОбъект.Наименование  = Лев(НаименованиеРегламентногоЗадания, 120);
	РегламентноеЗаданиеОбъект.Использование = Использование;
	РегламентноеЗаданиеОбъект.Параметры     = ПараметрыРЗ;
	
	РегламентноеЗаданиеОбъект.Расписание = Расписание;
	
КонецПроцедуры

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

КонецПроцедуры

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

// Для внутреннего использования
// 
Процедура НачалоВыполненияОбработки(ДополнительнаяОбработкаСсылка, ИдентификаторКоманды)
	
	ТекстСообщения = НСтр("ru = 'Запуск обработчика. Команда: " + ИдентификаторКоманды + "'");
	
	ЗаписатьСобытиеВЖурналРегистрации(ДополнительнаяОбработкаСсылка, ТекстСообщения);
	
КонецПроцедуры

// Для внутреннего использования
// 
Процедура ОкончаниеРаботыОбработки(ДополнительнаяОбработкаСсылка, ИдентификаторКоманды)
	
	ТекстСообщения = НСтр("ru = 'Возврат из обработчика. Команда: " + ИдентификаторКоманды + "'");
	ЗаписатьСобытиеВЖурналРегистрации(ДополнительнаяОбработкаСсылка, ТекстСообщения);
	
КонецПроцедуры

// Для внутреннего использования
// 
Процедура ЗаписатьСобытиеВЖурналРегистрации(ДополнительнаяОбработкаСсылка, ТекстСообщения)
	
	ЗаписьЖурналаРегистрации(
		НСтр("ru = 'Дополнительные отчеты и обработки'"),
		УровеньЖурналаРегистрации.Информация,
		ДополнительнаяОбработкаСсылка.Метаданные(),
		ДополнительнаяОбработкаСсылка,
		ТекстСообщения
	);
	
КонецПроцедуры

// Сравнить две строки версий.
//
// Параметры
//  СтрокаВерсии1  – Строка – номер версии в формате РР.{П|ПП}.ЗЗ.СС
//  СтрокаВерсии2  – Строка – второй сравниваемый номер версии
//
// Возвращаемое значение:
//   Число   – больше 0, если СтрокаВерсии1 > СтрокаВерсии2; 0, если версии равны.
//
Функция СравнитьВерсииКлиентская(Знач СтрокаВерсии1, Знач СтрокаВерсии2)
	
	Строка1 = ?(ПустаяСтрока(СтрокаВерсии1), "0.0.0.0", СтрокаВерсии1);
	Строка2 = ?(ПустаяСтрока(СтрокаВерсии2), "0.0.0.0", СтрокаВерсии2);
	Версия1 = РазложитьСтрокуВМассивПодстрокКлиентская(Строка1, ".");
	Если Версия1.Количество() <> 4 Тогда
		СтрокаИсключения = НСтр("ru = 'Неправильный формат строки версии: " + СтрокаВерсии1 + "'");
		ВызватьИсключение СтрокаИсключения;
	КонецЕсли;
	Версия2 = РазложитьСтрокуВМассивПодстрокКлиентская(Строка2, ".");
	Если Версия2.Количество() <> 4 Тогда
		СтрокаИсключения = НСтр("ru = 'Неправильный формат строки версии: " + СтрокаВерсии2 + "'");
		ВызватьИсключение СтрокаИсключения;
	КонецЕсли;
	
	Результат = 0;
	Для Разряд = 0 По 3 Цикл
		Результат = Число(Версия1[Разряд]) - Число(Версия2[Разряд]);
		Если Результат <> 0 Тогда
			Возврат Результат;
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;
	
КонецФункции

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

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

		ПредставлениеПустогоРасписания = Строка(Новый РасписаниеРегламентногоЗадания);
		Если ЭлементКоманда.Расписание.Количество() > 0 Тогда
			Расписание = ЭлементКоманда.Расписание.Получить(0).Значение;
		Иначе
			Расписание = ПредставлениеПустогоРасписания
		КонецЕсли;
		
		КомандаВОбъекте = Источник.Команды.НайтиСтроки(Новый Структура("Идентификатор", ЭлементКоманда.Идентификатор))[0];
		
		Если Строка(Расписание) = ПредставлениеПустогоРасписания Тогда // возможно было удалено регламентное задание
			Если ЗначениеЗаполнено(КомандаВОбъекте.РегламентноеЗаданиеGUID) Тогда
				УдалитьРегламентноеЗадание(КомандаВОбъекте.РегламентноеЗаданиеGUID);
				КомандаВОбъекте.РегламентноеЗаданиеGUID = "";
			КонецЕсли;
		Иначе
			ОбновитьСведенияПоРасписанию(Источник, КомандаВОбъекте, Расписание, Истина, Отказ);
		КонецЕсли;
		
	КонецЦикла; 

	
КонецПроцедуры

Добавим подписку на событие ПриЗаписиВнешнейОбработки для события ПриЗаписи, в качестве обработчика будет выступать ДополнительныеОтчетыИОбработки.ПриЗаписиВнешнейОбработки:

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

Готово) 

А теперь создадим, какую-нибудь внешнюю обработку, которую хотим запускать по расписанию, для этого в модуле обработки обязательно наличие следующей процедуры:

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

	СтрокаКоманды = тзКоманд.Добавить();
	СтрокаКоманды.Идентификатор = Новый УникальныйИдентификатор;  
	СтрокаКоманды.Представление = "Рассылка не отосланных электронных писем";
	
	РегистрационныеДанные.Вставить("Команды", ТЗКоманд);
	
	Возврат РегистрационныеДанные;
	
КонецФункции

Процедура ВыполнитьКоманду(ИдентификаторКоманды,ПараметрыОбработки) Экспорт
	
	//здесь пишем алгоритм
	
КонецПроцедуры

Теперь запустим конфигурацию, добавим внешнюю обработку и посмотрим, что получилось, появилась настройка расписания:

Проверяем через консоль заданий, и видим, что добавилось регламентное задание с названием нашей внешней обработки:

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

Внешние обработки по расписанию БСП

См. также

Шаблоны новых объектов 1С для 1С:Бухгалтерии предприятия

Инструментарий разработчика БСП (Библиотека стандартных подсистем) Механизмы типовых конфигураций Платформа 1С v8.3 1С:Бухгалтерия 3.0 Бесплатно (free)

Используются для создания новых объектов в конфигурации, чтобы не забыть, что нужно сделать. Сделано на примере 1С:Бухгалтерия предприятия, в других конфигурациях могут быть другие, а могут быть и похожие объекты.

28.12.2023    4823    mrXoxot    11    

99

Переоткрытие внешних обработок

Универсальные функции Платформа 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    3956    ke.92@mail.ru    16    

61

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

28.08.2023    8802    YA_418728146    6    

141

Печать непроведенных документов для УТ, КА, ERP. Настройка печати по пользователям, документам и печатным формам

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    2071    21    progmaster    7    

3

Многопоточное выполнение процедуры с помощью ДлительныеОперации

БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

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

1 стартмани

26.02.2023    8538    egoriy111    26    

88

Пример многопоточной обработки (БСП)

HighLoad оптимизация БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

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

13.02.2023    9315    6    echo77    8    

93