///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

#Область ОбработчикиСобытийПодсистемБСП

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

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

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

// Формирует список параметров ИБ.
//
// Параметры:
//   ТаблицаПараметров - ТаблицаЗначений - таблица описания параметров. Описание и состав колонок 
//                                         см. РаботаВМоделиСервиса.ПолучитьТаблицуПараметровИБ().
//
Процедура ПриЗаполненииТаблицыПараметровИБ(Знач ТаблицаПараметров) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса") Тогда
		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		МодульРаботаВМоделиСервиса.ДобавитьКонстантуВТаблицуПараметровИБ(ТаблицаПараметров, "АдресДляВосстановленияПароляУчетнойЗаписи");
	КонецЕсли;
	
КонецПроцедуры

// Заполняет структуру массивами поддерживаемых версий всех подлежащих версионированию подсистем,
// используя в качестве ключей названия подсистем.
// Обеспечивает функциональность Web-сервиса InterfaceVersion.
// При внедрении надо поменять тело процедуры так, чтобы она возвращала актуальные наборы версий (см. пример.ниже).
//
// Параметры:
//   СтруктураПоддерживаемыхВерсий - Структура - имена подсистем и соответствующие им наборы поддерживаемых версий.
//	                                 В качестве ключа структуры выступает название подсистемы,
//                                   а в качестве значения - массив названий поддерживаемых версий.
//
// Пример:
//	 // СервисПередачиФайлов
//	 МассивВерсий = Новый Массив;
//	 МассивВерсий.Добавить("1.0.1.1");	
//	 МассивВерсий.Добавить("1.0.2.1"); 
//	 СтруктураПоддерживаемыхВерсий.Вставить("СервисПередачиФайлов", МассивВерсий);
//	 // Конец СервисПередачиФайлов
//
Процедура ПриОпределенииПоддерживаемыхВерсийПрограммныхИнтерфейсов(Знач СтруктураПоддерживаемыхВерсий) Экспорт
	
	МассивВерсий = Новый Массив;
	МассивВерсий.Добавить("2.0.1.6");
	МассивВерсий.Добавить("2.1.1.7");
	МассивВерсий.Добавить("2.1.2.1");
	МассивВерсий.Добавить("2.1.5.17");
	МассивВерсий.Добавить("2.1.6.1");
	МассивВерсий.Добавить("2.4.5.1");
	СтруктураПоддерживаемыхВерсий.Вставить("ОбменДаннымиВМоделиСервиса", МассивВерсий);
	
	МассивВерсий = Новый Массив();
	МассивВерсий.Добавить("1.0.0.1");
	СтруктураПоддерживаемыхВерсий.Вставить("ОбновлениеПравилРегистрацииОбъектовВМоделиСервиса", МассивВерсий);
	
КонецПроцедуры

// Получает список обработчиков сообщений, которые обрабатывают подсистемы библиотеки.
// 
// Параметры:
//  Обработчики - ТаблицаЗначений - состав полей см. в ОбменСообщениями.НоваяТаблицаОбработчиковСообщений.
// 
Процедура ПриОпределенииОбработчиковКаналовСообщений(Обработчики) Экспорт
	
	СообщенияОбменаДаннымиОбработчикСообщения.ПолучитьОбработчикиКаналовСообщений(Обработчики);
	
КонецПроцедуры

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

// Заполняет структуру параметров, необходимых для работы клиентского кода
// конфигурации.
//
// Параметры:
//   Параметры   - Структура - структура параметров.
//
Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт
	
	ДобавитьПараметрыРаботыКлиента(Параметры);
	
КонецПроцедуры

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

	КонецЕсли;
	
КонецПроцедуры

// Выполняет удаление файлов сообщений обмена, которые не были удалены из-за сбоев в работе системы.
// Удалению подлежат файлы с датой размещения более суток от текущей универсальной даты.
// Анализируется РС.СообщенияОбменаДаннымиОбластейДанных.
//
Процедура ПриУдаленииНеактуальныхСообщенийОбмена() Экспорт
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	СообщенияОбменаДанными.ИдентификаторСообщения КАК ИдентификаторСообщения,
	|	СообщенияОбменаДанными.ИмяФайлаСообщения КАК ИмяФайла,
	|	СообщенияОбменаДанными.ОбластьДанныхВспомогательныеДанные КАК ОбластьДанныхВспомогательныеДанные,
	|	СообщенияОбменаДанными.ДатаЗакладкиСообщения КАК ДатаЗакладкиСообщения
	|ИЗ
	|	РегистрСведений.СообщенияОбменаДаннымиОбластейДанных КАК СообщенияОбменаДанными
	|ГДЕ
	|	СообщенияОбменаДанными.ДатаЗакладкиСообщения < &ДатаАктуальности
	|
	|УПОРЯДОЧИТЬ ПО
	|	ОбластьДанныхВспомогательныеДанные";
	
	УниверсальнаяДата = ТекущаяУниверсальнаяДата();
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ДатаАктуальности", УниверсальнаяДата - 60 * 60 * 24);
	Запрос.Текст = ТекстЗапроса;
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	ПараметрыСеанса.ОбластьДанныхИспользование = Истина;
	ОбластьДанныхВспомогательныеДанные = Неопределено;
	
	Пока Выборка.Следующий() Цикл
		
		Если ОбластьДанныхВспомогательныеДанные <> Выборка.ОбластьДанныхВспомогательныеДанные Тогда
			
			ОбластьДанныхВспомогательныеДанные = Выборка.ОбластьДанныхВспомогательныеДанные;
			ПараметрыСеанса.ОбластьДанныхЗначение = ОбластьДанныхВспомогательныеДанные;
			
		КонецЕсли;
		
		УзелОбщиеНастройки = Неопределено;
		
		ЗапросОбщиеНастройки = Новый Запрос(
		"ВЫБРАТЬ
		|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы КАК УзелИнформационнойБазы
		|ИЗ
		|	РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз КАК ОбщиеНастройкиУзловИнформационныхБаз
		|ГДЕ
		|	ОбщиеНастройкиУзловИнформационныхБаз.СообщениеДляСопоставленияДанных = &СообщениеДляСопоставленияДанных");
		ЗапросОбщиеНастройки.УстановитьПараметр("СообщениеДляСопоставленияДанных", Выборка.ИдентификаторСообщения);
		
		ВыборкаОбщиеНастройки = ЗапросОбщиеНастройки.Выполнить().Выбрать();
		Если ВыборкаОбщиеНастройки.Следующий() Тогда
			Если Не (Выборка.ДатаЗакладкиСообщения < УниверсальнаяДата - 60 * 60 * 24 * 7) Тогда
				Продолжить;
			КонецЕсли;
			
			УзелОбщиеНастройки = ВыборкаОбщиеНастройки.УзелИнформационнойБазы;
		КонецЕсли;
		
		ПолноеИмяФайлаСообщения = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(ОбменДаннымиСервер.КаталогВременногоХранилищаФайлов(), Выборка.ИмяФайла);
		
		ФайлСообщения = Новый Файл(ПолноеИмяФайлаСообщения);
		
		Если ФайлСообщения.Существует() Тогда
			
			Попытка
				УдалитьФайлы(ФайлСообщения.ПолноеИмя);
			Исключение
				ЗаписьЖурналаРегистрации(НСтр("ru = 'Обмен данными'", ОбщегоНазначения.КодОсновногоЯзыка()),
					УровеньЖурналаРегистрации.Ошибка,,, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				Продолжить;
			КонецПопытки;
		КонецЕсли;
		
		// Удаляем информацию о файле сообщения обмена из хранилища
		СтруктураЗаписи = Новый Структура;
		СтруктураЗаписи.Вставить("ИдентификаторСообщения", Строка(Выборка.ИдентификаторСообщения));
		РегистрыСведений.СообщенияОбменаДаннымиОбластейДанных.УдалитьЗапись(СтруктураЗаписи);
		
		Если Не УзелОбщиеНастройки = Неопределено Тогда
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("УзелИнформационнойБазы",          УзелОбщиеНастройки);
			СтруктураЗаписи.Вставить("СообщениеДляСопоставленияДанных", "");
			
			ОбменДаннымиСлужебный.ОбновитьЗаписьВРегистрСведений(СтруктураЗаписи, "ОбщиеНастройкиУзловИнформационныхБаз");
		КонецЕсли;
		
	КонецЦикла;
	
	ПараметрыСеанса.ОбластьДанныхИспользование = Ложь;
	
КонецПроцедуры

// Получение имени файла по его идентификатору из хранилища.
// Если файла с указанным идентификатором нет, то вызывается исключение.
// Если файл найден, то возвращается его имя, при этом удаляется информация об этом файле из хранилища.
//
// Параметры:
//  ИдентификаторФайла - УникальныйИдентификатор - идентификатор получаемого файла.
//  ИмяФайла           - Строка - имя файла, из хранилища.
//
Процедура ПриПолученииФайлаИзХранилища(Знач ИдентификаторФайла, ИмяФайла) Экспорт
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	СообщенияОбменаДанными.ИмяФайлаСообщения КАК ИмяФайла
	|ИЗ
	|	РегистрСведений.СообщенияОбменаДаннымиОбластейДанных КАК СообщенияОбменаДанными
	|ГДЕ
	|	СообщенияОбменаДанными.ИдентификаторСообщения = &ИдентификаторСообщения";
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ИдентификаторСообщения", Строка(ИдентификаторФайла));
	Запрос.Текст = ТекстЗапроса;
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Описание = НСтр("ru = 'Файл с идентификатором %1 не обнаружен.'");
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Описание, Строка(ИдентификаторФайла));
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	Выборка.Следующий();
	ИмяФайла = Выборка.ИмяФайла;
	
	// Удаляем информацию о файле сообщения обмена из хранилища
	СтруктураЗаписи = Новый Структура;
	СтруктураЗаписи.Вставить("ИдентификаторСообщения", Строка(ИдентификаторФайла));
	РегистрыСведений.СообщенияОбменаДаннымиОбластейДанных.УдалитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

// Помещение файла в хранилище
//
// Параметры:
//   СтруктураЗаписи - Структура - имена и значения измерений регистра сведений "СообщенияОбменаДаннымиОбластейДанных".
//
Процедура ПриПомещенииФайлаВХранилище(Знач СтруктураЗаписи) Экспорт
	
	РегистрыСведений.СообщенияОбменаДаннымиОбластейДанных.ДобавитьЗапись(СтруктураЗаписи);
	
КонецПроцедуры

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

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

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

#КонецОбласти

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

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

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

Процедура ИзменитьПризнакНеобходимостиОбменаДаннымиВМоделиСервиса(НеобходимоВыполнитьОбмен, ДополнительныеПараметры = Неопределено) Экспорт
	
	НеобходимоВыполнитьОбмен = (НеобходимоВыполнитьОбмен = Истина); // Защита на не булевское значение
	
	ИнтервалОжидания = 180; // 1 попытка в 200 секунд (180 ожидание + 20 секунд попытка блокировки платформы)
	КоличествоПопыток = 65; // По умолчанию 3 часа 30 минут (12600 секунд)
	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
		
		Если ДополнительныеПараметры.Свойство("ИнтервалОжидания") Тогда
			
			ИнтервалОжидания = ДополнительныеПараметры.ИнтервалОжидания;
			
		КонецЕсли;
		
		Если ДополнительныеПараметры.Свойство("КоличествоПопыток") Тогда
			
			КоличествоПопыток = ДополнительныеПараметры.КоличествоПопыток;
			
		КонецЕсли;
		
	КонецЕсли;
	
	БлокировкаДанных = Новый БлокировкаДанных;
	ЭлементБлокировки = БлокировкаДанных.Добавить("Константа.ЗарегистрированыИзмененияДанных");
	ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
	
	ЗначениеКонстантыИзменено = Ложь;
	Для ПопыткаИзменения = 1 По КоличествоПопыток Цикл
		
		НачатьТранзакцию();
		Попытка
			
			БлокировкаДанных.Заблокировать();
			Константы.ЗарегистрированыИзмененияДанных.Установить(НеобходимоВыполнитьОбмен);
			ЗначениеКонстантыИзменено = Истина;
			
			ЗафиксироватьТранзакцию();
			Прервать;
			
		Исключение
			
			ОтменитьТранзакцию();
			Если ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса") Тогда
				
				МодульОбщегоНазначенияБТС = ОбщегоНазначения.ОбщийМодуль("ОбщегоНазначенияБТС");
				МодульОбщегоНазначенияБТС.Пауза(ИнтервалОжидания);
				
			КонецЕсли;
			
		КонецПопытки
		
	КонецЦикла;
	
	Если НЕ ЗначениеКонстантыИзменено Тогда
		
		ТекстИсключения = НСтр("ru ='Ошибка блокировки константы ""Зарегистрированы изменения данных"".
			|Повторите попытку позже.'", ОбщегоНазначения.КодОсновногоЯзыка());
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
			УровеньЖурналаРегистрации.Ошибка, , , ТекстИсключения);
		ВызватьИсключение ТекстИсключения;
		
	КонецЕсли;
	
КонецПроцедуры

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

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

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

// Обработчики обновления ИБ

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

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

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

	КонецЕсли;
	
КонецПроцедуры

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

			    ЗафиксироватьТранзакцию();
			Исключение
			    ОтменитьТранзакцию();
			    ВызватьИсключение;
			КонецПопытки;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

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

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

//

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

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

//

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

// Генерирует код узла плана обмена для заданной области данных.
//
// Параметры:
//   НомерОбласти - Число - значение разделителя. 
//
// Возвращаемое значение:
//   Строка - код узла плана обмена для заданной области. 
//
Функция КодУзлаПланаОбменаВСервисе(Знач НомерОбласти) Экспорт
	
	Если ТипЗнч(НомерОбласти) <> Тип("Число") Тогда
		ВызватьИсключение НСтр("ru = 'Неправильный тип параметра номер [1].'");
	КонецЕсли;
	
	Результат = "S0[НомерОбласти]";
	
	Возврат СтрЗаменить(Результат, "[НомерОбласти]", Формат(НомерОбласти, "ЧЦ=7; ЧВН=; ЧГ=0"));
	
КонецФункции

Процедура ПолучитьСостоянияОбменовДанными(МенеджерВременныхТаблиц) Экспорт
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	СостоянияОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияОбменовДанными.ДатаНачала КАК ДатаНачала,
	|	СостоянияОбменовДанными.ДатаОкончания КАК ДатаОкончания,
	|	ВЫБОР
	|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Предупреждение_СообщениеОбменаБылоРанееПринято)
	|				ИЛИ СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
	|			ТОГДА 2
	|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
	|			ТОГДА ВЫБОР
	|					КОГДА ЕСТЬNULL(КоличествоПроблем.Количество, 0) > 0
	|						ТОГДА 2
	|					ИНАЧЕ 0
	|				КОНЕЦ
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК РезультатВыполненияОбмена
	|ПОМЕСТИТЬ СостоянияОбменовДаннымиЗагрузка
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДаннымиОбластейДанных КАК СостоянияОбменовДанными
	|		ЛЕВОЕ СОЕДИНЕНИЕ КоличествоПроблем КАК КоличествоПроблем
	|		ПО СостоянияОбменовДанными.УзелИнформационнойБазы = КоличествоПроблем.УзелИнформационнойБазы
	|			И СостоянияОбменовДанными.ДействиеПриОбмене = КоличествоПроблем.ДействиеПриОбмене
	|ГДЕ
	|	СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СостоянияОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияОбменовДанными.ДатаНачала КАК ДатаНачала,
	|	СостоянияОбменовДанными.ДатаОкончания КАК ДатаОкончания,
	|	ВЫБОР
	|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
	|			ТОГДА 2
	|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
	|			ТОГДА ВЫБОР
	|					КОГДА ЕСТЬNULL(КоличествоПроблем.Количество, 0) > 0
	|						ТОГДА 2
	|					ИНАЧЕ 0
	|				КОНЕЦ
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК РезультатВыполненияОбмена
	|ПОМЕСТИТЬ СостоянияОбменовДаннымиВыгрузка
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДаннымиОбластейДанных КАК СостоянияОбменовДанными
	|		ЛЕВОЕ СОЕДИНЕНИЕ КоличествоПроблем КАК КоличествоПроблем
	|		ПО СостоянияОбменовДанными.УзелИнформационнойБазы = КоличествоПроблем.УзелИнформационнойБазы
	|			И СостоянияОбменовДанными.ДействиеПриОбмене = КоличествоПроблем.ДействиеПриОбмене
	|ГДЕ
	|	СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СостоянияУспешныхОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияУспешныхОбменовДанными.ДатаОкончания КАК ДатаОкончания
	|ПОМЕСТИТЬ СостоянияУспешныхОбменовДаннымиЗагрузка
	|ИЗ
	|	РегистрСведений.СостоянияУспешныхОбменовДаннымиОбластейДанных КАК СостоянияУспешныхОбменовДанными
	|ГДЕ
	|	СостоянияУспешныхОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СостоянияУспешныхОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияУспешныхОбменовДанными.ДатаОкончания КАК ДатаОкончания
	|ПОМЕСТИТЬ СостоянияУспешныхОбменовДаннымиВыгрузка
	|ИЗ
	|	РегистрСведений.СостоянияУспешныхОбменовДаннымиОбластейДанных КАК СостоянияУспешныхОбменовДанными
	|ГДЕ
	|	СостоянияУспешныхОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)");
	
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
КонецПроцедуры

