Копирование группы номенклатуры с иерархией вложенных элементов

27.02.17

Задачи пользователя - Адаптация типовых решений

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

Нередко возникает задача скопировать определённую ветку номенклатуры для того, чтобы в дальнейшем поменять определённые реквизиты и использовать уже "новую" номенклатуру в документах.

Передо мной конфигурация Управление Торговым Предприятием для Украины, описывать действия буду исходя из этого.

Для начала открываем конфигурацию и в справочнике "Номенклатура" открываем "Форму списка" выбираем табличное поле "Список" и в свойствах ставим птицу "Разрешить перетаскивание".

Листаем свойства вниз и нажимаем открыть на трёх следующих событиях:

"Начало перетаскивания" - втавляем следующий код

Процедура СписокНачалоПеретаскивания(Элемент, ПараметрыПеретаскивания, Выполнение)
    ПараметрыПеретаскивания.ДопустимыеДействия = ДопустимыеДействияПеретаскивания.КопированиеИПеремещение;
КонецПроцедуры

"Проверка перетаскивания" - втавляем следующий код 

Процедура СписокПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)
    СтандартнаяОбработка=Ложь;
КонецПроцедуры

и напоследок само "Претаскивание" - втавляем следующий код

Процедура СписокПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Колонка)

    // Для Левой клавиши мышки происходит простое перетаскивание и тут нам ничего не нужно делать
    // Если же оператор потянул группу товаров правой клавишей...

    Если ПараметрыПеретаскивания.Действие=ДействиеПеретаскивания.Выбор Тогда
        СтандартнаяОбработка=Ложь;

        //Готовим список действий для нашего контекстного меню
        Действия=Новый СписокЗначений;
        Действия.Добавить("Переместить","Переместить");
        Действия.Добавить("Копировать","Копировать");
        Действия.Добавить("Отмена","Отмена");

        //Выводим меню рядом с нашим элементом и ждём ответа пользователя
        Попытка
            Действие=ВыбратьИзМеню(Действия,Элемент).Значение;
        Исключение
            Действие="Отмена"; //Если щёлкнул вообще мимо 
        КонецПопытки;

        Если Действие="Переместить" Тогда //Передаём обработку стандартному механизму перетаскивания

            ПараметрыПеретаскивания.Действие=ДействиеПеретаскивания.Перемещение;
            СтандартнаяОбработка=Истина;

        ИначеЕсли Действие="Копировать" Тогда //Собственно выбираем элементы (ветку) для дальнейшей обработки
            Запрос = Новый Запрос("ВЫБРАТЬ
            |    Номенклатура.Ссылка
            |ИЗ
            |    Справочник.Номенклатура КАК Номенклатура
            |ГДЕ
            |    Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)
            |УПОРЯДОЧИТЬ ПО
            |    Номенклатура.Ссылка ИЕРАРХИЯ"
            );
            Запрос.УстановитьПараметр("Группа", Элемент.ТекущаяСтрока);

            //Вызываем рекурсивную процедуру, параметр "строка" - это "получатель", куда будет скопирована ветка
            Копировать(Строка,Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией));

        КонецЕсли;

    КонецЕсли;    
КонецПроцедуры

Для того, чтобы всё заработало нам нужна ещё одна рекурсивная процедура "Копировать"

Процедура Копировать(Предок,Выборка) //Рекурсивная процедура для обхода всего дерева

    Если Не Предок.ЭтоГруппа Тогда //Если перетащили не на группу, то кидаем всё дерево в корень
        Предок=Справочники.Номенклатура.ПустаяСсылка();
    КонецЕсли;    

    Пока Выборка.Следующий() Цикл //Обходим все элементы и просто копируем всё подряд
        
        //Поскольку выборка добывает нам ссылки для изменения с объекта его необходимо получить
        ТекСпр = Выборка.Ссылка.ПолучитьОбъект();
        элементСправочника = ТекСпр.Скопировать();
        элементСправочника.Родитель=Предок;

        // ** Если мы хотим запомнить откуда была скопирована номенклатура - нужно            **
        // ** предварительно добавить реквизит ОбразецНоменклатуры в справочник Номенклатура  **  
        // ** типа "СправочникСсылка.Номенклатура" а затем раскомментировать следующую строку **
        //элементСправочника.ОбразецНоменклатуры=ТекСпр.Ссылка;

        // При желании здесь можно создавать подчинённые справочники вроде "единицы измерения" 
        // и сюда записывать все необходимые ссылки

        элементСправочника.Записать();

        Если ТекСпр.ЭтоГруппа Тогда //Когда встречаем группу, то заходим внутрь и повторяем действия
            Копировать(элементСправочника.Ссылка,Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией));
        КонецЕсли;

    КонецЦикла;    
КонецПроцедуры

