RDT1C/DataProcessors/ирПоискДублейИЗаменаСсылок/Ext/ObjectModule.bsl
Администратор 1456e97cdc Интерфейсная панель
*Исправлена ошибка открытия форм отчетов через контекстное меню
        *Ускорена фильтрация по подсистемам
    Редактор объекта БД
        *Устранен избыточный вызов перезаполнения данных на закладке "Связанные колонки", если тип объекта не менялся
    Консоль запросов
        *Устранено в некоторых случаях ошибочное применение выборок итогов при выгрузке в дерево
        +Над деревом запросов добавлено поле строки поиска
        *Исправлено в дерево запроса некорректное определение имени создаваемой временной таблицы при наличии в выбранных полях запроса выражения "<Таблица>.*"
        +В контекстном меню дерева запроса добавлена команда "Выполнить запросы пакета (F9)"
        +При выполнении пакетного запроса теперь обновляется колонка "Количество строк" в дереве запроса
    Конструктор запроса
        *Звездочка в предложении ВЫБРАТЬ при сборке текста теперь не вставляется в объединениях
        *Исправлено разворачивание звездочки в некоторых случаях
        *Исправлено обнаружение параметров в логических выражениях
    Контекстная подсказка
        *Исправлена ошибка при вычислении свойств виртуальной таблицы с некорректными параметрами
    Консоль кода
        +Над деревом алгоритмов добавлено поле строки поиска
    Динамический список
        *Исправлена доступность сортировки по номеру стандартными средствами
    Функции режима отладки
        +В функции От() добавлен учет уничтожений временных таблиц при поиске использованных в запросе временных таблиц
2016-12-04 00:34:24 +03:00

