Процедура ВывестиПодчиненныеЭлементыДерева(СтрокиДерева,Таблица,УровеньРекурсии)

	Для каждого СтрокаДерева Из СтрокиДерева Цикл

		ЭтоТекущийДокумент = (СтрокаДерева.Ссылка = ДокументСсылка);
		ЭтоИсходныйДокумент = (СтрокаДерева.Ссылка = ИсходныйДокумент);
		ПодчиненныеЭлементыДерева = СтрокаДерева.ПолучитьЭлементы();

		ВывестиДокументИКартинку(СтрокаДерева,Таблица,УровеньРекурсии+1,Ложь,Истина);

		// Вывод подчиненных элементов дерева.
		ВывестиПодчиненныеЭлементыДерева(ПодчиненныеЭлементыДерева,Таблица,УровеньРекурсии + 1);

	КонецЦикла;

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

&НаСервере

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

&НаКлиенте

Процедура УстановитьФлажки(Команда)
	Для каждого стр из ТаблицаСтруктураПодчиненности Цикл
		стр.Выбрана = Истина;
	КонецЦикла;
КонецПроцедуры

&НаКлиенте

Процедура СнятьФлажки(Команда)
	Для каждого стр из ТаблицаСтруктураПодчиненности Цикл
		стр.Выбрана = Ложь;
	КонецЦикла;
КонецПроцедуры

&НаКлиенте

Процедура КорзинаСсылокПриИзменении(Элемент)
	ИзменитьЗаголовокПоместитьВКорзину();
КонецПроцедуры

&НаКлиенте

Процедура ДокументСсылкаПриИзменении(Элемент)
	ВывестиСтруктуруПодчиненности();
КонецПроцедуры

&НаКлиенте

Процедура ВернутьсяНазад(Команда)
	Если ЛогТекущихПорядкаВыбораСсылок.Количество()>0 Тогда
		стр = ЛогТекущихПорядкаВыбораСсылок[ЛогТекущихПорядкаВыбораСсылок.Количество()-1];
		Если ДокументСсылка=стр.Ссылка Тогда
			Если ЛогТекущихПорядкаВыбораСсылок.Количество()>=2 Тогда
				ЛогТекущихПорядкаВыбораСсылок.Удалить(стр);
				стр2 = ЛогТекущихПорядкаВыбораСсылок[ЛогТекущихПорядкаВыбораСсылок.Количество()-1];
				ДокументСсылка = стр2.Ссылка;
			КонецЕсли;
		Иначе
			ДокументСсылка = стр.Ссылка;
			Если ЛогТекущихПорядкаВыбораСсылок.Количество()>1 Тогда
				ЛогТекущихПорядкаВыбораСсылок.Удалить(стр);
			КонецЕсли;
		КонецЕсли;

		ТипДокументСсылка = ПолучитьОписаниеТипМетаданныхПоСсылке(ДокументСсылка);
		Элементы.ДокументСсылка.ОграничениеТипа = ТипДокументСсылка;

		ОбновитьДеревоСтруктурыПодчиненности(Истина);

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

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

#область ФункцииДляСовместимости

&НаСервере

Функция СтруктураПодчиненностиПереопределяемый_МассивДополнительныхРеквизитовДокумента(ИмяДокумента) Экспорт

	МассивДопРеквизитов = Новый Массив;

	Возврат МассивДопРеквизитов

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

&НаСервере

Функция СтруктураПодчиненностиПереопределяемый_ПолучитьПредставлениеДокументаДляПечати(Выборка) Экспорт

	СтруктураПодчиненностиПереопределяемый_СнятьПривилегированныйРежим();

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

	Возврат Неопределено;

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

&НаСервере

Функция СтруктураПодчиненностиПереопределяемый_ИмяРеквизитаДокумента(ИмяДокумента, Реквизит) Экспорт

	МетаданныеДокумента = Метаданные.Документы.Найти(ИмяДокумента);

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

	Возврат Неопределено;

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

&НаСервере

Функция СтруктураПодчиненностиПереопределяемый_ПроверитьДоступностьОбъектаПоРЛС(СсылкаНаОбъект) Экспорт

	СтруктураПодчиненностиПереопределяемый_СнятьПривилегированныйРежим();

	Запрос = Новый Запрос(
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	ИСТИНА
	|ИЗ
	|	" + СсылкаНаОбъект.Метаданные().ПолноеИмя() + " КАК ПсевдонимЗаданнойТаблицы
	|ГДЕ
	|	ПсевдонимЗаданнойТаблицы.Ссылка = &СсылкаНаОбъект");
	Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект);

	Возврат Не Запрос.Выполнить().Пустой();

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

&НаСервере

Функция СтруктураПодчиненностиПереопределяемый_СнятьПривилегированныйРежим() Экспорт

	КоличествоОтмен = 0;

	Пока ПривилегированныйРежим() Цикл
		УстановитьПривилегированныйРежим(Ложь);
		КоличествоОтмен = КоличествоОтмен + 1;
	КонецЦикла;

	Возврат КоличествоОтмен;

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

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


Функция ЗначенияРеквизитовОбъектов(МассивСсылок, ИменаРеквизитов, ВыбратьРазрешенные = Ложь) Экспорт

	ЗначенияРеквизитов = Новый Соответствие;
	Если МассивСсылок.Количество() = 0 Тогда
		Возврат ЗначенияРеквизитов;
	КонецЕсли;

	Запрос = Новый Запрос;
	Запрос.Текст =
		"ВЫБРАТЬ " + ?(ВыбратьРазрешенные, "РАЗРЕШЕННЫЕ", "") + "
		|	Ссылка КАК Ссылка, " + ИменаРеквизитов + "
		|ИЗ
		|	" + МассивСсылок[0].Метаданные().ПолноеИмя() + " КАК Таблица
		|ГДЕ
		|	Таблица.Ссылка В (&МассивСсылок)";
	Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
	Выборка = Запрос.Выполнить().Выбрать();

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

	Пока Выборка.Следующий() Цикл
		ЗаполнитьЗначенияСвойств(ЗначенияРеквизитов[Выборка.Ссылка], Выборка);
	КонецЦикла;

	Возврат ЗначенияРеквизитов;

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

// Преобразует строку таблицы значений в структуру.
// Свойства структуры и их значения совпадают с колонками переданной строки.
//
// Параметры:
//  СтрокаТаблицыЗначений - СтрокаТаблицыЗначений - строка таблицы значений.
//
// Возвращаемое значение:
//  Структура - преобразованная строка таблицы значений.
//
&НаСервере

Функция СтрокаТаблицыЗначенийВСтруктуру(СтрокаТаблицыЗначений) Экспорт

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

	Возврат Структура;

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

// Подставляет параметры в строку. Максимально возможное число параметров - 9.
// Параметры в строке задаются как %<номер параметра>. Нумерация параметров начинается с единицы.
//
// Параметры:
//  ШаблонСтроки  - Строка - шаблон строки с параметрами (вхождениями вида "%<номер параметра>",
//                           например, "%1 пошел в %2");
//  Параметр<n>   - Строка - значение подставляемого параметра.
//
// Возвращаемое значение:
//  Строка   - текстовая строка с подставленными параметрами.
//
// Пример:
//  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru='%1 пошел в %2'"), "Вася", "Зоопарк") = "Вася пошел
//  в Зоопарк".
//
&НаСервере

Функция ПодставитьПараметрыВСтроку(Знач ШаблонСтроки,
	Знач Параметр1, Знач Параметр2 = Неопределено, Знач Параметр3 = Неопределено,
	Знач Параметр4 = Неопределено, Знач Параметр5 = Неопределено, Знач Параметр6 = Неопределено,
	Знач Параметр7 = Неопределено, Знач Параметр8 = Неопределено, Знач Параметр9 = Неопределено) Экспорт

	ЕстьПараметрыСПроцентом = Найти(Параметр1, "%") > 0
		Или Найти(Параметр2, "%") > 0
		Или Найти(Параметр3, "%") > 0
		Или Найти(Параметр4, "%") > 0
		Или Найти(Параметр5, "%") > 0
		Или Найти(Параметр6, "%") > 0
		Или Найти(Параметр7, "%") > 0
		Или Найти(Параметр8, "%") > 0
		Или Найти(Параметр9, "%") > 0;

	Если ЕстьПараметрыСПроцентом Тогда
		Возврат ПодставитьПараметрыСПроцентом(ШаблонСтроки, Параметр1,
			Параметр2, Параметр3, Параметр4, Параметр5, Параметр6, Параметр7, Параметр8, Параметр9);
	КонецЕсли;

	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%1", Параметр1);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%2", Параметр2);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%3", Параметр3);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%4", Параметр4);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%5", Параметр5);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%6", Параметр6);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%7", Параметр7);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%8", Параметр8);
	ШаблонСтроки = СтрЗаменить(ШаблонСтроки, "%9", Параметр9);
	Возврат ШаблонСтроки;

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

// Вставляет параметры в строку, учитывая, что в параметрах могут использоваться подстановочные слова %1, %2 и т.д.
&НаСервере

Функция ПодставитьПараметрыСПроцентом(Знач СтрокаПодстановки,
	Знач Параметр1, Знач Параметр2 = Неопределено, Знач Параметр3 = Неопределено,
	Знач Параметр4 = Неопределено, Знач Параметр5 = Неопределено, Знач Параметр6 = Неопределено,
	Знач Параметр7 = Неопределено, Знач Параметр8 = Неопределено, Знач Параметр9 = Неопределено)

	Результат = "";
	Позиция = Найти(СтрокаПодстановки, "%");
	Пока Позиция > 0 Цикл
		Результат = Результат + Лев(СтрокаПодстановки, Позиция - 1);
		СимволПослеПроцента = Сред(СтрокаПодстановки, Позиция + 1, 1);
		ПодставляемыйПараметр = "";
		Если СимволПослеПроцента = "1" Тогда
			ПодставляемыйПараметр =  Параметр1;
		ИначеЕсли СимволПослеПроцента = "2" Тогда
			ПодставляемыйПараметр =  Параметр2;
		ИначеЕсли СимволПослеПроцента = "3" Тогда
			ПодставляемыйПараметр =  Параметр3;
		ИначеЕсли СимволПослеПроцента = "4" Тогда
			ПодставляемыйПараметр =  Параметр4;
		ИначеЕсли СимволПослеПроцента = "5" Тогда
			ПодставляемыйПараметр =  Параметр5;
		ИначеЕсли СимволПослеПроцента = "6" Тогда
			ПодставляемыйПараметр =  Параметр6;
		ИначеЕсли СимволПослеПроцента = "7" Тогда
			ПодставляемыйПараметр =  Параметр7
		ИначеЕсли СимволПослеПроцента = "8" Тогда
			ПодставляемыйПараметр =  Параметр8;
		ИначеЕсли СимволПослеПроцента = "9" Тогда
			ПодставляемыйПараметр =  Параметр9;
		КонецЕсли;
		Если ПодставляемыйПараметр = "" Тогда
			Результат = Результат + "%";
			СтрокаПодстановки = Сред(СтрокаПодстановки, Позиция + 1);
		Иначе
			Результат = Результат + ПодставляемыйПараметр;
			СтрокаПодстановки = Сред(СтрокаПодстановки, Позиция + 2);
		КонецЕсли;
		Позиция = Найти(СтрокаПодстановки, "%");
	КонецЦикла;
	Результат = Результат + СтрокаПодстановки;

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