Процедура ПолучитьСообщенияДляСопоставленияДанных(МенеджерВременныхТаблиц) Экспорт
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	ВЫБОР
	|		КОГДА КОЛИЧЕСТВО(ОбщиеНастройкиУзловИнформационныхБаз.СообщениеДляСопоставленияДанных) > 0
	|			ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК ПолученоСообщениеДляСопоставленияДанных,
	|	МАКСИМУМ(СообщенияОбменаДанными.ДатаЗакладкиСообщения) КАК ДатаЗакладкиПоследнегоСообщения
	|ПОМЕСТИТЬ СообщенияДляСопоставленияДанных
	|ИЗ
	|	РегистрСведений.ОбщиеНастройкиУзловИнформационныхБаз КАК ОбщиеНастройкиУзловИнформационныхБаз
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СообщенияОбменаДаннымиОбластейДанных КАК СообщенияОбменаДанными
	|		ПО (СообщенияОбменаДанными.ИдентификаторСообщения = ОбщиеНастройкиУзловИнформационныхБаз.СообщениеДляСопоставленияДанных)
	|
	|СГРУППИРОВАТЬ ПО
	|	ОбщиеНастройкиУзловИнформационныхБаз.УзелИнформационнойБазы");
	
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
КонецПроцедуры

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

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

Процедура ОбновитьНастройкиТранспортаОбластиДанных(Параметры) Экспорт
	
	Корреспондент                = Параметры.Корреспондент;
	КодЭтогоУзла                 = Параметры.КодЭтогоУзла;
	КодКорреспондента            = Параметры.КодКорреспондента;
	КонечнаяТочкаКорреспондента  = Параметры.КонечнаяТочкаКорреспондента;
	ЭтоКорреспондент             = Параметры.ЭтоКорреспондент;
	РежимСовместимостиСБСП_2_0_0 = Параметры.РежимСовместимостиСБСП_2_0_0;
	ПсевдонимЭтогоУзла           = Параметры.ПсевдонимЭтогоУзла;
	
	Если ЭтоКорреспондент Тогда
		Если Не ПустаяСтрока(ПсевдонимЭтогоУзла) Тогда
			ОтносительныйКаталогОбменаИнформацией = ИмяКаталогаСообщенийОбмена(КодКорреспондента, ПсевдонимЭтогоУзла);
		Иначе
			ОтносительныйКаталогОбменаИнформацией = ИмяКаталогаСообщенийОбмена(КодКорреспондента, КодЭтогоУзла);
		КонецЕсли;
	Иначе
		Если Не ПустаяСтрока(ПсевдонимЭтогоУзла) Тогда
			ОтносительныйКаталогОбменаИнформацией = ИмяКаталогаСообщенийОбмена(ПсевдонимЭтогоУзла, КодКорреспондента);
		Иначе
			ОтносительныйКаталогОбменаИнформацией = ИмяКаталогаСообщенийОбмена(КодЭтогоУзла, КодКорреспондента);
		КонецЕсли;
	КонецЕсли;
	
	НастройкиТранспорта = РегистрыСведений.НастройкиТранспортаОбменаОбластейДанных.НастройкиТранспорта(КонечнаяТочкаКорреспондента);
	
	Если НастройкиТранспорта.ВидТранспортаСообщенийОбменаПоУмолчанию = Перечисления.ВидыТранспортаСообщенийОбмена.FILE Тогда
		
		// Обмен через сетевой каталог
		
		FILEОбщийКаталогОбменаИнформацией = СокрЛП(НастройкиТранспорта.FILEКаталогОбменаИнформацией);
		
		Если ПустаяСтрока(FILEОбщийКаталогОбменаИнформацией) Тогда
			
			СтрокаСообщения = НСтр("ru = 'Не задан каталог обмена информацией для конечной точки ""%1"".'");
			СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, Строка(КонечнаяТочкаКорреспондента));
			ВызватьИсключение СтрокаСообщения;
		КонецЕсли;
		
		ОбщийКаталог = Новый Файл(FILEОбщийКаталогОбменаИнформацией);
		
		Если Не ОбщийКаталог.Существует() Тогда
			
			СтрокаСообщения = НСтр("ru = 'Каталог обмена информацией ""%1"" не существует.'");
			СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, FILEОбщийКаталогОбменаИнформацией);
			ВызватьИсключение СтрокаСообщения;
		КонецЕсли;
		
		Если Не РежимСовместимостиСБСП_2_0_0 Тогда
			
			FILEАбсолютныйКаталогОбменаИнформацией = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
				FILEОбщийКаталогОбменаИнформацией,
				ОтносительныйКаталогОбменаИнформацией);
			
			// Создаем каталог обмена сообщениями
			АбсолютныйКаталог = Новый Файл(FILEАбсолютныйКаталогОбменаИнформацией);
			Если Не АбсолютныйКаталог.Существует() Тогда
				СоздатьКаталог(АбсолютныйКаталог.ПолноеИмя);
			КонецЕсли;
			
			// Сохраняем настройки транспорта сообщений обмена для текущей области данных
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("Корреспондент", Корреспондент);
			СтруктураЗаписи.Вставить("КонечнаяТочкаКорреспондента", КонечнаяТочкаКорреспондента);
			СтруктураЗаписи.Вставить("КаталогОбменаИнформацией", ОтносительныйКаталогОбменаИнформацией);
			
			РегистрыСведений.НастройкиТранспортаОбменаОбластиДанных.ОбновитьЗапись(СтруктураЗаписи);
		КонецЕсли;
		
	ИначеЕсли НастройкиТранспорта.ВидТранспортаСообщенийОбменаПоУмолчанию = Перечисления.ВидыТранспортаСообщенийОбмена.FTP Тогда
		
		// Обмен через FTP-сервер
		
		НастройкиFTP = ТранспортСообщенийОбмена.FTPНастройкиСоединения();
		НастройкиFTP.Сервер               = НастройкиТранспорта.FTPСервер;
		НастройкиFTP.Порт                 = НастройкиТранспорта.FTPСоединениеПорт;
		НастройкиFTP.ИмяПользователя      = НастройкиТранспорта.FTPСоединениеПользователь;
		НастройкиFTP.ПарольПользователя   = НастройкиТранспорта.FTPСоединениеПароль;
		НастройкиFTP.ПассивноеСоединение  = НастройкиТранспорта.FTPСоединениеПассивноеСоединение;
		НастройкиFTP.ЗащищенноеСоединение = ОбменДаннымиСервер.ЗащищенноеСоединение(НастройкиТранспорта.FTPСоединениеПуть);
		
		FTPСоединение = ТранспортСообщенийОбмена.FTPСоединение(НастройкиFTP);
		
		АбсолютныйКаталогОбменаИнформацией = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
			НастройкиТранспорта.FTPПуть,
			ОтносительныйКаталогОбменаИнформацией);

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

