Задвоились предопределенные элементы справочников? Выход есть!

Аватар пользователя mykib.org
Файлы для скачивания: 

Задвоились предопределенные элементы справочников? Выход есть!

Это может произойти как по причине того, что при обмене данными в режиме загрузки уникальность предопределенного элемента в пределах области информационной базы не проверяется, так и при объединении/обновлении конфигураций.

При попытке переименовать, или, например, пометить на удаление показывает сообщение «Предопределенный элемент не уникален».

В этой статье мы напишем обработку, которая позволит избавиться от дублей предопределенных элементов справочника.

Алгоритм следующий:

  • Первым делом мы найдем задвоенные (затроенные и т.д.) предопределенные элементы всех справочников.
  • Затем определим на какие элементы больше всего ссылаются другие объекты базы.
  • С учетом количества ссылок, определим как «правильные» те, на которые меньше всего других ссылок.
  • Оставим эти элементы предопределенными, а дубликаты сделаем непредопределенными (наименование сделаем как у предопределенных, для возможности дальнейшей замены всех ссылок на «правильный» соответствующий предопределенный элемент справочника).
  • Дальше можно заменить все ссылки объектов к этим дубликатам ссылками на те элементы, которые мы решили оставить предопределенными и при необходимости удалить дубликаты. Мы просто предложим пометить дубликаты на удаление.

Создадим новую обработку, и добавим табличную часть «ЗадублированныеСправочники»:

 

Создадим новую обработку, и добавим табличную часть

Реквизиты табличной части «ИмяСправочника», «СинонимСправочника» и «ИмяПредопределенныхДанных» - переменная строка неограниченной длины;

«КоличествоДублей» и «КоличествоСсылок» - неотрицательное число;

«ОставитьПредопределенным» - булево;

«ЭлементСправочника» тип «Справочник».

Создадим основную форму и разместим на ней табличную часть и кнопки «1. Заполнить», «2. Подсказать правильные», «3. Оставить предопределенными только отмеченные»:

 

кнопки Заполнить, Подсказать правильные, Оставить предопределенными только отмеченные

В теле процедуры обработчика нажатия кнопки «1. Заполнить» будем вызывать процедуру ЗадублированныеСправочникиЗаполнить()

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

В процессе работы данной процедуры мы будем следить за тем, какие справочники проверяются на дубли в специальном окне:

 

Это окно реализовано функцией глобального контекста ПоказатьОповещениеПользователя

Это окно реализовано функцией глобального контекста ПоказатьОповещениеПользователя()

При окончании процедуры мы получим заполненную дубликатами табличную часть, в колонке «Правильные» указывается предопределенный элемент справочника, который необходимо оставить:

 

Заполненная дубликатами табличная часть

Теперь пользователь может либо сам определить «правильные» предопределенные, либо воспользоваться подсказкой по кнопке «2. Подсказать правильные».

В теле процедуры обработчика нажатия этой кнопки будем вызывать процедуру ПодсказатьПравильные() – как уже было сказано, подсказка заключается в определении количества ссылающихся объектов информационной базы на предопределенный элемент справочника – чем больше ссылок на элемент, тем он «правильнее» (меньше ссылок придется заменять в дальнейшем):

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

Данная операция будет довольно длительной – производится поиск всех ссылающихся объектов, по окончании мы получим рекомендации:

 

Теперь пользователь может определить правильный элемент

Теперь пользователь может определить «правильный» элемент, руководствуясь данными о количестве ссылающихся объектов базы на конкретный элемент предопределенного справочника:

 

Правильные предопределенные элементы справочника

В теле процедуры обработчика нажатия кнопки «3. Оставить предопределенными только отмеченные» будем вызывать процедуру ОставитьТолькоОдинПредопределенный(). Кстати, спросим – помечать ли на удаление «неправильные».

 

спросим пользователя – помечать ли на удаление неправильные

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

Ну, и по традиции - во вложении исходная Обработка.

Ключевые фразы:

Комментарии

Аватар пользователя Евгений

Спасибо большое! Работает! Помогло для обновления Розницы 2.0 до 2.2.7
Аватар пользователя Гость

Спасибо