Как реализовать выбор значения в табличной части из реквизитов других документов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке конфигураций на платформе 1С:Предприятие 8.3 часто возникают задачи, выходящие за рамки стандартного выбора ссылочных данных. Типичный пример — учебные задачи при подготовке к экзамену «1С:Специалист по платформе», где требуется организовать выбор строкового значения (например, номера договора) в одном документе на основе данных, которые были введены ранее в другом документе. В этом руководстве мы разберем, как реализовать такой механизм максимально эффективно и правильно с точки зрения архитектуры управляемого приложения.

Анализ постановки задачи

Рассмотрим ситуацию: у нас есть документ ПриходнаяНакладная, где в табличной части (или в шапке) указывается реквизит Договор (тип Строка). Нам необходимо, чтобы в документе РасходнаяНакладная при заполнении табличной части пользователь не вводил договор вручную, а мог выбрать его из списка тех договоров, которые уже фигурировали в приходных накладных для конкретной номенклатуры. Проблема заключается в том, что Договор не является ссылкой на справочник, поэтому стандартная кнопка выбора не предложит нам готового списка.

Способ 1: Реализация через событие НачалоВыбора

Этот метод считается наиболее гибким и часто ожидаемым на экзамене. Мы перехватываем момент нажатия пользователем на кнопку выбора в поле табличной части и программно подменяем стандартный список своим собственным. Разберем алгоритм по шагам.

Во-первых, нам необходимо настроить элемент формы. В форме документа РасходнаяНакладная для поля ввода Договор установим свойство КнопкаВыбора в значение Да.

Во-вторых, создадим обработчик события НачалоВыбора. В этом обработчике критически важно установить параметр СтандартнаяОбработка = Ложь, чтобы система не пыталась открыть стандартную форму выбора для строкового типа данных.

Рассмотрим пример программного кода для реализации этой логики:


&НаКлиенте
Процедура СписокНоменклатураДоговорНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Получаем текущую строку, чтобы знать, для какой номенклатуры ищем договор
    ТекущаяСтрока = Элементы.СписокНоменклатура.ТекущиеДанные;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем серверную функцию для получения списка уникальных договоров
    СписокДоговоров = ПолучитьСписокДоговоровНаСервере(ТекущаяСтрока.Номенклатура);
    
    // Предлагаем пользователю выбрать значение из сформированного списка
    Если СписокДоговоров.Количество() > 0 Тогда
        ВыбранныйЭлемент = ВыбратьИзСписка(СписокДоговоров, Элемент);
        Если ВыбранныйЭлемент <> Неопределено Тогда
            ТекущаяСтрока.Договор = ВыбранныйЭлемент.Значение;
        КонецЕсли;
    Иначе
        Сообщить("По данной номенклатуре договоров не найдено!");
    КонецЕсли;
    
КонецПроцедуры

Проанализируем серверную часть. Нам необходимо выполнить запрос к базе данных, чтобы выбрать уникальные значения из проведенных документов ПриходнаяНакладная. Посмотрим на структуру запроса:


&НаСервереБезКонтекста
Функция ПолучитьСписокДоговоровНаСервере(ВыбраннаяНоменклатура)
    
    Список = Новый СписокЗначений;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |	ПриходнаяНакладнаяСписокНоменклатуры.Договор КАК Договор
        |ИЗ
        |	Документ.ПриходнаяНакладная.СписокНоменклатуры КАК ПриходнаяНакладнаяСписокНоменклатуры
        |ГДЕ
        |	ПриходнаяНакладнаяСписокНоменклатуры.Ссылка.Проведен = ИСТИНА
        |	И ПриходнаяНакладнаяСписокНоменклатуры.Номенклатура = &Номенклатура
        |	И ПриходнаяНакладнаяСписокНоменклатуры.Договор <> """"";
    
    Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
    
    РезультатЗапроса = Запрос.Выполнить();
    Если Не РезультатЗапроса.Пустой() Тогда
        Список.ЗагрузитьЗначения(РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Договор"));
    КонецЕсли;
    
    Возврат Список;
    
КонецФункции

В этом примере мы используем ключевое слово РАЗЛИЧНЫЕ, чтобы в список выбора не попадали дублирующиеся названия договоров из разных накладных. Также мы добавили условие на пустую строку, чтобы не предлагать пользователю пустые варианты выбора.

Способ 2: Использование свойства СписокВыбора (Drop-down)

Если мы хотим улучшить UX (User Experience), можно сделать так, чтобы список доступных договоров выпадал сразу при нажатии на стрелочку в поле ввода, без открытия отдельного модального окна выбора. Для этого проанализируем возможности свойства СписокВыбора.

Алгоритм действий следующий:

  1. В свойствах поля формы установим РежимВыбораИзСписка в значение Да.
  2. В событии ПриАктивизацииСтроки или НачалоРедактирования табличной части будем программно заполнять коллекцию СписокВыбора для элемента формы.

Рассмотрим пример кода для события ПриАктивизацииСтроки:


&НаКлиенте
Процедура СписокНоменклатураПриАктивизацииСтроки(Элемент)
    
    ТекущиеДанные = Элементы.СписокНоменклатура.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // Очищаем старый список выбора и заполняем новый для текущей номенклатуры
        Элементы.СписокНоменклатураДоговор.СписокВыбора.Очистить();
        
        СписокДоступныхДоговоров = ПолучитьСписокДоговоровНаСервере(ТекущиеДанные.Номенклатура);
        
        Для Каждого СтрИзСписка Из СписокДоступныхДоговоров Цикл
            Элементы.СписокНоменклатураДоговор.СписокВыбора.Добавить(СтрИзСписка.Значение);
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

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

Способ 3: Динамический список в форме выбора

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

Выясним преимущество этого подхода: пользователю будут доступны стандартные механизмы поиска, отбора и сортировки, встроенные в динамический список. Это особенно полезно, если количество уникальных договоров исчисляется сотнями.

В тексте запроса динамического списка пропишем:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Приходная.Договор КАК Договор
ИЗ
    Документ.ПриходнаяНакладная.СписокНоменклатуры КАК Приходная
ГДЕ
    Приходная.Ссылка.Проведен = ИСТИНА

После создания такой формы, ее нужно назначить в свойство ФормаВыбора реквизита Договор в документе РасходнаяНакладная.

Рекомендации для успешной сдачи экзамена

Проанализируем типичные ошибки, которые допускают кандидаты при решении подобных задач:

  1. Отсутствие проверки на проведение: всегда делайте отбор Ссылка.Проведен = ИСТИНА. Считается некорректным предлагать данные из черновиков или помеченных на удаление документов.
  2. Игнорирование контекста строки: если в строке уже выбрана Номенклатура, список договоров должен фильтроваться именно по этому товару. Предлагать договоры от «цемента», когда выбраны «гвозди», — методическая ошибка.
  3. Использование справочников: если в условии задачи сказано, что договор — это строка, ни в коем случае не создавайте справочник Договоры. Экзаменатор проверяет ваше умение работать с данными «на лету» через запросы.
  4. Отсутствие РАЗЛИЧНЫЕ в запросе: без этого ключевого слова пользователь увидит список из 10 одинаковых строк «Договор №1», если было 10 приходных накладных с таким договором.

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

← На главную