Как в 1С отобрать номенклатуру по единицам измерения программно?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Метод 1: Использование объектной модели и метода «Выбрать()»

Метод Выбрать() у менеджера справочника позволяет получить выборку элементов. Однако у него есть существенное ограничение: отбор (третий параметр метода) может осуществляться только по тем реквизитам, для которых в конфигураторе установлено свойство «Индексировать». Если вы попытаетесь передать в структуру отбора неиндексированное поле, система выдаст ошибку «Недопустимое значение параметра 3».

Рассмотрим пример кода, который изначально вызывал затруднения:


Отбор = Новый Структура("БазоваяЕдиницаИзмерения", Справочники.КлассификаторЕдиницИзмерения.НайтиПоНаименованию("уп"));
Выборка = Справочники.Номенклатура.Выбрать(,, Отбор);
Пока Выборка.Следующий() Цикл
    // Обработка элемента
КонецЦикла;

Почему этот код может не работать? Если в вашей конфигурации (например, в «Управление торговлей 10.3») реквизит БазоваяЕдиницаИзмерения не имеет индекса, программа выдаст исключение. Чтобы решить эту проблему, необходимо либо изменить свойства метаданных в конфигураторе, установив значение «Индексировать» для данного поля, либо воспользоваться механизмом запросов, который лишен этого ограничения.

Метод 2: Использование запросов для отбора данных

Запросы — это наиболее гибкий и производительный способ получения данных в 1С. Рассмотрим ситуацию, когда нам нужно найти номенклатуру по строковому представлению единицы измерения. Важно помнить: БазоваяЕдиницаИзмерения — это ссылка, а не строка. Поэтому прямое сравнение с текстом "уп" в запросе не сработает корректно, если не обращаться к свойству Наименование.

Проанализируем правильный подход с использованием параметров запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   Номенклатура.Ссылка КАК Ссылка
|ИЗ
|   Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|   Номенклатура.БазоваяЕдиницаИзмерения = &ВыбЕдиница";

// Находим ссылку на объект классификатора
СсылкаНаЕдиницу = Справочники.КлассификаторЕдиницИзмерения.НайтиПоНаименованию("уп");

Запрос.УстановитьПараметр("ВыбЕдиница", СсылкаНаЕдиницу);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Пока Выборка.Следующий() Цикл
    // Действия с найденной номенклатурой
КонецЦикла;

Если же вам необходимо выполнить поиск по части наименования (например, условие «Содержит»), в запросах используется оператор ПОДОБНО (LIKE). Это позволяет находить элементы, даже если вы не знаете точного соответствия ссылки.


Запрос.Текст = 
"ВЫБРАТЬ
|   Номенклатура.Ссылка
|ИЗ
|   Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|   Номенклатура.БазоваяЕдиницаИзмерения.Наименование ПОДОБНО ""%"" + &ТекстПоиска + ""%""";
Запрос.УстановитьПараметр("ТекстПоиска", "уп");

Метод 3: Использование Построителя отчета для автоматизации фильтров

В обычных формах (ОФ) часто возникает задача: пользователь уже настроил сложные фильтры в списке номенклатуры на форме (используя стандартный диалог отбора), и программисту нужно получить именно те элементы, которые видит пользователь, чтобы обработать их в цикле. Вручную разбирать коллекцию Отбор у объекта СправочникСписок крайне трудозатратно, так как видов сравнения может быть много (в списке, в иерархии, содержит и т.д.).

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

  1. Создадим объект ПостроительОтчета.
  2. Укажем в качестве источника данных наш список (номенклатуру).
  3. Перенесем активные настройки отбора из элемента формы в настройки построителя.
  4. Выполним запрос и выгрузим результат.

Пример реализации данной логики:


// Предположим, СписокНоменклатуры — это реквизит формы с типом СправочникСписок.Номенклатура
ТекОтбор = ЭлементыФормы.СписокНоменклатуры.ОтборСтрок; // Или просто СписокНоменклатуры.Отбор

Построитель = Новый ПостроительОтчета;
// Инициализируем источник данных
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(СписокНоменклатуры);

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

// Получаем результат в таблицу значений
Результат = Построитель.Результат;
ТаблицаЭлементов = Результат.Выгрузить();

Для каждого Строка Из ТаблицаЭлементов Цикл
    // Работаем с отобранной номенклатурой
    Сообщить(Строка.Ссылка);
КонецЦикла;

Этот метод является наиболее «элегантным» и профессиональным, так как он автоматически учитывает все сложности: иерархические отборы, сравнения по подстрокам и логику работы платформы 1С с динамическими списками.

Важные нюансы работы с типами единиц измерения

При выполнении отборов важно не путать два разных реквизита, которые часто встречаются в типовых конфигурациях:

Если ваша задача — найти всю номенклатуру, которая измеряется в «упаковках» (как в классификаторе), используйте первый вариант. Если же нужно найти номенклатуру, у которой конкретная единица хранения имеет определенные свойства — используйте второй вариант, обращаясь к подчиненному справочнику через запрос.

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

← На главную