копирование номенклатура иерархия вложенные

См. также

Адаптация типовых решений Платформа 1С v8.3 1С:Документооборот Россия Платные (руб)

Расширение конфигурации для «1С:Документооборот КОРП», редакция 3.0. позволяет: 1.использовать произвольные табличные части в качестве дополнительных реквизитов к документу; 2 использовать произвольные табличные части в шаблонах в формате docx для автоматического заполнения таблиц.

29400 руб.

29.06.2023    5650    14    5    

24

Логистика, склад и ТМЦ Адаптация типовых решений Пользователь Платформа 1С v8.3 1С:Управление нашей фирмой 1.6 1С:Управление нашей фирмой 3.0 Россия Управленческий учет Платные (руб)

Чтобы не допустить путаницы с обещаниями клиентам и для четкого контроля исполнения заказов мы используем резервирование товаров. Мы доработали УНФ, чтобы она автоматически отменяла старые резервы и не мешала эффективно продавать.

7200 руб.

02.08.2023    3913    11    0    

29

Адаптация типовых решений Программист Пользователь Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Абонемент ($m)

Каждый из нас сталкивается с ситуацией, когда какой-нибудь менеджер показывает свой Excel и рассказывает, как он что-то из 1С копирует в него, снабжает пояснениями, выделяет цветом и т.д. и т.п. Заканчивается все просьбой сделать вот чтобы также было в 1С. И оказывается такой человек (почти с гарантией) либо лучшим продажником, либо каким-то важным, за все отвечающим, - на ком все держится.

2 стартмани

22.04.2024    5088    dimanich70    15    

21

БСП (Библиотека стандартных подсистем) Адаптация типовых решений Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

Понадобилось в подменю "Создать на основании" добавить свою команду, которая открывает обработку. В процессе доработок появилась проблема двух подменю "Создать на основании". В статье о том, как решились проблемы.

01.03.2024    5475    dimanich70    9    

18
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. rus128 2 01.03.17 11:40 Сейчас в теме
Все хорошо, только опечатка "втавляем" (3 раза).
2. japopov 68 01.03.17 11:54 Сейчас в теме
По-первых, у Вас - под обычные формы, хорошо бы предупредить. Под управляемое приложение придётся переписывать.
Во-вторых, плохая реализация. Рекурсия отрабатывает очень медленно, нагружает машину (в Вашем случае - клиента) и чревата переполнением стека для многоуровневых справочников.
Тем более, что Вы делаете запрос по копируемым объектам. Что мешает обойтись вообще без рекурсии? Немного подумать - и сделать простым построчным обходом таблицы. Сработает в разы быстрее, и разница будет тем больше, чем большее число уровней вложенности.
3. DrAku1a 1739 02.03.17 02:58 Сейчас в теме
Копирование без рекурсии
Запрос = Новый Запрос("ВЫБРАТЬ
	|	Номенклатура.Ссылка,
	|	Номенклатура.ЭтоГруппа,
	|	Номенклатура.Родитель
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|	Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)
	|
	|УПОРЯДОЧИТЬ ПО
	|	Номенклатура.Ссылка ИЕРАРХИЯ");
Запрос.УстановитьПараметр("Группа", Элемент.ТекущаяСтрока);

РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
	Возврат;
КонецЕсли;

Предок = ?(Строка.ЭтоГруппа, Строка, Справочники.Номенклатура.ПустаяСсылка()); //Если перетащили не на группу, то кидаем всё дерево в корень
мСоответствиеГрупп = новый Соответствие;
мСоответствиеГрупп.Вставить(Элемент.ТекущаяСтрока.Родитель, Предок);

Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.Прямой);
Пока Выборка.Следующий() Цикл
      ТекСпр = Выборка.Ссылка.ПолучитьОбъект();
      элементСправочника = ТекСпр.Скопировать();
      элементСправочника.Родитель = мСоответствиеГрупп[Выборка.Родитель];

      // ** Если мы хотим запомнить откуда была скопирована номенклатура - нужно            **
      // ** предварительно добавить реквизит ОбразецНоменклатуры в справочник Номенклатура  **  
      // ** типа "СправочникСсылка.Номенклатура" а затем раскомментировать следующую строку **
      //элементСправочника.ОбразецНоменклатуры=ТекСпр.Ссылка;

      // При желании здесь можно создавать подчинённые справочники вроде "единицы измерения" 
      // и сюда записывать все необходимые ссылки

      элементСправочника.Записать();

      Если Выборка.ЭтоГруппа Тогда //Когда встречаем группу, то запоминаем её
          мСоответствиеГрупп.Вставить(Выборка.Ссылка, элементСправочника.Ссылка);
      КонецЕсли;	
