При разработке расширений для 1С:Розница часто возникает задача дополнить стандартную форму списка номенклатуры дополнительными данными, такими как актуальные цены и остатки товаров на складах. Начинающие разработчики часто сталкиваются с трудностями при работе с запросами, параметрами и механизмом динамических списков. Рассмотрим подробно, как правильно реализовать эту задачу, избежав типичных синтаксических и логических ошибок.
Первая и самая важная деталь, которую мы проанализируем — это контекст выполнения кода. В управляемых формах 1С список номенклатуры отображается с помощью объекта Динамический список. Попытка написать код типа Запрос.Выполнить() внутри процедуры ПриСозданииНаСервере является архитектурной ошибкой для данной задачи. Такой запрос выполнится в памяти сервера, но его результат никак не отразится в таблице, которую видит пользователь.
Для вывода данных в список нам необходимо не выполнять отдельный запрос, а модифицировать текст запроса самого Динамического списка (обычно он называется Список) и устанавливать параметры именно в него.
При использовании конструкторов запросов или консолей (например, консоли Чистова) в коде часто остаются пустые места или подсказки в угловых скобках <>. Посмотрим на пример некорректного кода, который вызывает ошибку "Ожидается выражение":
Запрос.УстановитьПараметр("ВидЦены", < >); // Ошибка: Ожидается выражение
Проанализируем ситуацию: платформа ожидает, что вторым аргументом метода УстановитьПараметр будет конкретное значение или переменная. Если мы хотим использовать конкретный вид цены (например, "Розничная"), нам нужно сначала получить ссылку на этот объект в базе данных.
Прежде чем устанавливать параметр запроса, выясним, какой именно вид цены нам нужен. Не рекомендуется искать объект по наименованию НайтиПоНаименованию("Розничная"), так как пользователь может его переименовать. Однако для учебного примера или быстрой правки рассмотрим этот вариант, добавив проверку.
Рассмотрим правильный алгоритм действий в коде:
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// 1. Находим вид цены (лучше использовать предопределенные или настройки)
ВидЦеныСсылка = Справочники.ВидыЦен.НайтиПоНаименованию("Розничная");
Если ВидЦеныСсылка.Пустая() Тогда
// Сообщим, если вид цены не найден, чтобы избежать ошибки в запросе
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не найден вид цены 'Розничная'!");
Возврат;
КонецЕсли;
// 2. Устанавливаем параметр именно в Динамический Список формы
// Предположим, основной реквизит формы называется "Список"
Список.Параметры.УстановитьЗначениеПараметра("ВидЦены", ВидЦеныСсылка);
КонецПроцедуры
Разберем типичную ошибку в соединении таблиц. В сообщении автора темы была допущена критическая логическая ошибка в блоке ПО при соединении с регистром цен. Рассмотрим, как это выглядит и как это исправить.
Неправильно:
ПО (ЦеныНоменклатурыСрезПоследних.Цена = СправочникНоменклатура.Ссылка)
Здесь поле Цена (число) сравнивается со Ссылкой (уникальный идентификатор). Это никогда не будет работать.
Правильно:
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СправочникНоменклатура.Ссылка)
Теперь соберем полный текст запроса для динамического списка, учитывая левое соединение с остатками и ценами:
ВЫБРАТЬ
СправочникНоменклатура.Ссылка КАК Ссылка,
СправочникНоменклатура.Наименование КАК Наименование,
СправочникНоменклатура.Артикул КАК Артикул,
ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КАК Остаток,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК ЦенаРозничная
ИЗ
Справочник.Номенклатура КАК СправочникНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
ПО (ТоварыНаСкладахОстатки.Номенклатура = СправочникНоменклатура.Ссылка)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(, ВидЦены = &ВидЦены) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СправочникНоменклатура.Ссылка)
ГДЕ
НЕ СправочникНоменклатура.ЭтоГруппа
При работе через расширение (особенно в версии 2.2.7.37) важно помнить следующие моменты:
Номенклатура, справочник ВидыЦен, регистры ТоварыНаСкладах и ЦеныНоменклатуры.&ВидЦены используется в виртуальной таблице СрезПоследних, его обязательная установка в коде через УстановитьЗначениеПараметра критична. Если этого не сделать, система выдаст ошибку "Не задано значение параметра".Если после исправления кода вы видите ошибку Переменная не определена (Результат), это значит, что вы скопировали код из консоли, где результат выполнения запроса присваивался одной переменной, а выборка пыталась начаться от другой. Посмотрите на этот пример:
РезультатЗапроса = Запрос.Выполнить();
Выборка = Результат.Выбрать(); // Ошибка! Должно быть РезультатЗапроса.Выбрать()
Всегда следите за именованием переменных. Однако, как мы выяснили выше, для динамического списка в форме эти строки (Выполнить, Выбрать, Следующий) вообще не нужны. Платформа сама выполнит запрос и отобразит данные в таблице на форме, достаточно просто настроить текст запроса и параметры объекта Список.
Проанализируем производительность. Вывод остатков и цен по всей номенклатуре может замедлить открытие формы, если товаров десятки тысяч. Чтобы ускорить работу:
СрезПоследних).&Склад в таблицу остатков.Таким образом, для успешного решения задачи нам потребовалось изменить подход с "программного запроса" на "настройку динамического списка", исправить синтаксис передачи параметров и логику соединения таблиц по ссылкам, а не по значениям цен.