//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирКлиент Экспорт;

Перем мПлатформа Экспорт;
Перем мСервисныйПроцессор Экспорт; // Для программного вызова из Интеграции
Перем мТаблицаБукв;
Перем мИскомыйОбъектПоискаДублей Экспорт;
Перем мСтруктураПоиска Экспорт;
Перем мБылиИсключения;
Перем мСуффиксСлужбеныхПолей Экспорт;
Перем мИмяПоляЦенность Экспорт;
Перем мИмяПоляКоличествоЭлементов Экспорт;
Перем мИмяПоляКоличествоСсылок Экспорт;
Перем мИмяПоляНомерГруппы Экспорт;
Перем мИмяПоляНеправильныеСсылки Экспорт;
Перем мИмяПоляПравильныйЭлемент Экспорт;
Перем мИмяПоляНеправильныйЭлемент Экспорт;
Перем мИмяПоляПравильныеДанные Экспорт;
Перем мИмяФлагаПравильныйЭлемент Экспорт;
Перем мИмяФлагаПравильныеДанные Экспорт;
Перем мИмяПоляИдентификатор Экспорт;
Перем мРезультатыПоиска Экспорт;
Перем мПоляСравнения Экспорт;

Перем мПутьКДаннымПоляНечеткогоСравнения Экспорт;
Перем мПредставления Экспорт;
Перем мСтруктураКлючаПоиска Экспорт;
Перем мИмяТипаСсылки Экспорт;

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

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