КонецЦикла;
Показать
Поручик; +1 Ответить
4. пользователь 02.03.17 02:58
Сообщение было скрыто модератором.
...
5. пользователь 02.03.17 02:59
Сообщение было скрыто модератором.
...
6. Поручик 4691 17.09.18 08:53 Сейчас в теме
7. elian 137 19.02.19 21:21 Сейчас в теме
Действительно хорошая задумка!
8. user705522_constantin_h 37 26.06.19 11:25 Сейчас в теме
Для управляемых форм:
&НаКлиенте
Процедура СписокПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)

    // Для Левой клавиши мышки происходит простое перетаскивание и тут нам ничего не нужно делать
    // Если же оператор потянул группу товаров правой клавишей...

    Если ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Выбор Тогда
        СтандартнаяОбработка = Ложь;

        //Готовим список действий для нашего контекстного меню
        Действия = Новый СписокЗначений;
        Действия.Добавить("Переместить","Переместить");
        Действия.Добавить("Копировать","Копировать");
        Действия.Добавить("Отмена","Отмена");

		ДополнительныеПараметры = Новый Структура;
		ДополнительныеПараметры.Вставить("ПараметрыПеретаскивания", ПараметрыПеретаскивания);
		ДополнительныеПараметры.Вставить("Элемент", Элемент);
		ДополнительныеПараметры.Вставить("Строка", Строка);
		
        //Выводим меню рядом с нашим элементом и ждём ответа пользователя
		ОповещениеПослеВыбораЭлемента = Новый ОписаниеОповещения("СообщитьРезультат", ЭтотОбъект, ДополнительныеПараметры);
		Действия.ПоказатьВыборЭлемента(ОповещениеПослеВыбораЭлемента, "Выберите действие");

    КонецЕсли;    
КонецПроцедуры

&НаКлиенте
Процедура СообщитьРезультат(Элемент, Параметры) Экспорт
		Если Элемент.Значение = "Переместить" Тогда //Передаём обработку стандартному механизму перетаскивания

            Параметры.ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Перемещение;
            СтандартнаяОбработка=Истина;

        ИначеЕсли Элемент.Значение = "Копировать" Тогда //Собственно выбираем элементы (ветку) для дальнейшей обработки

			ВыполнитьКопирование(Параметры.Элемент.ТекущаяСтрока, Параметры.Строка);
        КонецЕсли;
КонецПроцедуры


&НаСервере
Процедура ВыполнитьКопирование(ТекущаяГруппа, Строка)
	Запрос = Новый Запрос("ВЫБРАТЬ
	|    Номенклатура.Ссылка,
	|    Номенклатура.ЭтоГруппа,
	|    Номенклатура.Родитель
	|ИЗ
	|    Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|    Номенклатура.Ссылка В ИЕРАРХИИ(&Группа)
	|
	|УПОРЯДОЧИТЬ ПО
	|    Номенклатура.Ссылка ИЕРАРХИЯ");
	Запрос.УстановитьПараметр("Группа", ТекущаяГруппа);
	
	РезультатЗапроса = Запрос.Выполнить();
	Если РезультатЗапроса.Пустой() Тогда
		Возврат;
	КонецЕсли;
	
	Предок = ?(Строка.ЭтоГруппа, Строка, Справочники.Номенклатура.ПустаяСсылка()); //Если перетащили не на группу, то кидаем всё дерево в корень
	мСоответствиеГрупп = новый Соответствие;
	мСоответствиеГрупп.Вставить(ТекущаяГруппа.Родитель, Предок);
	
	Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.Прямой);
	Пока Выборка.Следующий() Цикл
		ТекСпр = Выборка.Ссылка.ПолучитьОбъект();
		элементСправочника = ТекСпр.Скопировать();
		элементСправочника.Родитель = мСоответствиеГрупп[Выборка.Родитель];
		
		// ** Если мы хотим запомнить откуда была скопирована номенклатура - нужно            **
		// ** предварительно добавить реквизит ОбразецНоменклатуры в справочник Номенклатура  **  
		// ** типа "СправочникСсылка.Номенклатура" а затем раскомментировать следующую строку **
		//элементСправочника.ОбразецНоменклатуры=ТекСпр.Ссылка;
		
		// При желании здесь можно создавать подчинённые справочники вроде "единицы измерения" 
		// и сюда записывать все необходимые ссылки
		
		элементСправочника.Записать();
		
		Если Выборка.ЭтоГруппа Тогда //Когда встречаем группу, то запоминаем её
			мСоответствиеГрупп.Вставить(Выборка.Ссылка, элементСправочника.Ссылка);
		КонецЕсли;    
	КонецЦикла;
КонецПроцедуры
Показать
9. gusen_it 6 05.12.21 13:53 Сейчас в теме
Разве такой скопировать иерархию уапковок?
Оставьте свое сообщение