&НаСервере

Функция РазложитьСтрокуВМассивПодстрок(Знач Строка, Знач Разделитель = ",", Знач ПропускатьПустыеСтроки = Неопределено) Экспорт

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

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

	Позиция = Найти(Строка, Разделитель);
	Пока Позиция > 0 Цикл
		Подстрока = Лев(Строка, Позиция - 1);
		Если Не ПропускатьПустыеСтроки Или Не ПустаяСтрока(Подстрока) Тогда
			Результат.Добавить(Подстрока);
		КонецЕсли;
		Строка = Сред(Строка, Позиция + СтрДлина(Разделитель));
		Позиция = Найти(Строка, Разделитель);
	КонецЦикла;

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

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

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

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

//
&НаКлиенте

Функция ПрочитатьСоответствиеИзСтрокиJSON(Знач ИсхСтрока)
	ЧтениеJSON = Новый ЧтениеJSON;
	ЧтениеJSON.УстановитьСтроку(ИсхСтрока);

	НастроенноеСоответствие = ПрочитатьJSON(ЧтениеJSON, Истина);

	Возврат НастроенноеСоответствие;

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

#Область КлючиНастроек

//
&НаКлиентеНаСервереБезКонтекста

Функция КлючНастройкиОткрытиеФорм()

	Возврат "smoke";

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

&НаКлиентеНаСервереБезКонтекста

Функция КлючНастройкиМодальныеОкна()

	Возврат "МодальныеОкна";

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

&НаКлиентеНаСервереБезКонтекста

Функция КлючНастройкиКомандныйИнтерфейс()

	Возврат "CommandInterface";

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

&НаКлиентеНаСервереБезКонтекста

Функция КлючНастройкиМакетыСКД()

	Возврат "МакетыСКД";

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

&НаКлиентеНаСервереБезКонтекста

Функция КлючНастройкиПроведениеДокументов()

	Возврат "ПроведениеДокументов";

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

&НаКлиентеНаСервереБезКонтекста

Функция КлючНастройкиФормированиеПечатныхФорм()

	Возврат "ФормированиеПечатныхФорм";

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

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

#Область ИсключениеОбъектов

&НаСервере


Функция ЭтоОписательОбъектаСсылки(ОписательОбъекта, РезСсылка = Неопределено)

	ЭтоСсылочныйОбъект = ОписательОбъекта.Свойство(ВернутьЗначениеСоответствия("Ссылка"), РезСсылка) И РезСсылка <> Неопределено;
	Возврат ЭтоСсылочныйОбъект;

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

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

Функция ШапкаДанныхВМакете()
	рез = Новый Структура();
	рез.Вставить("Тип", 1);
	рез.Вставить("Вид", 2);
	рез.Вставить("ИмяПеременной", 3);
	рез.Вставить("ТЧ", 4);
	рез.Вставить("Реквизит", 5);
	рез.Вставить("Значение", 6);
	рез.Вставить("Режим", 7);
	рез.Вставить("ДополнительныйТипЗначения", 8);
	Возврат рез;
КонецФункции

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

Функция ПолучитьКорневойТипКонфигурации_ирЛкс(пОбъект, пЛиТолькоДляКорневого = Ложь) Экспорт

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

КонецФункции // ЛксПолучитьКорневойТипКонфигурации()

// Проверяет, является ли значение ссылкой на объект БД. На базе ЛксЛиСсылкаНаОбъектБД
//
// Параметры:
//  пЗначение    – ОбъектМетаданных, Произвольный – проверяемое значение.
//
// Возвращаемое значение:
//  Истина       – значение является ссылкой на объект БД;
//  Ложь         – значение не является ссылкой на объект БД.
//

Функция ЛиСсылкаНаОбъектБД_ирЛкс(пЗначение) Экспорт

	Возврат ЛиКорневойТипОбъектаБД_ирЛкс(ПолучитьКорневойТипКонфигурации_ирЛкс(пЗначение, Истина));

КонецФункции // ЛксЛиСсылкаНаОбъектБД

// Проверяет, является ли значение ссылкой на значение перечисления.
//
// Параметры:
//  пЗначение    – Произвольный – проверяемое значение.
//
// Возвращаемое значение:
//  Истина       – значение является ссылкой на объект БД;
//  Ложь         – значение не является ссылкой на объект БД.
//

Функция ЛиСсылкаНаПеречисление_ирЛкс(пЗначение) Экспорт

	Возврат (ПолучитьКорневойТипКонфигурации_ирЛкс(пЗначение) = ВернутьЗначениеСоответствия("Перечисление"));

КонецФункции // ЛксЛиСсылкаНаПеречисление()

// Проверяет, является ли строка именем корневого типа объекта БД.
//
// Параметры:
//  пИмяКорневогоТипа - Строка, Неопределено - имя корневого типа.
//
// Возвращаемое значение:
//  Истина       – тип является корневым типом объекта БД;
//  Ложь         – иначе.
//

Функция ЛиКорневойТипОбъектаБД_ирЛкс(КорневойТип) Экспорт

	Если Ложь
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("БизнесПроцесс")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("Задача")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("Документ")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("ПланВидовРасчета")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("ПланВидовХарактеристик")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("ПланОбмена")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("ПланСчетов")
		ИЛИ КорневойТип = ВернутьЗначениеСоответствия("Справочник")

	Тогда
		Возврат Истина;
	КонецЕсли;
	Возврат Ложь;

КонецФункции // ЛксЛиКорневойТипОбъектаБД()

// Получает менеджер по описанию типов, типу, метаданным, ссылке или объекту. На базе метода ЛксПолучитьМенеджер
// Для описания типов берется первый тип массива типов.
//
// Параметры:
//  пОбъект      – Произвольный – для чего получаем менеджер.
//
// Возвращаемое значение:
//               – МенеджерОбъекта - для ссылки или ссылочного типа;
//  Неопределено - не удалось получить.
//

Функция ПолучитьМенеджерОбъекта_ирЛкс(пОбъект) Экспорт

	Если ТипЗнч(пОбъект) = Тип("ОбъектМетаданных") Тогда
		МетаданныеОбъекта = пОбъект;
	Иначе
		МетаданныеОбъекта = ПолучитьМетаданные_ирЛкс(пОбъект);
	КонецЕсли;
	Если МетаданныеОбъекта = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	МассивФрагментов = ПолучитьМассивИзСтрокиСРазделителем_ирЛкс(МетаданныеОбъекта.ПолноеИмя());
	КорневойТип = МассивФрагментов[0];
	Менеджер = Неопределено;
	Если Истина
		И МассивФрагментов.Количество() = 4
		И КорневойТип = "ВнешнийИсточникДанных"
	Тогда
		ИмяТипаМенеджера = МассивФрагментов[0] + "ТаблицаМенеджер." + МассивФрагментов[1] + "." + МассивФрагментов[3];
	Иначе
		//КорневойТип = ЛксПолучитьКорневойТипКонфигурации(МетаданныеОбъекта, Истина); // Изменил 02.03.2012
		Если КорневойТип <> Неопределено Тогда
			Если НЕ ВариантВстроенногоЯзыкаАнглийский Тогда
				ИмяМенеджер = "Менеджер.";
			Иначе
				ИмяМенеджер = "Manager.";
			КонецЕсли;
			ИмяТипаМенеджера = КорневойТип + ИмяМенеджер + МетаданныеОбъекта.Имя;
		Иначе
			ИмяТипаМенеджера = "Неопределено";
		КонецЕсли;
	КонецЕсли;
	Попытка
		Менеджер = Новый (ИмяТипаМенеджера);
	Исключение
	КонецПопытки;
	Возврат Менеджер;

КонецФункции // ЛксПолучитьМенеджер()

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

Функция ПолучитьМетаданные_ирЛкс(пОбъект) Экспорт

	Если ТипЗнч(пОбъект) = Тип("Строка") Тогда
		Если ПустаяСтрока(пОбъект) Тогда
			Результат = Неопределено;
		Иначе
			Фрагменты = ПолучитьМассивИзСтрокиСРазделителем_ирЛкс(пОбъект);
			Если Фрагменты.Количество() = 3 Тогда
				// ВидыСубконто, Изменения
				ПолноеИмяМД = Фрагменты[0] + "." + Фрагменты[1];
			Иначе
				ПолноеИмяМД = пОбъект;
			КонецЕсли;
			Результат = Метаданные.НайтиПоПолномуИмени(ПолноеИмяМД);
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;
	ТипОбъекта = ПолучитьТипОбъекта_ирЛкс(пОбъект);
	Результат = Метаданные.НайтиПоТипу(ТипОбъекта);
	Возврат Результат;

КонецФункции // ЛксПолучитьМетаданные()

// Получает тип из описания типов, типа или значения. На базе ЛксПолучитьТипОбъекта
//
// Параметры:
//  пОбъект    – Тип, ОписаниеТипов, Произвольный – проверяемое значение.
//
// Возвращаемое значение:
//  Тип - найденный тип.
//


// Реализация шагов BDD-фич/сценариев c помощью фреймворка https://github.com/artbear/1bdd
#Использовать fs

Перем БДД; //контекст фреймворка 1bdd

// Метод выдает список шагов, реализованных в данном файле-шагов
Функция ПолучитьСписокШагов(КонтекстФреймворкаBDD) Экспорт
	БДД = КонтекстФреймворкаBDD;

	ВсеШаги = Новый Массив;

	ВсеШаги.Добавить("ВКаталогеЕстьФайлыПлагинов");
	ВсеШаги.Добавить("ЯСоздаюКаталогПриложенияВРабочемКаталоге");

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

