Каталог решений - Полная копия элемента справочника не своими руками

Полная копия элемента справочника не своими руками

Полная копия элемента справочника не своими руками

В наличии

Копируем элемент справочника, элементы подчиненных справочников и записи регистров сведений, относящиеся к элементу. Одним движением.

Категория:

Описание

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

При копировании Номенклатуры нужно было воспроизвести единицы измерения, свойства, штрихкоды и т.д. Так как данные, относящиеся к предмету, раскиданы по подчиненным справочникам и регистрам сведений, пользователи весьма удивлялись, почему по кнопочке «создать элемент копированием» у них на форме копии заполненными оказывалась едва ли треть от привычных им сведений.

Чтобы не утомлять их объяснениями, почему в 1С все так сделано. я сел и написал функцию, которая скопирует практически все, что имеет отношение к объекту. Кроме, конечно, регистров накопления и расчета, а также регистров сведений, связанных с регистраторами.

На этом описательную часть считаю законченой. Собственно сама функция:

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

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