При разработке механизмов автоматического заполнения документов в 1С:Предприятие часто возникает задача: выбрать все элементы, входящие в определенную папку (группу) справочника Номенклатура, включая вложенные подпапки, и перенести их в табличную часть документа. На первый взгляд задача кажется простой, но начинающие разработчики часто сталкиваются с ошибками типизации и неправильной работой запросов. В этой статье мы подробно разберем, как правильно реализовать этот механизм, проанализируем типичные ошибки и выясним, как дополнить выборку данными об остатках на складах.
Рассмотрим ситуацию, когда при выполнении запроса система выдает ошибку "Неверные параметры" или сообщает, что переменная не определена. Чаще всего это происходит в обычных формах (платформа 8.2 или 8.3 в режиме совместимости), когда разработчик пытается передать в запрос непосредственно элемент управления с формы.
Проанализируем пример ошибочного кода:
Запрос.УстановитьПараметр("Папка", ЭлементыФормы.ПолеВводаРодитель); // ОШИБКА!
Выясним причину: ЭлементыФормы.ПолеВводаРодитель — это объект типа ПолеВвода, то есть визуальный элемент интерфейса. Запрос же ожидает ссылку на объект базы данных (тип СправочникСсылка.Номенклатура). Чтобы исправить ситуацию, необходимо обращаться либо напрямую к реквизиту объекта, с которым связана форма, либо извлекать значение из элемента управления.
Правильный вариант обращения будет выглядеть так:
// Если ПолеВводаРодитель — это имя реквизита формы:
Запрос.УстановитьПараметр("Папка", ПолеВводаРодитель);
// Или явное обращение к значению элемента формы:
Запрос.УстановитьПараметр("Папка", ЭлементыФормы.ПолеВводаРодитель.Значение);
Для того чтобы выбрать не только элементы, находящиеся непосредственно в указанной папке, но и содержимое всех дочерних подпапок, в языке запросов 1С используется специальный оператор В ИЕРАРХИИ. В отличие от обычного равенства (Родитель = &Папка), этот оператор заставляет систему рекурсивно обходить дерево групп.
Рассмотрим структуру правильного запроса для выбора элементов:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Номенклатура
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В ИЕРАРХИИ(&Папка)
| И Номенклатура.ЭтоГруппа = ЛОЖЬ";
Запрос.УстановитьПараметр("Папка", ВыбраннаяГруппа);
Обратим внимание на важное условие Номенклатура.ЭтоГруппа = ЛОЖЬ. Если его не добавить, запрос вернет в том числе и сами группы (папки), что при заполнении табличной части "Товары" в документе обычно не требуется и может привести к ошибкам проведения.
После того как мы получили список нужных товаров, их необходимо добавить в документ. Разберем по шагам наиболее эффективный способ заполнения табличной части (например, Материалы или Товары).
Проанализируем программный цикл добавления строк:
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
// Добавляем новую строку в табличную часть документа
НоваяСтрока = Материалы.Добавить();
// Используем универсальный метод заполнения по именам полей
ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
// Если в запросе поле названо так же, как колонка в ТЧ ("Номенклатура"),
// значение перенесется автоматически.
КонецЦикла;
Использование метода ЗаполнитьЗначенияСвойств значительно сокращает код и уменьшает количество ошибок, связанных с опечатками в именах реквизитов.
Часто задача усложняется: нужно заполнить документ не просто всей номенклатурой из папки, а только той, которая реально есть в наличии на конкретном складе. Для этого нам потребуется соединение справочника с виртуальной таблицей остатков.
Рассмотрим, как изменить запрос для получения остатков:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период,
| Склад = &Склад И Номенклатура В ИЕРАРХИИ(&Папка)
| ) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("Папка", ПолеВводаРодитель);
Запрос.УстановитьПараметр("Склад", ВыбранныйСклад);
Запрос.УстановитьПараметр("Период", ТекущаяДата()); // или МоментВремени() документа
Результат = Запрос.Выполнить();
Важный нюанс: Условие В ИЕРАРХИИ мы помещаем непосредственно в параметры виртуальной таблицы Остатки. Это работает гораздо быстрее, чем если бы мы сначала выбрали все остатки, а потом фильтровали их через ГДЕ в основном теле запроса.
Если вам не нужны сложные фильтры или остатки, а требуется просто быстро перебрать элементы в коде (например, для вывода сообщений), можно воспользоваться методом ВыбратьИерархически(). Однако помните, что для заполнения больших документов запросы всегда предпочтительнее из-за их производительности.
Пример использования объектного метода:
Выборка = Справочники.Номенклатура.ВыбратьИерархически(ПолеВводаРодитель);
Пока Выборка.Следующий() Цикл
Если Выборка.ЭтоГруппа Тогда
Продолжить;
КонецЕсли;
Сообщить("Обработка элемента: " + Выборка.Наименование);
КонецЦикла;
Для корректного выбора элементов из группы и заполнения документа следует придерживаться следующих правил:
ЗаполнитьЗначенияСвойств().Соблюдение этих рекомендаций позволит вам создавать надежные и быстрые механизмы автоматизации в любых конфигурациях на платформе 1С.