Процедура УдалитьСеансыИнформационнойБазы(Знач ПараметрыАдминистрированияКластера, Знач ПараметрыАдминистрированияИБ = Неопределено,
	Знач Фильтр = Неопределено) Экспорт

	Если ПараметрыАдминистрированияИБ = Неопределено Тогда
		ПараметрыАдминистрированияИБ = ПараметрыАдминистрированияКластера;
	КонецЕсли;

	МенеджерАдминистрирования = МенеджерАдминистрирования(ПараметрыАдминистрированияКластера);

	МенеджерАдминистрирования.УдалитьСеансыИнформационнойБазы(
		ПараметрыАдминистрированияКластера,
		ПараметрыАдминистрированияИБ,
		Фильтр);

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

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

Функция ФильтрСеансов() Экспорт

	Результат = Новый Структура();

	Результат.Вставить("Свойство");
	Результат.Вставить("ВидСравнения", ВидСравнения.Равно);
	Результат.Вставить("Значение");

	Возврат Результат;

КонецФункции

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

#Область СоединенияСИнформационнойБазой

// Свойства соединения с информационной базой.
//
// Возвращаемое значение:
//   Структура:
//     * Номер - Число - номер соединения с информационной базой.
//     * ИмяПользователя - Строка - имя пользователя 1С:Предприятия, подсоединенного к информационной базе.
//     * ИмяКлиентскогоКомпьютера - Строка - имя компьютера, с которого установлено соединение.
//     * ИдентификаторКлиентскогоПриложения - Строка - идентификатор приложения, установившего соединение.
//                  Возможные значения - см. описание к функции глобального контекста ПредставлениеПриложения(),
//     * МоментУстановкиСоединения - Дата - момент установки соединения.
//     * РежимСоединенияСИнформационнойБазой - Число - режим соединения с информационной базой (0 -
//                  разделяемый, 1 - монопольный),
//     * РежимСоединенияСБазойДанных - Число - режим соединения с базой данных (0 - соединение не установлено,
//                  1 - разделяемый, 2 - монопольный).
//     * БлокировкаСУБД - Число - идентификатор соединения, блокирующего работу данного соединения в СУБД.
//     * Передано - Число - объем данных, полученных и отправленных соединением.
//     * ПереданоЗа5Минут - Число - объем данных, полученных и отправленных соединением за последние 5 минут.
//     * СерверныхВызовов - Число - количество серверных вызовов.
//     * СерверныхВызововЗа5Минут - Число - количество серверных вызовов соединения за последние 5 минут.
//     * ПереданоСУБД - Число - объем данных, переданных между сервером 1С:Предприятия и сервером баз данных,
//                  с момента установки данного соединения,
//     * ПереданоСУБДЗа5Минут - Число - объем данных, переданных между сервером 1С:Предприятия и сервером баз
//                  данных за последние 5 минут,
//     * СоединениеСУБД - Строка - идентификатор процесса соединения с СУБД (если на момент получения списка
//                  соединений данное соединение выполняло обращение к серверу СУБД, в противном случае - значение равно
//                  пустой строке). Идентификатор возвращается в терминах сервера СУБД.
//     * ВремяСУБД - Число - время в секундах, в течении которого выполняется обращение к серверу СУБД (если на момент
//                  получения списка соединений данное соединение выполняло обращение к серверу СУБД, в противном случае
//                  значение равно 0).
//     * МоментЗахватаСоединенияСУБД - Дата - момент последнего захвата соединения с сервером СУБД.
//     * ДлительностьСерверныхВызовов - Число - длительность всех серверных вызовов соединения.
//     * ДлительностьВызововСУБД - Число - время вызовов СУБД, инициированных соединением.
//     * ДлительностьТекущегоСерверногоВызова - Число - длительность текущего серверного вызова.
//     * ДлительностьТекущегоВызоваСУБД - Число - длительность текущего вызова сервера СУБД.
//     * ДлительностьСерверныхВызововЗа5Минут - Число - длительность серверных вызовов соединения за последние 5 минут.
//     * ДлительностьВызововСУБДЗа5Минут - Число - длительность вызовов соединения СУБД за последние 5 минут.
//     * ПрочитаноСДиска - Число - содержит количество данных в байтах, прочитанных с диска сеансом с момента начала сеанса.
//     * ПрочитаноСДискаВТекущемВызове - Число - содержит количество данных в байтах, прочитанных с диска с начала
//                  выполнения текущего вызова.
//     * ПрочитаноСДискаЗа5Минут - Число - содержит количество данных в байтах, прочитанных с диска сеансом за
//                  последние 5 минут.
//     * ЗанятоПамяти - Число - содержит объем памяти в байтах, занятый в процессе вызовов с момента начала сеанса.
//     * ЗанятоПамятиВТекущемВызове - Число - содержит объем памяти в байтах, занятый с начала выполнения текущего
//                  вызова. Если в данный момент вызов не выполняется, содержит 0.
//     * ЗанятоПамятиЗа5Минут - Число - содержит объем памяти в байтах, занятый в процессе вызовов за последние 5 минут.
//     * ЗаписаноНаДиск - Число - содержит количество данных в байтах, записанных на диск сеансом с момента начала сеанса.
//     * ЗаписаноНаДискВТекущемВызове - Число - содержит количество данных в байтах, записанных на диск с начала
//                  выполнения текущего вызова.
//     * ЗаписаноНаДискЗа5Минут - Число - содержит количество данных в байтах, записанных на диск сеансом за
//                  последние 5 минут.
//     * УправлениеНаходитсяНаСервере - Число - указывает, находится ли управление на сервере (0 - не находится, 1 - находится).
//


Функция ПолучитьРазрешенныеВнешниеКомпоненты(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)

	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"addin", // Не локализуется
		СловарьСвойствВнешнейКомпоненты());

КонецФункции

Функция ПолучитьРазрешенныеВнешниеМодули(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)

	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"module", // Не локализуется
		СловарьСвойствВнешнегоМодуля());

КонецФункции

Функция ПолучитьРазрешенныеПриложенияОС(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)

	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"app", // Не локализуется
		СловарьСвойствПриложенияОС());

КонецФункции

Функция ПолучитьРазрешенныеИнтернетРесурсы(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач Фильтр = Неопределено)

	Возврат СпискиКонтроляДоступа(
		ИдентификаторКластера,
		ПараметрыАдминистрированияКластера,
		ИмяПрофиля,
		"inet", // Не локализуется
		СловарьСвойствИнтернетРесурса());

КонецФункции

// Параметры:
//  ИдентификаторКластера - Строка
//  ПараметрыАдминистрированияКластера - Структура:
//   * ТипПодключения - Строка
//   * АдресАгентаСервера - Строка
//   * ПортАгентаСервера - Число
//   * АдресСервераАдминистрирования - Строка
//   * ПортСервераАдминистрирования - Число
//   * ПортКластера - Число
//   * ИмяАдминистратораКластера - Строка
//   * ПарольАдминистратораКластера - Строка
//  ИмяПрофиля - Строка
//  ИмяСписка - Строка
//  Словарь - ФиксированнаяСтруктура:
//   * Имя - Строка
//   * Описание - Строка
//   * ХэшСумма - Строка - для обратной совместимости.
//  Фильтр - Неопределено
// Возвращаемое значение:
//  Массив из см. СловарьСвойствВнешнейКомпоненты
//

Функция СпискиКонтроляДоступа(Знач ИдентификаторКластера, Знач ПараметрыАдминистрированияКластера, Знач ИмяПрофиля, Знач ИмяСписка, Знач Словарь, Знач Фильтр = Неопределено)

	Шаблон = "%rac profile --cluster=%cluster% --cluster-user=%?cluster-user% --cluster-pwd=%?cluster-pwd% acl --name=%name% directory list";
	Шаблон = СтрЗаменить(Шаблон, "directory", ИмяСписка);

	Параметры = Новый Соответствие();

	Параметры.Вставить("cluster", ИдентификаторКластера);
	ЗаполнитьПараметрыАутентификацииВКластере(ПараметрыАдминистрированияКластера, Параметры);

	Параметры.Вставить("name", ИмяПрофиля);

	ПотокВывода = ВыполнитьКоманду(Шаблон, ПараметрыАдминистрированияКластера, Параметры);
	Результат = ПарсерВывода(ПотокВывода, Словарь, Фильтр);
	Возврат Результат;

КонецФункции


Функция СловарьСвойствПрофиляБезопасности(Знач ВключаяСвойстваИспользованияСписковКонтроляДоступа = Истина)

	Результат = Новый Структура();

	Результат.Вставить("Имя", "name");
	Результат.Вставить("Описание", "descr");
	Результат.Вставить("ПрофильБезопасногоРежима", "config");
	Результат.Вставить("ПолныйДоступКПривилегированномуРежиму", "priv");

	Если ВключаяСвойстваИспользованияСписковКонтроляДоступа Тогда

		СловарьСвойствИспользованияСписковКонтроляДоступа = СловарьСвойствИспользованияСписокКонтроляДоступа();

		Для Каждого ФрагментСловаря Из СловарьСвойствИспользованияСписковКонтроляДоступа Цикл
			Результат.Вставить(ФрагментСловаря.Ключ, ФрагментСловаря.Значение);
		КонецЦикла;

	КонецЕсли;

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьСвойствИспользованияСписокКонтроляДоступа()

	Результат = Новый Структура();

	Результат.Вставить("ПолныйДоступКФайловойСистеме", "directory");
	Результат.Вставить("ПолныйДоступКCOMОбъектам", "com");
	Результат.Вставить("ПолныйДоступКВнешнимКомпонентам", "addin");
	Результат.Вставить("ПолныйДоступКВнешнимМодулям", "module");
	Результат.Вставить("ПолныйДоступКПриложениямОперационнойСистемы", "app");
	Результат.Вставить("ПолныйДоступКИнтернетРесурсам", "inet");

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьСвойствВиртуальногоКаталога()

	Результат = Новый Структура();

	Результат.Вставить("ЛогическийURL", "alias");
	Результат.Вставить("ФизическийURL", "physicalPath");

	Результат.Вставить("Описание", "descr");

	Результат.Вставить("ЧтениеДанных", "allowedRead");
	Результат.Вставить("ЗаписьДанных", "allowedWrite");

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьСвойствCOMКласса()

	Результат = Новый Структура();

	Результат.Вставить("Имя", "name");
	Результат.Вставить("Описание", "descr");

	Результат.Вставить("ФайлМоникер", "fileName");
	Результат.Вставить("CLSID", "id");
	Результат.Вставить("Компьютер", "host");

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

// Возвращаемое значение:
//  ФиксированнаяСтруктура:
//   * Имя - Строка
//   * Описание - Строка
//   * ХэшСумма - Строка - для обратной совместимости.
//

Функция СловарьСвойствВнешнейКомпоненты()

	Результат = Новый Структура();
	Результат.Вставить("Имя", "name");
	Результат.Вставить("Описание", "descr");
	Результат.Вставить("ХэшСумма", "hash"); // АПК:1036 для обратной совместимости
	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьСвойствВнешнегоМодуля()

	Результат = Новый Структура();
	Результат.Вставить("Имя", "name");
	Результат.Вставить("Описание", "descr");
	Результат.Вставить("ХэшСумма", "hash"); // АПК:1036 для обратной совместимости
	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьСвойствПриложенияОС()

	Результат = Новый Структура();

	Результат.Вставить("Имя", "name");
	Результат.Вставить("Описание", "descr");

	Результат.Вставить("ШаблонСтрокиЗапуска", "wild");

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьСвойствИнтернетРесурса()

	Результат = Новый Структура();

	Результат.Вставить("Имя", "name");
	Результат.Вставить("Описание", "descr");

	Результат.Вставить("Протокол", "protocol");
	Результат.Вставить("Адрес", "url");
	Результат.Вставить("Порт", "port");

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция КлючиСписковКонтроляДоступа()

	Результат = Новый Структура();

	Результат.Вставить("directory", "alias");
	Результат.Вставить("com", "name");
	Результат.Вставить("addin", "name");
	Результат.Вставить("module", "name");
	Результат.Вставить("inet", "name");

	Возврат Новый ФиксированнаяСтруктура(Результат);