Процедура НайтиПоПохожимСловам(ЗапросПоиска, ТекстИндексов, ТекстУпорядочить) Экспорт 
	
	РезультатПакета = ЗапросПоиска.ВыполнитьПакет();
	#Если Сервер И Не Сервер Тогда
	    мПлатформа = Обработки.ирПлатформа.Создать();
	#КонецЕсли
	ИндексыИменРезультатов = мПлатформа.СтруктураРезультатаПакетногоЗапроса(ЗапросПоиска.Текст);
	ПервичныеГруппы = РезультатПакета[ИндексыИменРезультатов.ФинальныеГруппы].Выгрузить();
	ОбщаяТаблицаОбъекта = РезультатПакета[ИндексыИменРезультатов.ЭлементыФинальныхГрупп].Выгрузить();
	#Если Сервер И Не Сервер Тогда
		ПервичныеГруппы = Новый ТаблицаЗначений;
		ОбщаяТаблицаОбъекта = Новый ТаблицаЗначений;
	#КонецЕсли
	мРезультатыПоиска = ОбщаяТаблицаОбъекта.СкопироватьКолонки();
	ИмяПоляНечеткогоСравнения = ирОбщий.ИдентификаторИзПредставленияЛкс(мПутьКДаннымПоляНечеткогоСравнения);
	ТаблицаСлов = мРезультатыПоиска.Скопировать();
	ТаблицаСлов.Колонки.Добавить("СписокСлов");
	МассивСтроковыхПолейСравнения = Новый Массив;
	Для Каждого ЭлементСравнения Из мСтруктураКлючаПоиска Цикл
		Если ПервичныеГруппы.Колонки[ЭлементСравнения.Ключ].ТипЗначения.СодержитТип(Тип("Строка")) Тогда
			МассивСтроковыхПолейСравнения.Добавить(ЭлементСравнения.Ключ);
		КонецЕсли;
	КонецЦикла;
	Для Каждого СтрокаГруппы Из ПервичныеГруппы Цикл
		ВосстановитьЗначенияСтрокВСтрокеРезультатаЗапроса(МассивСтроковыхПолейСравнения, СтрокаГруппы);
	КонецЦикла;
	ОбщаяТаблицаОбъекта.Индексы.Добавить(Сред(ТекстИндексов, 2));
	
	НомерГруппы = 1;
	ДобавитьОбщиеКолонкиВРезультатыПоиска();
	НечеткоеСравнениеСлов = мПлатформа.ПолучитьОбъектВнешнейКомпонентыИзМакета("FuzzySearch", "AddIn.FuzzySearch.FuzzyStringMatchExtension", "FuzzySearch");
	Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ПервичныеГруппы.Количество(), "Первичные группы элементов");
	КлючПоиска = Новый Структура(Сред(ТекстИндексов, 2));
	ПорогПохожести = 0.49 + 0.5 * Макс(0, (70 - ДопустимоеРазличиеСлов) / 70);
	Для Каждого ПервичнаяГруппа Из ПервичныеГруппы Цикл
		ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
		ЗаполнитьЗначенияСвойств(КлючПоиска, ПервичнаяГруппа); 
		ТаблицаОбъекта = ОбщаяТаблицаОбъекта.Скопировать(КлючПоиска);
		//Если НечеткоеСравнениеСлов <> Неопределено Тогда
			СчетчикОбработанныхСтрок = 0;
			// Сначала обработаем пустые строки, т.к. внешняя компонента их не видит
			СтрокиПустыхСтрок = ТаблицаОбъекта.НайтиСтроки(Новый Структура(ИмяПоляНечеткогоСравнения, ""));
			Если СтрокиПустыхСтрок.Количество() > 0 Тогда
				СтрокаЛевого = СтрокиПустыхСтрок[0];
				СтрокиПустыхСтрок.Удалить(0);
				НачальноеКоличество = СтрокиПустыхСтрок.Количество(); 
				ГруппаПустая = Истина;
				Для Счетчик = 1 По НачальноеКоличество Цикл
					СтрокаПравого = СтрокиПустыхСтрок[НачальноеКоличество - Счетчик];
					ПодобратьЭлементыГруппыПоПохожимСловам(ГруппаПустая, НомерГруппы, СтрокаЛевого, СтрокаПравого, СчетчикОбработанныхСтрок, ТаблицаОбъекта);
				КонецЦикла;
				ТаблицаОбъекта.Удалить(СтрокаЛевого);
				Если Не ГруппаПустая Тогда
					НомерГруппы = НомерГруппы + 1;
				КонецЕсли; 
			КонецЕсли; 
			ИндикаторПохожих = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаОбъекта.Количество(), "Поиск похожих слов");
			// Теперь обработаем все оставшиеся (непустые) строки
			Пока ТаблицаОбъекта.Количество() > 1 Цикл
				ирОбщий.ОбработатьИндикаторЛкс(ИндикаторПохожих, СчетчикОбработанныхСтрок);
				СтрокаЛевого = ТаблицаОбъекта[0];
				ЛевоеЗначение = СтрокаЛевого[ИмяПоляНечеткогоСравнения];
				ГруппаПустая = Истина;
				
				//ЛеваяДистанция = НечеткоеСравнениеСлов.Сравнить(ЛевоеЗначение, ЛевоеЗначение);
				//НачальноеКоличество = ТаблицаОбъекта.Количество(); 
				//Для СчетчикТаблицаОбъектов = 1 По НачальноеКоличество - 1 Цикл
				//	СтрокаПравого = ТаблицаОбъекта[НачальноеКоличество - СчетчикТаблицаОбъектов];
				//	ПравоеЗначение = СтрокаПравого[ИмяПоляНечеткогоСравнения];
				//	ПраваяДистанция = НечеткоеСравнениеСлов.Сравнить(ПравоеЗначение, ПравоеЗначение);
				//	Если ЛеваяДистанция > ПраваяДистанция Тогда
				//		БазоваяДистанция = ЛеваяДистанция;
				//	Иначе
				//		БазоваяДистанция = ПраваяДистанция;
				//	КонецЕсли; 
				//	Если БазоваяДистанция > 0 Тогда
				//		Дистанция = НечеткоеСравнениеСлов.Сравнить(ЛевоеЗначение, ПравоеЗначение);
				//		Если Дистанция / БазоваяДистанция >= ПорогПохожести Тогда
				//			ПодобратьЭлементыГруппыПоПохожимСловам(ГруппаПустая, НомерГруппы, СтрокаЛевого, СтрокаПравого, СчетчикОбработанныхСтрок, ТаблицаОбъекта);
				//		КонецЕсли;
				//	Иначе
				//		// нет буквенных символов
				//	КонецЕсли; 
				//КонецЦикла;
				МассивСтрок = ТаблицаОбъекта.ВыгрузитьКолонку(ИмяПоляНечеткогоСравнения);
				МассивСтрок.Удалить(0);
				РазделительСтрок = "~";
				СтрокаИзМассива = ирОбщий.СтрСоединитьЛкс(МассивСтрок, РазделительСтрок);
				// Параметры 4-5-6:
				//SmallStringLength - число, определяющее максимальную длину небольших строк(для них процент совпадения при поиске отличается от сравнения более длинных строк)
				//SmallStringMatch - минимальный процент совпадения для небольших строк.
				//Match - минимальный процент совпадения для больших строк.
				// Создаем компоненту каждый раз, т.к. у нее внутри что то засоряется и повторный вызов возвращает некорректный результат https://partners.v8.1c.ru/forum/t/1429261/m/1643666
				//НечеткоеСравнениеСлов = мПлатформа.ПолучитьОбъектВнешнейКомпонентыИзМакета("FuzzySearch", "AddIn.FuzzySearch.FuzzyStringMatchExtension", "FuzzySearch");
				//ИндексыНайденныхСовпадений = НечеткоеСравнениеСлов.StringSearch(Нрег(ЛевоеЗначение), Нрег(СтрокаИзМассива), РазделительСтрок, 10, Макс(0, Цел(ПорогПохожести * 100) - 10), Цел(ПорогПохожести * 100));
				ИндексыНайденныхСовпадений = НечеткоеСравнениеСлов.StringSearch(ЛевоеЗначение, СтрокаИзМассива, РазделительСтрок, 10, Макс(0, Цел(ПорогПохожести * 100) - 10), Цел(ПорогПохожести * 100));
				ИндексыПохожихСлов = ирОбщий.СтрРазделитьЛкс(ИндексыНайденныхСовпадений, ",",, Ложь);
				НачальноеКоличество = ИндексыПохожихСлов.Количество(); 
				Для Счетчик = 1 По НачальноеКоличество Цикл
					ИндексПохожегоСлова = ИндексыПохожихСлов[НачальноеКоличество - Счетчик];
					СтрокаПравого = ТаблицаОбъекта[Число(ИндексПохожегоСлова) + 1];
					ПодобратьЭлементыГруппыПоПохожимСловам(ГруппаПустая, НомерГруппы, СтрокаЛевого, СтрокаПравого, СчетчикОбработанныхСтрок, ТаблицаОбъекта);
				КонецЦикла;

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

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

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

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