// Событие для журнала регистрации настройки синхронизации данных
// 
// Возвращаемое значение:
//  Строка - событие журнала регистрации строкой
//
Функция СобытиеЖурналаРегистрацииНастройкаСинхронизацииДанных() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными в модели сервиса.Настройка синхронизации данных'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#Область ЭкспортныеСлужебныеПроцедурыИФункции

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

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

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

// Выполнить действие сценария обмена, заданное строкой таблицы значений, для первой из двух обменивающихся ИБ.
//
// Параметры:
//   ИндексСтрокиСценария - Число - индекс строки в таблице СценарийОбменаДанными.
//   СценарийОбменаДанными - ТаблицаЗначений.
//
Процедура ВыполнитьДействиеСценарияОбменаДаннымиВПервойИнформационнойБазе(ИндексСтрокиСценария, СценарийОбменаДанными) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если ИндексСтрокиСценария > СценарийОбменаДанными.Количество() - 1 Тогда
		ЗавершитьВыполнениеСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными);
		Возврат;
	КонецЕсли;
	
	ОписаниеВыполняемогоДействияЖР = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Выполнение шага сценария синхронизации (%1/%2).'"), ИндексСтрокиСценария + 1, СценарийОбменаДанными.Количество())
		+ Символы.ПС + ОписаниеСтрокиСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными);
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
		УровеньЖурналаРегистрации.Информация, , , ОписаниеВыполняемогоДействияЖР);
	
	СтрокаСценария = СценарийОбменаДанными[ИндексСтрокиСценария];
	
	СтруктураРезультат = Новый Структура;
	СтруктураРезультат.Вставить("Отказ",          Ложь);
	СтруктураРезультат.Вставить("ДатаНачала",     ТекущаяДатаСеанса());
	СтруктураРезультат.Вставить("ДатаЗавершения", '00010101');
	СтруктураРезультат.Вставить("Информация",     "");
	
	УзелИнформационнойБазы = Неопределено;
	
	Если СтрокаСценария.НомерИнформационнойБазы = 1 Тогда
		
		Попытка
			УзелИнформационнойБазы = НайтиУзелИнформационнойБазы(СтрокаСценария.ИмяПланаОбмена, СтрокаСценария.КодУзлаИнформационнойБазы);
			
			Если Не ОбменДаннымиСервер.НастройкаСинхронизацииЗавершена(УзелИнформационнойБазы) Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Настройка синхронизации данных в приложении ""%1"" не завершена.'"),
					УзелИнформационнойБазы);
			ИначеЕсли ОбменДаннымиСервер.ПолученоСообщениеСДаннымиДляСопоставления(УзелИнформационнойБазы) Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'В приложение ""%1"" загружено сообщение для ручного сопоставления.'"),
					УзелИнформационнойБазы);
			ИначеЕсли СтрокаСценария.ВыполняемоеДействие = "ЗагрузкаДанных" Тогда
				ВыполнитьЗагрузкуДанных(СтруктураРезультат.Отказ, УзелИнформационнойБазы);
			ИначеЕсли СтрокаСценария.ВыполняемоеДействие = "ВыгрузкаДанных" Тогда
				ВыполнитьВыгрузкуДанных(СтруктураРезультат.Отказ, УзелИнформационнойБазы);
			Иначе
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Неизвестное действие ""%1"" при обмене данными между областями данных.'"),
					СтрокаСценария.ВыполняемоеДействие);
			КонецЕсли;
		Исключение
			СтруктураРезультат.Отказ = Истина;
			СтруктураРезультат.Информация = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			СтруктураРезультат.ДатаЗавершения = ТекущаяДатаСеанса();
			
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
				УровеньЖурналаРегистрации.Ошибка, , , ОписаниеВыполняемогоДействияЖР + Символы.ПС + СтруктураРезультат.Информация);
				
			ЗаполнитьЗначенияСвойств(СтрокаСценария, СтруктураРезультат);
				
			ВыполнитьДействиеСценарияОбменаДаннымиВПервойИнформационнойБазе(ИндексСтрокиСценария + 1, СценарийОбменаДанными);
			Возврат;
		КонецПопытки;
		
		СтруктураРезультат.ДатаЗавершения = ТекущаяДатаСеанса();
		
		ЗаполнитьЗначенияСвойств(СтрокаСценария, СтруктураРезультат);
		
		ВыполнитьДействиеСценарияОбменаДаннымиВПервойИнформационнойБазе(ИндексСтрокиСценария + 1, СценарийОбменаДанными);
		
	ИначеЕсли СтрокаСценария.НомерИнформационнойБазы = 2 Тогда
		
		Попытка
			УзелИнформационнойБазы = НайтиУзелИнформационнойБазы(СтрокаСценария.ИмяПланаОбмена, СтрокаСценария.КодЭтогоУзла);
			
			ОписаниеWSПрокси = ОписаниеWSПроксиКорреспондента(УзелИнформационнойБазы);
			
			Если ОписаниеWSПрокси.WSПрокси = Неопределено Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось получить описание WS-прокси для приложения ""%1"".'"),
					УзелИнформационнойБазы);
			Иначе
				ПараметрСценарийОбменаДанными = ?(ОписаниеWSПрокси.ПоддерживаетсяСериализацияXDTO,
					СериализаторXDTO.ЗаписатьXDTO(СценарийОбменаДанными),
					ЗначениеВСтрокуВнутр(СценарийОбменаДанными));
					
				ОписаниеWSПрокси.WSПрокси.StartExchangeExecutionInSecondDataBase(ИндексСтрокиСценария, ПараметрСценарийОбменаДанными);
			КонецЕсли;
		Исключение
			СтруктураРезультат.Отказ = Истина;
			СтруктураРезультат.Информация = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
			СтруктураРезультат.ДатаЗавершения = ТекущаяДатаСеанса();
			
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
				УровеньЖурналаРегистрации.Ошибка, , , ОписаниеВыполняемогоДействияЖР + Символы.ПС + СтруктураРезультат.Информация);
				
			ЗаполнитьЗначенияСвойств(СтрокаСценария, СтруктураРезультат);
				
			ВыполнитьДействиеСценарияОбменаДаннымиВПервойИнформационнойБазе(ИндексСтрокиСценария + 1, СценарийОбменаДанными);
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