КонецФункции

Функция СловарьФорматированияБулевыхСвойств()

	ФорматOnOff = "БЛ=off; БИ=on";
	ФорматYesNo = "БЛ=no; БИ=yes";

	Результат = Новый Соответствие();

	// Свойства блокировки сеансов и заданий.
	Словарь = СловарьСвойствБлокировкиСеансовИРегламентныхЗаданий();
	Результат.Вставить(Словарь.БлокировкаСеансов, ФорматOnOff);
	Результат.Вставить(Словарь.БлокировкаРегламентныхЗаданий, ФорматOnOff);

	// Свойства профиля безопасности.
	Словарь = СловарьСвойствПрофиляБезопасности(Ложь);
	Результат.Вставить(Словарь.ПрофильБезопасногоРежима, ФорматYesNo);
	Результат.Вставить(Словарь.ПолныйДоступКПривилегированномуРежиму, ФорматYesNo);

	// Свойства виртуального каталога.
	Словарь = СловарьСвойствВиртуальногоКаталога();
	Результат.Вставить(Словарь.ЧтениеДанных, ФорматYesNo);
	Результат.Вставить(Словарь.ЗаписьДанных, ФорматYesNo);

	Возврат Новый ФиксированноеСоответствие(Результат);

КонецФункции

Функция СвойстваЭкранируемыеКавычками()

	Результат = Новый Соответствие();
	Результат["denied-message"] = Истина;
	Результат["permission-code"] = Истина;
	Результат["denied-parameter"] = Истина;
	Возврат Новый ФиксированноеСоответствие(Результат);

КонецФункции

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

#КонецЕсли


Процедура СведенияПоСпискуОКМТОВебСервис(СписокОКТМО, Результат)

	СписокСокращений = АдресныйКлассификаторПовтИсп.СписокСокращений();
	ТипЧисло = Новый ОписаниеТипов("Число");

	Для Каждого ЗаписьОКТМО Из СписокОКТМО Цикл

		ТекстGETЗапроса = "selectByCode?code=%OKTMO%&codeType=OKTMO";
		ТекстGETЗапроса = СтрЗаменить(ТекстGETЗапроса, "%OKTMO%", ОКТМОИлиОКАТОСтрокой(ЗаписьОКТМО.ОКТМО));

		РезультатВебСервис = ВыполнитьЗапросЧерезВебСервис(ТекстGETЗапроса);

		Если РезультатВебСервис.Отказ Тогда
			Результат.Вставить(ЗаписьОКТМО.КлючЗаписиОКТМО, Неопределено);
			Продолжить;
		КонецЕсли;

		СведенияПоОКТМО = НовыйСведенияПоОКТМО();

		Для Каждого СтрокаДанных Из РезультатВебСервис.Данные Цикл

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "OKATO", "okato");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ОКТМО", "oktmo");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодИФНСФЛ", "ifnsFlCode");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодИФНСЮЛ", "ifnsUlCode");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодКЛАДР", "codeKLADR");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодУчасткаИФНСФЛ", "ifnsFlAreaCode");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодУчасткаИФНСЮЛ", "ifnsUlAreaCode");

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПочтовыйИндекс",
				ТипЧисло.ПривестиЗначение(СтрокаДанных.ZIPcode), Истина);
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Регион", "area");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "РегионТипКраткий", "areaType");

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "РегионТипПолный",
			СписокСокращений.Получить("1" + ВРег(СведенияПоОКТМО.РегионТипКраткий)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "РегионИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.areaId), Неопределено, Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.areaId))),
				Истина);

			НаименованиеРегиона = ПолноеНаименованиеРегиона(СведенияПоОКТМО.Регион, СведенияПоОКТМО.РегионТипКраткий);

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

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайон", "munDistrict");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайонТипКраткий", "munDistrictType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайонТипПолный",
				СписокСокращений.Получить("3" + ВРег(СведенияПоОКТМО.МуниципальныйРайонТипКраткий)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "МуниципальныйРайонИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.munDistrictId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.munDistrictId))), Истина);

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

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Город", "city");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ГородТипКраткий", "cityType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ГородТипПолный",
				СписокСокращений.Получить("5" + ВРег(СведенияПоОКТМО.ГородТипКраткий)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ГородИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.cityId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.cityId))), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПункт", "locality");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПунктТипКраткий", "localityType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПунктТипПолный",
				СписокСокращений.Получить("6" + ВРег(СведенияПоОКТМО.НаселенныйПунктТипКраткий)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "НаселенныйПунктИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.localityId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.localityId))), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Поселение", "settlement");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПоселениеТипКраткий", "settlementType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПоселениеТипПолный",
				СписокСокращений.Получить("4" + ВРег(СведенияПоОКТМО.ПоселениеТипКраткий)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ПоселениеИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.settlementId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.settlementId))), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "КодПоселения",
				КодПоселения(СведенияПоОКТМО.ПоселениеТипКраткий), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "Территория", "territory");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ТерриторияТипКраткий", "territoryType");
			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ТерриторияТипПолный",
				СписокСокращений.Получить("7" + ВРег(СведенияПоОКТМО.ТерриторияТипКраткий)), Истина);

			ЗаполнитьЗначениеСвойстваЕслиПустое(СведенияПоОКТМО, СтрокаДанных, "ТерриторияИдентификатор",
				?(ПустаяСтрока(СтрокаДанных.territoryId), Неопределено,
				Новый УникальныйИдентификатор(СокрЛП(СтрокаДанных.territoryId))), Истина);

		КонецЦикла;
		Результат.Вставить(ЗаписьОКТМО.КлючЗаписиОКТМО, СведенияПоОКТМО);

	КонецЦикла;

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

Процедура ЗаполнитьЗначениеСвойстваЕслиПустое(Приемник, Источник, ИмяСвойстваПриемника, ИмяСвойстваИлиЗначениеИсточника, ЭтоЗначение = Ложь)

	ЗначениеСвойства = ?(ЭтоЗначение, ИмяСвойстваИлиЗначениеИсточника, Источник[ИмяСвойстваИлиЗначениеИсточника]);

	Если ЗначениеЗаполнено(Приемник[ИмяСвойстваПриемника]) Или Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		Возврат;
	КонецЕсли;

	Если ТипЗнч(ЗначениеСвойства) = Тип("Строка") Тогда
		Приемник[ИмяСвойстваПриемника] = СокрЛП(ЗначениеСвойства);
	Иначе
		Приемник[ИмяСвойстваПриемника] = ЗначениеСвойства;
	КонецЕсли;

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

Функция ОКТМОИлиОКАТОСтрокой(ОКТМОИлиОКАТО)

	Результат = "";
	Результат = Формат(ОКТМОИлиОКАТО, "ЧРГ=' '; ЧГ=0");
	Если СтрДлина(Результат) = 7 Или СтрДлина(Результат) = 10 Тогда
		Возврат "0" + Результат;
	КонецЕсли;

	Возврат Результат;

КонецФункции

Функция ПолноеНаименованиеРегиона(НаименованиеРегиона, ТипРегиона)
	Возврат СокрЛП(НаименованиеРегиона + " " + ТипРегиона);
КонецФункции

Функция ИменаУровнейАдресаПоКодуУровня()

	Уровни = Новый Соответствие;

	Уровни.Вставить(1, "Регион");
	Уровни.Вставить(2, "Район");
	Уровни.Вставить(3, "МуниципальныйРайон");
	Уровни.Вставить(4, "Поселение");
	Уровни.Вставить(5, "Город");
	Уровни.Вставить(6, "НаселенныйПункт");
	Уровни.Вставить(7, "Территория");

	Возврат Уровни;
КонецФункции


Функция КоличествоНевыполненныхЗадачБизнесПроцессов(БизнесПроцессы) Экспорт

	МассивБизнесПроцессов = Новый Массив;
	Для каждого БизнесПроцесс Из БизнесПроцессы Цикл
		Если ТипЗнч(БизнесПроцесс) = Тип("СтрокаГруппировкиДинамическогоСписка") Тогда
			Продолжить;
		КонецЕсли;
		МассивБизнесПроцессов.Добавить(БизнесПроцесс);
	КонецЦикла;

	Если МассивБизнесПроцессов.Количество() = 0 Тогда
		Возврат 0;
	КонецЕсли;

	Запрос = Новый Запрос(
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	Задача.ЗадачаИсполнителя КАК Задачи
		|ГДЕ
		|	Задачи.БизнесПроцесс В (&БизнесПроцессы)
		|	И Задачи.Выполнена = ЛОЖЬ");

	Запрос.УстановитьПараметр("БизнесПроцессы", МассивБизнесПроцессов);
	Возврат Запрос.Выполнить().Выгрузить()[0].Количество;

КонецФункции

// Возвращаемое значение:
//  Число
//

Функция КоличествоНевыполненныхЗадачБизнесПроцесса(БизнесПроцесс) Экспорт

	Возврат КоличествоНевыполненныхЗадачБизнесПроцессов(ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(БизнесПроцесс));

КонецФункции

// Возвращаемое значение:
//  - БизнесПроцессСсылка
//  - Неопределено
//

Функция ПометитьНаУдалениеБизнесПроцессы(ВыделенныеСтроки) Экспорт

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

		Количество = Количество + 1;
	КонецЦикла;
	Возврат ?(Количество = 1, ВыделенныеСтроки[0].Владелец, Неопределено);
КонецФункции

Процедура ПриПеренаправленииЗадачи(ЗадачаОбъект, НоваяЗадачаОбъект)

	Если ЗадачаОбъект.БизнесПроцесс = Неопределено Или ЗадачаОбъект.БизнесПроцесс.Пустая() Тогда
		Возврат;
	КонецЕсли;

	ПодключенныеБизнесПроцессы = Новый Соответствие;
	ПодключенныеБизнесПроцессы.Вставить(Метаданные.БизнесПроцессы.Задание.ПолноеИмя(), "");
	БизнесПроцессыИЗадачиПереопределяемый.ПриОпределенииБизнесПроцессов(ПодключенныеБизнесПроцессы);

	ТипБизнесПроцесса = ЗадачаОбъект.БизнесПроцесс.Метаданные();
	СведенияОБизнесПроцессе = ПодключенныеБизнесПроцессы[ТипБизнесПроцесса.ПолноеИмя()];
	Если СведенияОБизнесПроцессе <> Неопределено Тогда
		БизнесПроцессы[ТипБизнесПроцесса.Имя].ПриПеренаправленииЗадачи(ЗадачаОбъект.Ссылка, НоваяЗадачаОбъект.Ссылка);
	КонецЕсли;

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

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


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

	Результат.Успех = Ложь;
	Результат.ТабличныйДокумент = Новый ТабличныйДокумент;
	Результат.ВариантМодифицирован = Ложь;
	Результат.ПользовательскиеНастройкиМодифицированы = Ложь;
	Результат.ДанныеЕщеОбновляются = Ложь;

	Если ПолучатьФлажокПустой Тогда
		Результат.Вставить("Пустой", Ложь);
	КонецЕсли;

	ПараметрыФормированияОтчета = ПараметрыФормированияОтчета();
	ЗаполнитьЗначенияСвойств(ПараметрыФормированияОтчета, Параметры);
	Параметры = ПараметрыФормированияОтчета;

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

	Если Не Подключение.Успех Тогда
		Результат.ТекстОшибки = НСтр("ru = 'Не удалось сформировать отчет:'") + Символы.ПС + Подключение.ТекстОшибки;
		Возврат Результат;
	КонецЕсли;

	ОтчетОбъект = Результат.Объект;
	КомпоновщикНастроекКД = ОтчетОбъект.КомпоновщикНастроек;

	ЗаполнитьДвоичныеДанныеВнешнегоОтчета(ОтчетОбъект, Параметры);

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

	// Проверка корректности данных, по которым формируется отчет.

	Если ПроверятьЗаполнение Тогда
		ИсходныеСообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
		ПроверкаПройдена = ОтчетОбъект.ПроверитьЗаполнение();
		СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);

		Для Каждого Сообщение Из ИсходныеСообщенияПользователю Цикл
			Сообщение.Сообщить();
		КонецЦикла;

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

	Попытка
		ИспользуемыеТаблицы = ИспользуемыеТаблицы(Результат.СхемаКД);
		ИспользуемыеТаблицы.Добавить(Результат.ПолноеИмя);

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

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

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

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

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

		Возврат Результат;
	КонецПопытки;

	Если ВыполнятьЗамеры Тогда
		МодульОценкаПроизводительности.ЗакончитьЗамерВремениТехнологический(
			ИмяКлючевойОперации,
			ВремяНачала,
			1,
			КомментарийКлючевойОперации);
	КонецЕсли;

	// Регистрация результата.

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

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

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

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

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

	// Установка колонтитулов.

	НастройкиКолонтитулов = Неопределено;
	Если Результат.НастройкиКД <> Неопределено Тогда
		Результат.НастройкиКД.ДополнительныеСвойства.Свойство("НастройкиКолонтитулов", НастройкиКолонтитулов);
	КонецЕсли;

	НазваниеОтчета = "";
	Если ЗначениеЗаполнено(Результат.СсылкаВарианта) Тогда
		НазваниеОтчета = Строка(Результат.СсылкаВарианта);
	ИначеЕсли Результат.Метаданные <> Неопределено Тогда
		НазваниеОтчета = Результат.Метаданные.Синоним;
	КонецЕсли;

	Если Не ОбщегоНазначения.РазделениеВключено()
		Или ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда

		УправлениеКолонтитулами.УстановитьКолонтитулы(Результат.ТабличныйДокумент, НазваниеОтчета,, НастройкиКолонтитулов);
	КонецЕсли;

	Результат.Успех = Истина;

	// Чистка мусора.

	ДопСвойства.Удалить("ВариантМодифицирован");
	ДопСвойства.Удалить("ПользовательскиеНастройкиМодифицированы");
	ДопСвойства.Удалить("КлючВарианта");
	ДопСвойства.Удалить("ОтчетПустой");
	ДопСвойства.Удалить("ИспользуемыеТаблицы");

	Возврат Результат;