// Реализация шагов

// Процедура выполняется перед запуском каждого сценария
Процедура ПередЗапускомСценария(Знач Узел) Экспорт

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

// Процедура выполняется после завершения каждого сценария
Процедура ПослеЗапускаСценария(Знач Узел) Экспорт

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

//В каталоге "КаталогПлагинов" есть файлы плагинов
Процедура ВКаталогеЕстьФайлыПлагинов(Знач ИмяКаталогПлагинов) Экспорт

	КаталогПлагинов = БДД.ПолучитьИзКонтекста(ИмяКаталогПлагинов);

	ФайлТестовогоПлагина= ОбъединитьПути(КаталогПлагинов, "test_plugin");

	МассивФайлов = НайтиФайлы(КаталогПлагинов, ПолучитьМаскуВсеФайлы());

	Если МассивФайлов.Количество() = 0 Тогда
		ВызватьИсключение "Файлы в каталоге плагинов не найдены";
	КонецЕсли;

	СообщитьСписокФайловВКаталоге(КаталогПлагинов);

	Если НЕ ФС.КаталогСуществует(ФайлТестовогоПлагина) Тогда
		ВызватьИсключение "Каталог тестового плагина не найден";
	КонецЕсли;

	// По умолчанию создается файл "plugins.json", но может быть и "gitsync-plugins.json"
	Если НЕ ФС.ФайлСуществует(ОбъединитьПути(КаталогПлагинов, "gitsync-plugins.json"))
		И НЕ ФС.ФайлСуществует(ОбъединитьПути(КаталогПлагинов, "plugins.json")) Тогда
		ВызватьИсключение "Файл настройки плагинов не найден";
	КонецЕсли;

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

//Я создаю каталог приложения в рабочем каталоге
Процедура ЯСоздаюКаталогПриложенияВРабочемКаталоге() Экспорт

	РабочийКаталог = ТекущийКаталог();

	ФС.ОбеспечитьПустойКаталог(".gitsync");

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

Процедура СообщитьСписокФайловВКаталоге(ПутьККаталогу)

	МассивФайлов = НайтиФайлы(ПутьККаталогу, ПолучитьМаскуВсеФайлы());

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

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


Перем Лог;

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

	Команда.Опция("u storage-user", "", "пользователь хранилища конфигурации")
					.ТСтрока()
					.ВОкружении("GITSYNC_STORAGE_USER")
					.ПоУмолчанию("Администратор");

	Команда.Опция("p storage-pwd", "", "пароль пользователя хранилища конфигурации")
					.ТСтрока()
					.ВОкружении("GITSYNC_STORAGE_PASSWORD GITSYNC_STORAGE_PWD");

	Команда.Опция("e ext extension", "", "имя расширения для работы с хранилищем расширения")
					.ТСтрока()
					.ВОкружении("GITSYNC_EXTENSION");

	Команда.Опция("d das disable-auto-src", Ложь, "Отключить автопоиск папки src")
					.ВОкружении("GITSYNC_DISABLE_AUTO_SRC");

	Команда.Аргумент("PATH", "", "Путь к хранилищу конфигурации 1С.")
					.ТСтрока()
					.ВОкружении("GITSYNC_STORAGE_PATH");
	Команда.Аргумент("WORKDIR", "", "Каталог исходников внутри локальной копии git-репозитория.")
					.ТСтрока()
					.ВОкружении("GITSYNC_WORKDIR")
					.Обязательный(Ложь)
					.ПоУмолчанию(ТекущийКаталог());

	ПараметрыПриложения.ВыполнитьПодпискуПриРегистрацииКомандыПриложения(Команда);

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

Процедура ВыполнитьКоманду(Знач Команда) Экспорт

	Лог.Информация("Начало выполнение команды <sync>");

	ПутьКХранилищу			= Команда.ЗначениеАргумента("PATH");
	КаталогРабочейКопии		= Команда.ЗначениеАргумента("WORKDIR");

	ПользовательХранилища		= Команда.ЗначениеОпции("storage-user");
	ПарольПользователяХранилища	= Команда.ЗначениеОпции("storage-pwd");
	ИмяРасширения				= Команда.ЗначениеОпции("extension");

	ПользовательИБ			= Команда.ЗначениеОпции("ib-user");
	ПарольПользователяИБ	= Команда.ЗначениеОпции("ib-pwd");
	СтрокаСоединенияИБ		= Команда.ЗначениеОпции("ib-connection");

	ФайлКаталогРабочейКопии = Новый Файл(КаталогРабочейКопии);
	КаталогРабочейКопии = ФайлКаталогРабочейКопии.ПолноеИмя;

	Лог.Отладка("ПутьКХранилищу = " + ПутьКХранилищу);
	Лог.Отладка("КаталогРабочейКопии = " + КаталогРабочейКопии);

	КаталогИсходников = КаталогРабочейКопии;

	АвтодополнениеПути = НЕ Команда.ЗначениеОпции("disable-auto-src");
	Если АвтодополнениеПути Тогда
		МассивФайлов = НайтиФайлы(КаталогРабочейКопии, "src");
		Если МассивФайлов.Количество() > 0  Тогда
			КаталогИсходников = МассивФайлов[0].ПолноеИмя;
		КонецЕсли;
	КонецЕсли;

	ОбщиеПараметры = ПараметрыПриложения.Параметры();
	МенеджерПлагинов = ПараметрыПриложения.МенеджерПлагинов();

	ИндексПлагинов = МенеджерПлагинов.ПолучитьИндексПлагинов();

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

	Лог.Информация("Завершено выполнение команды <sync>");

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

Лог = ПараметрыПриложения.Лог();


#Использовать fs
#Использовать json
#Использовать logos
#Использовать "./internal"

Перем ИндексПлагинов;
Перем КаталогПлагинов;

#Область Экспортные_методы

// Возвращает индекс плагинов
//
//  Возвращаемое значение:
//   Соответствие - набор плагинов
//                   * ключ - Строка - имя плагина
//                   * значение - Объект - ссылка на произвольный объект
//
Функция ПолучитьИндексПлагинов() Экспорт
	Возврат ИндексПлагинов;
КонецФункции

// Выполняет загрузку плагинов из каталога
//
Процедура ЗагрузитьПлагины() Экспорт

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

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

// Создает и возвращает новый МенеджерПодписок для текущего индекса плагинов
//
//  Возвращаемое значение:
//   Объект.МенеджерПодписок - ссылка на новый объект класса <МенеджерПодписок>
//
Функция НовыйМенеджерПодписок() Экспорт

	Возврат Новый МенеджерПодписок(ИндексПлагинов);

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

// Производит отключение массива плагинов
//
// Параметры:
//   МассивПлагинов - Массив - Элементы типа Строка, имена плагинов
//
Процедура ОтключитьПлагины(МассивПлагинов) Экспорт

	Для каждого ОтключаемыйПлагин Из МассивПлагинов Цикл

		Плагин = ИндексПлагинов[ОтключаемыйПлагин];

		Если Плагин = Неопределено Тогда
			Продолжить;
		КонецЕсли;

		Плагин.Отключить();

	КонецЦикла;

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

// Включает набор плагинов
//
// Параметры:
//   МассивПлагинов - Массив, Соответствие - набор наименований плагинов
//
Процедура ВключитьПлагины(МассивПлагинов) Экспорт

	Для каждого ВключаемыеПлагин Из МассивПлагинов Цикл

		Если ТипЗнч(ВключаемыеПлагин) = Тип("Строка") Тогда
			ВключитьПлагин(ВключаемыеПлагин);
		Иначе
			ВключитьПлагин(ВключаемыеПлагин.Ключ);
		КонецЕсли;

	КонецЦикла;

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

// Включает плагин к использованию
//
// Параметры:
//   ИмяПлагина - Строка - имя плагина для включения
//
Процедура ВключитьПлагин(Знач ИмяПлагина) Экспорт

	Плагин = ИндексПлагинов[ИмяПлагина];

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

	Плагин.Включить();

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

Процедура ВключитьВсеПлагины() Экспорт

	Для каждого КлючЗначение Из ИндексПлагинов Цикл

		Плагин = КлючЗначение.Значение;
		Плагин.Включить();

	КонецЦикла;

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

Процедура ОтключитьВсеПлагины() Экспорт

	Для каждого КлючЗначение Из ИндексПлагинов Цикл

		Плагин = КлючЗначение.Значение;
		Плагин.Отключить();

	КонецЦикла;

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

// Устанавливает каталог установки и чтения плагинов
//
// Параметры:
//   ПутьККаталогу - Строка - полный путь к каталогу хранения плагинов
//
Процедура УстановитьКаталогПлагинов(Знач ПутьККаталогу) Экспорт
	КаталогПлагинов = ПутьККаталогу;
КонецПроцедуры

// Производит установку пакета плагинов из файла
//
// Параметры:
//   ПутьКФайлуПакета - Строка - полный путь к файлу пакета плагина
//
Процедура УстановитьФайлПлагин(Знач ПутьКФайлуПакета) Экспорт

	Установщик = Новый УстановщикПлагинов();
	Установщик.УстановитьКаталогПлагинов(КаталогПлагинов);
	Установщик.УстановитьФайлПлагина(ПутьКФайлуПакета);

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

// Производит установку пакета плагинов по имени
//
// Параметры:
//   ИмяПлагина - Строка - имя пакета плагинов на хабе
//
Процедура УстановитьПлагинПоИмени(Знач ИмяПлагина) Экспорт

	Установщик = Новый УстановщикПлагинов();
	Установщик.УстановитьКаталогПлагинов(КаталогПлагинов);
	Установщик.УстановитьПлагинПоИмени(ИмяПлагина);

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

// Устанавливает режим отладки для индекса плагинов
//
Процедура УстановитьРежимОтладки() Экспорт

	Для каждого КлючЗначение Из ИндексПлагинов Цикл

		Плагин = КлючЗначение.Значение;
		Плагин.ВключитьОтладку();

	КонецЦикла;

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

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

#Область Вспомогательные_процедуры_и_функции

Процедура ПриСозданииОбъекта(Знач ЗначениеКаталогПлагинов = Неопределено)

	ИндексПлагинов = Новый Соответствие;

	Если ЗначениеЗаполнено(ЗначениеКаталогПлагинов) Тогда
		КаталогПлагинов = ЗначениеКаталогПлагинов;
	КонецЕсли;

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

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


#Использовать gitrunner
#Использовать tempfiles
#Использовать fs

Перем Лог;