// Выполнить действие сценария обмена, заданное строкой таблицы значений, для второй из двух обменивающихся ИБ.
//
// Параметры:
//   ИндексСтрокиСценария - Число - индекс строки в таблице СценарийОбменаДанными.
//   СценарийОбменаДанными - ТаблицаЗначений.
//
Процедура ВыполнитьДействиеСценарияОбменаДаннымиВоВторойИнформационнойБазе(ИндексСтрокиСценария, СценарийОбменаДанными) Экспорт
	
	ОписаниеВыполняемогоДействияЖР = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Выполнение шага сценария синхронизации (%1/%2).'"), ИндексСтрокиСценария + 1, СценарийОбменаДанными.Количество())
		+ Символы.ПС + ОписаниеСтрокиСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными);
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
		УровеньЖурналаРегистрации.Информация, , , ОписаниеВыполняемогоДействияЖР);
	
	УстановитьПривилегированныйРежим(Истина);
	
	СтрокаСценария = СценарийОбменаДанными[ИндексСтрокиСценария];
	
	Если СтрокаСценария.ПорядковыйНомерВыполнения = 1 Тогда
		// Сбрасываем признак кумулятивного изменения данных для обмена.
		ИзменитьПризнакНеобходимостиОбменаДаннымиВМоделиСервиса(Ложь);
	КонецЕсли;
	
	СтруктураРезультат = Новый Структура;
	СтруктураРезультат.Вставить("Отказ",          Ложь);
	СтруктураРезультат.Вставить("ДатаНачала",     ТекущаяДатаСеанса());
	СтруктураРезультат.Вставить("ДатаЗавершения", '00010101');
	СтруктураРезультат.Вставить("Информация",     "");
	
	УзелИнформационнойБазы = Неопределено;
	Попытка
		УзелИнформационнойБазы = НайтиУзелИнформационнойБазы(СтрокаСценария.ИмяПланаОбмена, СтрокаСценария.КодУзлаИнформационнойБазы);
	Исключение
		СтруктураРезультат.Отказ = Истина;
		СтруктураРезультат.Информация = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
			УровеньЖурналаРегистрации.Ошибка, , , ОписаниеВыполняемогоДействияЖР + Символы.ПС + СтруктураРезультат.Информация);
			
		ЗавершитьВыполнениеСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными, СтруктураРезультат);
		Возврат;
	КонецПопытки;
	
	Попытка
		Если Не ОбменДаннымиСервер.НастройкаСинхронизацииЗавершена(УзелИнформационнойБазы) Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Настройка синхронизации данных в приложении ""%1"" не завершена.'"),
				УзелИнформационнойБазы);
		ИначеЕсли ОбменДаннымиСервер.ПолученоСообщениеСДаннымиДляСопоставления(УзелИнформационнойБазы) Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В приложение ""%1"" загружено сообщение для ручного сопоставления.'"),
				УзелИнформационнойБазы);
		ИначеЕсли СтрокаСценария.ВыполняемоеДействие = "ЗагрузкаДанных" Тогда
			ВыполнитьЗагрузкуДанных(СтруктураРезультат.Отказ, УзелИнформационнойБазы);
		ИначеЕсли СтрокаСценария.ВыполняемоеДействие = "ВыгрузкаДанных" Тогда
			ВыполнитьВыгрузкуДанных(СтруктураРезультат.Отказ, УзелИнформационнойБазы);
		Иначе
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Неизвестное действие ""%1"" при обмене данными между областями данных.'"),
				СтрокаСценария.ВыполняемоеДействие);
		КонецЕсли;
	Исключение
		СтруктураРезультат.Отказ = Истина;
		СтруктураРезультат.Информация = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
			УровеньЖурналаРегистрации.Ошибка, , , ОписаниеВыполняемогоДействияЖР + Символы.ПС + СтруктураРезультат.Информация);
	КонецПопытки;
	СтруктураРезультат.ДатаЗавершения = ТекущаяДатаСеанса();
	
	ЗаполнитьЗначенияСвойств(СтрокаСценария, СтруктураРезультат);
	
	// Завершение выполнения сценария.
	Если ИндексСтрокиСценария = СценарийОбменаДанными.Количество() - 1 Тогда
		ЗавершитьВыполнениеСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными, СтруктураРезультат);
		Возврат;
	КонецЕсли;
	
	Попытка
		ОписаниеWSПрокси = ОписаниеWSПроксиКорреспондента(УзелИнформационнойБазы);
		
		Если ОписаниеWSПрокси.WSПрокси = Неопределено Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить описание WS-прокси для приложения ""%1"".'"),
				УзелИнформационнойБазы);
		Иначе
			ПараметрСценарийОбменаДанными = ?(ОписаниеWSПрокси.ПоддерживаетсяСериализацияXDTO,
				СериализаторXDTO.ЗаписатьXDTO(СценарийОбменаДанными),
				ЗначениеВСтрокуВнутр(СценарийОбменаДанными));
			
			ОписаниеWSПрокси.WSПрокси.StartExchangeExecutionInFirstDataBase(ИндексСтрокиСценария + 1, ПараметрСценарийОбменаДанными);
		КонецЕсли;
	Исключение
		СтруктураРезультат.Отказ = Истина;
		СтруктураРезультат.Информация = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		СтруктураРезультат.ДатаЗавершения = ТекущаяДатаСеанса();
		
		ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСинхронизацииДанных(),
			УровеньЖурналаРегистрации.Ошибка, , , ОписаниеВыполняемогоДействияЖР + Символы.ПС + СтруктураРезультат.Информация);
			
		ЗаполнитьЗначенияСвойств(СтрокаСценария, СтруктураРезультат);
			
		ЗавершитьВыполнениеСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными, СтруктураРезультат);
	КонецПопытки;
	
КонецПроцедуры

// Выполняет удаление узла обмена в этой базе.
//
Процедура УдалитьНастройкуСинхронизации(ИмяПланаОбмена, КодУзлаКорреспондента) Экспорт
	
	Корреспондент = НайтиУзелИнформационнойБазы(ИмяПланаОбмена, КодУзлаКорреспондента);
	
	ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Обработка сообщения удаления настройки синхронизации ""%1"" с приложением ""%2"".'"),
		ИмяПланаОбмена, КодУзлаКорреспондента);
	
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииНастройкаСинхронизацииДанных(),
		УровеньЖурналаРегистрации.Информация, , , ТекстСообщения);
	
	НастройкиТранспорта = РегистрыСведений.НастройкиТранспортаОбменаОбластиДанных.НастройкиТранспорта(Корреспондент);
	
	Если НастройкиТранспорта <> Неопределено Тогда
		
		Если НастройкиТранспорта.ВидТранспортаСообщенийОбменаПоУмолчанию = Перечисления.ВидыТранспортаСообщенийОбмена.FILE Тогда
			
			Если Не ПустаяСтрока(НастройкиТранспорта.FILEОбщийКаталогОбменаИнформацией)
				И Не ПустаяСтрока(НастройкиТранспорта.ОтносительныйКаталогОбменаИнформацией) Тогда
				
				АбсолютныйКаталогОбменаИнформацией = ОбщегоНазначенияКлиентСервер.ПолучитьПолноеИмяФайла(
					НастройкиТранспорта.FILEОбщийКаталогОбменаИнформацией,
					НастройкиТранспорта.ОтносительныйКаталогОбменаИнформацией);
				
				АбсолютныйКаталог = Новый Файл(АбсолютныйКаталогОбменаИнформацией);
				
				Попытка
					УдалитьФайлы(АбсолютныйКаталог.ПолноеИмя);
				Исключение
					ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииНастройкаСинхронизацииДанных(),
						УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				КонецПопытки;
				
			КонецЕсли;
			
		ИначеЕсли НастройкиТранспорта.ВидТранспортаСообщенийОбменаПоУмолчанию = Перечисления.ВидыТранспортаСообщенийОбмена.FTP Тогда
			
			Попытка
				
				НастройкиFTP = ТранспортСообщенийОбмена.FTPНастройкиСоединения();
				НастройкиFTP.Сервер               = НастройкиТранспорта.FTPСервер;
				НастройкиFTP.Порт                 = НастройкиТранспорта.FTPСоединениеПорт;
				НастройкиFTP.ИмяПользователя      = НастройкиТранспорта.FTPСоединениеПользователь;
				НастройкиFTP.ПарольПользователя   = НастройкиТранспорта.FTPСоединениеПароль;
				НастройкиFTP.ПассивноеСоединение  = НастройкиТранспорта.FTPСоединениеПассивноеСоединение;
				НастройкиFTP.ЗащищенноеСоединение = ОбменДаннымиСервер.ЗащищенноеСоединение(НастройкиТранспорта.FTPСоединениеПуть);
				
				FTPСоединение = ТранспортСообщенийОбмена.FTPСоединение(НастройкиFTP);
				
				Если ТранспортСообщенийОбмена.FTPКаталогСуществует(
					НастройкиТранспорта.FTPПуть,
					НастройкиТранспорта.ОтносительныйКаталогОбменаИнформацией, 
					FTPСоединение) Тогда
					
					FTPСоединение.Удалить(НастройкиТранспорта.FTPПуть);
					
				КонецЕсли;
				
			Исключение
				ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииНастройкаСинхронизацииДанных(),
					УровеньЖурналаРегистрации.Ошибка, , , ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			КонецПопытки;
			
		КонецЕсли;
		
	КонецЕсли;
	
	УдалитьУзелПланаОбмена(Корреспондент);
	
КонецПроцедуры

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

Функция ИмяКаталогаСообщенийОбмена(Знач Код1, Знач Код2)
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку("Exchange %1-%2", Код1, Код2);
	
КонецФункции

// Регистрирует обработчики поставляемых данных
//
Процедура ЗарегистрироватьОбработчикиПоставляемыхДанных(Знач Обработчики)
	
	Обработчик = Обработчики.Добавить();
	Обработчик.ВидДанных = ИдентификаторВидаПоставляемыхДанных();
	Обработчик.КодОбработчика = ИдентификаторВидаПоставляемыхДанных();
	Обработчик.Обработчик = ОбменДаннымиВМоделиСервиса;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.ВидДанных = ИдентификаторВидаПоставляемыхДанныхПравилаРегистрации();
	Обработчик.КодОбработчика = ИдентификаторВидаПоставляемыхДанныхПравилаРегистрации();
	Обработчик.Обработчик = ОбменДаннымиВМоделиСервиса;
	
КонецПроцедуры

// Вызывается при получении уведомления о новых данных.
// В теле следует проверить, необходимы ли эти данные приложению, 
// и если да - установить флажок Загружать.
// 
// Параметры:
//   Дескриптор   - ОбъектXDTO Descriptor.
//   Загружать    - Булево - возвращаемое.
//
Процедура ДоступныНовыеДанные(Знач Дескриптор, Загружать) Экспорт
	
	Если Дескриптор.DataType = ИдентификаторВидаПоставляемыхДанных()
		Или Дескриптор.DataType = ИдентификаторВидаПоставляемыхДанныхПравилаРегистрации() Тогда
		
		ОписаниеПоставляемыхПравил = РазобратьДескрипторПоставляемыхДанных(Дескриптор);
		
		Если ОписаниеПоставляемыхПравил.ИмяКонфигурации = Метаданные.Имя
			И ОписаниеПоставляемыхПравил.ВерсияКонфигурации = Метаданные.Версия
			И Метаданные.ПланыОбмена.Найти(ОписаниеПоставляемыхПравил.ИмяПланаОбмена) <> Неопределено
			И ОбменДаннымиПовтИсп.ПланОбменаИспользуетсяВМоделиСервиса(ОписаниеПоставляемыхПравил.ИмяПланаОбмена)
			И ОбменДаннымиСервер.ЭтоРазделенныйПланОбменаБСП(ОписаниеПоставляемыхПравил.ИмяПланаОбмена) Тогда // Правила совместимы с ИБ
			
			Загружать = Истина;
			
		Иначе
			
			Загружать = Ложь;
			
			ТекстСообщения = НСтр("ru = 'Поставляемые правила обмена не подходят для текущей конфигурации и предназначены для плана обмена %1 конфигурации %2 версии %3'");
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ТекстСообщения,
				ОписаниеПоставляемыхПравил.ИмяПланаОбмена, ОписаниеПоставляемыхПравил.ИмяКонфигурации, ОписаниеПоставляемыхПравил.ВерсияКонфигурации);
			
			ЗаписьЖурналаРегистрации(НСтр("ru = 'Поставляемые правила обмена данными.Загрузка поставляемых правил отменена'",
				ОбщегоНазначения.КодОсновногоЯзыка()), УровеньЖурналаРегистрации.Информация,,, ТекстСообщения);
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

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