КонецФункции

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


Процедура АктуализироватьКлючиПредопределенных(Режим, Результат)

	ПредставлениеПроцедуры = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Обновление ключей вариантов отчетов (%1)'"),
		?(Режим = "ОбщиеДанныеКонфигурации", НСтр("ru = 'метаданные конфигурации'"), НСтр("ru = 'метаданные расширений'")));
	ЗаписатьВЖурналЗапускПроцедуры(ПредставлениеПроцедуры);

	// Составить таблицу замен старых ключей вариантов на актуальные.
	Изменения = ИзмененияКлючей();

	// Получить ссылки вариантов отчетов для замены ключей,
	// исключив из списка замен те варианты отчетов,
	// актуальные ключи которых уже зарегистрированы,
	// или старые ключи которых уже не заняты.
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	Изменения.Отчет,
	|	Изменения.СтароеИмяВарианта,
	|	Изменения.АктуальноеИмяВарианта
	|ПОМЕСТИТЬ втИзменения
	|ИЗ
	|	&Изменения КАК Изменения
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	втИзменения.Отчет,
	|	втИзменения.АктуальноеИмяВарианта,
	|	ВариантыОтчетовСтарые.Ссылка
	|ИЗ
	|	втИзменения КАК втИзменения
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПредопределенныеВариантыОтчетов КАК ВариантыОтчетовАктуальные
	|		ПО втИзменения.Отчет = ВариантыОтчетовАктуальные.Отчет
	|			И втИзменения.АктуальноеИмяВарианта = ВариантыОтчетовАктуальные.КлючВарианта
	|		ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПредопределенныеВариантыОтчетов КАК ВариантыОтчетовСтарые
	|		ПО втИзменения.Отчет = ВариантыОтчетовСтарые.Отчет
	|			И втИзменения.СтароеИмяВарианта = ВариантыОтчетовСтарые.КлючВарианта
	|ГДЕ
	|	ВариантыОтчетовАктуальные.Ссылка ЕСТЬ NULL
	|	И НЕ ВариантыОтчетовСтарые.Ссылка ЕСТЬ NULL ";

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

	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Изменения", Изменения);
	Запрос.Текст = ТекстЗапроса;

	// Заменить старые имена вариантов на актуальные.
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Результат.ЕстьИзменения = Истина;
		Результат.ЕстьВажныеИзменения = Истина;

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

			ВариантОбъект = Выборка.Ссылка.ПолучитьОбъект();
			ВариантОбъект.КлючВарианта = Выборка.АктуальноеИмяВарианта;
			ЗаписатьПредопределенный(ВариантОбъект);

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

	ЗаписатьВЖурналЗавершениеПроцедуры(ПредставлениеПроцедуры);
КонецПроцедуры

Процедура ПометитьУдаленныеПредопределенные(Режим, Результат)

	ПредставлениеПроцедуры = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Обновление настроек предопределенных (%1)'"),
		?(Режим = "ОбщиеДанныеКонфигурации", НСтр("ru = 'метаданные конфигурации'"), НСтр("ru = 'метаданные расширений'")));
	ЗаписатьВЖурналЗапускПроцедуры(ПредставлениеПроцедуры);

	Если Режим = "ОбщиеДанныеКонфигурации" Тогда
		ТекстЗапроса = "ВЫБРАТЬ * ИЗ Справочник.ПредопределенныеВариантыОтчетов УПОРЯДОЧИТЬ ПО ПометкаУдаления";
		ПустаяСсылка = Справочники.ПредопределенныеВариантыОтчетов.ПустаяСсылка();
		ИмяТаблицы = "Справочник.ПредопределенныеВариантыОтчетов";
	ИначеЕсли Режим = "ОбщиеДанныеРасширений" Тогда
		ТекстЗапроса = "ВЫБРАТЬ * ИЗ Справочник.ПредопределенныеВариантыОтчетовРасширений УПОРЯДОЧИТЬ ПО ПометкаУдаления";
		ПустаяСсылка = Справочники.ПредопределенныеВариантыОтчетовРасширений.ПустаяСсылка();
		ИмяТаблицы = "Справочник.ПредопределенныеВариантыОтчетовРасширений";
	КонецЕсли;

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

	Запрос = Новый Запрос(ТекстЗапроса);
	ПредопределенныеВариантыОтчетов = Запрос.Выполнить().Выгрузить();

	Для Каждого ВариантИзБазы Из ПредопределенныеВариантыОтчетов Цикл

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

		Если ВариантИзБазы.ПометкаУдаления И ВариантИзБазы.Родитель = ПустаяСсылка Тогда
			Продолжить; // Действие не требуется.
		КонецЕсли;

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

			ВариантОбъект = ВариантИзБазы.Ссылка.ПолучитьОбъект();
			Если ВариантОбъект = Неопределено Тогда
				ОтменитьТранзакцию();
				Продолжить;
			КонецЕсли;

			ВариантОбъект.ПометкаУдаления = Истина;
			ВариантОбъект.Родитель = ПустаяСсылка;
			ЗаписатьПредопределенный(ВариантОбъект);

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

		Результат.ЕстьИзменения = Истина;
		Результат.ЕстьВажныеИзменения = Истина;

	КонецЦикла;

	ЗаписатьВЖурналЗавершениеПроцедуры(ПредставлениеПроцедуры);
КонецПроцедуры


Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента, Получатель) Экспорт

	ПриОтправкеДанныхПолучателю(ЭлементДанных, ОтправкаЭлемента, Получатель);

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

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииОбработчиковУстановкиПараметровСеанса.

Процедура ПриДобавленииОбработчиковУстановкиПараметровСеанса(Обработчики) Экспорт

	Обработчики.Вставить("ВыполняетсяЗаписьОбъекта",
		"ВерсионированиеОбъектов.УстановкаПараметровСеанса");

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

// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий

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

// Обработчик перехода на версию объекта.
//
// Параметры:
//  ОбъектСсылка - ЛюбаяСсылка - ссылка на объект, для которого имеется версия.
//  НомерВерсииДляПерехода - Число - номер версии, на которую необходимо выполнить переход.
//  НомерИгнорируемойВерсии - Число - номер версии, на которую необходимо проигнорировать.
//  ПропуститьПроверкуЗапретаИзменения - Булево - признак пропуска проверки даты запрета загрузки.
//

Процедура ПриПереходеНаВерсиюОбъекта(СсылкаНаОбъект, Знач НомерВерсии) Экспорт

	ОбъектМетаданных = СсылкаНаОбъект.Метаданные();
	ПроверитьНаличиеПравНаИзменениеОбъекта(ОбъектМетаданных);

	УстановитьПривилегированныйРежим(Истина);

	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ВерсииОбъектов");
	ЭлементБлокировки.УстановитьЗначение("Объект", СсылкаНаОбъект);

	ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
	ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаОбъект);

	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		ЗаблокироватьДанныеДляРедактирования(СсылкаНаОбъект);

		НаборЗаписей = ЗаписьОВерсииОбъекта(СсылкаНаОбъект, НомерВерсии);
		Запись = НаборЗаписей[0];

		Если Запись.ТипВерсииОбъекта = Перечисления.ТипыВерсийОбъекта.ПринятыеДанныеПоКоллизии Тогда
			НомерВерсии = НомерВерсии - 1;
			Если НомерВерсии <> 0 Тогда
				ПредыдущаяЗапись = ЗаписьОВерсииОбъекта(СсылкаНаОбъект, НомерВерсии)[0];
				НомерВерсии = ПредыдущаяЗапись.НомерВерсии;
			КонецЕсли;
		Иначе
			НомерВерсии = Запись.НомерВерсии;
		КонецЕсли;

		ТекстСообщенияОбОшибке = "";
		ПерейтиНаВерсиюСервер(СсылкаНаОбъект, НомерВерсии, ТекстСообщенияОбОшибке);

		Если Не ПустаяСтрока(ТекстСообщенияОбОшибке) Тогда
			ВызватьИсключение ТекстСообщенияОбОшибке;
		КонецЕсли;

		Запись.ВерсияПроигнорирована = Истина;
		НаборЗаписей.Записать();

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

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

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//

Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт

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

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

	ИнформацияОбУстаревшихВерсиях = ИнформацияОбУстаревшихВерсиях();
	РазмерУстаревшихДанных = ИнформацияОбУстаревшихВерсиях.РазмерДанныхСтрокой;
	Подсказка = НСтр("ru = 'Устаревших версий: %1 (%2)'");

	Для Каждого Раздел Из Разделы Цикл
		ИдентификаторУстаревшиеОбъекты = "УстаревшиеВерсииОбъектов" + СтрЗаменить(Раздел.ПолноеИмя(), ".", "");
		// Добавление дела.
		Дело = ТекущиеДела.Добавить();
		Дело.Идентификатор = ИдентификаторУстаревшиеОбъекты;
		// Выводим дело, если размер устаревших данных больше 1 Гб.
		Дело.ЕстьДела      = ИнформацияОбУстаревшихВерсиях.РазмерДанных > (1024 * 1024 * 1024);
		Дело.Представление = НСтр("ru = 'Устаревшие версии объектов'");
		Дело.Форма         = "РегистрСведений.НастройкиВерсионированияОбъектов.Форма.НастройкиХраненияИстории";
		Дело.Подсказка     = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Подсказка, ИнформацияОбУстаревшихВерсиях.КоличествоВерсий, РазмерУстаревшихДанных);
		Дело.Владелец      = Раздел;
	КонецЦикла;

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

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.

Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт

	СоответствиеИменПсевдонимам.Вставить("ВерсионированиеОбъектов.ОчиститьУстаревшиеВерсииОбъектов");

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

