Подбор товаров в табличную часть: команда, форма выбора и обработка результата

· 9 мин

Содержание

Кнопка подбора в 1С делается так: в конфигураторе добавьте форме документа команду Подбор, перетащите её в командную панель табличной части, а в обработчике откройте форму выбора справочника с параметрами ЗакрыватьПриВыборе = Ложь и МножественныйВыбор = Истина, указав владельцем таблицу формы. Выбранные значения придут в событие ОбработкаВыбора таблицы — там и добавляются строки.

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

Как устроен механизм выбора в управляемой форме

Подбор в 1С — это не отдельный объект метаданных, а связка трёх вещей:

  • 🔘 команда формы с клиентским обработчиком;
  • 📂 форма выбора, открытая в режиме выбора;
  • 📥 обработчик ОбработкаВыбора у владельца, который получает выбранное значение.

Ключевое слово здесь — владелец. Третьим параметром ОткрытьФорму() передаётся объект, которому форма выбора будет отправлять результат. От него зависит, какое событие сработает:

Кого передали владельцемКакое событие получит значение
Элемент формы Элементы.Товары (таблица)ТоварыОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка) у таблицы
Саму форму ЭтотОбъектОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора) у формы

Оба варианта рабочие. Владелец-таблица удобнее, когда в форме одна табличная часть. Владелец-форма — когда подбор открывается из нескольких мест и нужно различать источник через параметр ИсточникВыбора.

Главное отличие подбора от обычного выбора — форма не закрывается после выбора строки. Пользователь щёлкает по позициям одну за другой, а документ наполняется в фоне.

Стандартные параметры формы выбора (РежимВыбора, ЗакрыватьПриВыборе, МножественныйВыбор, Отбор) понимает и автоматически сгенерированная форма, и форма, созданная конструктором. Писать свою форму ради простого подбора не нужно.

Шаг 1. Добавляем кнопку подбора в конструкторе формы

Откройте форму документа в конфигураторе (в дереве метаданных: документ → Формы → форма документа).

  1. На закладке Команды (правая верхняя часть редактора формы) выберите вкладку Команды формы и нажмите «Добавить».
  2. Задайте имя Подбор и заголовок Подбор. Подсказку заполните по смыслу: «Подобрать товары из справочника».
  3. В свойстве Действие нажмите кнопку с лупой — конфигуратор предложит создать обработчик. Выберите вариант «Создать на клиенте».
  4. Перетащите команду мышью из списка команд в дерево элементов, в узел командной панели таблицы Товары. Появится кнопка.
  5. В свойствах кнопки при желании задайте Отображение — «Картинка и текст» и подберите картинку из библиотеки.

Если кнопка должна стоять рядом со стандартными «Добавить» и «Удалить», перетащите её в нужную позицию внутри командной панели таблицы. Порядок элементов в дереве = порядок кнопок на экране.

Если форма у документа ещё не создана и используется автоматическая, сначала создайте её конструктором формы. В автоматическую форму свою команду не добавить.

Типовая конфигурация: через расширение

В БП 3.0, ЗУП 3.1 или УТ 11 форму документа напрямую не меняют — это снимает базу с поддержки и усложняет обновления. Правильный путь — расширение конфигурации :

  1. Конфигурация → Расширения конфигурации → создать расширение .
  2. В дереве расширения найдите нужный документ и у его формы выберите «Добавить в расширение».
  3. В заимствованной форме добавьте новую команду и кнопку так же, как описано выше.
  4. Обработчик команды пишется в модуле формы расширения — это обычная новая процедура, не перехват.

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

Шаг 2. Пишем обработчик нажатия кнопки подбора

Обработчик команды открывает форму выбора справочника Номенклатура в режиме подбора:

&НаКлиенте
Процедура Подбор(Команда)

    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("РежимВыбора", Истина);
    ПараметрыФормы.Вставить("ЗакрыватьПриВыборе", Ложь);
    ПараметрыФормы.Вставить("МножественныйВыбор", Истина);

    ОткрытьФорму("Справочник.Номенклатура.ФормаВыбора",
        ПараметрыФормы,
        Элементы.Товары);

КонецПроцедуры

Что делает каждый параметр:

  • ✅ РежимВыбора — форма работает как форма выбора, двойной щелчок не открывает карточку, а передаёт ссылку владельцу;
  • 🔁 ЗакрыватьПриВыборе = Ложь — форма остаётся открытой, можно выбирать ещё;
  • 📑 МножественныйВыбор = Истина — пользователь может выделить несколько строк через Ctrl или Shift и передать их одним действием, тогда придёт массив.

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