// Вызывается при отмене обработки данных в случае сбоя
//
Процедура ОбработкаДанныхОтменена(Знач Дескриптор) Экспорт 
	
КонецПроцедуры

// Возвращает идентификатор вида поставляемых данных для правил обмена данными
//
// Возвращаемое значение:
//   Строка
//
Функция ИдентификаторВидаПоставляемыхДанных()
	
	Возврат "ER"; // Не локализуется
	
КонецФункции

// Возвращает идентификатор вида поставляемых данных для правил обмена данными
//
// Возвращаемое значение:
//   Строка
//
Функция ИдентификаторВидаПоставляемыхДанныхПравилаРегистрации()
	
	Возврат "RR"; // Не локализуется
	
КонецФункции

Функция ОписаниеПоставляемыхПравил()
	
	Возврат Новый Структура("ИмяКонфигурации, ВерсияКонфигурации, ИмяПланаОбмена, Использовать");
	
КонецФункции

Функция РазобратьДескрипторПоставляемыхДанных(Дескриптор)
	
	ОписаниеПоставляемыхПравил = ОписаниеПоставляемыхПравил();
	
	Для Каждого ХарактеристикаПоставляемыхДанных Из Дескриптор.Properties.Property Цикл
		
		ОписаниеПоставляемыхПравил[ХарактеристикаПоставляемыхДанных.Code] = ХарактеристикаПоставляемыхДанных.Value;
		
	КонецЦикла;
	
	Возврат ОписаниеПоставляемыхПравил;
	
КонецФункции

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

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

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

Функция ОписаниеСтрокиСценарияОбменаДанными(ИндексСтрокиСценария, СценарийОбменаДанными)
	
	СтруктураСтроки = Новый Структура;
	СтруктураСтроки.Вставить("ПорядковыйНомерВыполнения");
	СтруктураСтроки.Вставить("НомерИнформационнойБазы");
	СтруктураСтроки.Вставить("ВыполняемоеДействие");
	СтруктураСтроки.Вставить("Приложение1Код");
	СтруктураСтроки.Вставить("Приложение2Код");
	СтруктураСтроки.Вставить("Режим");
	
	ЗаполнитьЗначенияСвойств(СтруктураСтроки, СценарийОбменаДанными[ИндексСтрокиСценария]);
	
	Описание = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'ПорядковыйНомер: %1, Приложение: %2, Действие: %3(%4), Режим: %5.'"),
		СтруктураСтроки.ПорядковыйНомерВыполнения,
		?(СтруктураСтроки.НомерИнформационнойБазы = 1, СтруктураСтроки.Приложение1Код, СтруктураСтроки.Приложение2Код),
		СтруктураСтроки.ВыполняемоеДействие,
		?(СтруктураСтроки.НомерИнформационнойБазы = 1, СтруктураСтроки.Приложение2Код, СтруктураСтроки.Приложение1Код),
		СтруктураСтроки.Режим);
	
	Возврат Описание;
	
КонецФункции

Функция ОписаниеWSПроксиКорреспондента(Корреспондент)
	
	Описание = Новый Структура;
	Описание.Вставить("WSПрокси",                       Неопределено);
	Описание.Вставить("ПоддерживаетсяСериализацияXDTO", Истина);
	
	ВерсииКорреспондента = ВерсииКорреспондента(Корреспондент);
		
	Если ВерсииКорреспондента.Найти("2.4.5.1") <> Неопределено Тогда
		
		Описание.WSПрокси = ОбменДаннымиВМоделиСервисаПовтИсп.ПолучитьWSПроксиКорреспондента_2_4_5_1(Корреспондент);
		
	ИначеЕсли ВерсииКорреспондента.Найти("2.1.6.1") <> Неопределено Тогда
		
		Описание.WSПрокси = ОбменДаннымиВМоделиСервисаПовтИсп.ПолучитьWSПроксиКорреспондента_2_1_6_1(Корреспондент);
	
	ИначеЕсли ВерсииКорреспондента.Найти("2.0.1.6") <> Неопределено Тогда
		
		Описание.WSПрокси = ОбменДаннымиВМоделиСервисаПовтИсп.ПолучитьWSПроксиКорреспондента_2_0_1_6(Корреспондент);
		
	Иначе
		
		Описание.WSПрокси = ОбменДаннымиВМоделиСервисаПовтИсп.ПолучитьWSПроксиКорреспондента(Корреспондент);
		Описание.ПоддерживаетсяСериализацияXDTO = Ложь;
		
	КонецЕсли;
	
	Возврат Описание;
	
КонецФункции