// См. ЦентрМониторингаПереопределяемый.ПриСбореПоказателейСтатистикиКонфигурации.

Процедура ПриСбореПоказателейСтатистикиКонфигурации() Экспорт

	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЦентрМониторинга") Тогда
		Возврат;
	КонецЕсли;

	МодульЦентрМониторинга = ОбщегоНазначения.ОбщийМодуль("ЦентрМониторинга");

	ТекстЗапроса =
	"ВЫБРАТЬ
	|	ТИПЗНАЧЕНИЯ(ВерсииОбъектов.Объект) КАК ТипОбъекта,
	|	КОЛИЧЕСТВО(1) КАК Количество
	|ИЗ
	|	РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
	|
	|СГРУППИРОВАТЬ ПО
	|	ТИПЗНАЧЕНИЯ(ВерсииОбъектов.Объект)";

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

	ТекстЗапроса =
	"ВЫБРАТЬ
	|	НастройкиВерсионированияОбъектов.ТипОбъекта.ПолноеИмя КАК ИмяОбъекта
	|ИЗ
	|	РегистрСведений.НастройкиВерсионированияОбъектов КАК НастройкиВерсионированияОбъектов
	|ГДЕ
	|	НастройкиВерсионированияОбъектов.Использовать = ИСТИНА";

	Запрос = Новый Запрос(ТекстЗапроса);
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		МодульЦентрМониторинга.ЗаписатьСтатистикуОбъектаКонфигурации("ВключеноВерсионированиеОбъекта." + Выборка.ИмяОбъекта, Истина);
	КонецЦикла;

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

// См. ВыгрузкаЗагрузкаДанныхПереопределяемый.ПриРегистрацииОбработчиковВыгрузкиДанных

Процедура ПриРегистрацииОбработчиковВыгрузкиДанных(ТаблицаОбработчиков) Экспорт

	Обработчик = ТаблицаОбработчиков.Добавить();
	Обработчик.ОбъектМетаданных = Метаданные.РегистрыСведений.ВерсииОбъектов;
	Обработчик.Обработчик = РегистрыСведений.ВерсииОбъектов;
	Обработчик.ПередВыгрузкойОбъекта = Истина;
	Обработчик.Версия = "1.0.0.1";

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

// см. УдалениеПомеченныхОбъектовПереопределяемый.ПередУдалениемГруппыОбъектов

Процедура ПередУдалениемГруппыОбъектов(Контекст, УдаляемыеОбъекты) Экспорт

	Контекст.Вставить("Версионирование_УдаляемыеОбъекты", УдаляемыеОбъекты);

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

// см. УдалениеПомеченныхОбъектовПереопределяемый.ПослеУдаленияГруппыОбъектов

Процедура ПослеУдаленияГруппыОбъектов(Контекст, Успешно) Экспорт

	Если Не Успешно Тогда
		Возврат;
	КонецЕсли;

	Для Каждого Ссылка Из Контекст.Версионирование_УдаляемыеОбъекты Цикл
		Если Метаданные.РегистрыСведений.ВерсииОбъектов.Реквизиты.АвторВерсии.Тип.СодержитТип(ТипЗнч(Ссылка)) Тогда
			РегистрыСведений.ВерсииОбъектов.УдалитьИнформациюОбАвтореВерсии(Ссылка);
		КонецЕсли;
	КонецЦикла;

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

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

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

// Параметры:
//  ИмяПараметра - Строка
//  УстановленныеПараметры - Массив из Строка
//


Функция ЗапросПоУстаревшимВерсиям(ТекстЗапроса)

	Запрос = Новый Запрос;
	ГраницыУдаленияОбъектов = ГраницыУдаленияОбъектов();
	ДополнительныеУсловия = "";

	Для Индекс = 0 По ГраницыУдаленияОбъектов.Количество() - 1 Цикл
		Если Не ПустаяСтрока(ДополнительныеУсловия) Тогда
			ДополнительныеУсловия = ДополнительныеУсловия + "
			|	ИЛИ";
		КонецЕсли;
		ИндексСтрокой = Формат(Индекс, "ЧН=0; ЧГ=0");
		Условие = "";
		Для Каждого Тип Из ГраницыУдаленияОбъектов[Индекс].СписокТипов Цикл
			Если Не ПустаяСтрока(Условие) Тогда
				Условие = Условие + "
				|	ИЛИ";
			КонецЕсли;
			Условие = Условие + "
			|	ВерсииОбъектов.Объект ССЫЛКА " + Тип;
		КонецЦикла;
		Если ПустаяСтрока(Условие) Тогда
			Продолжить;
		КонецЕсли;
		Условие = "(" + Условие + ")";
		ДополнительныеУсловия = ДополнительныеУсловия + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		"
		|	%1
		|	И ВерсииОбъектов.ДатаВерсии < &ГраницаУдаления%2",
		Условие,
		ИндексСтрокой);
		Запрос.УстановитьПараметр("СписокТипов" + ИндексСтрокой, ГраницыУдаленияОбъектов[Индекс].СписокТипов);
		Запрос.УстановитьПараметр("ГраницаУдаления" + ИндексСтрокой, ГраницыУдаленияОбъектов[Индекс].ГраницаУдаления);
	КонецЦикла;

	Если ПустаяСтрока(ДополнительныеУсловия) Тогда
		ДополнительныеУсловия = "ЛОЖЬ";
	Иначе
		ДополнительныеУсловия = "(" + ДополнительныеУсловия + ")";
	КонецЕсли;

	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ДополнительныеУсловия", ДополнительныеУсловия);
	Запрос.Текст = ТекстЗапроса;

	Возврат Запрос;

КонецФункции

// Строковое представление объемов данных. Например: "1,23 Гб".

Функция РазмерДанныхСтрокой(Знач РазмерДанных)

	ЕдиницаИзмерения = НСтр("ru = 'байт'");
	Если 1024 <= РазмерДанных И РазмерДанных < 1024 * 1024 Тогда
		РазмерДанных = РазмерДанных / 1024;
		ЕдиницаИзмерения = НСтр("ru = 'Кб'");
	ИначеЕсли 1024 * 1024 <= РазмерДанных И  РазмерДанных < 1024 * 1024 * 1024 Тогда
		РазмерДанных = РазмерДанных / 1024 / 1024;
		ЕдиницаИзмерения = НСтр("ru = 'Мб'");
	ИначеЕсли 1024 * 1024 * 1024 <= РазмерДанных Тогда
		РазмерДанных = РазмерДанных / 1024 / 1024 / 1024;
		ЕдиницаИзмерения = НСтр("ru = 'Гб'");
	КонецЕсли;

	Если РазмерДанных < 10 Тогда
		РазмерДанных = Окр(РазмерДанных, 2);
	ИначеЕсли РазмерДанных < 100 Тогда
		РазмерДанных = Окр(РазмерДанных, 1);
	Иначе
		РазмерДанных = Окр(РазмерДанных, 0);
	КонецЕсли;

	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 %2'"), РазмерДанных, ЕдиницаИзмерения);

КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Функции для получения отчета по объекту.

// Возвращает сериализованный объект в виде двоичных данных.
//
// Параметры:
//  Объект - Произвольный - сериализуемый объект.
//
// Возвращаемое значение:
//  ДвоичныеДанные - сериализованный объект.
//

Функция СериализоватьОбъект(Объект) Экспорт

	ЗаписьXML = Новый ЗаписьFastInfoset;
	ЗаписьXML.УстановитьДвоичныеДанные();
	ЗаписьXML.ЗаписатьОбъявлениеXML();

	ЗаписатьXML(ЗаписьXML, Объект, НазначениеТипаXML.Явное);

	Возврат ЗаписьXML.Закрыть();

КонецФункции

// Процедура считывает данные XML из файла и заполняет структуры данных.
//
// Параметры:
//  ДанныеВерсии - ДвоичныеДанные
//               - Структура
//  Ссылка - ЛюбаяСсылка
//
// Возвращаемое значение:
//  Структура:
//   * Реквизиты - ТаблицаЗначений:
//    ** НаименованиеРеквизита - Строка
//    ** ЗначениеРеквизита - Произвольный
//    ** ТипРеквизита - Строка
//    ** Тип - Тип
//   * ТабличныеЧасти - Соответствие из КлючИЗначение:
//    ** Ключ - Строка
//    ** Значение - ТаблицаЗначений
//   * ТабличныеДокументы - см. ВерсионированиеОбъектовПереопределяемый.ПриПолученииТабличныхДокументовОбъекта.ТабличныеДокументы
//   * ДополнительныеРеквизиты - см. ВерсионированиеОбъектовПереопределяемый.ПриПодготовкеДанныхОбъекта.ДополнительныеРеквизиты
//   * СкрываемыеРеквизиты - Массив
//


