Не редко необходимо делать перенос данных из Динамического списка в Таблицу значений, к примеру, когда нужно сделать подбор номенклатуры для какого-либо документа.

К примеру имеем иерархический Справочник «Номенклатура» и периодический Регистр сведений «ЦеныНоменклатуры» и необходимо из Динамического списка, содержащий данные по номенклатуре с ценами, перенести в таблицу значений выбранную номенклатуру вместе с ценами.
Исходные данные для примера
- Иерархический справочник Номенклатура. Без дополнительных реквизитов.
- Регистр сведений ЦеныНоменклатуры.
- Измерение: Номенклатура
- Ресурс: Цена.
- Разрешить итоги СрезПоследних = Истина (для ускорения получения данных по ценам).
- Периодичность: День.
- Независимый от регистратора, т.е. ввод данных вручную.
- Справочник и регистр заполняется первоначальными данными.
Решение задачи
Создаю обработку (её проще запускать из пустой конфигурации) и в ней основную форму. Добавляются реквизиты формы:
- Отобранная номенклатура с типом Таблица значений со следующими колонками реквизита:
- Номенклатура со ссылкой на справочник Номенклатура
- Цена — Тип Число
- Количество — Тип Число
- Сумма — Тип Число
- Номенклатура с типом Динамический список, где с помощью произвольного запроса будем получать данные
|
1 2 3 4 5 6 7 8 |
ВЫБРАТЬ СписокНоменклатуры.Ссылка КАК Номенклатура, СписокНоменклатуры.ЭтоГруппа КАК ЭтоГруппа, ЦеныНоменклатурыСрезПоследних.Цена КАК Цена ИЗ Справочник.Номенклатура КАК СписокНоменклатуры ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних ПО СписокНоменклатуры.Ссылка = ЦеныНоменклатурыСрезПоследних.Номенклатура |
Далее необходимо выставить Основную таблицу и Динамическое считывание данных:

Что бы дальше лишний раз не обращаться к базе данных при переносе номенклатуры, раскрываем реквизит динамического списка и напротив ЭтоГруппа ставится галочка — Использовать всегда

Оба реквизита переносятся на форму и приступаем к написанию кода.

Первым делом делается перенос данных по двойному клику или по клавиши Enter. Для этого у Элемента формы Динамического списка создаём процедуру на клиенте для события Выбор.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
&НаКлиенте Процедура НоменклатураВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка) ВыбранныеДанные = Элемент.ТекущиеДанные; //Проверяем, является ли группой выбранный элемент. Если ВыбранныеДанные.ЭтоГруппа Тогда //Если является, то делаем возврат. Возврат; КонецЕсли; //Что бы не открывалась форма редактирования номенклатуры ставим Стандартную обработку в Ложь СтандартнаяОбработка = Ложь; //Процедура на сервере по добавлению (обновлению) таблицы с отобранными товарами ДобавлениеОтобраннойНоменклатуры(ВыбранныеДанные); КонецПроцедуры |
Вот для этого кода ВыбранныеДанные.ЭтоГруппа выше ставили для ЭтоГруппа «Использовать всегда». Иначе пришлось бы делать запрос, что бы понять является ли группой данный элемент. Либо воспользоваться Объектной моделью, что ещё хуже.

И так как одна и та же процедура ДобавлениеОтобраннойНоменклатуры(ВыбранныеДанные) сначала вызывается с клиента, а дальше будет вызываться с сервера, то и сразу эту процедуру пишем с директивой &НаСервере
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
&НаСервере Процедура ДобавлениеОтобраннойНоменклатуры(ВыбранныеДанные) //Ищем в Таблице отобранной номенклатуры выбранную номенклатуру СтруктураПоиска = Новый Структура; СтруктураПоиска.Вставить("Номенклатура", ВыбранныеДанные.Номенклатура); НайденныеСтроки = ОтобраннаяНоменклатура.НайтиСтроки(СтруктураПоиска); Если НайденныеСтроки.Количество() > 0 Тогда //Если такая номенклатура уже была в списке, то количество увеличиваем на единицу и соответственно пересчитываем сумму НайденныеСтроки[0].Количество = НайденныеСтроки[0].Количество + 1; НайденныеСтроки[0].Сумма = НайденныеСтроки[0].Количество * НайденныеСтроки[0].Цена; Иначе //Если такой номенклатуры нет, то добавляем строку номенклатуры НоваяСтрока = ОтобраннаяНоменклатура.Добавить(); НоваяСтрока.Номенклатура = ВыбранныеДанные.Номенклатура; НоваяСтрока.Цена = ВыбранныеДанные.Цена; НоваяСтрока.Количество = 1; НоваяСтрока.Сумма = НоваяСтрока.Цена; КонецЕсли; //Если что-то изменяет форму, то надо дать понять системе, что форма изменилась Модифицированность = Истина; КонецПроцедуры |
С копированием Номенклатуры по двойному клику разобрались, теперь делаем перетаскивание. Для этого у элемента формы Динамического списка ставим галочку «Разрешить начало перетаскивания» и снять галочку «Разрешить перетаскивание». А у элемента формы Таблицы значений делаем наоборот — снимаем галочку у «Разрешить начало перетаскивания» и ставим галочку «Разрешить перетаскивание».
Т.е. таким образом мы показываем, что является источником данных, а что является приёмником данных.
Далее для события Перетаскивание элемента формы Таблицы значений пишем следующую процедуру:
|
1 2 3 4 5 6 7 8 9 10 11 |
&НаКлиенте Процедура ОтобраннаяНоменклатураПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле) //Проверяем, являются ли перетаскиваемые данные массивом Если ТипЗнч(ПараметрыПеретаскивания.Значение) = Тип("Массив") Тогда //Так как у Динамического списка по умолчанию стоит Множественный выбор, то нет возможности без запроса узнать является ли конкретный элемент группой ЗапросНоменклатуры(ПараметрыПеретаскивания.Значение); КонецЕсли; КонецПроцедуры |
Делается запрос к Базе данных, исключая запросы в цикле.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
&НаСервере Процедура ЗапросНоменклатуры(Значение) Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ | СписокНоменклатуры.Ссылка КАК Номенклатура, | ЦеныНоменклатурыСрезПоследних.Цена КАК Цена |ИЗ | Справочник.Номенклатура КАК СписокНоменклатуры | ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних | ПО СписокНоменклатуры.Ссылка = ЦеныНоменклатурыСрезПоследних.Номенклатура |ГДЕ | СписокНоменклатуры.Ссылка В(&Значение) | И НЕ СписокНоменклатуры.ЭтоГруппа"; Запрос.УстановитьПараметр("Значение", Значение); РезультатЗапроса = Запрос.Выполнить(); Выборка = РезультатЗапроса.Выбрать(); Пока Выборка.Следующий() Цикл //Процедура на сервере по добавлению (обновлению) таблицы с отобранными товарами ДобавлениеОтобраннойНоменклатуры(Выборка); КонецЦикла; КонецПроцедуры |
И вот из-за того, что процедура ЗапросНоменклатуры должен выполняться на сервере, а с сервера вызвать клиент нельзя, процедура ДобавлениеОтобраннойНоменклатуры делается так же на сервере, о чем я выше писал.
Готово.
В ближайших публикациях разовью данную тему и сделаю перенос «Отобранной номенклатуры» в документ.