// Для внутреннего использования
//
Процедура СоздатьНастройкуОбмена(НастройкиПодключения,
			ЭтоКорреспондент = Ложь,
			РежимСовместимостиСБСП_2_0_0 = Ложь,
			ПсевдонимЭтогоУзла = "") Экспорт
			
	КодЭтогоУзла = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ПланыОбмена[НастройкиПодключения.ИмяПланаОбмена].ЭтотУзел(), "Код");
	// Проверяем, что для текущего узла задан код
	Если ПустаяСтрока(КодЭтогоУзла) Тогда
		// Код узла задается в обработчике обновления ИБ
		СтрокаСообщения = НСтр("ru = 'Для предопределенного узла плана обмена ""%1"" не задан код.'");
		СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения, НастройкиПодключения.ИмяПланаОбмена);
		ВызватьИсключение СтрокаСообщения;
	КонецЕсли;
	
	// Создаем/обновляем узел корреспондента
	Корреспондент = ПланыОбмена[НастройкиПодключения.ИмяПланаОбмена].НайтиПоКоду(НастройкиПодключения.КодКорреспондента);
			
	НачатьТранзакцию();
	Попытка
		Если Не Корреспондент.Пустая() Тогда
			Блокировка = Новый БлокировкаДанных;
		    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(Корреспондент));
		    ЭлементБлокировки.УстановитьЗначение("Ссылка", Корреспондент);
		    Блокировка.Заблокировать();
		КонецЕсли;
		
		// Проверяем префикс этой ИБ
		Если ПустаяСтрока(ПолучитьФункциональнуюОпцию("ПрефиксИнформационнойБазы")) Тогда
			Если ПустаяСтрока(НастройкиПодключения.Префикс) Тогда
				ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Для продолжения настройки синхронизации данных необходимо
					|задать префикс информационной базы в приложении ""%1"".'"),
					Метаданные.Синоним);
			КонецЕсли;
				
			ОбменДаннымиСервер.УстановитьПрефиксИнформационнойБазы(НастройкиПодключения.Префикс);
		КонецЕсли;
		
		ПроверитьКод = Ложь;
		
		Если Корреспондент.Пустая() Тогда
			КорреспондентОбъект = ПланыОбмена[НастройкиПодключения.ИмяПланаОбмена].СоздатьУзел();
			КорреспондентОбъект.Код = НастройкиПодключения.КодКорреспондента;
			ПроверитьКод = Истина;
		Иначе
			ЗаблокироватьДанныеДляРедактирования(Корреспондент);
			КорреспондентОбъект = Корреспондент.ПолучитьОбъект();
		КонецЕсли;
		
		КорреспондентОбъект.Наименование = НастройкиПодключения.НаименованиеКорреспондента;
		
		ОбменДаннымиСобытия.УстановитьЗначенияОтборовНаУзле(КорреспондентОбъект, НастройкиПодключения.Настройки);
		
		КорреспондентОбъект.НомерОтправленного = 0;
		КорреспондентОбъект.НомерПринятого     = 0;
		
		КорреспондентОбъект.РегистрироватьИзменения = Истина;
		
		КорреспондентОбъект.ОбменДанными.Загрузка = Истина;
		КорреспондентОбъект.Записать();
		
		Если Не ПустаяСтрока(ПсевдонимЭтогоУзла) Тогда
			МенеджерРегистра = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.ПсевдонимыПредопределенныхУзлов");
			ВиртуальныеКоды = МенеджерРегистра.СоздатьНаборЗаписей();
			ВиртуальныйКод = ВиртуальныеКоды.Добавить();
			ВиртуальныйКод.Корреспондент = КорреспондентОбъект.Ссылка;
			ВиртуальныйКод.КодУзла       = ПсевдонимЭтогоУзла;
			
			ВиртуальныеКоды.Записать();
		КонецЕсли;
		
		Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(НастройкиПодключения.ИмяПланаОбмена) Тогда
			
			ТаблицаОбъектыБазы = ОбменДаннымиXDTOСервер.ПоддерживаемыеОбъектыФормата(НастройкиПодключения.ИмяПланаОбмена,
				"ОтправкаПолучение", КорреспондентОбъект.Ссылка);
			ТаблицаОбъектыКорреспондента = ТаблицаОбъектыБазы.СкопироватьКолонки();
			
			Для Каждого СтрокаОбъектыБазы Из ТаблицаОбъектыБазы Цикл
				СтрокаОбъектыКорреспондента = ТаблицаОбъектыКорреспондента.Добавить();
				ЗаполнитьЗначенияСвойств(СтрокаОбъектыКорреспондента, СтрокаОбъектыБазы, "Версия, Объект");
				СтрокаОбъектыКорреспондента.Отправка  = СтрокаОбъектыБазы.Получение;
				СтрокаОбъектыКорреспондента.Получение = СтрокаОбъектыБазы.Отправка;
			КонецЦикла;
			
			МенеджерНастройкиXDTO = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.НастройкиОбменаДаннымиXDTO");
			МенеджерНастройкиXDTO.ОбновитьНастройки(
				КорреспондентОбъект.Ссылка, "ПоддерживаемыеОбъекты", ТаблицаОбъектыБазы);
			МенеджерНастройкиXDTO.ОбновитьНастройкиКорреспондента(
				КорреспондентОбъект.Ссылка, "ПоддерживаемыеОбъекты", ТаблицаОбъектыКорреспондента);
			
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("УзелИнформационнойБазы",       КорреспондентОбъект.Ссылка);
			СтруктураЗаписи.Вставить("ИмяПланаОбменаКорреспондента", НастройкиПодключения.ИмяПланаОбмена);
			
			ОбменДаннымиСлужебный.ОбновитьЗаписьВРегистрСведений(СтруктураЗаписи, "НастройкиОбменаДаннымиXDTO");
		КонецЕсли;
		
		// Общие данные узлов.
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ОбновитьПрефиксы(
			КорреспондентОбъект.Ссылка,
			НастройкиПодключения.Префикс);
			
		Если Не ОбменДаннымиСервер.НастройкаСинхронизацииЗавершена(КорреспондентОбъект.Ссылка) Тогда
			ОбменДаннымиСервер.ЗавершитьНастройкуСинхронизацииДанных(КорреспондентОбъект.Ссылка);
		КонецЕсли;
		
		Корреспондент = КорреспондентОбъект.Ссылка;
		
		ФактическийКодКорреспондента = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Корреспондент, "Код");
		
		Если ПроверитьКод И НастройкиПодключения.КодКорреспондента <> ФактическийКодКорреспондента Тогда
			
			СтрокаСообщения = НСтр("ru = 'Ошибка назначения кода узла корреспондента.
				|Назначенное значение ""%1""
				|Фактическое значение ""%2"".'");
			СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
				НастройкиПодключения.КодКорреспондента, ФактическийКодКорреспондента);
			ВызватьИсключение СтрокаСообщения;
		КонецЕсли;
		
		// Работа с настройками транспорта.
		Параметры = Новый Структура;
		Параметры.Вставить("Корреспондент", Корреспондент);
		Параметры.Вставить("КодЭтогоУзла", КодЭтогоУзла);
		Параметры.Вставить("КодКорреспондента", НастройкиПодключения.КодКорреспондента);
		Параметры.Вставить("КонечнаяТочкаКорреспондента", НастройкиПодключения.КонечнаяТочкаКорреспондента);
		Параметры.Вставить("ЭтоКорреспондент", ЭтоКорреспондент);
		Параметры.Вставить("РежимСовместимостиСБСП_2_0_0", РежимСовместимостиСБСП_2_0_0);
		Параметры.Вставить("ПсевдонимЭтогоУзла", ПсевдонимЭтогоУзла);
		
		ОбновитьНастройкиТранспортаОбластиДанных(Параметры);
		
		НастройкиПодключения.Корреспондент = Корреспондент;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Процедура СоздатьНастройкуОбмена_3_0_1_1(НастройкиПодключения,
		ЭтоКорреспондент = Ложь,
		РежимСовместимостиСБСП_2_0_0 = Ложь,
		ПсевдонимЭтогоУзла = "") Экспорт
		
	КодЭтогоУзла = НастройкиПодключения.ИдентификаторИнформационнойБазыИсточника;
	
	// Проверяем, что для текущего узла задан код.
	Если ПустаяСтрока(КодЭтогоУзла) Тогда
		// Код узла задается в обработчике обновления ИБ.
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Для предопределенного узла плана обмена ""%1"" не задан код.'"),
			НастройкиПодключения.ИмяПланаОбмена);
	КонецЕсли;
		
	УстановитьПрефикс = Ложь;
	Если ПустаяСтрока(ОбменДаннымиСервер.ПрефиксИнформационнойБазы()) Тогда
		Если ПустаяСтрока(НастройкиПодключения.Префикс) Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для продолжения настройки синхронизации данных необходимо
				|задать префикс информационной базы в приложении ""%1"".'"),
				Метаданные.Синоним);
		КонецЕсли;
		
		УстановитьПрефикс = Истина;
	Иначе
		НастройкиПодключения.Префикс = ОбменДаннымиСервер.ПрефиксИнформационнойБазы();
	КонецЕсли;
	
	// Создаем/обновляем узел корреспондента.
	Корреспондент = ПланыОбмена[НастройкиПодключения.ИмяПланаОбмена].НайтиПоКоду(
		НастройкиПодключения.ИдентификаторИнформационнойБазыПриемника);
	
	НачатьТранзакцию();
	Попытка
		Если Не Корреспондент.Пустая() Тогда
			Блокировка = Новый БлокировкаДанных;
		    ЭлементБлокировки = Блокировка.Добавить(ОбщегоНазначения.ИмяТаблицыПоСсылке(Корреспондент));
		    ЭлементБлокировки.УстановитьЗначение("Ссылка", Корреспондент);
		    Блокировка.Заблокировать();
		КонецЕсли;
		
		Если УстановитьПрефикс Тогда
			ОбменДаннымиСервер.УстановитьПрефиксИнформационнойБазы(НастройкиПодключения.Префикс);
		КонецЕсли;
		
		ПроверитьКод = Ложь;
		Если Корреспондент.Пустая() Тогда
			КорреспондентОбъект = ПланыОбмена[НастройкиПодключения.ИмяПланаОбмена].СоздатьУзел();
			КорреспондентОбъект.Код = НастройкиПодключения.ИдентификаторИнформационнойБазыПриемника;
			
			Если ОбщегоНазначения.ЕстьРеквизитОбъекта("ВариантНастройки", КорреспондентОбъект.Метаданные())
				И НастройкиПодключения.Свойство("ИдентификаторНастройки") Тогда
				КорреспондентОбъект.ВариантНастройки = НастройкиПодключения.ИдентификаторНастройки;
			КонецЕсли;
			
			ПроверитьКод = Истина;
		Иначе
			ЗаблокироватьДанныеДляРедактирования(Корреспондент);
			КорреспондентОбъект = Корреспондент.ПолучитьОбъект();
		КонецЕсли;
		
		КорреспондентОбъект.Наименование = НастройкиПодключения.НаименованиеКорреспондента;
		
		Если ПроверитьКод Тогда
			КорреспондентОбъект.Заполнить(Неопределено);
		КонецЕсли;
		
		КорреспондентОбъект.НомерОтправленного = 0;
		КорреспондентОбъект.НомерПринятого     = 0;
		
		КорреспондентОбъект.РегистрироватьИзменения = Истина;
		
		// Версия формата обмена.
		Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(НастройкиПодключения.ИмяПланаОбмена)
			И НастройкиПодключения.Свойство("НастройкиXDTOКорреспондента") Тогда
			
			КорреспондентОбъект.ВерсияФорматаОбмена = ОбменДаннымиXDTOСервер.МаксимальнаяОбщаяВерсияФормата(
				НастройкиПодключения.ИмяПланаОбмена, НастройкиПодключения.НастройкиXDTOКорреспондента.ПоддерживаемыеВерсии);
				
		КонецЕсли;
		
		КорреспондентОбъект.ОбменДанными.Загрузка = Истина;
		КорреспондентОбъект.Записать();
		
		Корреспондент = КорреспондентОбъект.Ссылка;
		
		// Настройки XDTO корреспондента.
		Если ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(НастройкиПодключения.ИмяПланаОбмена) Тогда
			
			Если НастройкиПодключения.Свойство("НастройкиXDTOКорреспондента") Тогда
				РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбновитьНастройкиКорреспондента(Корреспондент,
					"ПоддерживаемыеОбъекты",
					НастройкиПодключения.НастройкиXDTOКорреспондента.ПоддерживаемыеОбъекты.Получить());
			КонецЕсли;
			
			РегистрыСведений.НастройкиОбменаДаннымиXDTO.ОбновитьНастройкиКорреспондента(Корреспондент,
				"ОбластьДанныхКорреспондента",
				НастройкиПодключения.ОбластьДанныхКорреспондента);
			
			СтруктураЗаписи = Новый Структура;
			СтруктураЗаписи.Вставить("УзелИнформационнойБазы",       Корреспондент);
			СтруктураЗаписи.Вставить("ИмяПланаОбменаКорреспондента", НастройкиПодключения.ИмяПланаОбмена);
			
			ОбменДаннымиСлужебный.ОбновитьЗаписьВРегистрСведений(СтруктураЗаписи, "НастройкиОбменаДаннымиXDTO");
			
		КонецЕсли;
		
		// Общие данные узлов.
		РегистрыСведений.ОбщиеНастройкиУзловИнформационныхБаз.ОбновитьПрефиксы(
			Корреспондент,
			НастройкиПодключения.Префикс,
			НастройкиПодключения.ПрефиксКорреспондента);
			
		Если Не ПустаяСтрока(ПсевдонимЭтогоУзла) Тогда
			МенеджерРегистра = ОбщегоНазначения.ОбщийМодуль("РегистрыСведений.ПсевдонимыПредопределенныхУзлов");
			ВиртуальныеКоды = МенеджерРегистра.СоздатьНаборЗаписей();
			ВиртуальныйКод = ВиртуальныеКоды.Добавить();
			ВиртуальныйКод.Корреспондент = Корреспондент;
			ВиртуальныйКод.КодУзла       = ПсевдонимЭтогоУзла;
			
			ВиртуальныеКоды.Записать();
		КонецЕсли;
		
		ФактическийКодКорреспондента = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Корреспондент, "Код");
		
		Если ПроверитьКод
			И НастройкиПодключения.ИдентификаторИнформационнойБазыПриемника <> ФактическийКодКорреспондента Тогда
			СтрокаСообщения = НСтр("ru = 'Ошибка назначения кода узла корреспондента.
				|Назначенное значение ""%1""
				|Фактическое значение ""%2"".'");
			СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
				НастройкиПодключения.ИдентификаторИнформационнойБазыПриемника,
				ФактическийКодКорреспондента);
			ВызватьИсключение СтрокаСообщения;
		КонецЕсли;
		
		// Работа с настройками транспорта.
		Параметры = Новый Структура;
		Параметры.Вставить("Корреспондент", Корреспондент);
		Параметры.Вставить("КодЭтогоУзла", КодЭтогоУзла);
		Параметры.Вставить("КодКорреспондента", НастройкиПодключения.ИдентификаторИнформационнойБазыПриемника);
		Параметры.Вставить("КонечнаяТочкаКорреспондента", НастройкиПодключения.КонечнаяТочкаКорреспондента);
		Параметры.Вставить("ЭтоКорреспондент", ЭтоКорреспондент);
		Параметры.Вставить("РежимСовместимостиСБСП_2_0_0", РежимСовместимостиСБСП_2_0_0);
		Параметры.Вставить("ПсевдонимЭтогоУзла", ПсевдонимЭтогоУзла);
		
		ОбновитьНастройкиТранспортаОбластиДанных(Параметры);
				
		НастройкиТранспорта = Новый Структура;
		НастройкиТранспорта.Вставить("КонечнаяТочкаКорреспондента", НастройкиПодключения.КонечнаяТочкаКорреспондента);
		НастройкиТранспорта.Вставить("НаименованиеКорреспондента", НастройкиПодключения.НаименованиеКорреспондента);
		НастройкиТранспорта.Вставить("ОбластьДанныхКорреспондента", НастройкиПодключения.ОбластьДанныхКорреспондента);
		НастройкиТранспорта.Вставить("ВнутренняяПубликация", Ложь);
				
		ТранспортСообщенийОбмена.СохранитьНастройкиТранспорта(Корреспондент, "SM", НастройкиТранспорта, Истина);
		
		НастройкиПодключения.Корреспондент = Корреспондент;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

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

	    // установка значений по умолчанию 
		ОбменДаннымиСобытия.УстановитьЗначенияПоУмолчаниюНаУзле(КорреспондентОбъект, ЗначенияПоУмолчаниюНаУзле);
		
		КорреспондентОбъект.ДополнительныеСвойства.Вставить("ПолучениеСообщенияОбмена");
		КорреспондентОбъект.Записать();

	    ЗафиксироватьТранзакцию();
	Исключение
	    ОтменитьТранзакцию();
	    ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Сохраняет данные сессии и отмечает успешное выполнение сессии