Функция РазборПредставленияОбъектаXML(ДанныеВерсии, Ссылка) Экспорт

	Результат = Новый Структура;
	Результат.Вставить("ТабличныеДокументы");
	Результат.Вставить("ДополнительныеРеквизиты");
	Результат.Вставить("СкрываемыеРеквизиты", Новый Массив);

	ДвоичныеДанные = ДанныеВерсии;
	Если ТипЗнч(ДанныеВерсии) = Тип("Структура") Тогда
		ДвоичныеДанные = ДанныеВерсии.Объект;
		ДанныеВерсии.Свойство("ТабличныеДокументы", Результат.ТабличныеДокументы);
		ДанныеВерсии.Свойство("ДополнительныеРеквизиты", Результат.ДополнительныеРеквизиты);
		ДанныеВерсии.Свойство("СкрываемыеРеквизиты", Результат.СкрываемыеРеквизиты);
	КонецЕсли;

	ЗначенияРеквизитов = Новый ТаблицаЗначений;
	ЗначенияРеквизитов.Колонки.Добавить("НаименованиеРеквизита");
	ЗначенияРеквизитов.Колонки.Добавить("ЗначениеРеквизита");
	ЗначенияРеквизитов.Колонки.Добавить("ТипРеквизита");
	ЗначенияРеквизитов.Колонки.Добавить("Тип");

	ТабличныеЧасти = Новый Соответствие;

	ЧтениеXML = Новый ЧтениеFastInfoSet;
	ЧтениеXML.УстановитьДвоичныеДанные(ДвоичныеДанные);

	// Уровень позиции маркера в иерархии XML:
	// 0 - уровень не задан
	// 1 - первый элемент (имя объекта)
	// 2 - описание реквизита или табличной части
	// 3 - описание строки табличной части
	// 4 - описание поля строки табличной части.
	УровеньЧтения = 0;

	МетаданныеОбъекта = Ссылка.Метаданные();
	ТипЗначенияПоляТЧ = "";

	// Основной цикл разбора по XML.
	Пока ЧтениеXML.Прочитать() Цикл
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
			УровеньЧтения = УровеньЧтения + 1;
			Если УровеньЧтения = 1 Тогда // Указатель на первом элементе XML - корень XML.
				// В ЧтениеXML.Имя имя объекта, но оно нам не нужно.
			ИначеЕсли УровеньЧтения = 2 Тогда // Указатель на втором уровне - это реквизит или имя табличной части.
				ИмяРеквизита = ЧтениеXML.Имя;

				// Любой реквизит "может оказаться" табличной частью, поэтому на всякий случай его запомним.
				ИмяТабличнойЧасти = ИмяРеквизита;
				Если МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти) <> Неопределено Тогда
					ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, Новый ТаблицаЗначений);
				КонецЕсли;

				НовоеЗначение = ЗначенияРеквизитов.Добавить();
				НовоеЗначение.НаименованиеРеквизита = ИмяРеквизита;

				Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
					Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
						Если ЧтениеXML.ТипУзла = ТипУзлаXML.Атрибут
							И ЧтениеXML.Имя = "xsi:type" Тогда
								НовоеЗначение.ТипРеквизита = ЧтениеXML.Значение;
								XMLТип = ЧтениеXML.Значение;
								Если СтрНачинаетсяС(XMLТип, "xs:") Тогда
									НовоеЗначение.Тип = ИзXMLТипа(Новый ТипДанныхXML(Прав(XMLТип, СтрДлина(XMLТип)-3), "http://www.w3.org/2001/XMLSchema"));
								Иначе
									НовоеЗначение.Тип = ИзXMLТипа(Новый ТипДанныхXML(XMLТип, ""));
								КонецЕсли;
						КонецЕсли;
					КонецЦикла;
				КонецЕсли;

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

					Если ОписаниеРеквизита <> Неопределено
						И ОписаниеРеквизита.Тип.Типы().Количество() = 1 Тогда
						НовоеЗначение.Тип = ОписаниеРеквизита.Тип.Типы()[0];
					КонецЕсли;
				КонецЕсли;
			ИначеЕсли (УровеньЧтения = 3) И ЧтениеXML.Имя = "Row" Тогда // Указатель на поле табличной части.
				Если ТабличныеЧасти[ИмяТабличнойЧасти] = Неопределено Тогда
					ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, Новый ТаблицаЗначений);
				КонецЕсли;
				ТабличныеЧасти[ИмяТабличнойЧасти].Добавить();
			ИначеЕсли УровеньЧтения = 4 Тогда
				Если ЧтениеXML.Имя = "v8:Type" Тогда
					Если НовоеЗначение.ЗначениеРеквизита = Неопределено Тогда
						НовоеЗначение.ЗначениеРеквизита = "";
					КонецЕсли;
				Иначе // Указатель на поле табличной части.
					ТипЗначенияПоляТЧ = "";
					ИмяПоляТЧ = ЧтениеXML.Имя;
					Таблица   = ТабличныеЧасти[ИмяТабличнойЧасти];// ТаблицаЗначений
					Если Таблица.Колонки.Найти(ИмяПоляТЧ)= Неопределено Тогда
						Таблица.Колонки.Добавить(ИмяПоляТЧ);
					КонецЕсли;

					Если ЧтениеXML.КоличествоАтрибутов() > 0 Тогда
						Пока ЧтениеXML.ПрочитатьАтрибут() Цикл
							Если ЧтениеXML.ТипУзла = ТипУзлаXML.Атрибут
								И ЧтениеXML.Имя = "xsi:type" Тогда
									XMLТип = ЧтениеXML.Значение;
									Если СтрНачинаетсяС(XMLТип, "xs:") Тогда
										ТипЗначенияПоляТЧ = ИзXMLТипа(Новый ТипДанныхXML(Прав(XMLТип, СтрДлина(XMLТип)-3), "http://www.w3.org/2001/XMLSchema"));
									Иначе
										ТипЗначенияПоляТЧ = ИзXMLТипа(Новый ТипДанныхXML(XMLТип, ""));
									КонецЕсли;
							КонецЕсли;
						КонецЦикла;
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
		ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
			УровеньЧтения = УровеньЧтения - 1;
		ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
			Если (УровеньЧтения = 2) Тогда // значение реквизита
				Попытка
					НовоеЗначение.ЗначениеРеквизита = ?(ЗначениеЗаполнено(НовоеЗначение.Тип), XMLЗначение(НовоеЗначение.Тип, ЧтениеXML.Значение), ЧтениеXML.Значение);
				Исключение
					НовоеЗначение.ЗначениеРеквизита = ЧтениеXML.Значение;
				КонецПопытки;
			ИначеЕсли (УровеньЧтения = 4) Тогда // значение реквизита
				Если НовоеЗначение.Тип = Тип("ОписаниеТипов") Тогда
					ТипСтрокой = Строка(ИзXMLТипа(Новый ТипДанныхXML(ЧтениеXML.Значение, "")));
					Если ПустаяСтрока(ТипСтрокой) Тогда
						ТипСтрокой = ЧтениеXML.Значение;
					КонецЕсли;
					Если Не ПустаяСтрока(НовоеЗначение.ЗначениеРеквизита) Тогда
						НовоеЗначение.ЗначениеРеквизита = НовоеЗначение.ЗначениеРеквизита + Символы.ПС;
					КонецЕсли;
					НовоеЗначение.ЗначениеРеквизита = НовоеЗначение.ЗначениеРеквизита + ТипСтрокой;
				Иначе
					Если ТипЗначенияПоляТЧ = "" Тогда
						ОписаниеРеквизита = Неопределено;
						МетаданныеТабличнойЧасти = МетаданныеТабличнойЧасти(МетаданныеОбъекта, ИмяТабличнойЧасти);
						Если МетаданныеТабличнойЧасти <> Неопределено Тогда
							ОписаниеРеквизита = МетаданныеРеквизитаТабличнойЧасти(МетаданныеТабличнойЧасти, ИмяПоляТЧ);
							Если ОписаниеРеквизита = Неопределено И Метаданные.ПланыСчетов.Содержит(МетаданныеОбъекта) Тогда
								ОписаниеРеквизита = МетаданныеОбъекта.ПризнакиУчетаСубконто.Найти(ИмяПоляТЧ);
							КонецЕсли;
							Если ОписаниеРеквизита <> Неопределено
								И ОписаниеРеквизита.Тип.Типы().Количество() = 1 Тогда
									ТипЗначенияПоляТЧ = ОписаниеРеквизита.Тип.Типы()[0];
							КонецЕсли;
						КонецЕсли;
					КонецЕсли;
					ПоследняяСтрока = ТабличныеЧасти[ИмяТабличнойЧасти].Получить(ТабличныеЧасти[ИмяТабличнойЧасти].Количество()-1);
					Значение = ЧтениеXML.Значение;
					Если ЗначениеЗаполнено(ТипЗначенияПоляТЧ) Тогда
						Попытка
							Значение = XMLЗначение(ТипЗначенияПоляТЧ, ЧтениеXML.Значение);
						Исключение
							Значение = ЧтениеXML.Значение;
						КонецПопытки;
					КонецЕсли;
					ПоследняяСтрока[ИмяПоляТЧ] = Значение;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

	// Из списка реквизитов исключаем табличные части.
	Для Каждого Элемент Из ТабличныеЧасти Цикл
		ЗначенияРеквизитов.Удалить(ЗначенияРеквизитов.Найти(Элемент.Ключ));
	КонецЦикла;

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

	Результат.Вставить("Реквизиты", ЗначенияРеквизитов);
	Результат.Вставить("ТабличныеЧасти", ТабличныеЧасти);

	Если Результат.СкрываемыеРеквизиты <> Неопределено Тогда
		Для Каждого ИмяРеквизита Из Результат.СкрываемыеРеквизиты Цикл
			Если СтрЗаканчиваетсяНа(ИмяРеквизита, ".*") Тогда
				ИмяТабличнойЧасти = Лев(ИмяРеквизита, СтрДлина(ИмяРеквизита) - 2);
				Если Результат.ТабличныеЧасти[ИмяТабличнойЧасти] <> Неопределено Тогда
					Результат.ТабличныеЧасти.Удалить(ИмяТабличнойЧасти);
				КонецЕсли;
			Иначе
				НайденныеРеквизиты = Результат.Реквизиты.НайтиСтроки(Новый Структура("НаименованиеРеквизита", ИмяРеквизита));
				Для Каждого Реквизит Из НайденныеРеквизиты Цикл
					Результат.Реквизиты.Удалить(Реквизит);
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Если Результат.ДополнительныеРеквизиты <> Неопределено Тогда
		Для Каждого ДополнительныйРеквизит Из Результат.ДополнительныеРеквизиты Цикл
			Реквизит = ЗначенияРеквизитов.Добавить();
			Реквизит.НаименованиеРеквизита = ДополнительныйРеквизит.Наименование;
			Реквизит.ЗначениеРеквизита = ДополнительныйРеквизит.Значение;
			Реквизит.Тип = ТипЗнч(ДополнительныйРеквизит.Значение);
		КонецЦикла;
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Параметры:
//  МетаданныеОбъекта - ОбъектМетаданных
//  ИмяРеквизита - Строка
// Возвращаемое значение:
//  ОписаниеСтандартногоРеквизита, ОбъектМетаданныхРеквизит, Неопределено
//


Функция КонтактыЗаполнены(ВзаимодействиеОбъект, ВидДокумента)

	МассивТабличныхЧастей = Новый Массив;

	Если ВидДокумента = "ЭлектронноеПисьмоИсходящее" Тогда

		МассивТабличныхЧастей.Добавить("ПолучателиПисьма");
		МассивТабличныхЧастей.Добавить("ПолучателиКопий");
		МассивТабличныхЧастей.Добавить("ПолучателиОтвета");
		МассивТабличныхЧастей.Добавить("ПолучателиСкрытыхКопий");

	ИначеЕсли ВидДокумента = "ЭлектронноеПисьмоВходящее" Тогда

		Если НЕ ЗначениеЗаполнено(ВзаимодействиеОбъект.ОтправительКонтакт) Тогда
			Возврат Ложь;
		КонецЕсли;

		МассивТабличныхЧастей.Добавить("ПолучателиПисьма");
		МассивТабличныхЧастей.Добавить("ПолучателиКопий");
		МассивТабличныхЧастей.Добавить("ПолучателиОтвета");

	ИначеЕсли ВидДокумента = "Встреча"
		ИЛИ ВидДокумента = "ЗапланированноеВзаимодействие" Тогда

		МассивТабличныхЧастей.Добавить("Участники");

	ИначеЕсли ВидДокумента = "СообщениеSMS" Тогда

		МассивТабличныхЧастей.Добавить("Адресаты");

	ИначеЕсли ВидДокумента = "ТелефонныйЗвонок" Тогда

		Если НЕ ЗначениеЗаполнено(ВзаимодействиеОбъект.АбонентКонтакт) Тогда
			Возврат Ложь;
		КонецЕсли;

	КонецЕсли;

	Для каждого ИмяТабличнойЧасти Из МассивТабличныхЧастей Цикл
		Для каждого СтрокаТабличнойЧасти Из ВзаимодействиеОбъект[ИмяТабличнойЧасти] Цикл

			Если НЕ ЗначениеЗаполнено(СтрокаТабличнойЧасти.Контакт) Тогда
				Возврат Ложь;
			КонецЕсли;

		КонецЦикла;
	КонецЦикла;

	Возврат Истина;

КонецФункции

Процедура УстановитьСвойствоЭлементовГруппы(ГруппаЭлементов, ИмяСвойства, ЗначениеСвойства) Экспорт

	Для каждого ПодчиненныйЭлемент Из ГруппаЭлементов.ПодчиненныеЭлементы Цикл

		Если ТипЗнч(ПодчиненныйЭлемент) = Тип("ГруппаФормы") Тогда

			УстановитьСвойствоЭлементовГруппы(ПодчиненныйЭлемент, ИмяСвойства, ЗначениеСвойства);

		Иначе

			ПодчиненныйЭлемент[ИмяСвойства] = ЗначениеСвойства;

		КонецЕсли;

	КонецЦикла;

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