Процедура ПолучитьИсходники(Знач URLРепозитория, Знач УказательКоммита, Знач Каталог)

	ГитРепозиторий = Новый ГитРепозиторий;

	ГитРепозиторий.УстановитьРабочийКаталог(Каталог);

	ГитРепозиторий.КлонироватьРепозиторий(URLРепозитория, Каталог);
	ГитРепозиторий.ПерейтиВВетку(УказательКоммита);

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

Процедура СобратьПакет(Знач Каталог)

	Лог.Информация("Каталог сборки <%1>", Каталог);

	Лог.Информация("Сборка пакета библиотеки плагинов");

	КомандаOpm = Новый Команда;
	КомандаOpm.УстановитьРабочийКаталог(Каталог);
	КомандаOpm.УстановитьКоманду("opm");
	КомандаOpm.ДобавитьПараметр("build");
	КомандаOpm.ДобавитьПараметр(Каталог);
	КомандаOpm.ДобавитьЛогВыводаКоманды("task.install-opm");

	КодВозврата = КомандаOpm.Исполнить();

	Если КодВозврата <> 0  Тогда
		ВызватьИсключение КомандаOpm.ПолучитьВывод();
	КонецЕсли;

	МассивФайлов = НайтиФайлы(Каталог, "*.ospx");

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

	ФайлПлагина = МассивФайлов[0].ПолноеИмя;

	КаталогПроекта = ОбъединитьПути(ТекущийСценарий().Каталог, "..", "embedded_plugins");

	ФС.ОбеспечитьКаталог(КаталогПроекта);

	УдалитьФайлы(КаталогПроекта, "gitsync-plugins*.ospx");

	ФайлПриемник = ОбъединитьПути(КаталогПроекта, МассивФайлов[0].Имя);

	КопироватьФайл(ФайлПлагина, ФайлПриемник);

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