//
Процедура СохранитьДанныеСессии(Знач Сообщение, Знач Представление = "") Экспорт
	
	Если Не ПустаяСтрока(Представление) Тогда
		Представление = " "+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '{%1}'"), Представление);
	КонецЕсли;
	
	СтрокаСообщения = НСтр("ru = 'Сессия обмена сообщениями системы ""%1"" успешно завершена.%2'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
		Строка(Сообщение.Body.SessionId), Представление);
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСессииОбменаСообщениямиСистемы(),
		УровеньЖурналаРегистрации.Информация,,, СтрокаСообщения);
	РегистрыСведений.СессииОбменаСообщениямиСистемы.СохранитьДанныеСессии(Сообщение.Body.SessionId, Сообщение.Body.Data);
	
КонецПроцедуры

// Отмечает успешное выполнение сессии
//
Процедура ЗафиксироватьУспешноеВыполнениеСессии(Знач Сообщение, Знач Представление = "") Экспорт
	
	Если Не ПустаяСтрока(Представление) Тогда
		Представление = " " + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '{%1}'"), Представление);
	КонецЕсли;
	
	СтрокаСообщения = НСтр("ru = 'Сессия обмена сообщениями системы ""%1"" успешно завершена.%2'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
		Строка(Сообщение.Body.SessionId), Представление);
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСессииОбменаСообщениямиСистемы(),
		УровеньЖурналаРегистрации.Информация,,, СтрокаСообщения);
	РегистрыСведений.СессииОбменаСообщениямиСистемы.ЗафиксироватьУспешноеВыполнениеСессии(Сообщение.Body.SessionId);
	
КонецПроцедуры

// Отмечает неуспешное выполнение сессии
//
Процедура ЗафиксироватьНеуспешноеВыполнениеСессии(Знач Сообщение, Знач Представление = "") Экспорт
	
	Если Не ПустаяСтрока(Представление) Тогда
		Представление = " " + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '{%1}'"), Представление);
	КонецЕсли;
	
	СтрокаСообщения = НСтр("ru = 'Ошибка выполнения сессии обмена сообщениями системы ""%1"".%2
		|Описание ошибки из корреспондента: %3'", ОбщегоНазначения.КодОсновногоЯзыка());
	СтрокаСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(СтрокаСообщения,
		Строка(Сообщение.Body.SessionId), Представление, Сообщение.Body.ErrorDescription);
	ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрацииСессииОбменаСообщениямиСистемы(),
		УровеньЖурналаРегистрации.Ошибка,,, СтрокаСообщения);
		
	РегистрыСведений.СессииОбменаСообщениямиСистемы.ЗафиксироватьНеуспешноеВыполнениеСессии(
		Сообщение.Body.SessionId, Сообщение.Body.ErrorDescription);
	
КонецПроцедуры

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

// Событие для журнала регистрации монитора синхронизации данных
// 
// Возвращаемое значение:
//  Строка - событие журнала регистрации строкой
//
Функция СобытиеЖурналаРегистрацииМониторСинхронизацииДанных() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными в модели сервиса.Монитор синхронизации данных'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