Процедура НастроитьКолонкиНайденныхГрупп(Знач ТекстИндексов)
	
	НайденныеГруппы.Колонки.Удалить("Пустышка");
	НайденныеГруппы.Колонки.Вставить(0, мИмяПоляНомерГруппы);
	НайденныеГруппы.Индексы.Добавить(Сред(ТекстИндексов, 2));
	НайденныеГруппы.Индексы.Добавить(мИмяПоляНомерГруппы);

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

Процедура ВосстановитьЗначенияСтрокВСтрокеРезультатаЗапроса(Знач МассивСтроковыхПолейСравнения, Знач СтрокаГруппы)
	
	Для Каждого СтроковоеПоле Из МассивСтроковыхПолейСравнения Цикл
		ЗначениеПоля = НРег(СокрП(СтрокаГруппы[СтроковоеПоле]));
		// Заменим неразрывный пробел на нормальный
		ЗначениеПоля = СтрЗаменить(ЗначениеПоля, Символ(10 * 16), " ");
		Если УчитыватьПравыеПробелыСтрок Тогда
			// Удалим служебный символ "_" в конце строки
			ЗначениеПоля = Лев(ЗначениеПоля, СтрДлина(ЗначениеПоля) - 1);
		КонецЕсли; 
		СтрокаГруппы[СтроковоеПоле] = ЗначениеПоля;
	КонецЦикла;

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

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

Функция ДобавитьОбщиеКолонкиВРезультатыПоиска() Экспорт 

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

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

Функция ЭтоБукваЛкс(Символ)
	
	Код = КодСимвола(Символ);
	
	Если (Код<=47) ИЛИ (Код>=58 И Код<=64) ИЛИ (Код>=91 И Код<=96)  ИЛИ (Код>=123 И Код<=126) Тогда
		Возврат Ложь;
	Иначе
		Возврат Истина;
	КонецЕсли;
	
КонецФункции

Функция АнализРазличийВСловах(Список1, Список2, ПолныйСписок, ОдинаковыхСлов, ДопустимоеРазличиеСлов) Экспорт
	
	Если Ложь
		Или Список1.Количество() = ПолныйСписок.Количество()
		Или Список2.Количество() = ПолныйСписок.Количество() 
	Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если ПолныйСписок.Количество() = 0 Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если Список1.Количество() = Список2.Количество() Тогда
		ЕстьОтличия = ПроверитьСловаНаОтличие(Список1, Список2, ДопустимоеРазличиеСлов);
		ЕСли НЕ ЕстьОтличия Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	ЦелоеСлово = "";
	Для Каждого Слово ИЗ ПолныйСписок Цикл
		ЦелоеСлово = ЦелоеСлово + Слово.Значение;
	КонецЦикла;
	Слово1 = "";
	Для Каждого Слово ИЗ Список1 Цикл
		Слово1 = Слово1 + Слово.Значение;
	КонецЦикла;
	Слово2 = "";
	Для Каждого Слово ИЗ Список2 Цикл
		Слово2 = Слово2 + Слово.Значение;
	КонецЦикла;
	
	Если Истина
		И Окр(СтрДлина(Слово1)/СтрДлина(ЦелоеСлово)*100) < ДопустимоеРазличиеСлов
		И Окр(СтрДлина(Слово2)/СтрДлина(ЦелоеСлово)*100) < ДопустимоеРазличиеСлов
	Тогда
		Возврат Ложь;
	КонецЕсли;	
	
	Возврат Истина;
	
КонецФункции

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

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

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

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

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

Процедура ДобавитьОбъектВОчередьОбработки(Знач Заменяемые, Знач НеправильныеСсылкиВОбъекте, Знач РодителиПравильных, Знач ТранзакцииРазрешены, Знач ОписаниеОбъекта, СтруктураПотоков)
	

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

Процедура ЗагрузитьРезультатОбработкиОбъекта(Знач РезультатОбработки, _БылиИсключения) Экспорт 
	
	Если РезультатОбработки.БылиИсключения Тогда
		мБылиИсключения = РезультатОбработки.БылиИсключения;
	КонецЕсли;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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