Функция ПолучитьПредставлениеКонтакта(Контакт)

	Возврат Строка(Контакт);

КонецФункции

// Параметры:
//  Список  - ДинамическийСписок - список, для которого надо определить отбор.
//
// Возвращаемое значение:
//   Отбор   - требуемый отбор.
//

Функция ОтборДинамическогоСписка(Список) Экспорт

	Возврат Список.КомпоновщикНастроек.ФиксированныеНастройки.Отбор;

КонецФункции

// Параметры:
//  МенеджерОбъекта     - ДокументОбъект.ТелефонныйЗвонок
//                      - ДокументОбъект.ЗапланированноеВзаимодействие
//                      - ДокументОбъект.СообщениеSMS
//                      - ДокументОбъект.Встреча
//                      - ДокументОбъект.ЭлектронноеПисьмоВходящее
//                      - ДокументОбъект.ЭлектронноеПисьмоИсходящее - взаимодействие, для которого получается представление.
//  Данные              - Структура:
//                        * ДатаНачала - Дата - начало запланированного взаимодействия.
//  Представление        - Строка - формируемое представление.
//  СтандартнаяОбработка - Булево - признак необходимости стандартной обработки.
//

Процедура ОбработкаПолученияПредставления(МенеджерОбъекта, Данные, Представление, СтандартнаяОбработка) Экспорт

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

	ШаблонПредставления = НСтр("ru = '%1 от %2 (%3)'");
	Представление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонПредставления, Тема, Дата, ТипДокумента);

	СтандартнаяОбработка = Ложь;

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

// Получает поля, необходимые для формирования представления для взаимодействий.
//
// Параметры:
//  МенеджерОбъекта - ДокументОбъект.ТелефонныйЗвонок
//                  - ДокументОбъект.ЗапланированноеВзаимодействие
//                  - ДокументОбъект.СообщениеSMS
//                  - ДокументОбъект.Встреча
//                  - ДокументОбъект.ЭлектронноеПисьмоВходящее
//                  - ДокументОбъект.ЭлектронноеПисьмоИсходящее - взаимодействие, для которого получается представление.
//  Поля                  - Массив - имена полей, которые нужны для формирования представления объекта или ссылки.
//  СтандартнаяОбработка  - Булево - признак необходимости выполнения стандартной обработки.
//

Процедура ОбработкаПолученияПолейПредставления(МенеджерОбъекта, Поля, СтандартнаяОбработка) Экспорт

	Поля.Добавить("Тема");
	Поля.Добавить("Дата");
	Если ТипЗнч(МенеджерОбъекта) = Тип("ДокументМенеджер.Встреча") Тогда
		Поля.Добавить("ДатаНачала");
	КонецЕсли;
	СтандартнаяОбработка = Ложь;

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

Функция МассивРасширенийФайлаПисьма()

	МассивРасширенийФайла = Новый Массив;
	МассивРасширенийФайла.Добавить("msg");
	МассивРасширенийФайла.Добавить("eml");

	Возврат МассивРасширенийФайла;

КонецФункции

Функция ТемаВзаимодействия(Тема) Экспорт

	Возврат ?(ПустаяСтрока(Тема), НСтр("ru = '<Без темы>'"), Тема);

КонецФункции

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


Процедура ОбновитьОбщуюКомпоненту(ОписаниеКомпоненты) Экспорт

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаВМоделиСервиса.ВнешниеКомпонентыВМоделиСервиса") Тогда
		МодульВнешниеКомпонентыВМоделиСервисаСлужебный = ОбщегоНазначения.ОбщийМодуль("ВнешниеКомпонентыВМоделиСервисаСлужебный");
		МодульВнешниеКомпонентыВМоделиСервисаСлужебный.ОбновитьОбщуюКомпоненту(ОписаниеКомпоненты);
	КонецЕсли;

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

// Для версий БИП старше 2.7.2.0 следует использовать ИспользуемыеКомпоненты("ДляОбновления").
// Возвращает таблицу описаний внешних компонент, которые требуется обновлять автоматически с Портала 1С:ИТС.
//
// Возвращаемое значение:
//   см. ПолучениеВнешнихКомпонент.ОписаниеВнешнихКомпонент
//

Функция АвтоматическиОбновляемыеКомпоненты() Экспорт

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

	МодульПолучениеВнешнихКомпонент = ОбщегоНазначения.ОбщийМодуль("ПолучениеВнешнихКомпонент");
	ОписаниеВнешнихКомпонент = МодульПолучениеВнешнихКомпонент.ОписаниеВнешнихКомпонент();

	ДанныеВнешнихКомпонент = ВнешниеКомпонентыСлужебный.ДанныеВнешнихКомпонент("ДляОбновления");

	Для Каждого ОписаниеКомпоненты Из ДанныеВнешнихКомпонент Цикл
		НоваяСтрока = ОписаниеВнешнихКомпонент.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, ОписаниеКомпоненты);
	КонецЦикла;

	Возврат ОписаниеВнешнихКомпонент;

КонецФункции

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

// Конец ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент

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


Функция ПараметрыПроверкиДатЗапрета() Экспорт

	Результат = Новый Структура;
	Результат.Вставить("ПроверкаЗапретаИзменения",    Ложь);
	Результат.Вставить("УзелПроверкиЗапретаЗагрузки", Неопределено);
	Результат.Вставить("ОписаниеОшибки",              Null);
	Возврат Результат;

КонецФункции

// Проверяет даты запрета изменения/загрузки данных для объекта.
// В случае если изменение/загрузка невозможно, устанавливает параметр Отказ в Истина.
//
// Параметры:
//  Источник        - СправочникОбъект
//                  - ПланВидовХарактеристикОбъект
//                  - ПланСчетовОбъект
//                  - ПланВидовРасчетаОбъект
//                  - БизнесПроцессОбъект
//                  - ЗадачаОбъект
//                  - ПланОбменаОбъект
//                  - ДокументОбъект - объект данных.
//                  - РегистрСведенийНаборЗаписей
//                  - РегистрНакопленияНаборЗаписей
//                  - РегистрБухгалтерииНаборЗаписей
//                  - РегистрРасчетаНаборЗаписей - набор записей.
//                  - УдалениеОбъекта - удаление объекта при загрузке.
//
//  ИсточникРегистр - Булево - Ложь - Источник является регистром, иначе объектом.
//
//  Замещение       - Булево - если источник является регистром и выполняется добавление,
//                    нужно указать Ложь.
//
//  Удаление        - Булево - если источник является объектом и выполняется удаление объекта,
//                    нужно указать Истина.
//
//  ДополнительныеПараметры - Неопределено - параметры имеют начальные значения.
//                          - см. ПараметрыПроверкиДатЗапрета
//
// Возвращаемое значение:
//   Структура:
//    * ИзменениеЗапрещено - Булево - Истина, если объект не проходит проверки дат запрета.
//    * ОписаниеОшибки     - Null
//                         - Строка
//                         - Структура - результат зависит от ДополнительныеПараметры.ОписаниеОшибки.
//

Функция ПроверитьДатыЗапретаИзмененияЗагрузкиДанных(Источник, ИсточникРегистр, Замещение, Удаление,
	ДополнительныеПараметры = Неопределено) Экспорт

	Результат = Новый Структура;
	Результат.Вставить("ИзменениеЗапрещено", Ложь);
	Результат.Вставить("ОписаниеОшибки", "");

	ПроверкаЗапретаИзменения    = Истина;
	УзелПроверкиЗапретаЗагрузки = Неопределено;

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

	ВерсияОбъекта = "";
	Если ПропуститьПроверкуДатЗапрета(Источник, ПроверкаЗапретаИзменения,
			УзелПроверкиЗапретаЗагрузки, ВерсияОбъекта) Тогда
		Возврат Результат;
	КонецЕсли;

	Если НЕ ИсточникРегистр И НЕ Удаление И НЕ Источник.ЭтоНовый() Тогда

		Если ИзменениеЗапрещено(
				?(ВерсияОбъекта <> "СтараяВерсия", Источник, Источник.Метаданные().ПолноеИмя()),
				?(ВерсияОбъекта <> "НоваяВерсия",  Источник.Ссылка, Неопределено),
				Результат.ОписаниеОшибки,
				УзелПроверкиЗапретаЗагрузки) Тогда

			Результат.ИзменениеЗапрещено = Истина;
		КонецЕсли;

	ИначеЕсли ИсточникРегистр И Замещение Тогда

		Если ИзменениеЗапрещено(
				?(ВерсияОбъекта <> "СтараяВерсия", Источник, Источник.Метаданные().ПолноеИмя()),
				?(ВерсияОбъекта <> "НоваяВерсия",  Источник.Отбор, Неопределено),
				Результат.ОписаниеОшибки,
				УзелПроверкиЗапретаЗагрузки) Тогда

			Результат.ИзменениеЗапрещено = Истина;
		КонецЕсли;

	ИначеЕсли ТипЗнч(Источник) = Тип("УдалениеОбъекта") Тогда

		Если ВерсияОбъекта <> "НоваяВерсия"
		   И ИзменениеЗапрещено(Источник.Ссылка.Метаданные().ПолноеИмя(), Источник.Ссылка,
				Результат.ОписаниеОшибки, УзелПроверкиЗапретаЗагрузки) Тогда

			Результат.ИзменениеЗапрещено = Истина;
		КонецЕсли;

	Иначе
		// Выполняется при условии:
		//     НЕ ИсточникРегистр И Источник.ЭтоНовый()
		// ИЛИ    ИсточникРегистр И НЕ Замещение
		// ИЛИ НЕ ИсточникРегистр И Удаление.
		Если ВерсияОбъекта <> "СтараяВерсия"
		   И ИзменениеЗапрещено(Источник, Неопределено,	Результат.ОписаниеОшибки, УзелПроверкиЗапретаЗагрузки) Тогда

			Результат.ИзменениеЗапрещено = Истина;
		КонецЕсли;
	КонецЕсли;

	Возврат Результат;

КонецФункции

// Проверяет необходимость проверки запрета изменения или загрузки данных.
//
// Возвращаемое значение:
//  Булево - Истина, если проверка не требуется.
//

Функция ПропуститьПроверкуДатЗапрета(Объект, ПроверкаЗапретаИзменения, УзелПроверкиЗапретаЗагрузки,
	ВерсияОбъекта) Экспорт

	Если ТипЗнч(Объект) <> Тип("УдалениеОбъекта")
	   И Объект.ДополнительныеСвойства.Свойство("ПропуститьПроверкуЗапретаИзменения") Тогда

		Возврат Истина;
	КонецЕсли;

	Если ПроверкаДатЗапретаОтключена(ПроверкаЗапретаИзменения, УзелПроверкиЗапретаЗагрузки) Тогда
		Возврат Истина;
	КонецЕсли;

	ДатыЗапретаИзмененияПереопределяемый.ПередПроверкойЗапретаИзменения(
		Объект, ПроверкаЗапретаИзменения, УзелПроверкиЗапретаЗагрузки, ВерсияОбъекта);

	Возврат ПроверкаЗапретаИзменения    = Ложь          // НЕ проверять запрет изменения.
	      И УзелПроверкиЗапретаЗагрузки = Неопределено; // НЕ проверять запрет загрузки.

КонецФункции