// Событие для журнала регистрации синхронизации данных
// 
// Возвращаемое значение:
//  Строка - событие журнала регистрации строкой
//
Функция СобытиеЖурналаРегистрацииСинхронизацииДанных() Экспорт
	
	Возврат НСтр("ru = 'Обмен данными в модели сервиса.Синхронизация данных'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

Функция СобытиеЖурналаРегистрацииСессииОбменаСообщениямиСистемы()
	
	Возврат НСтр("ru = 'Обмен данными в модели сервиса.Сессии обмена сообщениями системы'",
		ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции


#КонецОбласти

#Область ПроцедурыИФункцииМонитораОбменаДанными

// Для внутреннего использования
// 
// Параметры:
//  ПланыОбменаМетода - Массив из Строка - массив имен планов обмена, как в конфигурации
//  ДополнительныеСвойстваПланаОбмена - Строка - дополнительные свойства плана обмена
//  ТолькоНеуспешные - Булево
// 
// Возвращаемое значение:
//  ТаблицаЗначений - таблица монитора обмена данными
//
Функция ТаблицаМонитораОбменаДанными(Знач ПланыОбменаМетода, Знач ДополнительныеСвойстваПланаОбмена = "", Знач ТолькоНеуспешные = Ложь) Экспорт
	
	ТекстЗапроса = "ВЫБРАТЬ
	|	СостоянияОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияОбменовДанными.ДатаОкончания КАК ДатаОкончания,
	|	ВЫБОР
	|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
	|			ИЛИ СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
	|			ТОГДА 0
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК РезультатВыполненияОбмена
	|ПОМЕСТИТЬ СостоянияОбменовДаннымиЗагрузка
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДаннымиОбластейДанных КАК СостоянияОбменовДанными
	|ГДЕ
	|	СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СостоянияОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияОбменовДанными.ДатаОкончания КАК ДатаОкончания,
	|	ВЫБОР
	|		КОГДА СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.Выполнено)
	|			ИЛИ СостоянияОбменовДанными.РезультатВыполненияОбмена = ЗНАЧЕНИЕ(Перечисление.РезультатыВыполненияОбмена.ВыполненоСПредупреждениями)
	|			ТОГДА 0
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК РезультатВыполненияОбмена
	|ПОМЕСТИТЬ СостоянияОбменовДаннымиВыгрузка
	|ИЗ
	|	РегистрСведений.СостоянияОбменовДаннымиОбластейДанных КАК СостоянияОбменовДанными
	|ГДЕ
	|	СостоянияОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СостоянияУспешныхОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияУспешныхОбменовДанными.ДатаОкончания КАК ДатаОкончания
	|ПОМЕСТИТЬ СостоянияУспешныхОбменовДаннымиЗагрузка
	|ИЗ
	|	РегистрСведений.СостоянияУспешныхОбменовДаннымиОбластейДанных КАК СостоянияУспешныхОбменовДанными
	|ГДЕ
	|	СостоянияУспешныхОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ЗагрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	СостоянияУспешныхОбменовДанными.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	СостоянияУспешныхОбменовДанными.ДатаОкончания КАК ДатаОкончания
	|ПОМЕСТИТЬ СостоянияУспешныхОбменовДаннымиВыгрузка
	|ИЗ
	|	РегистрСведений.СостоянияУспешныхОбменовДаннымиОбластейДанных КАК СостоянияУспешныхОбменовДанными
	|ГДЕ
	|	СостоянияУспешныхОбменовДанными.ДействиеПриОбмене = ЗНАЧЕНИЕ(Перечисление.ДействияПриОбмене.ВыгрузкаДанных)
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ПланыОбмена.ИмяПланаОбмена КАК ИмяПланаОбмена,
	|	ПланыОбмена.УзелИнформационнойБазы КАК УзелИнформационнойБазы,
	|	ПланыОбмена.ОбластьДанныхОсновныеДанные КАК ОбластьДанных,
	|
	|	&ДополнительныеСвойстваПланаОбмена,
	|
	|	ЕСТЬNULL(СостоянияОбменовДаннымиВыгрузка.РезультатВыполненияОбмена, 0) КАК РезультатПоследнейВыгрузкиДанных,
	|	ЕСТЬNULL(СостоянияОбменовДаннымиЗагрузка.РезультатВыполненияОбмена, 0) КАК РезультатПоследнейЗагрузкиДанных,
	|	СостоянияОбменовДаннымиЗагрузка.ДатаОкончания КАК ДатаПоследнейЗагрузки,
	|	СостоянияОбменовДаннымиВыгрузка.ДатаОкончания КАК ДатаПоследнейВыгрузки,
	|	СостоянияУспешныхОбменовДаннымиЗагрузка.ДатаОкончания КАК ДатаПоследнейУспешнойЗагрузки,
	|	СостоянияУспешныхОбменовДаннымиВыгрузка.ДатаОкончания КАК ДатаПоследнейУспешнойВыгрузки
	|ИЗ
	|	ПланыОбменаКонфигурации КАК ПланыОбмена
	|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияОбменовДаннымиЗагрузка КАК СостоянияОбменовДаннымиЗагрузка
	|		ПО ПланыОбмена.УзелИнформационнойБазы = СостоянияОбменовДаннымиЗагрузка.УзелИнформационнойБазы
	|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияОбменовДаннымиВыгрузка КАК СостоянияОбменовДаннымиВыгрузка
	|		ПО ПланыОбмена.УзелИнформационнойБазы = СостоянияОбменовДаннымиВыгрузка.УзелИнформационнойБазы
	|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияУспешныхОбменовДаннымиЗагрузка КАК СостоянияУспешныхОбменовДаннымиЗагрузка
	|		ПО ПланыОбмена.УзелИнформационнойБазы = СостоянияУспешныхОбменовДаннымиЗагрузка.УзелИнформационнойБазы
	|		ЛЕВОЕ СОЕДИНЕНИЕ СостоянияУспешныхОбменовДаннымиВыгрузка КАК СостоянияУспешныхОбменовДаннымиВыгрузка
	|		ПО ПланыОбмена.УзелИнформационнойБазы = СостоянияУспешныхОбменовДаннымиВыгрузка.УзелИнформационнойБазы
	|
	|ГДЕ &Отбор
	|
	|УПОРЯДОЧИТЬ ПО
	|	ПланыОбмена.ИмяПланаОбмена,
	|	ПланыОбмена.Наименование";
	
	УстановитьПривилегированныйРежим(Истина);
	
	МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	
	ПодготовитьДанныеУзловПлановОбменаДляМонитора(МенеджерВременныхТаблиц, ПланыОбменаМетода, ДополнительныеСвойстваПланаОбмена);
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеСвойстваПланаОбмена,",
		ПолучитьДополнительныеСвойстваПланаОбменаСтрокой(ДополнительныеСвойстваПланаОбмена));
	
	Если ТолькоНеуспешные Тогда
		Отбор = "
			|ГДЕ
			|	    ЕСТЬNULL(СостоянияОбменовДаннымиВыгрузка.РезультатВыполненияОбмена, 0) <> 0
			|	ИЛИ ЕСТЬNULL(СостоянияОбменовДаннымиЗагрузка.РезультатВыполненияОбмена, 0) <> 0";
	Иначе
		Отбор = "";
	КонецЕсли;
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ГДЕ &Отбор", Отбор);
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапроса;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	
	НастройкиСинхронизации = Запрос.Выполнить().Выгрузить();
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейЗагрузки");
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейВыгрузки");
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейУспешнойЗагрузки");
	НастройкиСинхронизации.Колонки.Добавить("ПредставлениеДатыПоследнейУспешнойВыгрузки");
	
	Для Каждого НастройкаСинхронизации Из НастройкиСинхронизации Цикл
		
		НастройкаСинхронизации.ПредставлениеДатыПоследнейЗагрузки         = ОбменДаннымиСервер.ОтносительнаяДатаСинхронизации(НастройкаСинхронизации.ДатаПоследнейЗагрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнейВыгрузки         = ОбменДаннымиСервер.ОтносительнаяДатаСинхронизации(НастройкаСинхронизации.ДатаПоследнейВыгрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнейУспешнойЗагрузки = ОбменДаннымиСервер.ОтносительнаяДатаСинхронизации(НастройкаСинхронизации.ДатаПоследнейУспешнойЗагрузки);
		НастройкаСинхронизации.ПредставлениеДатыПоследнейУспешнойВыгрузки = ОбменДаннымиСервер.ОтносительнаяДатаСинхронизации(НастройкаСинхронизации.ДатаПоследнейУспешнойВыгрузки);
		
	КонецЦикла;
	
	Возврат НастройкиСинхронизации;
КонецФункции

// Для внутреннего использования
// 
Функция ПолучитьДополнительныеСвойстваПланаОбменаСтрокой(Знач СвойстваСтрокой)
	
	Результат = "";
	
	Шаблон = "ПланыОбмена.[СвойствоСтрокой] КАК [СвойствоСтрокой]";
	
	СвойстваМассив = СтрРазделить(СвойстваСтрокой, ",", Ложь);
	
	Для Каждого СвойствоСтрокой Из СвойстваМассив Цикл
		
		СвойствоСтрокойВЗапросе = СтрЗаменить(Шаблон, "[СвойствоСтрокой]", СвойствоСтрокой);
		
		Результат = Результат + СвойствоСтрокойВЗапросе + ", ";
		
	КонецЦикла;
	
	Возврат Результат;
КонецФункции

// Для внутреннего использования
// 
Процедура ПодготовитьДанныеУзловПлановОбменаДляМонитора(Знач МенеджерВременныхТаблиц, Знач ПланыОбменаМетода, Знач ДополнительныеСвойстваПланаОбмена)
	
	ДополнительныеСвойстваПланаОбменаСтрокой = ?(ПустаяСтрока(ДополнительныеСвойстваПланаОбмена), "", ДополнительныеСвойстваПланаОбмена + ", ");
	
	Запрос = Новый Запрос;
	
	ШаблонЗапроса = "
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|////////////////////////////////////////////////////////"
	+
	"
	|ВЫБРАТЬ
	|
	|	&ДополнительныеСвойстваПланаОбмена,
	|
	|	Ссылка                      КАК УзелИнформационнойБазы,
	|	ОбластьДанныхОсновныеДанные КАК ОбластьДанныхОсновныеДанные,
	|	Наименование                КАК Наименование,
	|	""ИмяПланаОбменаСиноним""   КАК ИмяПланаОбмена
	|ИЗ
	|	&ИмяПланаОбмена
	|ГДЕ
	|	РегистрироватьИзменения
	|	И НЕ ПометкаУдаления
	|";
	
	ТекстЗапроса = "";
	
	Если ПланыОбменаМетода.Количество() > 0 Тогда
		
		ШаблонТекста = "ПланОбмена.%1";
		
		Для Каждого ИмяПланаОбмена Из ПланыОбменаМетода Цикл
			
			ИмяПланаОбменаСтрокой = СтрШаблон(ШаблонТекста, ИмяПланаОбмена);
			
			ТекстЗапросаДляПланаОбмена = СтрЗаменить(ШаблонЗапроса,              "&ИмяПланаОбмена", ИмяПланаОбменаСтрокой);
			ТекстЗапросаДляПланаОбмена = СтрЗаменить(ТекстЗапросаДляПланаОбмена, "ИмяПланаОбменаСиноним", Метаданные.ПланыОбмена[ИмяПланаОбмена].Синоним);
			ТекстЗапросаДляПланаОбмена = СтрЗаменить(ТекстЗапросаДляПланаОбмена, "&ДополнительныеСвойстваПланаОбмена,", ДополнительныеСвойстваПланаОбменаСтрокой);
			
			// удаляем литерал объединения для первой таблицы
			Если ПустаяСтрока(ТекстЗапроса) Тогда
				
				ТекстЗапросаДляПланаОбмена = СтрЗаменить(ТекстЗапросаДляПланаОбмена, "ОБЪЕДИНИТЬ ВСЕ", "");
				
			КонецЕсли;
			
			ТекстЗапроса = ТекстЗапроса + ТекстЗапросаДляПланаОбмена;
			
		КонецЦикла;
		
	Иначе
		
		ДополнительныеСвойстваБезИсточникаДанныхСтрокой = "";
		
		Если Не ПустаяСтрока(ДополнительныеСвойстваПланаОбмена) Тогда
			
			ДополнительныеСвойства = СтрРазделить(ДополнительныеСвойстваПланаОбмена, ",");
			
			ДополнительныеСвойстваБезИсточникаДанных = Новый Массив;
			
			Для Каждого Свойство Из ДополнительныеСвойства Цикл
				
				ДополнительныеСвойстваБезИсточникаДанных.Добавить(СтрЗаменить("Неопределено КАК [Свойство]", "[Свойство]", Свойство));
				
			КонецЦикла;
			
			ДополнительныеСвойстваБезИсточникаДанныхСтрокой = СтрСоединить(ДополнительныеСвойстваБезИсточникаДанных) + ", ";
			
		КонецЕсли;
		
		ТекстЗапроса = "
		|ВЫБРАТЬ
		|
		|	&ДополнительныеСвойстваБезИсточникаДанныхСтрокой,
		|
		|	Неопределено КАК УзелИнформационнойБазы,
		|	0            КАК ОбластьДанныхОсновныеДанные,
		|	Неопределено КАК Наименование,
		|	Неопределено КАК ИмяПланаОбмена
		|";
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеСвойстваБезИсточникаДанныхСтрокой,", ДополнительныеСвойстваБезИсточникаДанныхСтрокой);
		
	КонецЕсли;
	
	ТекстЗапросаРезультат = "
	|////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|
	|	&ДополнительныеСвойстваПланаОбмена,
	|
	|	УзелИнформационнойБазы,
	|	ОбластьДанныхОсновныеДанные,
	|	Наименование,
	|	ИмяПланаОбмена
	|ПОМЕСТИТЬ ПланыОбменаКонфигурации
	|ИЗ
	|	&ТекстЗапроса
	|	КАК ВложенныйЗапрос
	|;
	|";
	
	ТекстВставкиЗапроса = СтрШаблон("(%1)", ТекстЗапроса);
	ТекстЗапросаРезультат = СтрЗаменить(ТекстЗапросаРезультат, "&ТекстЗапроса", ТекстВставкиЗапроса);
	ТекстЗапросаРезультат = СтрЗаменить(ТекстЗапросаРезультат, "&ДополнительныеСвойстваПланаОбмена,", ДополнительныеСвойстваПланаОбменаСтрокой);
	
	Запрос.Текст = ТекстЗапросаРезультат;
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.Выполнить();
	
КонецПроцедуры

#КонецОбласти

#Область ЛокальныеСлужебныеПроцедурыИФункции

Функция НайтиУзелИнформационнойБазы(Знач ИмяПланаОбмена, Знач КодУзла)
	
	ОбластьДанных = СтроковыеФункцииКлиентСервер.СтрокаВЧисло(КодУзла);
	
	КодУзлаСПрефиксом = КодУзлаПланаОбменаВСервисе(ОбластьДанных);
	
	// Поиск узла по формату кода узла "S00000123".
	Результат = ОбменДаннымиСервер.УзелПланаОбменаПоКоду(ИмяПланаОбмена, КодУзлаСПрефиксом);
	
	Если Результат = Неопределено Тогда
		
		// Поиск узла по формату кода узла "0000123" (старый формат)
		Результат = ОбменДаннымиСервер.УзелПланаОбменаПоКоду(ИмяПланаОбмена, КодУзла);
		
	КонецЕсли;
	
	Если Результат = Неопределено
		И ОбменДаннымиПовтИсп.ЭтоПланОбменаXDTO(ИмяПланаОбмена) Тогда
		
		Запрос = Новый Запрос(
		"ВЫБРАТЬ
		|	Т.Ссылка КАК УзелОбмена
		|ИЗ
		|	#ТаблицаПланаОбмена КАК Т
		|ГДЕ
		|	НЕ Т.ЭтотУзел");
		
		Запрос.Текст = СтрЗаменить(Запрос.Текст,
			"#ТаблицаПланаОбмена", "ПланОбмена." + ИмяПланаОбмена);
		
		Выборка = Запрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			
			ОбластьДанныхКорреспондента = РегистрыСведений.НастройкиОбменаДаннымиXDTO.ЗначениеНастройкиКорреспондента(Выборка.УзелОбмена,
				"ОбластьДанныхКорреспондента");
			
			Если ОбластьДанныхКорреспондента = ОбластьДанных Тогда
				Результат = Выборка.УзелОбмена;
				Прервать;
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
	
	Если Результат = Неопределено Тогда
		
		Сообщение = НСтр("ru = 'Не найден узел плана обмена. Имя плана обмена %1; код узла %2 или %3'");
		Сообщение = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Сообщение, ИмяПланаОбмена, КодУзла, КодУзлаСПрефиксом);
		
		ВызватьИсключение Сообщение;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ВерсииКорреспондента(Знач УзелИнформационнойБазы)
	
	СтруктураНастроек = РегистрыСведений.НастройкиТранспортаОбменаОбластиДанных.НастройкиТранспортаWS(УзелИнформационнойБазы);
	
	ПараметрыПодключения = Новый Структура;
	ПараметрыПодключения.Вставить("URL",      СтруктураНастроек.WSURLВебСервиса);
	ПараметрыПодключения.Вставить("UserName", СтруктураНастроек.WSИмяПользователя);
	ПараметрыПодключения.Вставить("Password", СтруктураНастроек.WSПароль);
	
	Возврат ОбщегоНазначения.ПолучитьВерсииИнтерфейса(ПараметрыПодключения, "ОбменДаннымиВМоделиСервиса");
КонецФункции

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

// Добавляет параметры работы клиентской логики для подсистемы обмена данными в модели сервиса.
//
Процедура ДобавитьПараметрыРаботыКлиента(Параметры)
	
КонецПроцедуры

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

#КонецОбласти

#Область ПолучениеСсылокНаОбщиеСтраницыИнформацииСервиса

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

// Возвращает адрес ссылки на статью по настройке тонкого клиента
// Для внутреннего использования.
// 
// Возвращаемое значение:
//  Строка
//
Функция АдресИнструкцииПоНастройкеТонкогоКлиента() Экспорт
	
	Возврат АдресСсылкиИзИнформационногоЦентра("ИнструкцияПоНастройкеТонкогоКлиента");
	
КонецФункции

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

#КонецОбласти

#КонецОбласти