1218 lines
87 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//ирПортативный Перем ирПортативный Экспорт;
//ирПортативный Перем ирОбщий Экспорт;
//ирПортативный Перем ирСервер Экспорт;
//ирПортативный Перем ирКэш Экспорт;
//ирПортативный Перем ирПривилегированный Экспорт;
Перем мПлатформа Экспорт;
Перем мСервисныйПроцессор Экспорт; // Для программного вызова из Интеграции
Перем ТаблицаБукв;
Перем мИскомыйОбъектПоискаДублей Экспорт;
Перем мСтруктураПоиска Экспорт;
Функция ЭтоБуква (Символ)
Код = КодСимвола(Символ);
Если (Код<=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);
Если ЭтоБуква(Символ) Тогда
Слово = Слово + Символ;
Иначе
Если Слово<>"" Тогда
СписокСлов.Добавить(ВРЕГ(Слово));
Слово = "";
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Слово<>"" Тогда
СписокСлов.Добавить(ВРЕГ(Слово));
КонецЕсли;
СписокСлов.СортироватьПоЗначению();
Возврат СписокСлов;
КонецФункции // ()
Функция _НайтиДубли(ИскомыйОбъект, СтруктураПоиска) Экспорт
мИскомыйОбъектПоискаДублей = ИскомыйОбъект;
мСтруктураПоиска = СтруктураПоиска;
НайденныеОбъекты = Новый ТаблицаЗначений;
НайденныеОбъекты.Колонки.Добавить("Ссылка");
ИмяСправочника = ИскомыйОбъект.Метаданные().Имя;
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ Разрешенные
| Ссылка*
|Из Справочник." + ИмяСправочника + " КАК Спр
|Где Не Спр.ЭтоГруппа";
Реквизиты = "";
СтрокаГде = "";
ВЗапросеТолькоРавенство = Истина;
МетаданныеОбъекта = ИскомыйОбъект.Метаданные();
МетаданныеРеквизитов = МетаданныеОбъекта.Реквизиты;
СтруктураИсходныхРеквизитов = Новый Структура;
Для каждого КлючИЗначение Из СтруктураПоиска Цикл
ИмяРеквизита = КлючИЗначение.Ключ;
СтепеньСхожести = КлючИЗначение.Значение;
ЗначениеРеквизита = ИскомыйОбъект[ИмяРеквизита];
МетаданныеРеквизита = МетаданныеРеквизитов.Найти(ИмяРеквизита);
ПредставлениеРеквизита = ?(МетаданныеРеквизита = Неопределено, ИмяРеквизита, Строка(МетаданныеРеквизита));
СтруктураИсходногоРеквизита = Новый Структура("ЗначениеРеквизита,СтепеньСхожести,СписокСлов"
,ЗначениеРеквизита,СтепеньСхожести,ПолучитьСписокСлов(ЗначениеРеквизита));
СтруктураИсходныхРеквизитов.Вставить(ИмяРеквизита,СтруктураИсходногоРеквизита);
Если Не МетаданныеРеквизита = Неопределено Тогда
ТипРеквизита = МетаданныеРеквизита.Тип;
ИначеЕсли ИмяРеквизита = "Код" Тогда
Если МетаданныеОбъекта.ТипКода = Метаданные.СвойстваОбъектов.ТипКодаСправочника.Строка Тогда
ТипРеквизита = Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(МетаданныеОбъекта.ДлинаКода));
Иначе
ТипРеквизита = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(МетаданныеОбъекта.ДлинаКода));
КонецЕсли;
ИначеЕсли ИмяРеквизита = "Наименование" Тогда
ТипРеквизита = Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(МетаданныеОбъекта.ДлинаНаименования));
Иначе
ТипРеквизита = Неопределено;
КонецЕсли;
НайденныеОбъекты.Колонки.Добавить(ИмяРеквизита, ТипРеквизита, ПредставлениеРеквизита);
НайденныеОбъекты.Колонки.Добавить(ИмяРеквизита+"_Флаг");
Реквизиты = Реквизиты+",
| "+ ИмяРеквизита;
Если ЗначениеЗаполнено(ЗначениеРеквизита) Тогда
Если СтепеньСхожести = "=" Тогда
ЗнакСравнения = ?(Не МетаданныеРеквизита = Неопределено И МетаданныеРеквизита.Тип.СодержитТип(Тип("Строка")) и МетаданныеРеквизита.Тип.КвалификаторыСтроки.Длина = 0,"Подобно","=");
СтрокаГде = ?(СтрокаГде = "", "",СтрокаГде +" или ")+"Спр."+ИмяРеквизита +" " +ЗнакСравнения+ " &"+ИмяРеквизита;
Запрос.УстановитьПараметр(""+ИмяРеквизита,ЗначениеРеквизита);
ИначеЕсли Не СтепеньСхожести = Неопределено Тогда
ВЗапросеТолькоРавенство = Ложь;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Запрос.Текст = СтрЗаменить(Запрос.Текст, "*", Реквизиты);
Если ВЗапросеТолькоРавенство Тогда
Запрос.Текст = Запрос.Текст + Символы.ПС + " И("+СтрокаГде+")";
КонецЕсли;
ТаблицаСправочника = Запрос.Выполнить().Выгрузить();
Для каждого Строка Из ТаблицаСправочника Цикл
СтруктураНайденных = Новый Структура;
Для каждого КлючИЗначение Из СтруктураИсходныхРеквизитов Цикл
СтепеньСхожести = КлючИЗначение.Значение.СтепеньСхожести;
Если СтепеньСхожести = "=" Тогда
ИмяРеквизита = КлючИЗначение.Ключ;
ЗначениеРеквизита = КлючИЗначение.Значение.ЗначениеРеквизита;
//Поиск по равному значению
Если ЗначениеРеквизита = Строка[ИмяРеквизита] Тогда
СтруктураНайденных.Вставить(ИмяРеквизита);
КонецЕсли;
ИначеЕсли Не СтепеньСхожести = Неопределено Тогда
ИмяРеквизита = КлючИЗначение.Ключ;
//Поиск по похожим словам
СписокИскомыхСлов = КлючИЗначение.Значение.СписокСлов.Скопировать();
СписокНайденыхСлов = ПолучитьСписокСлов(Строка[ИмяРеквизита]);
Если Не ПроверитьСловаНаОтличие(СписокИскомыхСлов,СписокНайденыхСлов,СтепеньСхожести) Тогда
СтруктураНайденных.Вставить(ИмяРеквизита);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Не СтруктураНайденных.Количество()=0 Тогда
НоваяСтрока = НайденныеОбъекты.Добавить();
НоваяСтрока.Ссылка = Строка.Ссылка;
Для каждого КлючИЗначение Из СтруктураПоиска Цикл
ИмяРеквизита = КлючИЗначение.Ключ;
НоваяСтрока[ИмяРеквизита] = Строка[ИмяРеквизита];
НоваяСтрока[ИмяРеквизита+"_Флаг"] = СтруктураНайденных.Свойство(ИмяРеквизита);
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат НайденныеОбъекты;
КонецФункции // ()
// Заменяемые - Соответствие, Массив строк таблицы
// ТаблицаСсылающихсяОбъектов - ТаблицаЗначений, *Неопределено - таблица ссылающихся объектов возвращаемая методом НайтиПоСсылкам или ее часть
// ЗамещениеВсегда - Число - замещение к ключах независимых регистров сведений, 1 - замещать, 0 - спрашивать (на клиенте) или пропускать
//
Функция ВыполнитьЗаменуЭлементов(Заменяемые, ТаблицаСсылающихсяОбъектов = Неопределено, Знач ЗаголовокИндикации = "", ЗамещениеВсегда = 0) Экспорт
//Если ТранзакцияАктивна() Тогда
// ВызватьИсключение "Замена ссылок не допускается в общей транзакции";
//КонецЕсли;
БылиИсключения = Ложь;
Параметры = Новый Структура;
Параметры.Вставить("Объект", Неопределено);
СтруктураКоллизий = Новый Структура;
ИзмененныеПроведенныеДокументы.Очистить();
Если ТаблицаСсылающихсяОбъектов = Неопределено Тогда
СписокСсылок = Новый Массив;
Для Каждого КлючИЗначение Из Заменяемые Цикл
СписокСсылок.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
ТаблицаСсылающихсяОбъектов = НайтиПоСсылкам(СписокСсылок);
КонецЕсли;
РодителиПравильных = Новый Соответствие;
Для Каждого КлючИЗначение Из Заменяемые Цикл
ОбъектМД = Метаданные.НайтиПоТипу(ТипЗнч(КлючИЗначение.Ключ));
Если ОбъектМД = Неопределено Тогда
ВызватьИсключение "Не найден объект метаданных по типу";
КонецЕсли;
Если ирОбщий.ЛиМетаданныеИерархическогоОбъектаЛкс(ОбъектМД) Тогда
МассивРодителей = Новый Массив;
Родитель = КлючИЗначение.Значение;
Если ТипЗнч(Родитель) = Тип("Структура") Тогда
Родитель = Родитель.Значение;
КонецЕсли;
Пока ЗначениеЗаполнено(Родитель) Цикл
МассивРодителей.Добавить(Родитель);
Родитель = Родитель.Родитель;
КонецЦикла;
РодителиПравильных[КлючИЗначение.Значение] = МассивРодителей;
КонецЕсли;
КонецЦикла;
Если ТаблицаСсылающихсяОбъектов.Количество() > 0 Тогда
Если Не ЗначениеЗаполнено(ЗаголовокИндикации) Тогда
ЗаголовокИндикации = "Замена ссылок";
КонецЕсли;
СтрокаГруппировок = "Метаданные,Данные";
Если ТипЗнч(ТаблицаСсылающихсяОбъектов) = Тип("ТаблицаЗначений") Тогда
СсылающиесяОбъекты = ТаблицаСсылающихсяОбъектов.Скопировать(, СтрокаГруппировок);
Иначе
СсылающиесяОбъекты = ТаблицаСсылающихсяОбъектов.Выгрузить(, СтрокаГруппировок);
КонецЕсли;
СсылающиесяОбъекты.Индексы.Добавить(СтрокаГруппировок);
СсылающиесяОбъекты.Свернуть(СтрокаГруппировок);
СсылающиесяОбъекты.Сортировать(СтрокаГруппировок);
КлючПоиска = Новый Структура("Данные");
Если мСервисныйПроцессор <> Неопределено Тогда
Индикатор = мСервисныйПроцессор.ПолучитьИндикаторПроцесса(СсылающиесяОбъекты.Количество(), ЗаголовокИндикации);
Иначе
Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(СсылающиесяОбъекты.Количество(), ЗаголовокИндикации);
КонецЕсли;
ТранзакцииРазрешены = Истина;
Если Истина
И ЗаписьНаСервере
И ирКэш.ЛиПортативныйРежимЛкс()
И Не ирПортативный.ЛиСерверныйМодульДоступенЛкс(Ложь)
И ирПортативный.ЭмуляцияЗаписиНаСервере
Тогда
Сообщить("В режиме эмуляции записи на сервере транзакции не поддерживаются");
ТранзакцииРазрешены = Ложь;
ОбщаяТранзакция = Ложь;
КонецЕсли;
Если ОбщаяТранзакция Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
Для Каждого ОписаниеОбъекта Из СсылающиесяОбъекты Цикл
Если мСервисныйПроцессор <> Неопределено Тогда
мСервисныйПроцессор.ОбновитьИндикатор(Индикатор);
Иначе
ирОбщий.ОбработатьИндикаторЛкс(Индикатор);
КонецЕсли;
ОбъектИзменен = Ложь;
Если ТипЗнч(ОписаниеОбъекта.Данные) = Тип("Строка") Тогда
ОбъектСодержащийСсылку = ЗначениеИзСтрокиВнутр(ОписаниеОбъекта.Данные);
Иначе
ОбъектСодержащийСсылку = ОписаниеОбъекта.Данные;
КонецЕсли;
Если ТипЗнч(ОписаниеОбъекта.Метаданные) = Тип("Строка") Тогда
//ОбъектМД = Метаданные.НайтиПоПолномуИмени(ОписаниеОбъекта.Метаданные);
ОбъектМД = мПлатформа.ПолучитьОбъектМДПоПолномуИмени(ОписаниеОбъекта.Метаданные);
Иначе
ОбъектМД = ОписаниеОбъекта.Метаданные;
КонецЕсли;
Если КомментироватьЗаменуСсылок Тогда
Сообщить("Обрабатывается " + ОбъектСодержащийСсылку);
КонецЕсли;
ПолноеИмяМД = ОбъектМД.ПолноеИмя();
ТипТаблицы = ирОбщий.ПолучитьТипТаблицыБДЛкс(ПолноеИмяМД);
ЗаполнитьЗначенияСвойств(КлючПоиска, ОписаниеОбъекта);
СсылкиВОбъектеНаНеправильныеЭлементы = ТаблицаСсылающихсяОбъектов.НайтиСтроки(КлючПоиска);
НеправильныеСсылкиВОбъекте = Новый Массив;
Для Каждого СтрокаНеправильнойСсылки Из СсылкиВОбъектеНаНеправильныеЭлементы Цикл
НеправильныеСсылкиВОбъекте.Добавить(СтрокаНеправильнойСсылки.Ссылка);
КонецЦикла;
Если ирОбщий.ЛиКорневойТипСсылочногоОбъектаБДЛкс(ТипТаблицы) Тогда
Если ТранзакцииРазрешены Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
ирОбщий.ЗаблокироватьСсылкуВТранзакцииЛкс(ОбъектСодержащийСсылку, Истина);
ОбъектБД = ОбъектСодержащийСсылку.ПолучитьОбъект();
Если ОбъектБД <> Неопределено Тогда
Для Каждого НеправильнаяСсылка Из НеправильныеСсылкиВОбъекте Цикл
ОбъектИзменен = ЗаменитьЗначениеВОбъектеБДЛкс(ОбъектБД, НеправильнаяСсылка, Заменяемые[НеправильнаяСсылка], РодителиПравильных[Заменяемые[НеправильнаяСсылка]]) Или ОбъектИзменен;
КонецЦикла;
КонецЕсли;
ЗаписатьОбъектЕслиИзменен(ОбъектБД, БылиИсключения, ОбъектИзменен, ОбъектМД);
Если ТранзакцииРазрешены Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ТранзакцииРазрешены Тогда
ОтменитьТранзакцию();
КонецЕсли;
БылиИсключения = Истина;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(ОбъектСодержащийСсылку) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
Если Не БылиИсключения Тогда
Если Метаданные.Документы.Содержит(ОбъектМД) Тогда
Для Каждого Движение ИЗ ОбъектМД.Движения Цикл
НаборЗаписей = Новый (СтрЗаменить(Движение.ПолноеИмя(), ".", "НаборЗаписей."));
НаборЗаписей.Отбор.Регистратор.Установить(ОбъектСодержащийСсылку);
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(НаборЗаписей, Заменяемые, НеправильныеСсылкиВОбъекте, ТранзакцииРазрешены);
КонецЦикла;
Для Каждого Последовательность ИЗ Метаданные.Последовательности Цикл
Если Последовательность.Документы.Содержит(ОбъектМД) Тогда
НаборЗаписей = Новый (СтрЗаменить(Последовательность.ПолноеИмя(), ".", "НаборЗаписей."));
НаборЗаписей.Отбор.Регистратор.Установить(ОбъектСодержащийСсылку);
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(НаборЗаписей, Заменяемые, НеправильныеСсылкиВОбъекте, ТранзакцииРазрешены);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
ИначеЕсли ирОбщий.ЛиКорневойТипКонстантыЛкс(ТипТаблицы) Тогда
Если ТранзакцииРазрешены Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
ОбъектБД = Константы[ОбъектМД.Имя].СоздатьМенеджерЗначения();
ирОбщий.ЗаблокироватьКонстантуЛкс(ОбъектБД, Истина);
ОбъектБД.Прочитать();
НовоеЗначение = Заменяемые[ОбъектБД.Значение];
Если НовоеЗначение <> Неопределено Тогда
ОбъектБД.Значение = НовоеЗначение;
ОбъектИзменен = Истина;
КонецЕсли;
Если ТранзакцииРазрешены Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ТранзакцииРазрешены Тогда
ОтменитьТранзакцию();
КонецЕсли;
БылиИсключения = Истина;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(ОбъектБД) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
ИначеЕсли ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ТипТаблицы) Тогда
МассивИзмененныхИзмерений = Новый Массив;
МенеджерЗаписи = РегистрыСведений[ОбъектМД.Имя].СоздатьМенеджерЗаписи();
КоллизийныйМенеджерЗаписи = РегистрыСведений[ОбъектМД.Имя].СоздатьМенеджерЗаписи();
Если ТранзакцииРазрешены Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
БылаКоллизия = Ложь;
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ОбъектСодержащийСсылку);
ЗаполнитьЗначенияСвойств(КоллизийныйМенеджерЗаписи, ОбъектСодержащийСсылку);
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(ОбъектМД);
НаборЗаписей = ирОбщий.ПолучитьНаборЗаписейПоКлючуЛкс(ИмяТаблицыРегистра, ОбъектСодержащийСсылку);
ирОбщий.ЗаблокироватьНаборЗаписейПоОтборуЛкс(НаборЗаписей, Истина);
КоллизийныйМенеджерЗаписи.Прочитать();
Если КоллизийныйМенеджерЗаписи.Выбран() Тогда
ПоляТаблицыБД = ирОбщий.ПолучитьПоляТаблицыМДЛкс(ПолноеИмяМД);
ОбъектИзменен = ВыполнитьЗаменуВСтрокеНабораЗаписей(КоллизийныйМенеджерЗаписи, Заменяемые, ПоляТаблицыБД);
Если Не БылиИсключения И ОбъектИзменен Тогда
Для каждого МетаИзмерение Из ОбъектМД.Измерения Цикл
Если КоллизийныйМенеджерЗаписи[МетаИзмерение.Имя] <> ОбъектСодержащийСсылку[МетаИзмерение.Имя] Тогда
МассивИзмененныхИзмерений.Добавить(МетаИзмерение.Имя);
КонецЕсли;
КонецЦикла;
Если МассивИзмененныхИзмерений.Количество() > 0 Тогда
НаборЗаписей = ирОбщий.ПолучитьНаборЗаписейПоКлючуЛкс(ИмяТаблицыРегистра, КоллизийныйМенеджерЗаписи);
ирОбщий.ЗаблокироватьНаборЗаписейПоОтборуЛкс(НаборЗаписей, Истина);
КоллизийныйМенеджерЗаписи.Прочитать();
Если КоллизийныйМенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.Прочитать();
МассивКоллекцийРеквизитов = Новый Массив;
МассивКоллекцийРеквизитов.Добавить(ОбъектМД.Ресурсы);
МассивКоллекцийРеквизитов.Добавить(ОбъектМД.Реквизиты);
Если Не СтруктураКоллизий.Свойство(ОбъектМД.Имя) Тогда
ТаблицаЗаписей = РегистрыСведений[ОбъектМД.Имя].СоздатьНаборЗаписей().Выгрузить();
ТаблицаЗаписей.Колонки.Добавить("МенеджерЗамены");
ТаблицаЗаписей.Колонки.Добавить("МенеджерОригинала");
Для Каждого КоллекцияРеквизитов Из МассивКоллекцийРеквизитов Цикл
Для Каждого МетаРеквизит Из КоллекцияРеквизитов Цикл
ИмяКолонки = МетаРеквизит.Имя;
ПредставлениеКолонки = МетаРеквизит.Представление();
КолонкаОригинала = ТаблицаЗаписей.Колонки[ИмяКолонки];
КолонкаОригинала.Имя = "Оригинал" + ИмяКолонки;
КолонкаОригинала.Заголовок = "Оригинал: " + ПредставлениеКолонки;
КолонкаЗамены = ТаблицаЗаписей.Колонки.Вставить(ТаблицаЗаписей.Колонки.Индекс(КолонкаОригинала),
"Замена" + ИмяКолонки, , "Замена: " + ПредставлениеКолонки);
ЗаполнитьЗначенияСвойств(КолонкаЗамены, КолонкаОригинала, , "Имя, Заголовок");
КонецЦикла;
КонецЦикла;
ТаблицаЗаписей.Колонки.Вставить(0, "Заменить", Новый ОписаниеТипов("Булево"), "Заменить");
СтруктураКоллизий.Вставить(ОбъектМД.Имя, ТаблицаЗаписей);
КонецЕсли;
НоваяКоллизийнаяЗапись = СтруктураКоллизий[ОбъектМД.Имя].Добавить();
Для Каждого КоллекцияРеквизитов Из МассивКоллекцийРеквизитов Цикл
Для Каждого МетаРеквизит Из КоллекцияРеквизитов Цикл
ИмяКолонки = МетаРеквизит.Имя;
ЗначениеРеквизита = МенеджерЗаписи[ИмяКолонки];
НоваяКоллизийнаяЗапись["Оригинал" + ИмяКолонки] = КоллизийныйМенеджерЗаписи[ИмяКолонки];
ЗаменаЗначения = Заменяемые[ЗначениеРеквизита];
Если ЗаменаЗначения <> Неопределено Тогда
НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки] = ЗаменаЗначения;
Иначе
НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки] = ЗначениеРеквизита;
КонецЕсли;
КоллизийныйМенеджерЗаписи[ИмяКолонки] = НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки];
Если НоваяКоллизийнаяЗапись["Оригинал" + ИмяКолонки] <> НоваяКоллизийнаяЗапись["Замена" + ИмяКолонки] Тогда
БылаКоллизия = Истина;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если БылаКоллизия И ЗамещениеВсегда <> 1 Тогда
ЗаполнитьЗначенияСвойств(НоваяКоллизийнаяЗапись, КоллизийныйМенеджерЗаписи);
Для Каждого ИмяКолонки Из МассивИзмененныхИзмерений Цикл
НоваяКоллизийнаяЗапись[ИмяКолонки] = МенеджерЗаписи[ИмяКолонки];
КонецЦикла;
НоваяКоллизийнаяЗапись.МенеджерЗамены = КоллизийныйМенеджерЗаписи;
НоваяКоллизийнаяЗапись.МенеджерОригинала = МенеджерЗаписи;
Иначе
СтруктураКоллизий[ОбъектМД.Имя].Удалить(НоваяКоллизийнаяЗапись);
МенеджерЗаписи.Удалить();
БылаКоллизия = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если БылаКоллизия Тогда
БылиИсключения = Ложь;
Иначе
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(МенеджерЗаписи, Заменяемые, НеправильныеСсылкиВОбъекте);
КонецЕсли;
Если ТранзакцииРазрешены Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ТранзакцииРазрешены Тогда
ОтменитьТранзакцию();
КонецЕсли;
БылиИсключения = Истина;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(НаборЗаписей) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
Иначе
БылиИсключения = Истина;
Сообщить("Замена ссылок в объектах типа " + ОбъектМД.ПолноеИмя() + " не поддерживается");
КонецЕсли;
КонецЦикла;
Если ОбщаяТранзакция Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если ОбщаяТранзакция Тогда
ОтменитьТранзакцию();
КонецЕсли;
ВызватьИсключение;
КонецПопытки;
Если мСервисныйПроцессор <> Неопределено Тогда
мСервисныйПроцессор.ОсвободитьИндикаторПроцесса(Индикатор, Истина);
Иначе
ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор, Истина);
КонецЕсли;
КонецЕсли;
МассивЭлементовКУдалению = Новый Массив;
Для Каждого ЭлементТаблицыРегистра Из СтруктураКоллизий Цикл
Если ЭлементТаблицыРегистра.Значение.Количество() = 0 Тогда
МассивЭлементовКУдалению.Добавить(ЭлементТаблицыРегистра.Ключ);
КонецЕсли;
КонецЦикла;
Для Каждого ЭлементКУдалению Из МассивЭлементовКУдалению Цикл
СтруктураКоллизий.Удалить(ЭлементКУдалению);
КонецЦикла;
Если СтруктураКоллизий.Количество() > 0 Тогда
Если ЗамещениеВсегда = 1 Тогда
ЗамещатьВЭтотРаз = Истина;
Иначе
#Если Клиент Тогда
ФормаЗамещенияВНезависимыхРегистрахСведений = ПолучитьФорму("ФормаЗамещенияВНезависимыхРегистрахСведений");
ФормаЗамещенияВНезависимыхРегистрахСведений.КодВсегда = ЗамещениеВсегда;
ФормаЗамещенияВНезависимыхРегистрахСведений.СтруктураКоллизий = СтруктураКоллизий;
ФормаЗамещенияВНезависимыхРегистрахСведений.ОткрытьМодально();
ЗамещениеВсегда = ФормаЗамещенияВНезависимыхРегистрахСведений.КодВсегда;
ЗамещатьВЭтотРаз = ФормаЗамещенияВНезависимыхРегистрахСведений.РезультатФормы;
#Иначе
ЗамещатьВЭтотРаз = Ложь;
#КонецЕсли
КонецЕсли;
Если ЗамещатьВЭтотРаз Тогда
Для Каждого ЭлементРегистра Из СтруктураКоллизий Цикл
Для Каждого СтрокаЗаписи Из ЭлементРегистра.Значение Цикл
Если СтрокаЗаписи.Заменить Тогда
СтрокаЗаписи.МенеджерЗамены.Записать();
КонецЕсли;
СтрокаЗаписи.МенеджерОригинала.Удалить();
КонецЦикла;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Возврат Не БылиИсключения;
КонецФункции
Процедура ЗаписатьОбъектЕслиИзменен(ОбъектБД, БылиИсключения, ОбъектИзменен, ОбъектМД)
Если ОбъектБД <> Неопределено Тогда
//Если Объект.Модифицированность() Тогда
Если ОбъектИзменен Тогда
Попытка
ирОбщий.ЗаписатьОбъектЛкс(ОбъектБД, ЗаписьНаСервере,,, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
//Если ОтключатьКонтрольЗаписи Тогда
// ЗаписьЖурналаРегистрации("Запись с флагом Загрузка", УровеньЖурналаРегистрации.Информация, ОбъектМД,
// ОбъектСодержащийСсылку, "");
//КонецЕсли;
Исключение
Сообщить(ОписаниеОшибки(), СтатусСообщения.Важное);
БылиИсключения = Истина;
ОбъектИзменен = Ложь;
КонецПопытки;
Если Истина
И ОбъектИзменен
И Метаданные.Документы.Содержит(ОбъектМД)
И ОбъектМД.Проведение = Метаданные.СвойстваОбъектов.Проведение.Разрешить
И ОбъектБД.Проведен
Тогда
СтрокаДляДокумента = ИзмененныеПроведенныеДокументы.Добавить();
СтрокаДляДокумента.ДатаДокумента = ОбъектБД.Дата;
СтрокаДляДокумента.ТипДокумента = ОбъектМД.Имя;
СтрокаДляДокумента.Документ = ОбъектБД.Ссылка;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры // ВыполнитьЗаменуЭлементов()
// Ищет все экземпляры значения ЧтоЗаменять в объекте и заменяет их на НаЧтоЗаменять
Функция ЗаменитьЗначениеВОбъектеБДЛкс(Объект, ЧтоЗаменять, НаЧтоЗаменять, РодителиПравильного = Неопределено)
ОбъектМД = Объект.Метаданные();
ПолноеИмяМД = ОбъектМД.ПолноеИмя();
ПоляТаблицыБД = ирОбщий.ПолучитьПоляТаблицыМДЛкс(ПолноеИмяМД);
#Если Сервер И Не Сервер Тогда
ПоляТаблицыБД = ПолучитьСтруктуруХраненияБазыДанных().Колонки;
#КонецЕсли
ОбъектИзменен = Ложь;
Для Каждого ПолеТаблицыБД Из ПоляТаблицыБД Цикл
Если ПолеТаблицыБД.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений")) Тогда
Попытка
ТабличнаяЧасть = Объект[ПолеТаблицыБД.Имя];
Исключение
// Сюда например попадаем в случае системной папки СистемныеПоля
ТабличнаяЧасть = Неопределено;
КонецПопытки;
Если ТабличнаяЧасть <> Неопределено Тогда
МетаТЧ = ОбъектМД.ТабличныеЧасти[ПолеТаблицыБД.Имя];
ПоляТаблицыТЧ = ирОбщий.ПолучитьПоляТаблицыМДЛкс(МетаТЧ.ПолноеИмя());
Для Каждого КолонкаТЧ Из ТабличнаяЧасть.Выгрузить().Колонки Цикл
ИмяРеквизита = КолонкаТЧ.Имя;
Если КолонкаТЧ.ТипЗначения.СодержитТип(ТипЗнч(ЧтоЗаменять)) Тогда
СтрокиТабЧасти = ТабличнаяЧасть.НайтиСтроки(Новый Структура(ИмяРеквизита, ЧтоЗаменять));
Для Каждого СтрокаТабЧасти Из СтрокиТабЧасти Цикл
ОбъектИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтрокаТабЧасти, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыТЧ) Или ОбъектИзменен;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Иначе
ИмяРеквизита = "" + ПолеТаблицыБД.Имя;
Если ирОбщий.СтрокиРавныЛкс(ИмяРеквизита, "Ссылка") Тогда
Продолжить;
КонецЕсли;
Если ПолеТаблицыБД.ТипЗначения.СодержитТип(ТипЗнч(ЧтоЗаменять)) И Объект[ИмяРеквизита] = ЧтоЗаменять Тогда
Если Истина
И РодителиПравильного <> Неопределено
И ирОбщий.СтрокиРавныЛкс(ПолеТаблицыБД.Имя, "Родитель")
И РодителиПравильного.Найти(Объект.Ссылка) <> Неопределено
Тогда
// Вместо зацикливания уровней иерархии поднимаем до ближайшего корректного родителя
лНаЧтоЗаменять = ЧтоЗаменять.Родитель;
Пока РодителиПравильного.Найти(лНаЧтоЗаменять) <> Неопределено Цикл
лНаЧтоЗаменять = лНаЧтоЗаменять.Родитель;
КонецЦикла;
Сообщить("Родитель объекта """ + Объект + """ был заменен на """ + лНаЧтоЗаменять + """ для избежания зацикливания уровней");
Иначе
лНаЧтоЗаменять = НаЧтоЗаменять;
КонецЕсли;
ОбъектИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(Объект, ИмяРеквизита, лНаЧтоЗаменять, ПоляТаблицыБД) Или ОбъектИзменен;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат ОбъектИзменен;
КонецФункции
// Результат - Булево - была ли выполнена замена
Функция ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтрокаТаблицы, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыБД)
ОбъектНеИзменен = Истина;
ПолнаяЗаменаВозможна = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицы, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыБД, , Истина);
Если ПолнаяЗаменаВозможна Тогда
ОбъектНеИзменен = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицы, ИмяРеквизита, НаЧтоЗаменять, ПоляТаблицыБД, , Ложь);
КонецЕсли;
Возврат Не ОбъектНеИзменен;
КонецФункции
// Результат - Булево
// Если ТолькоПроверитьВозможность = Истина, то содержит успешность полной замены
// Если ТолькоПроверитьВозможность = Ложь, то содержит факт отсутствия изменения объекта
Функция ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицыБД, ИмяРеквизита, Знач НаЧтоЗаменять, ПоляТаблицыБД, ПравилаЗаменыЗависимых = Неопределено,
ТолькоПроверитьВозможность = Истина, ИмяРеквизитаОтбора = "Ссылка", ИсключитьЗависимое = "", ИсключитьВлияющее = "")
Результат = Истина;
Если ТипЗнч(НаЧтоЗаменять) = Тип("Структура") Тогда
ПравилаЗаменыЗависимых = НаЧтоЗаменять.ПравилаЗависимых;
НаЧтоЗаменять = НаЧтоЗаменять.Значение;
КонецЕсли;
ЧтоЗаменять = СтрокаТаблицыБД[ИмяРеквизита];
Если ТипЗнч(ЧтоЗаменять) = Тип("ЭлементОтбора") Тогда
ЧтоЗаменять = ЧтоЗаменять.Значение;
КонецЕсли;
Если ЧтоЗаменять = НаЧтоЗаменять Тогда
Возврат Результат;
КонецЕсли;
Если ПравилаЗаменыЗависимых <> Неопределено Тогда
ПолеТаблицы = ПоляТаблицыБД.Найти(ИмяРеквизита, "Имя");
ДанныеДляПоискаСвязейПоВладельцу = Неопределено;
Если ОпределятьСвязьПоВладельцуПоДанным Тогда
ДанныеДляПоискаСвязейПоВладельцу = СтрокаТаблицыБД;
КонецЕсли;
Если ПолеТаблицы.Метаданные <> Неопределено Тогда
СвязиПараметровВыбора = Новый Массив(ПолеТаблицы.Метаданные.СвязиПараметровВыбора);
Если ОпределятьСвязьПоВладельцуПоДанным Тогда
Попытка
ЗначениеВладельца = ЧтоЗаменять.Владелец;
Исключение
ЗначениеВладельца = Неопределено;
КонецПопытки;
Если ЗначениеЗаполнено(ЗначениеВладельца) Тогда
Для Каждого ПолеТаблицыБДВладельца Из ПоляТаблицыБД Цикл
Попытка
ЗначениеПоляВладельца = ДанныеДляПоискаСвязейПоВладельцу[ПолеТаблицыБДВладельца.Имя];
Исключение
// Ссылка у строки ТЧ
Продолжить;
КонецПопытки;
Если ТипЗнч(ЗначениеПоляВладельца) = Тип("ЭлементОтбора") Тогда
ЗначениеПоляВладельца = ЗначениеПоляВладельца.Значение;
КонецЕсли;
Если ЗначениеПоляВладельца = ЗначениеВладельца Тогда
СвязиПараметровВыбора.Добавить(Новый Структура("Имя, ПутьКДанным", "Отбор.Владелец", ПолеТаблицыБДВладельца.Имя));
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
УжеОбработанныеРеквизиты = Новый Структура;
Для Каждого СвязьПараметровВыбора Из СвязиПараметровВыбора Цикл
ИмяРеквизитаСодежащегоВлияющее = СвязьПараметровВыбора.ПутьКДанным;
ИмяРеквизитаСодежащегоВлияющее = ирОбщий.ПолучитьПоследнийФрагментЛкс(ИмяРеквизитаСодежащегоВлияющее);
Если ИсключитьВлияющее = ИмяРеквизитаСодежащегоВлияющее Тогда
Продолжить;
КонецЕсли;
ИмяРеквизитаОтбора = СтрЗаменить(СвязьПараметровВыбора.Имя, "Отбор.", "");
Если УжеОбработанныеРеквизиты.Свойство(ИмяРеквизитаОтбора) Тогда
Продолжить;
КонецЕсли;
УжеОбработанныеРеквизиты.Вставить(ИмяРеквизитаОтбора);
ВлияющееЗначениеЧтоЗаменять = ЧтоЗаменять[ИмяРеквизитаОтбора];
ВлияющееЗначениеНаЧтоЗаменять = НаЧтоЗаменять[ИмяРеквизитаОтбора];
Если ВлияющееЗначениеЧтоЗаменять <> ВлияющееЗначениеНаЧтоЗаменять Тогда
Результат = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицыБД, ИмяРеквизитаСодежащегоВлияющее, ВлияющееЗначениеНаЧтоЗаменять, ПоляТаблицыБД,
ПравилаЗаменыЗависимых, ТолькоПроверитьВозможность, ИмяРеквизитаОтбора, ИмяРеквизита) И Результат;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ЗависимыеРеквизиты = ПолучитьЗависимыеРеквизитыМД(ПоляТаблицыБД, ИмяРеквизита, ДанныеДляПоискаСвязейПоВладельцу);
Для Каждого КлючИЗначение Из ЗависимыеРеквизиты Цикл
Если ИсключитьЗависимое = КлючИЗначение.Ключ Тогда
Продолжить;
КонецЕсли;
ЗависимоеЗначение = СтрокаТаблицыБД[КлючИЗначение.Ключ];
Если ТипЗнч(ЗависимоеЗначение) = Тип("ЭлементОтбора") Тогда
ЗависимоеЗначение = ЗависимоеЗначение.Значение;
КонецЕсли;
Если Не ЗначениеЗаполнено(ЗависимоеЗначение) Тогда
Продолжить;
КонецЕсли;
КлючПоискаПравила = Новый Структура("ПутьКДаннымВлияющего, ТипЗначения, ЧтоЗаменять, ЗависимоеВлияющее, ВлияющееЧтоЗаменять",
ИмяРеквизитаОтбора, Новый (ТипЗнч(ЗависимоеЗначение)), ЗависимоеЗначение, КлючИЗначение.Значение, ЧтоЗаменять);
ПравилаЗаменыЗависимого = ПравилаЗаменыЗависимых.НайтиСтроки(КлючПоискаПравила);
Если ПравилаЗаменыЗависимого.Количество() > 0 Тогда
ПравилоЗаменыЗависимого = ПравилаЗаменыЗависимого[0];
Если ПравилоЗаменыЗависимого.Пометка Тогда
Результат = ЗаменитьЗначениеРеквизитаСВлияющимиИЗависимыми(СтрокаТаблицыБД, КлючИЗначение.Ключ, ПравилоЗаменыЗависимого.НаЧтоЗаменять, ПоляТаблицыБД,
ПравилаЗаменыЗависимых, ТолькоПроверитьВозможность, ПравилоЗаменыЗависимого.ЗависимоеВлияющее,, ИмяРеквизита) И Результат;
Иначе
Результат = Ложь;
КонецЕсли;
Иначе
ПравилоЗаменыЗависимого = ПравилаЗаменыЗависимых.Добавить();
ЗаполнитьЗначенияСвойств(ПравилоЗаменыЗависимого, КлючПоискаПравила);
Результат = Ложь;
КонецЕсли;
ПравилоЗаменыЗависимого.НайденоСтрок = ПравилоЗаменыЗависимого.НайденоСтрок + 1;
ПравилоЗаменыЗависимого.Требуется = Истина;
КонецЦикла;
КонецЕсли;
Если Не ТолькоПроверитьВозможность Тогда
Если ТипЗнч(СтрокаТаблицыБД[ИмяРеквизита]) = Тип("ЭлементОтбора") Тогда
Результат = Не ирОбщий.БезопасноПрисвоитьПроизвольнуюСсылкуЛкс(СтрокаТаблицыБД[ИмяРеквизита].Значение, НаЧтоЗаменять) И Результат;
Иначе
Результат = Не ирОбщий.БезопасноПрисвоитьПроизвольнуюСсылкуЛкс(СтрокаТаблицыБД[ИмяРеквизита], НаЧтоЗаменять) И Результат;
КонецЕсли;
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ВыполнитьЗаменуВНабореЗаписей(НаборЗаписейИлиМенеджерЗаписи, Заменяемые, НеправильныеСсылкиВОбъекте, Блокировать = Истина)
ОбъектМД = ирОбщий.ПолучитьМетаданныеЛкс(НаборЗаписейИлиМенеджерЗаписи);
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(ОбъектМД);
Если ирОбщий.ЛиМенеджерЗаписиРегистраЛкс(НаборЗаписейИлиМенеджерЗаписи) Тогда
НаборЗаписей = ирОбщий.ПолучитьНаборЗаписейПоКлючуЛкс(ИмяТаблицыРегистра, НаборЗаписейИлиМенеджерЗаписи);
Иначе
НаборЗаписей = НаборЗаписейИлиМенеджерЗаписи;
КонецЕсли;
Если Блокировать Тогда
НачатьТранзакцию();
КонецЕсли;
Попытка
Если Блокировать Тогда
ирОбщий.ЗаблокироватьНаборЗаписейПоОтборуЛкс(НаборЗаписей, Истина);
КонецЕсли;
ТипТаблицы = ирОбщий.ПолучитьТипТаблицыБДЛкс(ИмяТаблицыРегистра);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() = 0 Тогда
Если Блокировать Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Возврат Истина;
КонецЕсли;
ПоляТаблицыБД = ирОбщий.ПолучитьПоляТаблицыМДЛкс(ОбъектМД);
#Если Сервер И Не Сервер Тогда
ПоляТаблицыБД = ПолучитьСтруктуруХраненияБазыДанных().Колонки;
#КонецЕсли
// Старый пустой набор нужен для очистки строк по старому отбору в случае изменения отбора набора
СтарыйНабор = ирОбщий.СоздатьНаборЗаписейПоИмениТаблицыБДЛкс(ИмяТаблицыРегистра);
ирОбщий.СкопироватьОтборЛкс(СтарыйНабор.Отбор, НаборЗаписей.Отбор);
ОтборИзменен = Ложь;
Для Каждого ЭлементОтбора Из НаборЗаписей.Отбор Цикл
ЗначениеПоля = ЭлементОтбора.Значение;
НаЧтоЗаменять = Заменяемые[ЗначениеПоля];
Если НаЧтоЗаменять = Неопределено Тогда
Продолжить;
КонецЕсли;
ОтборИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(НаборЗаписей.Отбор, ЭлементОтбора.Имя, НаЧтоЗаменять, ПоляТаблицыБД) Или ОтборИзменен;
КонецЦикла;
ОбъектИзменен = ОтборИзменен; // Антибаг платформы 8.2. При изменении реквизитов строк набора записей для регистра бухгалтерии не взводится модифицированность
ЭтоРегистрБухгалтерии = ирОбщий.ПолучитьПервыйФрагментЛкс(ИмяТаблицыРегистра) = "РегистрБухгалтерии";
Если ЭтоРегистрБухгалтерии Тогда
ТаблицаНабора = НаборЗаписей.Выгрузить();
Иначе
ТаблицаНабора = НаборЗаписей;
КонецЕсли;
Для Каждого СтрокаНабора Из ТаблицаНабора Цикл
ОбъектИзменен = ВыполнитьЗаменуВСтрокеНабораЗаписей(СтрокаНабора, Заменяемые, ПоляТаблицыБД) Или ОбъектИзменен;
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
КонецЦикла;
Если ЭтоРегистрБухгалтерии Тогда
НаборЗаписей.Загрузить(ТаблицаНабора);
ирОбщий.НаборЗаписейПослеЗагрузкиИзТаблицыЗначенийЛкс(НаборЗаписей);
ИначеЕсли ТипТаблицы = "РегистрСведений" И ОбъектМД.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору Тогда
// Избавимся от неуникальных строк набора
Если НаборЗаписей.Количество() > 1 Тогда
СтруктураКлюча = ирОбщий.ПолучитьСтруктуруКлючаТаблицыБДЛкс(ИмяТаблицыРегистра,,, Ложь);
СтрокаПолейКлюча = "";
Для Каждого КлючИЗначение Из СтруктураКлюча Цикл
СтрокаПолейКлюча = СтрокаПолейКлюча + "," + КлючИЗначение.Ключ;
КонецЦикла;
СтрокаПолейКлюча = Сред(СтрокаПолейКлюча, 2);
НеуникальныеКлючи = ирОбщий.ПолучитьНеуникальныеКлючиКолонкиТаблицыЛкс(НаборЗаписей, СтрокаПолейКлюча);
Если НеуникальныеКлючи.Количество() > 0 Тогда
ТаблицаНабора = НаборЗаписей.Выгрузить();
Для Каждого НеуникальныйКлюч Из НеуникальныеКлючи Цикл
СтрокиНеуникальногоКлюча = ТаблицаНабора.НайтиСтроки(НеуникальныйКлюч);
Для ИндексУдаляемойСтроки = 0 По СтрокиНеуникальногоКлюча.Количество() - 2 Цикл
ТаблицаНабора.Удалить(СтрокиНеуникальногоКлюча[ИндексУдаляемойСтроки]);
КонецЦикла;
ПредставлениеСтруктуры = ирОбщий.ПолучитьПредставлениеСтруктурыЛкс(НеуникальныйКлюч);
Сообщить("Замещены неуникальные строки регистра сведений " + ОбъектМД.Имя + " по ключу " + ПредставлениеСтруктуры);
КонецЦикла;
НаборЗаписей.Загрузить(ТаблицаНабора);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ОбъектИзменен Тогда
Если ОтборИзменен Тогда
ирОбщий.ЗаписатьОбъектЛкс(СтарыйНабор, ЗаписьНаСервере,,, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
КонецЕсли;
ирОбщий.ЗаписатьОбъектЛкс(НаборЗаписей, ЗаписьНаСервере,,, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
КонецЕсли;
Если ТипТаблицы = "РегистрРасчета" Тогда
Для Каждого Перерасчет Из ОбъектМД.Перерасчеты Цикл
ИмяТаблицыПерерасчета = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(Перерасчет);
НаборЗаписейПерерасчета = ирОбщий.СоздатьНаборЗаписейПоИмениТаблицыБДЛкс(ИмяТаблицыПерерасчета);
НаборЗаписейПерерасчета.Отбор.ОбъектПерерасчета.Установить(НаборЗаписей.Отбор.Регистратор.Значение);
БылиИсключения = Не ВыполнитьЗаменуВНабореЗаписей(НаборЗаписейПерерасчета, Заменяемые, НеправильныеСсылкиВОбъекте, Ложь);
Если БылиИсключения Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если Блокировать Тогда
ЗафиксироватьТранзакцию();
КонецЕсли;
Исключение
Если Блокировать Тогда
ОтменитьТранзакцию();
КонецЕсли;
Если ОбщаяТранзакция Тогда
ВызватьИсключение;
КонецЕсли;
Сообщить("Ошибка обработки ссылающегося объекта " + ирОбщий.ПолучитьXMLКлючОбъектаБДЛкс(НаборЗаписей) + ": " + ОписаниеОшибки(), СтатусСообщения.Внимание);
Возврат Ложь;
КонецПопытки;
Возврат Истина;
КонецФункции
Функция ВыполнитьЗаменуВСтрокеНабораЗаписей(СтрокаНабора, Заменяемые, ПоляТаблицыБД)
ОбъектИзменен = Ложь;
Для Каждого ПолеТаблицыБД Из ПоляТаблицыБД Цикл
Если ПолеТаблицыБД.ТипЗначения.СодержитТип(Тип("ТаблицаЗначений")) Тогда
Продолжить;
КонецЕсли;
//Если Не Поле.Поле Тогда // было для полей построителя запроса
// // Антибаг платформы. Зачем то добавляются лишние поля в доступные поля, не свойственные по признаку наличия корресподнеции
// // у бухгалтерских таблиц.
// Продолжить;
//КонецЕсли;
//ИмяПоля = Поле.Имя;
ИмяПоля = ПолеТаблицыБД.Имя;
ЗначениеПоля = СтрокаНабора[ИмяПоля];
НаЧтоЗаменять = Заменяемые[ЗначениеПоля];
Если НаЧтоЗаменять = Неопределено Тогда
Продолжить;
КонецЕсли;
ОбъектИзменен = ЗаменитьЗначениеРеквизитаСПроверкойВозможности(СтрокаНабора, ИмяПоля, НаЧтоЗаменять, ПоляТаблицыБД) Или ОбъектИзменен;
КонецЦикла;
Возврат ОбъектИзменен;
КонецФункции
Функция ПолучитьЗависимыеРеквизитыМД(ПоляТаблицы, ИмяРеквизита, ДанныеДляПоискаСвязейПоВладельцу = Неопределено) Экспорт
Результат = Новый Структура;
Для Каждого ПолеТаблицы Из ПоляТаблицы Цикл
Если ПолеТаблицы.Метаданные = Неопределено Тогда
Продолжить;
КонецЕсли;
Для Каждого СвязьПараметровВыбора Из ПолеТаблицы.Метаданные.СвязиПараметровВыбора Цикл
ИмяРеквизитаСодежащегоВлияющее = СвязьПараметровВыбора.ПутьКДанным;
//Если Найти(ИмяРеквизитаСодежащегоВлияющее, ОбъектМД.Имя + ".") = 1 Тогда
// // Это строка ТЧ
ИмяРеквизитаСодежащегоВлияющее = ирОбщий.ПолучитьПоследнийФрагментЛкс(ИмяРеквизитаСодежащегоВлияющее);
//КонецЕсли;
Если ИмяРеквизитаСодежащегоВлияющее = ИмяРеквизита Тогда
ИмяРеквизитаОтбора = СтрЗаменить(СвязьПараметровВыбора.Имя, "Отбор.", "");
Результат.Вставить(ПолеТаблицы.Имя, ИмяРеквизитаОтбора);
КонецЕсли;
КонецЦикла;
Если ДанныеДляПоискаСвязейПоВладельцу <> Неопределено Тогда
Попытка
ЗначениеВладельца = ДанныеДляПоискаСвязейПоВладельцу[ПолеТаблицы.Имя].Владелец;
Исключение
ЗначениеВладельца = Неопределено;
КонецПопытки;
Если ЗначениеВладельца <> Неопределено Тогда
Если ЗначениеВладельца = ДанныеДляПоискаСвязейПоВладельцу[ИмяРеквизита] Тогда
Результат.Вставить(ПолеТаблицы.Имя, "Владелец");
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Функция ОбработатьНеправильныйОбъектПослеЗамены(УдаляемаяСсылка, НепосредственноеУдаление = Ложь, СсылкаДляЗаменыДанных = Неопределено) Экспорт
#Если Сервер И Не Сервер Тогда
УдаляемаяСсылка = Справочники.УчастникиИис.ПустаяСсылка();
#КонецЕсли
Объект = УдаляемаяСсылка.ПолучитьОбъект();
ОбъектУдалили = Объект = Неопределено;
Если Не ОбъектУдалили Тогда
КорневойТип = ирОбщий.ПолучитьКорневойТипКонфигурацииЛкс(УдаляемаяСсылка);
НачатьТранзакцию();
Попытка
ПредставлениеОбъекта = "" + Объект;
Если СсылкаДляЗаменыДанных <> Неопределено Тогда
ПравильныйЭлементСНеправильнымиДанными = СсылкаДляЗаменыДанных.ПолучитьОбъект();
СтандартнаяОбработка = Истина;
Если ЗначениеЗаполнено(ОбработкаЗаменыДанных) Тогда
ТекстАлгоритма = "ПравильныйОбъект = _П0; НеправильныйОбъект = _П1; СтандартнаяОбработка = _П2; " + ОбработкаЗаменыДанных + "; _П2 = СтандартнаяОбработка;";
ирОбщий.ВыполнитьАлгоритм(ТекстАлгоритма,,, ПравильныйЭлементСНеправильнымиДанными, Объект, СтандартнаяОбработка);
КонецЕсли;
Если СтандартнаяОбработка Тогда
НеправильныйОбъектXDTO = СериализаторXDTO.ЗаписатьXDTO(ПравильныйЭлементСНеправильнымиДанными);
НеправильныйОбъектXDTO.Ref = УдаляемаяСсылка;
ПравильныйОбъектXDTO = СериализаторXDTO.ЗаписатьXDTO(Объект);
ПравильныйОбъектXDTO.Ref = СсылкаДляЗаменыДанных;
ПравильныйОбъект = СериализаторXDTO.ПрочитатьXDTO(ПравильныйОбъектXDTO);
Если Истина
И Не ирОбщий.РежимСовместимостиМеньше8_3_4Лкс()
И ирОбщий.ЛиКорневойТипОбъектаСПредопределеннымЛкс(КорневойТип)
И (Ложь
Или Не НепосредственноеУдаление
Или (Истина
И НепосредственноеУдаление
И Не ЗначениеЗаполнено(ПравильныйОбъект.ИмяПредопределенныхДанных)))
Тогда
ПравильныйОбъект.ИмяПредопределенныхДанных = ПравильныйЭлементСНеправильнымиДанными.ИмяПредопределенныхДанных;
КонецЕсли;
Иначе
ПравильныйОбъект = ПравильныйЭлементСНеправильнымиДанными;
КонецЕсли;
ирОбщий.ЗаписатьОбъектЛкс(ПравильныйОбъект, ЗаписьНаСервере, , , Истина);
Если СтандартнаяОбработка Тогда
Объект = СериализаторXDTO.ПрочитатьXDTO(НеправильныйОбъектXDTO);
Объект.Прочитать();
ПредставлениеОбъекта = "" + Объект;
КонецЕсли;
КонецЕсли;
Если НепосредственноеУдаление Тогда
ирОбщий.УдалитьОбъектЛкс(Объект, ЗаписьНаСервере, ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
ОбъектУдалили = Истина;
Сообщить("Удалили """ + ПредставлениеОбъекта + """");
Иначе
ирОбщий.УстановитьПометкуУдаленияОбъектаЛкс(Объект, ЗаписьНаСервере, Истина);
Сообщить("Установили пометку удаления """ + ПредставлениеОбъекта + """");
КонецЕсли;
ЗафиксироватьТранзакцию();
Исключение
Сообщить("Обработка неправильного """ + ПредставлениеОбъекта + """: " + ОписаниеОшибки());
ОтменитьТранзакцию();
КонецПопытки;
КонецЕсли;
Возврат ОбъектУдалили;
КонецФункции
Процедура ОбработатьПравильныйОбъектПослеЗамены(ПравильнаяСсылка, СнятьПометкуУдаления = Ложь, Перезаписать = Ложь) Экспорт
Если Истина
И Не СнятьПометкуУдаления
И Не Перезаписать
Тогда
Возврат;
КонецЕсли;
Объект = ПравильнаяСсылка.ПолучитьОбъект();
Попытка
Если СнятьПометкуУдаления Тогда
Объект.ПометкаУдаления = Ложь;
Сообщить("Сняли пометку удаления """ + Объект + """");
КонецЕсли;
ирОбщий.ЗаписатьОбъектЛкс(Объект, ЗаписьНаСервере, , , ОтключатьКонтрольЗаписи, БезАвторегистрацииИзменений);
Исключение
Сообщить("Обработка правильного """ + Объект + """: " + ОписаниеОшибки(), СтатусСообщения.Внимание);
КонецПопытки;
КонецПроцедуры
Функция ПолучитьСсылочныеИзмеренияРегистраЛкс(НаборЗаписей, МетаРегистр) Экспорт
ПоляТаблицы = НаборЗаписей.ВыгрузитьКолонки();
Результат = Новый Структура;
Для Каждого МетаИзмерение Из МетаРегистр.Измерения Цикл
ПолеТаблицы = ПоляТаблицы.Найти(МетаИзмерение.Имя);
Если ПолеТаблицы = Неопределено Тогда
// Например, небалансовое измерение регистра бухгалтерии
Продолжить;
КонецЕсли;
Для Каждого Тип Из МетаИзмерение.Тип.Типы() Цикл
Если Найти(XMLТип(Тип).ИмяТипа, "Ref.") > 0 Тогда
Результат.Вставить(МетаИзмерение.Имя, МетаИзмерение.Тип);
Прервать;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ЗаблокироватьРегистрПоОтборуИИзмерениямПередЗаменой(НаборЗаписей, НайденныеВОбъектеНеправильныеСсылки) Экспорт
Блокировка = Новый БлокировкаДанных;
ОбъектМД = НаборЗаписей.Метаданные();
ПолноеИмяМД = ОбъектМД.ПолноеИмя();
ИмяТаблицыРегистра = ирОбщий.ПолучитьИмяТаблицыИзМетаданныхЛкс(ОбъектМД);
ТипТаблицы = ирОбщий.ПолучитьТипТаблицыБДЛкс(ИмяТаблицыРегистра);
// По регистратору
Если Ложь
Или Не ирОбщий.ЛиКорневойТипРегистраСведенийЛкс(ТипТаблицы)
Или ОбъектМД.РежимЗаписи = Метаданные.СвойстваОбъектов.РежимЗаписиРегистра.ПодчинениеРегистратору
Тогда
ПространствоБлокировок = ПолноеИмяМД + ".НаборЗаписей";
ЭлементБлокировки = Блокировка.Добавить(ПространствоБлокировок);
ЭлементБлокировки.УстановитьЗначение("Регистратор", НаборЗаписей.Отбор.Регистратор.Значение);
КонецЕсли;
// По измерениям блокируем все возможные диапазоны. В большинстве случаев при замене ссылок такие блокировки будут неоправданными
ПространствоБлокировок = ПолноеИмяМД;
ЭлементБлокировки = Блокировка.Добавить(ПространствоБлокировок);
СсылочныеИзмерения = ПолучитьСсылочныеИзмеренияРегистраЛкс(НаборЗаписей, ОбъектМД);
Для Каждого КлючЗначение Из СсылочныеИзмерения Цикл
ИмяИзмерения = КлючЗначение.Ключ;
ТипИзмерения = КлючЗначение.Значение;
Для Каждого НеправильнаяСсылка Из НайденныеВОбъектеНеправильныеСсылки Цикл
Если ТипИзмерения.СодержитТип(ТипЗнч(НеправильнаяСсылка)) Тогда
Блокировка.Добавить(ПространствоБлокировок).УстановитьЗначение(ИмяИзмерения, НеправильнаяСсылка);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Блокировка.Заблокировать();
КонецПроцедуры // ВыполнитьЗаменуВНабореЗаписей()
//ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла);
//ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf";
//ирПортативный #Если Клиент Тогда
//ирПортативный Контейнер = Новый Структура();
//ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер);
//ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда
//ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля);
//ирПортативный ирПортативный.Открыть();
//ирПортативный КонецЕсли;
//ирПортативный #Иначе
//ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта
//ирПортативный #КонецЕсли
//ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий");
//ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш");
//ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер");
//ирПортативный ирПривилегированный = ирПортативный.ПолучитьОбщийМодульЛкс("ирПривилегированный");
мПлатформа = ирКэш.Получить();
ТаблицаБукв = Новый ТаблицаЗначений;
ТаблицаБукв.Колонки.Добавить("Позиция");
ТаблицаБукв.Колонки.Добавить("КолвоПропущенных");
ТаблицаБукв.Колонки.Добавить("ДлинаСлова");
ТаблицаБукв.Колонки.Добавить("ПропущеноНа");
ЗаписьНаСервере = ирОбщий.ПолучитьРежимЗаписиНаСервереПоУмолчаниюЛкс();
ЭтотОбъект.ОтключатьКонтрольЗаписи = Истина;