Процедура ПолезнаяРабота(УказательКоммита)

	URLРепозитория = "https://github.com/oscript-library/gitsync-plugins.git";
	КаталогСборки = ВременныеФайлы.СоздатьКаталог();

	Лог.Информация("Установка плагинов из
	| репозиторий <%1>
	| указатель <%2>", URLРепозитория, УказательКоммита);

	ПолучитьИсходники(URLРепозитория, УказательКоммита, КаталогСборки);
	СобратьПакет(КаталогСборки);

	// При удалении временного каталога файлов исходников выводится ошибка
	// о невозможности удаления подкаталога Git и из-за этого не проходит тест
	Попытка
		УдалитьФайлы(КаталогСборки);
	Исключение
		ТекстОшибки = СтрШаблон("Попытка удаления временного каталога %1 закончилась неудачей", КаталогСборки);
		Лог.Предупреждение(ТекстОшибки);
	КонецПопытки;

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

Лог = Логирование.ПолучитьЛог("task.install-opm");

Если АргументыКоманднойСтроки.Количество() = 0 Тогда
	УказательКоммита = "v2.0.3";
Иначе
	УказательКоммита = АргументыКоманднойСтроки[0];
КонецЕсли;

ПолезнаяРабота(УказательКоммита);


Функция Обучение(Объект, СброситьСтарыеНастройки = Истина) Экспорт

	УстановитьПараметрыОбучения(Объект);
	МокитоСлужебный.ДобавитьНастройкуПерехватаВызововОбъекта(Объект, СброситьСтарыеНастройки);

	Возврат МокитоОбучение;

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

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

Функция Наблюдать(ИмяМетода, ПараметрыВызова = Неопределено) Экспорт

	ЗарегистрироватьПерехватВыражения(ИмяМетода, ПараметрыВызова);

	Возврат МокитоОбучение;

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

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

Функция Когда(ИмяМетода, ПараметрыВызова = Неопределено) Экспорт

	Возврат Наблюдать(ИмяМетода, ПараметрыВызова);

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

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

Функция Вернуть(Результат) Экспорт

	ЗарегистрироватьРеакцию(Новый Структура("ТипДействия, Результат", МокитоСлужебный.ТипыДействийРеакций().ВернутьРезультат, Результат));

	Возврат МокитоОбучение;

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

//  Указывает, что при соблюдении условий (см. Когда) метод должен выбросить исключение.
//
//  При этом сам метод не исполняется.
//
// Параметры:
//  ТекстИсключения - Строка
//
// Возвращаемое значение:
//  ОбщийМодуль - см. МокитоОбучение

Функция ВыброситьИсключение(ТекстИсключения) Экспорт

	ЗарегистрироватьРеакцию(Новый Структура("ТипДействия, Ошибка", МокитоСлужебный.ТипыДействийРеакций().ВыброситьИсключение, ТекстИсключения));

	Возврат МокитоОбучение;

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

// Указывает, что при соблюдении условий (см. Когда) метод не должен выполняться, его вызов пропускается.
//
// Если это функция, то будет возвращено `Неопределено`.
//
// Возвращаемое значение:
//  ОбщийМодуль - см. МокитоОбучение

Функция Пропустить() Экспорт

	ЗарегистрироватьРеакцию(Новый Структура("ТипДействия", МокитоСлужебный.ТипыДействийРеакций().Пропустить));

	Возврат МокитоОбучение;

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

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

Функция ВыполнитьМетод() Экспорт

	ЗарегистрироватьРеакцию(Новый Структура("ТипДействия", МокитоСлужебный.ТипыДействийРеакций().ВызватьОсновнойМетод));

	Возврат МокитоОбучение;

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

//  Переводит мокито в режим прогона тестов.
//
//  Вызов этого метода обязателен перед выполнением тестового прогона метода.

Процедура Прогон() Экспорт

	Мокито.Прогон();

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

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

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

Процедура ЗарегистрироватьПерехватВыражения(ИмяМетода, ПараметрыВызова)

	ПереданаСтруктураВызоваМетода = МокитоСлужебный.ЭтоСтруктураВызоваМетода(ИмяМетода);

	Если ПереданаСтруктураВызоваМетода Тогда
		Объект = ИмяМетода.Объект;
	Иначе
		Объект = ОбучаемыйОбъект();
	КонецЕсли;

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

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

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

	Методы = ДанныеПерехвата.Методы;

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

	Реакция = СоздатьОписаниеУсловнойРеакции(СтруктураВызоваМетода);

	РеакцииМетода = Методы[СтруктураВызоваМетода.ИмяМетода].Реакции;
	РеакцииМетода.Добавить(Реакция);

	ПараметрыОбучения = ПараметрыОбучения();
	ПараметрыОбучения.РеакцияТекущегоВыражения = Реакция;
	ПараметрыОбучения.Реакции = РеакцииМетода;

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

Функция ОписаниеПараметровПерехватаМетода()

	Возврат Новый Структура("Реакции", Новый Массив);

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

#Область Реакции

Функция ОписаниеУсловнойРеакции()

	Возврат Новый Структура("УсловиеРеакции, Действие");

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

Функция СоздатьОписаниеУсловнойРеакции(СтруктураВызоваМетода)

	Условия = МокитоСлужебный.УсловиеИзПараметров(СтруктураВызоваМетода.Параметры);
	ОписаниеУсловнойРеакции = ОписаниеУсловнойРеакции();
	ОписаниеУсловнойРеакции.УсловиеРеакции = Условия;
	Возврат ОписаниеУсловнойРеакции;

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

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

#Область Параметры

Функция ОбучаемыйОбъект()

	Возврат ПараметрыОбучения().ОбучаемыйОбъект;

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

Функция ПараметрыОбучения()

	Возврат МокитоСлужебный.Настройки().ПараметрыОбучения;

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

Процедура УстановитьПараметрыОбучения(Объект)

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

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

Процедура ЗарегистрироватьРеакцию(Действие)

	Параметры = ПараметрыОбучения();

	Действие.Вставить("Обработано", Ложь);

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

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

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

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


Функция Включен() Экспорт

	ДанныеКонтекста = ЮТКонтекстСлужебный.ДанныеКонтекста();
	Настройки = Неопределено;
	Возврат ДанныеКонтекста <> Неопределено И ДанныеКонтекста.Свойство(КлючНастроек(), Настройки) И Настройки <> Неопределено;

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

Процедура УстановитьРежим(Режим) Экспорт

	Контекст = Настройки();
	Контекст.Режим = Режим;
	ОчиститьСлужебныеПараметры();

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

// Настройки.
//
// Возвращаемое значение:
//  см. НовыеНастройки

Функция Настройки() Экспорт

	Настройки = ЮТКонтекстСлужебный.ЗначениеКонтекста(КлючНастроек());

	Если Настройки = Неопределено Тогда
		ВызватьИсключение "Что-то пошло не так, настройки Мокито не инициализированы";
	КонецЕсли;

	//@skip-check constructor-function-return-section
	Возврат Настройки;

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

Процедура СброситьПараметры() Экспорт

	ИнициализироватьНастройки();

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

#Область СтруктурыДанных

Функция РежимыРаботы() Экспорт

	Режимы = Новый Структура();
	Режимы.Вставить("Обучение", "Обучение");
	Режимы.Вставить("Тестирование", "Тестирование");
	Режимы.Вставить("Проверка", "Проверка");

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

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

Функция ТипыДействийРеакций() Экспорт

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

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

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

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

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

	ПрерватьВыполнение = Ложь;

	Если НЕ Включен() Тогда
		Возврат Неопределено;
	КонецЕсли;

	Настройки = Настройки();

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

	ПараметрыПерехвата = ДанныеПерехвата(Объект, Настройки);

	Если ПараметрыПерехвата = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	РежимыРаботы = РежимыРаботы();

	СтруктураВызоваМетода = СтруктураВызоваМетода(Объект, ИмяМетода, ПараметрыМетода);

	Если Настройки.Режим = РежимыРаботы.Обучение ИЛИ Настройки.Режим = РежимыРаботы.Проверка Тогда

		ПрерватьВыполнение = Истина;
		Возврат СтруктураВызоваМетода;

	ИначеЕсли Настройки.Режим = РежимыРаботы.Тестирование Тогда

		ЗарегистрироватьВызовМетода(Настройки, ПараметрыПерехвата, СтруктураВызоваМетода);
		Возврат ПерехватитьВызовМетода(ПараметрыПерехвата, СтруктураВызоваМетода, ПрерватьВыполнение);

	КонецЕсли;

	Возврат Неопределено;

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

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

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

	Если ЭтоСтруктураВызоваМетода(Объект) Тогда
		Возврат Объект;
	КонецЕсли;

	СтруктураВызоваМетода = Новый Структура("Объект, ИмяМетода, Параметры", Объект, ИмяМетода, ПараметрыМетода);
	СтруктураВызоваМетода.Вставить("Контекст");

	//@skip-check constructor-function-return-section
	Возврат СтруктураВызоваМетода;

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

Функция ЭтоСтруктураВызоваМетода(Объект) Экспорт

	Возврат ТипЗнч(Объект) = Тип("Структура");

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

#Область Предикаты

Функция ТипыУсловийПараметров() Экспорт

	Типы = Новый Структура;
	Типы.Вставить("Любой", "Любой");
	Типы.Вставить("Значение", "Значение");
	Типы.Вставить("Тип", "Тип");
	Типы.Вставить("ОписаниеТипа", "ОписаниеТипа");
	Типы.Вставить("Предикат", "Предикат");

	Возврат Новый ФиксированнаяСтруктура(Типы);

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

// Описание маски параметра.
//
// Параметры:
//  ТипУсловия - Строка - см. МокитоСлужебный.ТипыУсловийПараметров
//  Приоритет - Число - Приоритет маски
//
// Возвращаемое значение:
//  Структура - Описание маски параметра:
// * Режим - Строка - Тип условия
// * Приоритет - Число - Приоритет маски, используется если значение подпадает под несколько масок, чем выше приоритет, тем лучше

Функция ОписаниеМаскиПараметра(ТипУсловия, Приоритет) Экспорт

	МаскаПараметра = Новый Структура;
	ЮТОбщий.УказатьТипСтруктуры(МаскаПараметра, "МаскаПараметра");

	МаскаПараметра.Вставить("Режим", ТипУсловия);
	МаскаПараметра.Вставить("Приоритет", Приоритет);

	Возврат МаскаПараметра;

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

Функция ЭтоМаскаПарамера(Параметр) Экспорт

	Возврат ТипЗнч(Параметр) = Тип("Структура") И ЮТОбщий.ТипСтруктуры(Параметр) = "МаскаПараметра";

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

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

	ТипыУсловий = ТипыУсловийПараметров();
	Совпадает = Ложь;

	Если Условие.Режим = ТипыУсловий.Любой Тогда

		Совпадает = Истина;

	ИначеЕсли Условие.Режим = ТипыУсловий.Значение Тогда

		Совпадает = ЮТСравнениеСлужебныйКлиентСервер.ЗначенияРавны(Условие.Значение, Параметр);

	ИначеЕсли Условие.Режим = ТипыУсловий.Тип Тогда

		Совпадает = Условие.Тип = ТипЗнч(Параметр);

	ИначеЕсли Условие.Режим = ТипыУсловий.ОписаниеТипа Тогда

		Совпадает = Условие.Тип.СодержитТип(ТипЗнч(Параметр));

	ИначеЕсли Условие.Режим = ТипыУсловий.Предикат Тогда

		Результат = ЮТПредикатыСлужебныйКлиентСервер.ПроверитьПредикаты(Параметр, Условие.Предикат);
		Совпадает = Результат.Успешно;

	КонецЕсли;

	Возврат Совпадает;

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

Функция УсловиеИзПараметров(Параметры) Экспорт

	Если Параметры = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;

	Условия = Новый Массив;

	ТипыУсловий = ТипыУсловийПараметров();

	Для Каждого Параметр Из Параметры Цикл

		Если ЭтоМаскаПарамера(Параметр) Тогда

			Условия.Добавить(Параметр);

		ИначеЕсли ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикат(Параметр) Тогда

			Маска = ОписаниеМаскиПараметра(ТипыУсловий.Предикат, 90);
			Маска.Вставить("Предикат", ЮТПредикатыСлужебныйКлиентСервер.НаборПредикатов(Параметр));
			Условия.Добавить(Маска);

		Иначе

			Маска = ОписаниеМаскиПараметра(ТипыУсловий.Значение, 100);
			Маска.Вставить("Значение", Параметр);
			Условия.Добавить(Маска);

		КонецЕсли;

	КонецЦикла;

	Возврат Условия;

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

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

#Область Перехват

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

	Возврат Настройки().Перехват;

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

Функция НастройкиПерехватаОбъекта(Объект) Экспорт

	ПараметрыПерехвата = ПараметрыПерехвата();
	Возврат ПараметрыПерехвата[Объект];

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

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


Функция РезультатЗапроса(ОписаниеЗапроса, ДляКлиента) Экспорт

	Запрос = Запрос(ОписаниеЗапроса);
	РезультатЗапроса = Запрос.Выполнить();

	Возврат ВыгрузитьРезультатЗапроса(РезультатЗапроса, ДляКлиента);

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

// Результат пустой.
//
// Параметры:
//  ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса
//
// Возвращаемое значение:
//  Булево - Результат пустой

Функция РезультатПустой(ОписаниеЗапроса) Экспорт

	Запрос = Запрос(ОписаниеЗапроса);
	РезультатЗапроса = Запрос.Выполнить();

	Возврат РезультатЗапроса.Пустой();

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

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

Функция ЗначенияРеквизитов(Ссылка, ИменаРеквизитов, ОдинРеквизит) Экспорт

	ИмяТаблицы = Ссылка.Метаданные().ПолноеИмя();

	ТекстЗапроса = СтрШаблон("ВЫБРАТЬ ПЕРВЫЕ 1 %1 ИЗ %2 ГДЕ Ссылка = &Ссылка", ИменаРеквизитов, ИмяТаблицы); // BSLLS:QueryParseError-off
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Ссылка", Ссылка);

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

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

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

Функция Записи(ОписаниеЗапроса, ОднаЗапись, ДляКлиента) Экспорт

	Если ОднаЗапись Тогда
		ОписаниеЗапроса.КоличествоЗаписей = 1;
	КонецЕсли;

	Запрос = Запрос(ОписаниеЗапроса);
	РезультатЗапроса = Запрос.Выполнить();

	Записи = ВыгрузитьРезультатЗапроса(РезультатЗапроса, ДляКлиента);

	Если НЕ ОднаЗапись Тогда
		Возврат Записи;
	ИначеЕсли Записи.Количество() Тогда
		Возврат Записи[0];
	Иначе
		Возврат Неопределено;
	КонецЕсли;

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

// Возвращает значения реквизитов записи
//
// Параметры:
//  ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса
//  ОдинРеквизит - Булево
//
// Возвращаемое значение:
//  - Структура Из Произвольный - Значения множества реквизитов записи
//  - Произвольный - Значение одного реквизита записи
//

Функция ЗначенияРеквизитовЗаписи(ОписаниеЗапроса, ОдинРеквизит) Экспорт

	Запись = Записи(ОписаниеЗапроса, Истина, Истина);

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

	Если ОдинРеквизит Тогда
		Для Каждого КлючЗнач Из Запись Цикл
			Возврат КлючЗнач.Значение;
		КонецЦикла;
	Иначе
		Возврат Запись;
	КонецЕсли;

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

// Возвращает количество записей результата запроса
//
// Параметры:
//  ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса
//
// Возвращаемое значение:
//  Число
//

Функция КоличествоЗаписей(ОписаниеЗапроса) Экспорт

	Записи = РезультатЗапроса(ОписаниеЗапроса, Ложь);
	Возврат Записи.Количество();

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

// см. ЮТЗапросы.СлучайнаяЗапись

Функция СлучайнаяЗапись(МетаданныеОбъекта, Отборы = Неопределено) Экспорт
	ОписаниеОбъекта = ЮТМетаданные.ОписаниеОбъектаМетаданных(МетаданныеОбъекта, Истина);
	РеквизитУпорядочивания = РеквизитУпорядочивания(ОписаниеОбъекта);
	ВыбираемыеПоля = ВыбираемыеПоля(ОписаниеОбъекта, РеквизитУпорядочивания);
	Реквизиты = СтрСоединить(ВыбираемыеПоля, ", ");
	ИмяТаблицы = СтрШаблон("%1.%2", ОписаниеОбъекта.ОписаниеТипа.Имя, ОписаниеОбъекта.Имя);
	МаксимальноКоличествоЗаписей = 10000;

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

	Запрос.Текст = СтрШаблон(
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	КОЛИЧЕСТВО(*)
	|ИЗ
	|	%1 КАК Таблица %2", ИмяТаблицы, Условия);
	КоличествоЗаписей = Мин(МаксимальноКоличествоЗаписей, ЗначениеИзЗапроса(Запрос, 0, 0));

	Если КоличествоЗаписей = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;

	НомерЗаписи = ЮТТестовыеДанные.СлучайноеЧисло(1, КоличествоЗаписей);

	Запрос.Текст = СтрШаблон(
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
	|	*
	|ИЗ
	|	(ВЫБРАТЬ ПЕРВЫЕ %1
	|		%2
	|	ИЗ
	|		%3 КАК Выборка
	|	%4
	|	УПОРЯДОЧИТЬ ПО
	|		%5 УБЫВ) КАК ВЫБОРКА
	|
	|УПОРЯДОЧИТЬ ПО
	|	%5", ЮТОбщий.ЧислоВСтроку(НомерЗаписи), Реквизиты, ИмяТаблицы, Условия, РеквизитУпорядочивания);

	ЗначенияРеквизитов = ЗначенияИзЗапроса(Запрос, Реквизиты);

	Если ОписаниеОбъекта.ОписаниеТипа.Ссылочный Тогда
		Возврат ЗначенияРеквизитов.Ссылка;
	Иначе
		Возврат ЗначенияРеквизитов;
	КонецЕсли;

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

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

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

// Запрос.
//
// Параметры:
//  ОписаниеЗапроса - см. ЮТЗапросы.ОписаниеЗапроса
//
// Возвращаемое значение:
//  Запрос

Функция Запрос(ОписаниеЗапроса)

	Запрос = Новый Запрос;

	Строки = Новый Массив();
	Строки.Добавить("ВЫБРАТЬ ");

	Если ОписаниеЗапроса.КоличествоЗаписей <> Неопределено Тогда
		Строки.Добавить("ПЕРВЫЕ " + ЮТОбщий.ЧислоВСтроку(ОписаниеЗапроса.КоличествоЗаписей));
	КонецЕсли;

	Если ОписаниеЗапроса.ВыбираемыеПоля.Количество() Тогда
		ВыбираемыеПоля = ОписаниеЗапроса.ВыбираемыеПоля;
	Иначе
		ВыбираемыеПоля = ЮТКоллекции.ЗначениеВМассиве("1 КАК Поле");
	КонецЕсли;

	Строки.Добавить(СтрСоединить(ВыбираемыеПоля, "," + Символы.ПС));
	Строки.Добавить("ИЗ " + ОписаниеЗапроса.ИмяТаблицы);

	Условия = СформироватьУсловия(ОписаниеЗапроса.Условия, ОписаниеЗапроса.ИмяТаблицы, Запрос);

	Если ЗначениеЗаполнено(Условия) Тогда
		Строки.Добавить("ГДЕ");
		Строки.Добавить(Условия);
	КонецЕсли;

	Если ОписаниеЗапроса.Порядок.Количество() Тогда
		Строки.Добавить("УПОРЯДОЧИТЬ ПО ");
		Строки.Добавить(СтрСоединить(ОписаниеЗапроса.Порядок, ","));
	КонецЕсли;

	Запрос.Текст = СтрСоединить(Строки, Символы.ПС);
	ЮТКоллекции.ДополнитьСтруктуру(Запрос.Параметры, ОписаниеЗапроса.ЗначенияПараметров);

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

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

Функция ЗначенияИзЗапроса(Запрос, Реквизиты) Экспорт

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

	Если Выборка.Следующий() Тогда
		ЗаполнитьЗначенияСвойств(Результат, Выборка);
	КонецЕсли;

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

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

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

	Выборка = Запрос.Выполнить().Выбрать();

	Если Выборка.Следующий() Тогда
		Возврат Выборка[Реквизит];
	Иначе
		Возврат ЗначениеПоУмолчанию;
	КонецЕсли;

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

Функция ВыгрузитьРезультатЗапроса(РезультатЗапроса, ВМассив)

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

	Если РезультатЗапроса.Пустой() Тогда
		Возврат Результат;
	КонецЕсли;

	Реквизиты = Новый Массив();
	ТабличныеЧасти = Новый Массив();

	ТипРезультатЗапроса = Тип("РезультатЗапроса");
	Для Каждого Колонка Из РезультатЗапроса.Колонки Цикл

		Реквизиты.Добавить(Колонка.Имя);

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

	КонецЦикла;

	ПараметрыКонструктора = СтрСоединить(Реквизиты, ",");

	Выборка = РезультатЗапроса.Выбрать();

	Пока Выборка.Следующий() Цикл

		Запись = Новый Структура(ПараметрыКонструктора);
		ЗаполнитьЗначенияСвойств(Запись, Выборка);

		Для Каждого ТабличнаяЧасть Из ТабличныеЧасти Цикл
			Запись[ТабличнаяЧасть] = ВыгрузитьРезультатЗапроса(Выборка[ТабличнаяЧасть], ВМассив);
		КонецЦикла;

		Результат.Добавить(Запись);

	КонецЦикла;

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

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


Функция СоответствуетШаблону(ПроверяемаяСтрока, РегулярноеВыражение)

	РегулярныеВыражения = ЮТКомпоненты.РегулярныеВыражения();

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

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

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

Функция НайтиЗначение(ПроверяемоеЗначение, ОжидаемоеЗначение)

	ТипПроверяемогоЗначения = ТипЗнч(ПроверяемоеЗначение);

	Если ТипПроверяемогоЗначения = Тип("Строка") Или ТипПроверяемогоЗначения = Тип("ФорматированнаяСтрока") Тогда

		ИскомоеЗначениеНайдено = СтрНайти(ПроверяемоеЗначение, ОжидаемоеЗначение) > 0;

	ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоМассив(ТипПроверяемогоЗначения) Тогда

		Индекс = ПроверяемоеЗначение.Найти(ОжидаемоеЗначение);
		ИскомоеЗначениеНайдено = Индекс <> Неопределено;

	ИначеЕсли ЮТТипыДанныхСлужебный.ЭтоКлючЗначение(ТипПроверяемогоЗначения) Тогда

		ИскомоеЗначениеНайдено = Ложь;
		ТипОжидаемогоЗначения = ТипЗнч(ОжидаемоеЗначение);

		Для Каждого КлючЗначение Из ПроверяемоеЗначение Цикл
			Если КлючЗначение.Значение = ОжидаемоеЗначение И ТипЗнч(КлючЗначение.Значение) = ТипОжидаемогоЗначения Тогда
				ИскомоеЗначениеНайдено = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;

	ИначеЕсли ТипПроверяемогоЗначения = Тип("СписокЗначений") Тогда

		ИскомоеЗначениеНайдено = ПроверяемоеЗначение.НайтиПоЗначению(ОжидаемоеЗначение) <> Неопределено;

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

		ИскомоеЗначениеНайдено = ПроверяемоеЗначение.Найти(ОжидаемоеЗначение) <> Неопределено;

	Иначе

		ИскомоеЗначениеНайдено = Неопределено; // Обрабатывается вызывающим методом

	КонецЕсли;

	Возврат ИскомоеЗначениеНайдено;

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

#Область РеализацияПредикатов

Процедура ПроверитьВыражениеПредиката(Значение, Выражение, СтатусПроверки, ПараметрыСообщенийОбОшибке, ПараметрыСравнения) Экспорт

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

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

// Вычислить выражение предиката.
//
// Параметры:
//  Значение - Произвольный - Значение
//  Выражение - см. ЮТФабрика.ВыражениеПредиката
//  СтатусПроверки - см. ЮТФабрикаСлужебный.ОписаниеРезультатаПроверки
//  ПараметрыСообщенийОбОшибке - см. ПараметрыСообщенийОбОшибке
//  ПараметрыСравнения - Неопределено
//                     - Структура - Параметры сравнения значений, для разных выражений используются свои параметры

Процедура ВызватьОбработчикПредиката(Значение, Выражение, СтатусПроверки, ПараметрыСообщенийОбОшибке, ПараметрыСравнения)

// BSLLS:CognitiveComplexity-off
	ВидыСравнения = ЮТПредикаты.Выражения();

	ПараметрыПроверки = ПараметрыПроверки(Выражение.ВидСравнения, Значение, Выражение.ИмяРеквизита, Выражение.Значение, Ложь);

	ПараметрыПроверки.ОписаниеПроверки = ПараметрыСообщенийОбОшибке.ОписаниеПроверки;
	ПараметрыПроверки.ТекстПроверяемоеЗначение = ПараметрыСообщенийОбОшибке.ТекстПроверяемоеЗначение;
	ПараметрыПроверки.ОбъектПроверки.Представление = ПараметрыСообщенийОбОшибке.ПредставлениеПроверяемогоЗначения;

	Если СтрНачинаетсяС(Выражение.ВидСравнения, "Не") И ВидыСравнения.Свойство(Сред(Выражение.ВидСравнения, 3)) Тогда
		ПараметрыПроверки.Реверс = Истина;
		ВидСравненияВыражения = Сред(Выражение.ВидСравнения, 3);
	Иначе
		ВидСравненияВыражения = Выражение.ВидСравнения;
	КонецЕсли;

	Результат = Неопределено;

	ОжидаемоеЗначение = Выражение.Значение;
	ПроверяемоеЗначение = ПроверяемоеЗначение(ПараметрыПроверки);

	Если ВидСравненияВыражения = ВидыСравнения.Равно Тогда

		Результат = ЗначенияРавны(ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыСравнения);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Заполнено Тогда

		Результат = ЗначениеЗаполнено(ПроверяемоеЗначение);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Больше Тогда

		Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, Истина);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.БольшеРавно Тогда

		Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, Истина, , Истина);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Меньше Тогда

		Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, , Истина);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.МеньшеРавно Тогда

		Результат = ПроверитьНеравенство(ПроверяемоеЗначение, ОжидаемоеЗначение, , Истина, Истина);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ИмеетТип Тогда

		ПроверитьТипПараметра(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ИмеетСвойство Тогда

		Результат = ПроверитьНаличиеСвойства(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ИмеетДлину Тогда

		ПроверитьДлину(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.Содержит Тогда

		Результат = ПроверитьСодержит(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.СодержитСтрокуПоШаблону Тогда

		Результат = ПроверитьСоответствуетШаблону(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки);

	ИначеЕсли ВидСравненияВыражения = ВидыСравнения.ВСписке Тогда

		Результат = ПроверитьВСписке(СтатусПроверки, ПроверяемоеЗначение, ОжидаемоеЗначение, ПараметрыПроверки);

	ИначеЕсли ЮТПредикатыСлужебныйКлиентСервер.ЭтоПредикатМежду(Выражение) Тогда

		Результат = ПроверитьМежду(СтатусПроверки, ПроверяемоеЗначение, Выражение, ВидСравненияВыражения, ПараметрыПроверки);

	Иначе

		ВызватьИсключение СтрШаблон("Неизвестное выражение предиката `%1`", Выражение.ВидСравнения);

	КонецЕсли;
// BSLLS:CognitiveComplexity-on

	Если Результат = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Если ПараметрыПроверки.Реверс Тогда
		Результат = НЕ Результат;
	КонецЕсли;

	ОбработатьРезультатПроверкиПредиката(Результат, СтатусПроверки, Выражение, ПараметрыПроверки, ПроверяемоеЗначение);

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

Процедура ОбработатьРезультатПроверкиПредиката(Результат, СтатусПроверки, Предикат, ПараметрыПроверки, ФактическоеЗначение)

	Если Результат Тогда
		Возврат;
	КонецЕсли;

	Сообщение = ЮТПредикатыСлужебныйКлиентСервер.ПредставлениеПредиката(Предикат, Неопределено, Истина);

	ДобавитьОшибкуСравненияКРезультатуПроверки(СтатусПроверки, Сообщение, ПараметрыПроверки, ФактическоеЗначение);

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

Процедура ОбработатьРезультатСравнения(Результат, СтатусПроверки, ПараметрыПроверки, ФактическоеЗначение)

	Если Результат Тогда
		Возврат;
	КонецЕсли;

	ШаблонСообщения = ЮТПредикатыСлужебныйКлиентСервер.ШаблонВыражения(ПараметрыПроверки.ВидСравнения);
	Сообщение = ЮТСообщенияСлужебный.ПодставитьПредставлениеЗначенияВШаблон(ШаблонСообщения, ПараметрыПроверки.ОжидаемоеЗначение);

	ДобавитьОшибкуСравненияКРезультатуПроверки(СтатусПроверки, Сообщение, ПараметрыПроверки, ФактическоеЗначение);

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

Процедура ДобавитьОшибкуСравненияКРезультатуПроверки(СтатусПроверки, Сообщение, ПараметрыПроверки, ФактическоеЗначение)

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

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

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


Функция СформироватьКодПоСсылкамНаОбъекты(СсылкиНаОбъекты, ПараметрыФормирования) Экспорт

	ТекстКод1С = Новый ТекстовыйДокумент;

	Если ПараметрыФормирования.ТипКода = "ТаблицаMarkdownYaxunit" Тогда

		РезультатФормирования = СформироватьТаблицуMarkdownПоСсылкам(СсылкиНаОбъекты, ПараметрыФормирования);

		Возврат РезультатФормирования.ТекстКод1С;

	Иначе

		Для Каждого ЗначениеСсылка Из СсылкиНаОбъекты Цикл

			ПараметрыОбъектаМетаданных = ДанныеПоОбъектуМетаданных(ЗначениеСсылка);

			Если Не ЗначениеЗаполнено(ПараметрыОбъектаМетаданных.ВидОбъекта) Тогда
				Продолжить;
			КонецЕсли;

			ГотовыйКодПоСсылке = СформироватьКодПоСсылке(ПараметрыФормирования, ПараметрыОбъектаМетаданных, ЗначениеСсылка);

			ТекстКод1С.ДобавитьСтроку(ГотовыйКодПоСсылке.ПолучитьТекст());

		КонецЦикла;

	КонецЕсли;

	Возврат ТекстКод1С;

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

Функция ПараметрыСтруктурыСозданияОбъекта() Экспорт

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

	Возврат СтруктураСозданияОбъекта;

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

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

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

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

Процедура ДобавитьРеквизит(МассивРеквизитов, Реквизит, ЭтоСтандартныйРеквизит = Ложь)

	НовРеквизит = Новый Структура;

	НовРеквизит.Вставить("Представление", Реквизит.Представление()); // $* CaSH вместо ".Синоним" нужно писать ".Представление()"
	НовРеквизит.Вставить("Данные", 		  Реквизит.Имя);
	ШиринаРеквизита = 40;
	НовРеквизит.Вставить("ТипыРеквизитов", ПолучитьТипыСтрокой(Реквизит.Тип,, ШиринаРеквизита));
	НовРеквизит.Вставить("СтандартныйРеквизит", ЭтоСтандартныйРеквизит);

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

	МассивРеквизитов.Добавить(НовРеквизит);

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

Процедура ДобавитьРеквизитыТабличнойЧасти(МассивТабличныхЧастей, ТабличнаяЧасть)

	НовТаблЧасть = Новый Структура;

	НовТаблЧасть.Вставить("Представление", ТабличнаяЧасть.Представление()); // $* CaSH вместо ".Синоним" нужно писать ".Представление()"
	НовТаблЧасть.Вставить("Данные", 		  ТабличнаяЧасть.Имя);
	НовТаблЧасть.Вставить("ТипыРеквизитов", "ТабличнаяЧасть");
	НовТаблЧасть.Вставить("Реквизиты", Новый Массив);

	РеквизитыТЧ	= ТабличнаяЧасть.Реквизиты;
	Для Каждого РеквизитТЧ Из РеквизитыТЧ Цикл
		ДобавитьРеквизит(НовТаблЧасть.Реквизиты, РеквизитТЧ);
	КонецЦикла;

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

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

Функция ДанныеПоОбъектуМетаданных(СсылкаНаОбъект)

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

	ОбъектМетаданных = СсылкаНаОбъект.Метаданные();

	ПараметрыОбъекта.ОбъектМетаданных    = ОбъектМетаданных;
	ПараметрыОбъекта.ОбъектМетаданныхИмя = ОбъектМетаданных.Имя;

	Если Метаданные.Справочники.Содержит(ОбъектМетаданных) Тогда
		ПараметрыОбъекта.ВидОбъекта = "Справочник";
	ИначеЕсли Метаданные.Документы.Содержит(ОбъектМетаданных) Тогда
		ПараметрыОбъекта.ВидОбъекта = "Документ";
	ИначеЕсли Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных) Тогда
		ПараметрыОбъекта.ВидОбъекта = "ПланВидовХарактеристик";
	Иначе
		// без обработки
	КонецЕсли;

	// По стандартным реквизитам
	Для Каждого Реквизит Из ОбъектМетаданных.СтандартныеРеквизиты Цикл

		Если Реквизит.Имя = "ИмяПредопределенныхДанных"
			Или Реквизит.Имя = "Предопределенный" Тогда
			Продолжить;
		КонецЕсли;

		ДобавитьРеквизит(ПараметрыОбъекта.Реквизиты, Реквизит, Истина);

	КонецЦикла;

	// По реквизитам
	Для Каждого Реквизит Из ОбъектМетаданных.Реквизиты Цикл

		ДобавитьРеквизит(ПараметрыОбъекта.Реквизиты, Реквизит);

	КонецЦикла;

	// По табличным частям
	Для Каждого ТабличнаяЧасть Из ОбъектМетаданных.ТабличныеЧасти Цикл

		ДобавитьРеквизитыТабличнойЧасти(ПараметрыОбъекта.ТабличныеЧасти, ТабличнаяЧасть);

	КонецЦикла;

	Возврат ПараметрыОбъекта;

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

#Область ФормированиеКодаПоСсылке


Процедура ИзменитьРасширенияНаСервере_БСП_2_4(ПомещенныеФайлы, ИдентификаторРасширения, НеподключенныеРасширения)

	ПроверитьДоступностьРазделенныхДанных();

	РасширенияИзменены = Ложь;
	Расширение = Неопределено;

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

	ПроверяемыеРасширения = Новый Соответствие;
	ДобавленныеРасширения = Новый Массив;

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

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

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

&НаСервере

Процедура ОбновитьПараметрыРаботыРасширений_БСП_2_4(ПроверяемыеРасширения = Неопределено, НеподключенныеРасширения = "")

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

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

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

	Если ЗначениеЗаполнено(Результат.ТекстОшибки) Тогда
		ВызватьИсключение Результат.ТекстОшибки;
	КонецЕсли;

	Если ЗначениеЗаполнено(Результат.НеподключенныеРасширения) Тогда
		НеподключенныеРасширения = Результат.НеподключенныеРасширения;
	КонецЕсли;

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

СчетчикОжиданияРезультатов = 0;
МаксИтерацийОжиданияРезультатов = 5;


// BSLLS-off
&Лог("vrunner")
Перем Лог;

&Пластилин
Перем СервисКонфигурации;

&Пластилин
Перем СервисЗаполненияПараметров;

&Пластилин
Перем СервисОкружения;

&НаборОпций("НаборОпцийПодключения")
Перем ОпцииПодключения;

&НаборОпций("НаборОпцийПлатформы")
Перем ОпцииПлатформы;

&НаборОпций("НаборОпцийСУБД")
Перем ОпцииСУБД;

&Опция(Имя = "second-cf", Описание = "Путь ко второму cf-файлу (с чем сравниваем)")
&ТСтрока
&Обязательный
Перем ПутьКВторомуCf;

&Опция(Имя = "first-cf", Описание = "Путь к первому cf-файлу; если не задан - сравнивается конфигурация базы")
&ТСтрока
Перем ПутьКПервомуCf;

&Опция(Имя = "report-dir", Описание = "Каталог для сохранения отчёта (по умолчанию - текущий каталог)")
&ТСтрока
Перем КаталогОтчёта;

&Опция(Имя = "report-type", Описание = "Тип отчёта")
&ТПеречисление
&Перечисление(Имя = "Full", Описание = "Полный отчёт")
&Перечисление(Имя = "Brief", Описание = "Краткий отчёт")
&ПоУмолчанию("Full")
Перем ТипОтчёта;

&Опция(Имя = "report-format", Описание = "Формат файла отчёта")
&ТПеречисление
&Перечисление(Имя = "txt", Описание = "Текстовый файл")
&Перечисление(Имя = "mxl", Описание = "Табличный документ")
&ПоУмолчанию("txt")
Перем ФорматОтчёта;

&НаборОпций("НаборОпцийНастроек")
Перем ОпцииНастроек; // BSLLS:UnusedLocalVariable-off

&ПодкомандаПриложения(Имя = "compare", Родитель = "КомандаCf", Описание = "Сравнить конфигурации и сформировать отчёт")
Процедура ПриСозданииОбъекта()
КонецПроцедуры

&ВыполнениеКоманды
Процедура ВыполнитьДействие() Экспорт

	СервисЗаполненияПараметров.Заполнить(ЭтотОбъект);

	Лог.Отладка("Начало выполнения команды cf compare");

	ПроверитьЗаполненность(ПутьКВторомуCf,
		"Не задан второй cf-файл (--second-cf).");

	РежимСравненияСБазой = НЕ ЗначениеЗаполнено(ПутьКПервомуCf);
	Если РежимСравненияСБазой Тогда
		ПроверитьЗаполненность(ОпцииПодключения.СтрокаПодключения,
			"При сравнении с базой (без --first-cf) строка подключения обязательна (--ibconnection).");
	КонецЕсли;

	ПараметрыПлатформы = Новый Структура(
		"ВерсияПлатформы, КодРазрешения, Язык, Локаль",
		ОпцииПлатформы.ВерсияПлатформы,
		ОпцииПлатформы.КодРазрешения,
		ОпцииПлатформы.Язык,
		ОпцииПлатформы.Локаль
	);

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

	ЭффКаталогОтчёта = ?(ЗначениеЗаполнено(КаталогОтчёта), КаталогОтчёта, СервисОкружения.РабочийКаталог());
	ЭффТипОтчёта    = ?(ЗначениеЗаполнено(ТипОтчёта),    ТипОтчёта,    "Full");
	ЭффФорматОтчёта = ?(ЗначениеЗаполнено(ФорматОтчёта), ФорматОтчёта, "txt");

	ПутьОтчёта = СервисКонфигурации.СравнитьКонфигурации(
		ПараметрыПодключения,
		ПутьКВторомуCf,
		ЭффКаталогОтчёта,
		ЭффТипОтчёта,
		ЭффФорматОтчёта,
		ПутьКПервомуCf,
		ПараметрыПлатформы
	);

	Лог.Информация("Отчёт о сравнении сохранён: %1", ПутьОтчёта);

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

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

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

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


Процедура ПриСозданииОбъекта()
КонецПроцедуры

&ВыполнениеКоманды

Процедура ВыполнитьДействие() Экспорт

	СервисЗаполненияПараметров.Заполнить(ЭтотОбъект);

	ПутьИсточника = ИсточникИлиТекущийКаталог();

	ЕслиНеЗаполненоОпределитьИмяРасширения(ПутьИсточника);
	ПроверитьИмяРасширения(ИмяРасширения);

	Лог.Отладка("Начало выполнения команды cfe load");
	Лог.Отладка("Источник: %1", ПутьИсточника);
	Лог.Отладка("Имя расширения: %1", ИмяРасширения);

	ПараметрыПлатформы = Новый Структура(
		"ВерсияПлатформы, КодРазрешения, Язык, Локаль",
		ОпцииПлатформы.ВерсияПлатформы,
		ОпцииПлатформы.КодРазрешения,
		ОпцииПлатформы.Язык,
		ОпцииПлатформы.Локаль);

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

	ПараметрыРасширения = Новый Структура(
		"БезопасныйРежим, ЗащитаОтОпасныхДействий",
		БезопасныйРежим,
		ЗащитаОтОпасныхДействий);

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

	Если ОпцииПодключения.ИспользоватьIbcmd = Истина Тогда
		Если ЕстьСвойстваРасширения() Тогда
			УстановитьСвойстваРасширения(ПараметрыПодключения, ПараметрыПлатформы);
		КонецЕсли;
	// BSLLS:IfElseIfEndsWithElse-off
	ИначеЕсли ЕстьСвойстваТолькоIbcmd() Тогда
		Лог.Предупреждение("Свойства --active, --used-in-rib, --scope-infobase поддерживаются только в режиме ibcmd (--ibcmd). Свойства не применены.");
	КонецЕсли;
	// BSLLS:IfElseIfEndsWithElse-on

	Если ОбновитьБД = Истина Тогда
		НастройкиОбновления = ОпцииОбновленияБД.СформироватьНастройкиОбновления(ИмяРасширения);
		Лог.Информация("Обновление расширения '%1' БД (restr=%2)", ИмяРасширения, НастройкиОбновления.РежимРеструктуризации);
		СервисПлатформы.ОбновитьКонфигурациюБД(
			ПараметрыПодключения,
			ОпцииПодключения.ИспользоватьIbcmd,
			ПараметрыПлатформы,
			НастройкиОбновления);
	КонецЕсли;

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

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

Функция ИсточникИлиТекущийКаталог()

	Если ЗначениеЗаполнено(Источник) Тогда
		Возврат Источник;
	КонецЕсли;

	Возврат СервисОкружения.РабочийКаталог();

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

Процедура ЕслиНеЗаполненоОпределитьИмяРасширения(Знач ПутьИсточника)

	Если ЗначениеЗаполнено(ИмяРасширения) Тогда
		Возврат;
	КонецЕсли;

	ФайлИсточника = Новый Файл(ПутьИсточника);
	Если ЭтоФайлCfe(ПутьИсточника) Тогда
		ИмяРасширения = ФайлИсточника.ИмяБезРасширения;
	Иначе
		ИмяРасширения = ФайлИсточника.Имя;
	КонецЕсли;

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

Процедура ПроверитьИмяРасширения(Знач Имя)

	Если НЕ ЗначениеЗаполнено(Имя) Тогда
		ВызватьИсключение "Имя расширения не задано и не удалось определить его из пути источника.";
	КонецЕсли;

	Шаблон = Новый РегулярноеВыражение("^[a-zA-Zа-яА-ЯёЁ][a-zA-Zа-яА-ЯёЁ0-9_]*$");
	Если НЕ Шаблон.Совпадает(Имя) Тогда
		ВызватьИсключение "Неверное имя! Имя должно состоять из одного слова, начинаться с буквы и не иметь спецсимволов кроме _";
	КонецЕсли;

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

Функция ЭтоФайлCfe(Знач Путь)

	Возврат СтрЗаканчиваетсяНа(НРег(Путь), ".cfe");

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

Процедура ПроверитьСуществованиеФайла(Знач Путь)

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

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

Процедура ПроверитьСуществованиеКаталога(Знач Путь)

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

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

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

	// &Флаговый по умолчанию даёт Ложь, поэтому для определения факта явной установки
	// проверяем только значения = Истина. Это означает: чтобы изменить свойство расширения
	// нужно явно передать соответствующий флаг.
	Возврат БезопасныйРежим = Истина
		ИЛИ Активность = Истина
		ИЛИ ЗащитаОтОпасныхДействий = Истина
		ИЛИ ИспользуетсяВРИБ = Истина
		ИЛИ ОбластьДействия_ИБ = Истина;

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

Функция ЕстьСвойстваТолькоIbcmd()
	Возврат Активность = Истина ИЛИ ИспользуетсяВРИБ = Истина ИЛИ ОбластьДействия_ИБ = Истина;
КонецФункции

Процедура УстановитьСвойстваРасширения(ПараметрыПодключения, ПараметрыПлатформы)

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

	СервисРасширений.ИзменитьСвойстваРасширения(
		ПараметрыПодключения,
		ИмяРасширения,
		Свойства,
		ПараметрыПлатформы);

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

Функция ПреобразоватьБулевоеСвойство(Знач Значение, Знач ПоУмолчанию)

	Если НЕ ЗначениеЗаполнено(Значение) Тогда
		Возврат ПоУмолчанию;
	КонецЕсли;

	Если ТипЗнч(Значение) = Тип("Булево") Тогда
		// &Флаговый: Ложь означает "флаг не передан" - применяем безопасный дефолт
		Если Значение = Ложь Тогда
			Возврат ПоУмолчанию;
		КонецЕсли;
		Возврат Значение;
	КонецЕсли;

	ЗначениеНРег = НРег(СокрЛП(Значение));
	Если ЗначениеНРег = "yes" ИЛИ ЗначениеНРег = "true" ИЛИ ЗначениеНРег = "1" Тогда
		Возврат Истина;
	КонецЕсли;

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

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

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


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

	ТипОбъекта = "NULL";
	Если ЕстьСсылка(СтруктураОбъекта) И СтруктураОбъекта.Ссылка.Свойство("Тип") Тогда
		ТипОбъекта = СтруктураОбъекта.Ссылка.Тип;
	ИначеЕсли ЕстьСсылка(СтруктураОбъекта) И ЕстьТип(СтруктураОбъекта.Ссылка) Тогда
		ТипОбъекта = СтруктураОбъекта.Ссылка.__Тип;
	ИначеЕсли ЕстьТип(СтруктураОбъекта) Тогда
		ТипОбъекта = СтруктураОбъекта.__Тип;
	Иначе
		ТекстОшибки = "Структура не содержит указания типа значения или не является представлением ссылочного объекта. Поля %1 объекта:";

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

	Попытка
		ОписаниеВида = ПолучитьОписаниеВидаОбъектов(ТипОбъекта);
	Исключение
		ВызватьИсключение СтрШаблонВнутр("Ошибка получения описания вида объекта ""%1"": %2%3",
		                            ТипОбъекта,
		                            Символы.ПС,
		                            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;

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

КонецПроцедуры // ЗаполнитьОбъектИзСтруктуры()

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


Функция КлючОбласти(ИмяОбласти)
	Если НЕ АнглСинтаксис Тогда
		Возврат ИмяОбласти;
	КонецЕсли;

	СоответствиеОбластей = Новый Соответствие;
	СоответствиеОбластей.Вставить("ПрограммныйИнтерфейс", "Public");
	СоответствиеОбластей.Вставить("СлужебныйПрограммныйИнтерфейс", "Internal");
	СоответствиеОбластей.Вставить("СлужебныеПроцедурыИФункции", "Private");
	СоответствиеОбластей.Вставить("ОбновлениеИнформационнойБазы", "InfobaseUpdate");
	СоответствиеОбластей.Вставить("ОписаниеПеременных", "Variables");
	СоответствиеОбластей.Вставить("Инициализация", "Initialize");
	СоответствиеОбластей.Вставить("ОбработчикиСобытийФормы", "FormEventHandlers");
	СоответствиеОбластей.Вставить("ОбработчикиСобытийЭлементовШапкиФормы", "FormHeaderItemsEventHandlers");
	СоответствиеОбластей.Вставить("ОбработчикиСобытийЭлементовТаблицыФормы", "FormTableItemsEventHandlers");
	СоответствиеОбластей.Вставить("ОбработчикиКомандФормы", "FormCommandsEventHandlers");
	СоответствиеОбластей.Вставить("ОбработчикиСобытий", "EventHandlers");

	ИмяОбластиНаАнглийском = СоответствиеОбластей[ИмяОбласти];

	Если ИмяОбластиНаАнглийском <> Неопределено Тогда
		Возврат ИмяОбластиНаАнглийском;
	КонецЕсли;

	Если СтрНачинаетсяС(ИмяОбласти, "ОбработчикиСобытийЭлементовТаблицыФормы") Тогда
		ИмяТаблицы = Сред(ИмяОбласти, СтрДлина("ОбработчикиСобытийЭлементовТаблицыФормы") + 1);
		Возврат "FormTableItemsEventHandlers" + ИмяТаблицы;
	КонецЕсли;

	Возврат ИмяОбласти;
КонецФункции

Функция КудаОпределяемЭлемент(ЭлементСтруктуры, ИмяОбласти, ПорядокОбласти, ПорядокПодпрограммы = 10000, ДопПорядок = "")
	Если ИмяОбласти = "ОбработчикиСобытийЭлементовТаблицыФормы" Тогда
		ИмяОбластиПолное = ИмяОбласти + ДопПорядок;
	Иначе
		ИмяОбластиПолное = ИмяОбласти;
	КонецЕсли;

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

Функция КудаОпределяемМетод(СтрЭлемент)
	КудаОпределяем = Неопределено;

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

	// Обработчики команд Формы
	ИначеЕсли ЗначениеЗаполнено(СтрЭлемент.Содержимое.Параметры)
			  И СтрЭлемент.Содержимое.Параметры.Количество() = 1
			  И ВРег(СтрЭлемент.Содержимое.Параметры[0].Имя) = "КОМАНДА" Тогда

		КудаОпределяем = КудаОпределяемЭлемент(СтрЭлемент, "ОбработчикиКомандФормы", 250, 1);

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

		// Массив для хранения найденных вариантов соответствия
		НайденныеВарианты = Новый Массив;

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

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

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

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

				// Формируем результат с учетом всех параметров
				ПорядокОбласти = ПолучитьПорядокОбластиПоТипуОбработчика(ДанныеОбласти.ВФорме);
				КудаОпределяем = КудаОпределяемЭлемент(СтрЭлемент, ДанныеОбласти.Область, ПорядокОбласти, ДанныеОбласти.ПорядокМетода, ДопПорядок);
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;

	Возврат КудаОпределяем;
КонецФункции