Функция ПроверкаДатЗапретаОтключена(ПроверкаЗапретаИзменения, УзелПроверкиЗапретаЗагрузки) Экспорт

	УстановитьПривилегированныйРежим(Истина);
	Если ПараметрыСеанса.ПропуститьПроверкуЗапретаИзменения Тогда
		Возврат Истина;
	КонецЕсли;
	УстановитьПривилегированныйРежим(Ложь);

	Если ЗапретИзмененияДанныхНеИспользуется(ПроверкаЗапретаИзменения, УзелПроверкиЗапретаЗагрузки) Тогда
		Возврат Истина;
	КонецЕсли;

	Если ОбновлениеИнформационнойБазы.ВыполняетсяОбновлениеИнформационнойБазы()
	 Или ОбновлениеИнформационнойБазы.ЭтоВызовИзОбработчикаОбновления() Тогда

		Возврат Истина;
	КонецЕсли;

	Возврат Ложь;

КонецФункции

// См. ДатыЗапретаИзменения.ИзменениеЗапрещено.


Функция ДанныеДляПроверкиИзОбъекта(Данные, ДействующиеДаты, УзелПроверкиЗапретаЗагрузки)

	ЗначенияПолей = Новый Структура;
	ОбъектМетаданных = Данные.Метаданные();

	ДанныеДляПроверки = ДатыЗапретаИзменения.ШаблонДанныхДляПроверки();
	ДатыЗапретаИзмененияПереопределяемый.ПередПроверкойНовойВерсииДанных(ОбъектМетаданных, Данные,
		УзелПроверкиЗапретаЗагрузки, ДанныеДляПроверки);

	Если ДанныеДляПроверки.Количество() > 0 Тогда
		Возврат ДанныеДляПроверки;
	КонецЕсли;

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

	Таблица = ОбъектМетаданных.ПолноеИмя();
	ИсточникиДанных = ПолучитьИсточникиДанных(ДействующиеДаты, Таблица);

	ДанныеДляПроверки = ДатыЗапретаИзменения.ШаблонДанныхДляПроверки();

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

			Если Не ЗначениеЗаполнено(ИсточникДанных.ПолеДаты.ТабличнаяЧасть)
			   И Не ЗначениеЗаполнено(ИсточникДанных.ПолеОбъекта.ТабличнаяЧасть) Тогда
				// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
				ДобавитьСтрокуДанных(Данные, Данные, ИсточникДанных, ДанныеДляПроверки, БезОбъекта);

			ИначеЕсли Не ЗначениеЗаполнено(ИсточникДанных.ПолеДаты.ТабличнаяЧасть) Тогда

				Если БезОбъекта Тогда
					// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
					ДобавитьСтрокуДанных(Данные, Неопределено, ИсточникДанных, ДанныеДляПроверки, БезОбъекта);
				Иначе
					// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
					СтрокаДаты = Новый Структура("Значение", ЗначениеПоля(Данные, ИсточникДанных.ПолеДаты));
					Поле = ИсточникДанных.ПолеОбъекта.Имя;
					ЗначенияОбъекта = Данные[ИсточникДанных.ПолеОбъекта.ТабличнаяЧасть].Выгрузить(, Поле); // ТаблицаЗначений
					ЗначенияОбъекта.Свернуть(Поле);
					Для Каждого СтрокаОбъекта Из ЗначенияОбъекта Цикл
						// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
						ДобавитьСтрокуДанных(СтрокаДаты, СтрокаОбъекта, ИсточникДанных, ДанныеДляПроверки);
					КонецЦикла;
				КонецЕсли;

			ИначеЕсли Не ЗначениеЗаполнено(ИсточникДанных.ПолеОбъекта.ТабличнаяЧасть) Тогда

				Если Не БезОбъекта Тогда
					// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
					СтрокаОбъекта = Новый Структура("Значение", ЗначениеПоля(Данные, ИсточникДанных.ПолеОбъекта));
				КонецЕсли;
				Поле = ИсточникДанных.ПолеДаты.Имя;
				ЗначенияДаты = Данные[ИсточникДанных.ПолеДаты.ТабличнаяЧасть].Выгрузить(, Поле); // ТаблицаЗначений
				ЗначенияДаты.Свернуть(Поле);
				Для Каждого СтрокаДаты Из ЗначенияДаты Цикл
					// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
					ДобавитьСтрокуДанных(СтрокаДаты, СтрокаОбъекта, ИсточникДанных, ДанныеДляПроверки, БезОбъекта);
				КонецЦикла;

			ИначеЕсли ИсточникДанных.ПолеДаты.ТабличнаяЧасть = ИсточникДанных.ПолеОбъекта.ТабличнаяЧасть Тогда

				Если БезОбъекта Тогда
					Поля = ИсточникДанных.ПолеДаты.Имя;
				Иначе
					Поля = ИсточникДанных.ПолеДаты.Имя + "," + ИсточникДанных.ПолеОбъекта.Имя;
				КонецЕсли;
				Значения = Данные[ИсточникДанных.ПолеДаты.ТабличнаяЧасть].Выгрузить(, Поля); // ТаблицаЗначений
				Значения.Свернуть(Поля);
				Для Каждого Строка Из Значения Цикл
					// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
					ДобавитьСтрокуДанных(Строка, Строка, ИсточникДанных, ДанныеДляПроверки, БезОбъекта);
				КонецЦикла;
			Иначе
				Поле = ИсточникДанных.ПолеДаты.Имя;
				ЗначенияДаты = Данные[ИсточникДанных.ПолеДаты.ТабличнаяЧасть].Выгрузить(, Поле); // ТаблицаЗначений
				ЗначенияДаты.Свернуть(Поле);

				Если Не БезОбъекта Тогда
					Поле = ИсточникДанных.ПолеОбъекта.Имя;
					ЗначенияОбъекта = Данные[ИсточникДанных.ПолеОбъекта.ТабличнаяЧасть].Выгрузить(, Поле); // ТаблицаЗначений
					ЗначенияОбъекта.Свернуть(Поле);
				КонецЕсли;

				Для Каждого СтрокаДаты Из ЗначенияДаты Цикл
					// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
					СтрокаДаты = Новый Структура("Значение", ЗначениеПоля(СтрокаДаты, ИсточникДанных.ПолеДаты));
					Если БезОбъекта Тогда
						// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
						ДобавитьСтрокуДанных(СтрокаДаты, Неопределено, ИсточникДанных, ДанныеДляПроверки, БезОбъекта);
					Иначе
						Для Каждого СтрокаОбъекта Из ЗначенияОбъекта Цикл
							// @skip-check query-in-loop - Цикл для исключения разыменования составного типа (стандарт 654)
							ДобавитьСтрокуДанных(СтрокаДаты, СтрокаОбъекта, ИсточникДанных, ДанныеДляПроверки);
						КонецЦикла;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Возврат ДанныеДляПроверки;

КонецФункции

// Для процедур ДанныеДляПроверкиИзБазыДанных, ДанныеДляПроверкиИзОбъекта.
//
// Параметры:
//  ДействующиеДаты - ФиксированнаяСтруктура
//  Таблица - Строка
// Возвращаемое значение:
//  ФиксированнаяСтруктура:
//    * Состав - ФиксированныйМассив из см. ОписаниеИсточникаДанных
//    * ТекстЗапроса - Строка
//    * ТекстЗапросаТолькоДаты - Строка
//    * ЭтоРегистр - Булево
//

Функция ПолучитьИсточникиДанных(ДействующиеДаты, Таблица)

	ИсточникиДанных = ДействующиеДаты.ИсточникиДанных.Получить(Таблица);

	Если ИсточникиДанных = Неопределено
	 Или ИсточникиДанных.Количество() = 0 Тогда

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

	Возврат ИсточникиДанных;

КонецФункции

// Для функции ДанныеДляПроверкиИзБазыДанных.

Процедура ДобавитьСтрокуДанныхИзБазыДанных(Строка, ИсточникДанных, ДанныеДляПроверки, БезОбъекта)

	НоваяСтрока = ДанныеДляПроверки.Добавить();
	НоваяСтрока.Раздел = ИсточникДанных.Раздел;
	ПолеДаты = Новый Структура("Имя, Путь", "Дата", ИсточникДанных.ПолеДаты.Путь);
	НоваяСтрока.Дата = ЗначениеПоля(Строка, ПолеДаты);

	Если БезОбъекта Или Не ЗначениеЗаполнено(ИсточникДанных.ПолеОбъекта.Имя) Тогда
		Возврат;
	КонецЕсли;

	ПолеОбъекта = Новый Структура("Имя, Путь", "Объект", ИсточникДанных.ПолеОбъекта.Путь);
	НоваяСтрока.Объект = ЗначениеПоля(Строка, ПолеОбъекта);

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

// Для процедуры ДанныеДляПроверкиИзОбъекта.

Процедура ДобавитьСтрокуДанных(СтрокаДаты, СтрокаОбъекта, ИсточникДанных, ДанныеДляПроверки, БезОбъекта = Ложь)

	НоваяСтрока = ДанныеДляПроверки.Добавить();
	НоваяСтрока.Раздел = ИсточникДанных.Раздел;
	НоваяСтрока.Дата = ЗначениеПоля(СтрокаДаты, ИсточникДанных.ПолеДаты);

	Если БезОбъекта Или Не ЗначениеЗаполнено(ИсточникДанных.ПолеОбъекта.Имя) Тогда
		Возврат;
	КонецЕсли;

	НоваяСтрока.Объект = ЗначениеПоля(СтрокаОбъекта, ИсточникДанных.ПолеОбъекта);

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

// Для процедуры ДобавитьСтрокуДанных.


Функция ЗапуститьВыполнениеВФоне(Знач ИдентификаторФормы, Знач ИмяЭкспортнойПроцедуры, Знач Параметры,
	Знач НаименованиеЗадания = "", ИспользоватьДополнительноеВременноеХранилище = Ложь) Экспорт

	АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено, ИдентификаторФормы);

	Результат = Новый Структура;
	Результат.Вставить("АдресХранилища",       АдресХранилища);
	Результат.Вставить("ЗаданиеВыполнено",     Ложь);
	Результат.Вставить("ИдентификаторЗадания", Неопределено);

	Если Не ЗначениеЗаполнено(НаименованиеЗадания) Тогда
		НаименованиеЗадания = ИмяЭкспортнойПроцедуры;
	КонецЕсли;

	ПараметрыЭкспортнойПроцедуры = Новый Массив;
	ПараметрыЭкспортнойПроцедуры.Добавить(Параметры);
	ПараметрыЭкспортнойПроцедуры.Добавить(АдресХранилища);

	Если ИспользоватьДополнительноеВременноеХранилище Тогда
		АдресХранилищаДополнительный = ПоместитьВоВременноеХранилище(Неопределено, ИдентификаторФормы);
		ПараметрыЭкспортнойПроцедуры.Добавить(АдресХранилищаДополнительный);
	КонецЕсли;

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

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

		Задание = Задание.ОжидатьЗавершенияВыполнения(ВремяОжидания);

		Статус = ОперацияВыполнена(Задание.УникальныйИдентификатор);
		Результат.ЗаданиеВыполнено = Статус.Статус = "Выполнено";
		Результат.ИдентификаторЗадания = Задание.УникальныйИдентификатор;
	КонецЕсли;

	Если ИспользоватьДополнительноеВременноеХранилище Тогда
		Результат.Вставить("АдресХранилищаДополнительный", АдресХранилищаДополнительный);
	КонецЕсли;

	Возврат Результат;

КонецФункции

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

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

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

// Параметры:
//  ИдентификаторЗадания - УникальныйИдентификатор
//  Задание - ФоновоеЗадание - возвращаемое значение - найденное фоновое задание.
//          - Неопределено - если фоновое задание не найдено.
//
// Возвращаемое значение:
//   см. НовыйРезультатВыполненияОперации
//