&НаКлиенте
Процедура ТоварыОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)

    СтандартнаяОбработка = Ложь;

    Если ТипЗнч(ВыбранноеЗначение) = Тип("Массив") Тогда
        МассивТоваров = ВыбранноеЗначение;
    Иначе
        МассивТоваров = Новый Массив;
        МассивТоваров.Добавить(ВыбранноеЗначение);
    КонецЕсли;

    ДобавитьТоварыНаСервере(МассивТоваров);

КонецПроцедуры

&НаСервере
Процедура ДобавитьТоварыНаСервере(МассивТоваров)

    Для Каждого Товар Из МассивТоваров Цикл

        Если Товар.ЭтоГруппа Тогда
            Продолжить;
        КонецЕсли;

        Найденные = Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", Товар));

        Если Найденные.Количество() > 0 Тогда
            Строка = Найденные[0];
            Строка.Количество = Строка.Количество + 1;
        Иначе
            Строка = Объект.Товары.Добавить();
            Строка.Номенклатура = Товар;
            Строка.Количество = 1;
        КонецЕсли;

        Строка.Сумма = Строка.Количество * Строка.Цена;

    КонецЦикла;

КонецПроцедуры

Почему добавление вынесено на сервер:

  • 🗄️ обращение Товар.ЭтоГруппа — это чтение из базы, на клиенте оно недоступно;
  • 💰 на сервере удобно сразу подставить цену из регистра сведений или единицу измерения из карточки;
  • 📉 один серверный вызов на всю пачку вместо вызова на каждую строку.

Повторный выбор той же позиции увеличивает количество, а не плодит дубли. Если бизнес-логика требует отдельную строку на каждый выбор — уберите поиск через НайтиСтроки.

Цену при подборе берите не «как получится», а той же функцией, что заполняет её при ручном вводе номенклатуры в строку. Иначе подбор и ручной ввод начнут давать разные суммы.

Шаг 3. Отборы в форме подбора: только элементы, только нужная группа

Без отборов пользователь увидит весь справочник, включая услуги, архивные позиции и группы. Отбор передаётся параметром Отбор — это структура «имя поля → значение».

Отбор по реквизиту

ОтборФормы = Новый Структура;
ОтборФормы.Вставить("ВидНоменклатуры", ВидНоменклатурыТовар);

ПараметрыФормы.Вставить("Отбор", ОтборФормы);

Значение отбора устанавливается в динамическом списке формы выбора. По умолчанию пользователь видит отбор и может его снять — для подбора это обычно нормально.

Запрет выбора групп

У иерархического справочника можно выбирать группы. Для подбора это почти всегда лишнее:

ПараметрыФормы.Вставить("ВыборГруппИЭлементов", ИспользованиеГруппИЭлементов.Элементы);

С этим параметром двойной щелчок по группе просто раскрывает её. Проверку Товар.ЭтоГруппа в серверной процедуре всё равно оставьте: форма может быть своей, и параметр в ней не обработан.

Отбор по значению из шапки документа

Частая задача — подбирать только товары выбранного в шапке поставщика или только услуги для документа на услуги. Значение берётся из реквизита объекта прямо в клиентском обработчике:

Если ЗначениеЗаполнено(Объект.Контрагент) Тогда
    ОтборФормы.Вставить("ОсновнойПоставщик", Объект.Контрагент);
КонецЕсли;

Реквизит ОсновнойПоставщик здесь для примера — подставьте поле своего справочника.

Шаг 4. Своя форма подбора на динамическом списке с остатками

Стандартная форма выбора показывает только поля справочника. Когда кладовщику нужно видеть остаток и цену прямо в списке, делают собственную форму подбора. Удобнее всего — обработка ПодборТоваров с одной управляемой формой.

Динамический список на произвольном запросе

  1. Добавьте форме реквизит Список типа ДинамическийСписок.
  2. В его свойствах включите Произвольный запрос и откройте настройку списка.
  3. Напишите запрос с соединением к остаткам:
ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    Номенклатура.Артикул КАК Артикул,
    ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
    Справочник.Номенклатура КАК Номенклатура
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК Остатки
        ПО Номенклатура.Ссылка = Остатки.Номенклатура
ГДЕ
    НЕ Номенклатура.ЭтоГруппа

Имена регистра и его измерений здесь условные — возьмите их из своей конфигурации.

  1. Укажите Основная таблица — Справочник.Номенклатура. Без этого список не сможет корректно определять текущую строку и быстро прокручиваться.

Динамический список внутри построен на системе компоновки данных (СКД). Отсюда два практических плюса:

  • 🔍 у пользователя работают штатные «Найти», отборы по колонкам и сортировка;
  • ⚙️ на закладке настроек списка можно задать условное оформление — например, подсветить красным строки с нулевым остатком.

