Задвоились предопределенные элементы справочников? Выход есть!
Это может произойти как по причине того, что при обмене данными в режиме загрузки уникальность предопределенного элемента в пределах области информационной базы не проверяется, так и при объединении/обновлении конфигураций.
При попытке переименовать, или, например, пометить на удаление 1С [1] показывает сообщение «Предопределенный элемент не уникален».
В этой статье мы напишем обработку [1], которая позволит избавиться от дублей предопределенных элементов справочника.
Алгоритм следующий:
Создадим новую обработку [1], и добавим табличную часть «ЗадублированныеСправочники»:
Реквизиты табличной части «ИмяСправочника», «СинонимСправочника» и «ИмяПредопределенныхДанных» - переменная строка неограниченной длины;
«КоличествоДублей» и «КоличествоСсылок» - неотрицательное число;
«ОставитьПредопределенным» - булево;
«ЭлементСправочника» тип «Справочник».
Создадим основную форму и разместим на ней табличную часть и кнопки «1. Заполнить», «2. Подсказать правильные», «3. Оставить предопределенными только отмеченные»:
В теле процедуры обработчика нажатия кнопки «1. Заполнить» будем вызывать процедуру ЗадублированныеСправочникиЗаполнить()
Процедура ЗадублированныеСправочникиЗаполнить() //Очистим табличную часть, так как после выполнения конечного этапа //проконтролируем, что дубликаты исчезли ЗадублированныеСправочники.Очистить(); //Построим текст запроса, для определения дубликатов //предопределенных элементов справочника #ИмяСправочника ТекстЗапроса = "ВЫБРАТЬ | #ИмяСправочника.Ссылка КАК Ссылка, | #ИмяСправочника.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных |ПОМЕСТИТЬ ВремТЗ |ИЗ | Справочник.#ИмяСправочника КАК #ИмяСправочника |ГДЕ | #ИмяСправочника.Предопределенный |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | ВремТЗ.ИмяПредопределенныхДанных, | КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ВремТЗ.Ссылка) КАК КоличествоДублей |ПОМЕСТИТЬ Дубли |ИЗ | ВремТЗ КАК ВремТЗ | |СГРУППИРОВАТЬ ПО | ВремТЗ.ИмяПредопределенныхДанных |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | Дубли.ИмяПредопределенныхДанных КАК ИмяПредопределенныхДанных, | Дубли.КоличествоДублей КАК КоличествоДублей, | ""#ИмяСправочника"" КАК ИмяСправочника, | ""#СинонимСправочника"" КАК СинонимСправочника, | ЛОЖЬ КАК ОставитьПредопределенным, | ВремТЗ.Ссылка КАК ЭлементСправочника |ИЗ | Дубли КАК Дубли | ЛЕВОЕ СОЕДИНЕНИЕ ВремТЗ КАК ВремТЗ | ПО Дубли.ИмяПредопределенныхДанных = ВремТЗ.ИмяПредопределенныхДанных |ГДЕ | Дубли.КоличествоДублей > 1"; Запрос = Новый Запрос; //Предупреждая замечания читателей и вопреки всем рекомендациям, будем выполнять запрос в цикле //для каждого справочника - //это читабельней и не приводит к существенной нагрузке на информационную базу, //нежели одним запросом охватывать все справочники //(что, при определенных ограничениях на количество объединений может и вовсе не представлятся возможным) Для Каждого Стр Из Метаданные.Справочники Цикл ИмяСправочника = Стр.Имя; СинонимСправочника = Стр.Синоним; ПоказатьОповещениеПользователя("Поиск по справочнику " + СинонимСправочника); Запрос.Текст = ТекстЗапроса; Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ИмяСправочника", ИмяСправочника); Запрос.Текст = СтрЗаменить(Запрос.Текст, "#СинонимСправочника", СинонимСправочника); Результат = Запрос.Выполнить(); //В этом цикле добавляем строки в табличную часть Если Не Результат.Пустой() Тогда Выборка = Результат.Выбрать(); Пока Выборка.Следующий() Цикл НовСтр = ЗадублированныеСправочники.Добавить(); ЗаполнитьЗначенияСвойств(НовСтр, Выборка); КонецЦикла; КонецЕсли; КонецЦикла; //Отстортируем табличную часть и скроем колонку, в которой отображается //количество ссылок на предопределенный элемент справочника //(по количеству ссылок на объект, пользователю будет легче определить "правильный" объект) ЗадублированныеСправочники.Сортировать("ИмяСправочника, ИмяПредопределенныхДанных"); ЭлементыФормы.ЗадублированныеСправочники.Колонки.КоличествоСсылок.Видимость = Ложь; КонецПроцедуры
В процессе работы данной процедуры мы будем следить за тем, какие справочники проверяются на дубли в специальном окне:
Это окно реализовано функцией глобального контекста ПоказатьОповещениеПользователя()
При окончании процедуры мы получим заполненную дубликатами табличную часть, в колонке «Правильные» указывается предопределенный элемент справочника, который необходимо оставить:
Теперь пользователь может либо сам определить «правильные» предопределенные, либо воспользоваться подсказкой по кнопке «2. Подсказать правильные».
В теле процедуры обработчика нажатия этой кнопки будем вызывать процедуру ПодсказатьПравильные() – как уже было сказано, подсказка заключается в определении количества ссылающихся объектов информационной базы на предопределенный элемент справочника – чем больше ссылок на элемент, тем он «правильнее» (меньше ссылок придется заменять в дальнейшем):
Процедура ПодсказатьПравильные() //Находим ссылки на дубликаты ТаблицаСсылок = НайтиПоСсылкам(ЗадублированныеСправочники.ВыгрузитьКолонку("ЭлементСправочника")); ТаблицаСсылок.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число")); ТаблицаСсылок.ЗаполнитьЗначения(1,"Количество"); //считаем количество ссылок на каждый дубликат ТаблицаСсылок.Свернуть("Ссылка", "Количество"); //Заполняем колонку "Количество ссылок" Для Каждого СтрТаблицаСсылок Из ТаблицаСсылок Цикл НайденныеСтроки = ЗадублированныеСправочники.НайтиСтроки(Новый Структура("ЭлементСправочника, КоличествоСсылок", СтрТаблицаСсылок.Ссылка, 0)); Если НайденныеСтроки.Количество() > 0 Тогда НайденныеСтроки[0].КоличествоСсылок = СтрТаблицаСсылок.Количество; КонецЕсли; КонецЦикла; //Пусть максимальное количество каждого предопределенного элемента //будет наверху в группе каждого типа справочника ЗадублированныеСправочники.Сортировать("ИмяСправочника, ИмяПредопределенныхДанных, КоличествоСсылок Убыв"); //Покажем эту колонку пользователю ЭлементыФормы.ЗадублированныеСправочники.Колонки.КоличествоСсылок.Видимость = Истина; КонецПроцедуры
Данная операция будет довольно длительной – производится поиск всех ссылающихся объектов, по окончании мы получим рекомендации:
Теперь пользователь может определить «правильный» элемент, руководствуясь данными о количестве ссылающихся объектов базы на конкретный элемент предопределенного справочника:
В теле процедуры обработчика нажатия кнопки «3. Оставить предопределенными только отмеченные» будем вызывать процедуру ОставитьТолькоОдинПредопределенный(). Кстати, спросим – помечать ли на удаление «неправильные».
Процедура ОставитьТолькоОдинПредопределенный() ПометкаУдаления = Ложь; ВыполненоУспешно = Ложь; //спросим – помечать ли на удаление «неправильные» Режим = РежимДиалогаВопрос.ДаНет; Ответ = Вопрос("Пометить на удаление дубли элементов?", Режим, 0); Если Ответ = КодВозвратаДиалога.Да Тогда ПометкаУдаления = Истина; КонецЕсли; ОставитьПредопределеннымКонтроль = ЗадублированныеСправочники.Выгрузить(); ОставитьПредопределеннымКонтроль.Свернуть("ИмяСправочника, ИмяПредопределенныхДанных", "ОставитьПредопределенным"); Для Каждого Стр Из ЗадублированныеСправочники Цикл ОтборНеУказанОставитьПредопределенным = Новый Структура("ИмяСправочника, ИмяПредопределенныхДанных, ОставитьПредопределенным", Стр.ИмяСправочника, Стр.ИмяПредопределенныхДанных, Ложь); Если НЕ Стр.ОставитьПредопределенным И ОставитьПредопределеннымКонтроль.НайтиСтроки(ОтборНеУказанОставитьПредопределенным).Количество() = 0 Тогда ЭлементОбъект = Стр.ЭлементСправочника.ПолучитьОбъект(); Если ЭлементОбъект <> Неопределено Тогда Если Не ЗначениеЗаполнено(ЭлементОбъект.Наименование) Тогда ЭлементОбъект.Наименование = ЭлементОбъект.ИмяПредопределенныхДанных; КонецЕсли; ЭлементОбъект.ИмяПредопределенныхДанных = "";//Именно в этом месте мы избавляемся от предопределенности ЭлементОбъект.ПометкаУдаления = ПометкаУдаления; ЭлементОбъект.Записать(); ВыполненоУспешно = Истина; Сообщить("Элемент" + ЭлементОбъект.Наименование + " справочника " + Стр.СинонимСправочника + " сделан непредопределенным."); КонецЕсли; КонецЕсли; КонецЦикла; //Проконтролируем результат, а также, возможно пользователь "работал" только с определенными справочниками Если ВыполненоУспешно Тогда ЗадублированныеСправочникиЗаполнить(); КонецЕсли; КонецПроцедуры
Ну, и по традиции - во вложении исходная Обработка [1].
Ссылки
[1] https://www.mykib.org/article/den-devyatyy-integriroval-samyy-bolshoy-katalog-razrabotok-dlya-platformy-1s
[2] https://www.mykib.org/tags/1s-8
[3] https://www.mykib.org/sites/default/files/downloads/search_dubl_own.zip
[4] https://www.mykib.org/comment/13096#comment-13096
[5] https://www.mykib.org/comment/44099#comment-44099
Комментарии
работает! [4]
Спасибо [5]