Функция ОперацияВыполнена(Знач ИдентификаторЗадания, Задание = Неопределено) Экспорт

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

	Результат = НовыйРезультатВыполненияОперации();
	ПоследнийИдентификатор = ПоследнийИдентификатор(ИдентификаторЗадания);

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

	ЗаписатьОстаткиСообщенийПользователю(ИдентификаторЗадания);

	Если Задание.Состояние = СостояниеФоновогоЗадания.Активно
	 Или ВыполненПерезапускУправляющегоПотока(ИдентификаторЗадания, Задание) Тогда
		Возврат Результат;
	КонецЕсли;

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

	Если Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно
		Или Задание.Состояние = СостояниеФоновогоЗадания.Отменено Тогда

		Результат.Статус = "Ошибка";
		Если Задание.ИнформацияОбОшибке <> Неопределено Тогда
			УстановитьСвойстваОшибки(Результат, Задание.ИнформацияОбОшибке);
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;

	Результат.Статус = "Выполнено";
	Возврат Результат;

КонецФункции

Процедура ВыполнитьПроцедуруМодуляОбъектаОбработки(Параметры, АдресХранилища) Экспорт

	Если БезопасныйРежим() <> Ложь Тогда
		БезопасныйРежим = БезопасныйРежим();
	ИначеЕсли Параметры.Свойство("БезопасныйРежим") И Параметры.БезопасныйРежим <> Ложь Тогда
		БезопасныйРежим = Параметры.БезопасныйРежим;
	Иначе
		БезопасныйРежим = Ложь;
	КонецЕсли;

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

	Если БезопасныйРежим() = Ложь И БезопасныйРежим <> Ложь Тогда
		УстановитьБезопасныйРежим(БезопасныйРежим);
	КонецЕсли;

	Попытка
		ПолноеИмяПроцедуры = Обработка.Метаданные().ПолноеИмя() + "." + Параметры.ИмяМетода;
	Исключение
		ПолноеИмяПроцедуры = Параметры.ИмяМетода;
	КонецПопытки;

	УстановитьПолноеИмяПрикладнойПроцедуры(ПолноеИмяПроцедуры);

	ПараметрыМетода = Новый Массив;
	ПараметрыМетода.Добавить(Параметры.ПараметрыВыполнения);
	ПараметрыМетода.Добавить(АдресХранилища);
	ОбщегоНазначения.ВыполнитьМетодОбъекта(Обработка, Параметры.ИмяМетода, ПараметрыМетода);

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


Процедура ПрочитатьСобытияЖурналаРегистрации(ПараметрыОтчета, АдресХранилища) Экспорт

	ОтборЖурналаНаКлиенте          = ПараметрыОтчета.ОтборЖурналаРегистрации;
	КоличествоСобытий              = ПараметрыОтчета.КоличествоПоказываемыхСобытий;
	МенеджерВладельца              = ПараметрыОтчета.МенеджерВладельца;
	ДобавлятьДополнительныеКолонки = ПараметрыОтчета.ДобавлятьДополнительныеКолонки;

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

	Если ДатыОтбораУказаны И ДатаНачала > ДатаОкончания Тогда
		ВызватьИсключение НСтр("ru = 'Некорректно заданы условия отбора журнала регистрации. Дата начала больше даты окончания.'");
	КонецЕсли;
	СмещениеВремениСервера = СмещениеВремениСервера();

	// Подготовка отбора
	Отбор = Новый Структура;
	Для Каждого ЭлементОтбора Из ОтборЖурналаНаКлиенте Цикл
		Отбор.Вставить(ЭлементОтбора.Ключ, ЭлементОтбора.Значение);
	КонецЦикла;
	ПреобразованиеОтбора(Отбор, СмещениеВремениСервера);

	// Выгрузка отбираемых событий и формирование структуры таблицы.
	СобытияЖурнала = Новый ТаблицаЗначений;
	ВыгрузитьЖурналРегистрации(СобытияЖурнала, Отбор, , , КоличествоСобытий);

	СобытияЖурнала.Колонки.Дата.Имя = "ДатаНаСервере";
	СобытияЖурнала.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));

	СобытияЖурнала.Колонки.Добавить("НомерРисунка", Новый ОписаниеТипов("Число"));
	СобытияЖурнала.Колонки.Добавить("АдресДанных",  Новый ОписаниеТипов("Строка"));

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

	Если ДобавлятьДополнительныеКолонки Тогда
		МенеджерВладельца.ДобавитьДополнительныеКолонкиСобытия(СобытияЖурнала);
	КонецЕсли;

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

		МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
		ПсевдонимыПользователей    = Новый Соответствие();
	Иначе
		МодульРаботаВМоделиСервиса = Неопределено;
		ПсевдонимыПользователей    = Неопределено;
	КонецЕсли;

	Для Каждого СобытиеЖурнала Из СобытияЖурнала Цикл
		СобытиеЖурнала.Дата = СобытиеЖурнала.ДатаНаСервере - СмещениеВремениСервера;

		// Заполнение номеров картинок строк.
		МенеджерВладельца.УстановитьНомерРисунка(СобытиеЖурнала);

		Если ДобавлятьДополнительныеКолонки Тогда
			// Заполнение дополнительных полей, определенных только у владельца.
			МенеджерВладельца.ЗаполнитьДополнительныеКолонкиСобытия(СобытиеЖурнала);
		КонецЕсли;

		// Преобразование массива метаданных в список значений.
		СписокПредставленийМетаданных = Новый СписокЗначений;
		Если ТипЗнч(СобытиеЖурнала.ПредставлениеМетаданных) = Тип("Массив") Тогда
			СписокПредставленийМетаданных.ЗагрузитьЗначения(СобытиеЖурнала.ПредставлениеМетаданных);
			СобытиеЖурнала.ПредставлениеМетаданных = СписокПредставленийМетаданных;
		Иначе
			СобытиеЖурнала.ПредставлениеМетаданных = Строка(СобытиеЖурнала.ПредставлениеМетаданных);
		КонецЕсли;

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

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

		// Обработка данных специальных событий.
		Если СобытиеЖурнала.Событие = "_$Access$_.Access" Тогда
			УстановитьСтрокуАдресаДанных(СобытиеЖурнала);

			Если СобытиеЖурнала.Данные <> Неопределено Тогда
				СобытиеЖурнала.Данные = ?(СобытиеЖурнала.Данные.Данные = Неопределено, "", "...");
			КонецЕсли;

		ИначеЕсли СобытиеЖурнала.Событие = "_$Access$_.AccessDenied" Тогда
			УстановитьСтрокуАдресаДанных(СобытиеЖурнала);

			Если СобытиеЖурнала.Данные <> Неопределено Тогда
				Если СобытиеЖурнала.Данные.Свойство("Право") Тогда
					СобытиеЖурнала.Данные = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Право: %1'"),
						СобытиеЖурнала.Данные.Право);
				Иначе
					ДанныеЖурнала = СобытиеЖурнала.Данные; // Структура
					СобытиеЖурнала.Данные = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Действие: %1%2'"),
						ДанныеЖурнала.Действие, ?(Не СобытиеЖурнала.Данные.Свойство("Данные") Или СобытиеЖурнала.Данные.Данные = Неопределено, "", ", ...") );
				КонецЕсли;
			КонецЕсли;

		ИначеЕсли СобытиеЖурнала.Событие = "_$Session$_.Authentication"
		      Или СобытиеЖурнала.Событие = "_$Session$_.AuthenticationError" Тогда

			УстановитьСтрокуАдресаДанных(СобытиеЖурнала);

			СобытиеЖурналаДанные = "";
			Если СобытиеЖурнала.Данные <> Неопределено Тогда
				Для Каждого КлючИЗначение Из СобытиеЖурнала.Данные Цикл
					Если ЗначениеЗаполнено(СобытиеЖурналаДанные) Тогда
						СобытиеЖурналаДанные = СобытиеЖурналаДанные + ", ...";
						Прервать;
					КонецЕсли;
					СобытиеЖурналаДанные = КлючИЗначение.Ключ + ": " + КлючИЗначение.Значение;
				КонецЦикла;
			КонецЕсли;
			СобытиеЖурнала.Данные = СобытиеЖурналаДанные;

		ИначеЕсли СобытиеЖурнала.Событие = "_$User$_.Delete" Тогда
			УстановитьСтрокуАдресаДанных(СобытиеЖурнала);

			СобытиеЖурналаДанные = "";
			Если СобытиеЖурнала.Данные <> Неопределено Тогда
				Для каждого КлючИЗначение Из СобытиеЖурнала.Данные Цикл
					СобытиеЖурналаДанные = КлючИЗначение.Ключ + ": " + КлючИЗначение.Значение;
					Прервать;
				КонецЦикла;
			КонецЕсли;
			СобытиеЖурнала.Данные = СобытиеЖурналаДанные;

		ИначеЕсли СобытиеЖурнала.Событие = "_$User$_.New"
		      ИЛИ СобытиеЖурнала.Событие = "_$User$_.Update" Тогда
			УстановитьСтрокуАдресаДанных(СобытиеЖурнала);

			ИмяПользователяИБ = "";
			Если СобытиеЖурнала.Данные <> Неопределено Тогда
				СобытиеЖурнала.Данные.Свойство("Имя", ИмяПользователяИБ);
			КонецЕсли;
			СобытиеЖурнала.Данные = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Имя: %1, ...'"), ИмяПользователяИБ);

		КонецЕсли;

		УстановитьПривилегированныйРежим(Истина);
		// Уточнение имени пользователя.
		Если СобытиеЖурнала.Пользователь = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
			СобытиеЖурнала.ИмяПользователя = НСтр("ru = '<Неопределен>'");

		ИначеЕсли СобытиеЖурнала.ИмяПользователя = "" Тогда
			СобытиеЖурнала.ИмяПользователя = Пользователи.ПолноеИмяНеУказанногоПользователя();

		ИначеЕсли ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(СобытиеЖурнала.Пользователь) = Неопределено Тогда
			СобытиеЖурнала.ИмяПользователя = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 <Удален>'"), СобытиеЖурнала.ИмяПользователя);
		КонецЕсли;

		Если МодульРаботаВМоделиСервиса <> Неопределено Тогда
			Если ПсевдонимыПользователей.Получить(СобытиеЖурнала.Пользователь) = Неопределено Тогда
				ПсевдонимПользователя = МодульРаботаВМоделиСервиса.ПсевдонимПользователяИнформационнойБазы(СобытиеЖурнала.Пользователь);
				ПсевдонимыПользователей.Вставить(СобытиеЖурнала.Пользователь, ПсевдонимПользователя);
			Иначе
				ПсевдонимПользователя = ПсевдонимыПользователей.Получить(СобытиеЖурнала.Пользователь);
			КонецЕсли;

			Если ЗначениеЗаполнено(ПсевдонимПользователя) Тогда
				СобытиеЖурнала.ИмяПользователя = ПсевдонимПользователя;
			КонецЕсли;
		КонецЕсли;

		// Преобразование идентификатора в имя для использования в дальнейшем при установке отборе.
		ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(СобытиеЖурнала.Пользователь);
		Если ПользовательИБ <> Неопределено Тогда
			СобытиеЖурнала.Пользователь = ПользовательИБ.Имя;
		КонецЕсли;
		УстановитьПривилегированныйРежим(Ложь);
	КонецЦикла;

	// Успешное завершение
	Результат = Новый Структура;
	Результат.Вставить("СобытияЖурнала", СобытияЖурнала);

	ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
КонецПроцедуры

// Создает пользовательское представление отбора журнала регистрации.
//
// Параметры:
//  ПредставлениеОтбора - Строка - строка, содержащая пользовательское представление отбора.
//  ОтборЖурналаРегистрации - Структура - значения отбора журнала регистрации.
//  ОтборЖурналаРегистрацииПоУмолчанию - Структура - значения отбора журнала регистрации по умолчанию
//     (не включаются в пользовательское представления).
//