Передача параметра запроса

Параметр &Склад заполняется при открытии формы. Склад передайте из документа параметром формы:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

    Список.Параметры.УстановитьЗначениеПараметра("Склад", Параметры.Склад);

КонецПроцедуры

Чтобы Параметры.Склад был доступен, добавьте форме обработки параметр Склад на закладке Параметры редактора формы.

Неустановленный параметр динамического списка — ошибка при открытии формы. Если склад в документе может быть пустым, установите параметр всё равно (пустой ссылкой), а остатки при пустом складе получите без отбора по складу отдельным вариантом запроса.

Корзина и перенос в документ

В форме подбора заведите реквизит Корзина — таблицу значений с колонками Номенклатура и Количество. Двойной щелчок по строке списка добавляет позицию в корзину. Кнопка «Перенести в документ» отправляет корзину владельцу.

Таблицу значений нельзя передать на клиент владельца как есть. Её кладут во временное хранилище, а владельцу отправляют адрес:

&НаКлиенте
Процедура ПеренестиВДокумент(Команда)

    Адрес = ПоместитьКорзинуВХранилище();
    ОповеститьОВыборе(Новый Структура("АдресКорзины", Адрес));
    Закрыть();

КонецПроцедуры

&НаСервере
Функция ПоместитьКорзинуВХранилище()

    Таблица = РеквизитФормыВЗначение("Корзина");
    Возврат ПоместитьВоВременноеХранилище(Таблица, Параметры.ИдентификаторВладельца);

КонецФункции

ИдентификаторВладельца — ещё один параметр формы. В документе при открытии подбора передайте в него УникальныйИдентификатор формы документа. Хранилище будет привязано к форме документа и не исчезнет вместе с закрытой формой подбора.

Метод ОповеститьОВыборе вызывает у владельца то же событие ОбработкаВыбора. В нём нужно отличать структуру от ссылки или массива:

Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура")
    И ВыбранноеЗначение.Свойство("АдресКорзины") Тогда
    ЗагрузитьКорзинуНаСервере(ВыбранноеЗначение.АдресКорзины);
    Возврат;
КонецЕсли;

На сервере корзина достаётся вызовом ПолучитьИзВременногоХранилища(Адрес) и раскладывается в Объект.Товары тем же циклом, что и в шаге 2, только количество берётся из корзины.

Что ещё можно добавить к подбору

Когда базовая схема работает, её обычно доращивают:

  • 🧾 Запрос количества. После выбора позиции открыть модальный ввод числа нельзя — используйте ПоказатьВводЧисла() с описанием оповещения, а строку добавляйте в обработчике оповещения.
  • 🏷️ Подбор по штрихкоду. Отдельная команда, которая ищет номенклатуру по штрихкоду и добавляет строку тем же серверным методом.
  • 📦 Подбор из нескольких справочников. Например, товары и услуги в одну таблицу. Владельцем делайте форму, а источник различайте по параметру ИсточникВыбора или по типу пришедшей ссылки.
  • 🔒 Доступность кнопки. Если документ проведён или открыт только на чтение, отключите кнопку: Элементы.ТоварыПодбор.Доступность = НЕ ТолькоПросмотр; в ПриСозданииНаСервере. Имя элемента кнопки смотрите в дереве элементов.

Если в форме больше одной табличной части, сделайте отдельную команду подбора на каждую. Один общий обработчик с ветвлениями быстро превращается в трудно читаемый код.

Почему кнопка подбора не работает: разбор симптомов

Диагностика: выберите симптом

Частые вопросы

Можно ли сделать подбор без программного кода?
Частично. Если в табличную часть добавлять строки кнопкой «Добавить» и выбирать номенклатуру в ячейке — код не нужен. Но множественный выбор с наполнением строк без кода не настроить.
Чем подбор отличается от обычного выбора в поле?
Выбор в поле подставляет одно значение и закрывает форму. Подбор держит форму открытой и добавляет строки в таблицу, пока пользователь не закроет её сам.
Работает ли этот код в веб-клиенте и тонком клиенте?
Да. Весь пример написан для управляемых форм без модальных вызовов, поэтому одинаково работает в тонком клиенте, веб-клиенте и в сервисе.
Как подобрать товар сразу с ценой из прайса?
В серверной процедуре добавления строки получите цену запросом к регистру сведений с ценами на дату документа и запишите её в строку перед расчётом суммы.
Можно ли открыть подбор горячей клавишей?
Да. В свойствах команды формы задайте Сочетание клавиш. Выберите сочетание, которое не занято стандартными командами таблицы, иначе сработает стандартная команда.