Почему не работает выборка из регистра сведений по структуре и как правильно получить цены номенклатуры в 1С?

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

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

Анализ проблемы: почему возникает ошибка при вызове метода Выбрать

Рассмотрим исходный пример кода, вызвавший затруднение:


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

Выборка = РегистрыСведений.ЦеныНоменклатуры.Выбрать(,,Структура);

На последней строке платформа выбрасывает исключение: «Недопустимое значение параметра (параметр номер '3')». При этом аналогичный запрос к регистру сведений с теми же параметрами успешно отрабатывает. Выясним причину такого поведения платформы 1С:Предприятие:

  1. Ограничение на количество полей в структуре отбора: В объекте РегистрСведенийМенеджер метод Выбрать(<НачалоПериода>, <КонецПериода>, <Отбор>, <Порядок>) имеет строгое системное ограничение. Параметр Отбор (тип Структура) может содержать только один элемент. Попытка передать структуру с двумя и более измерениями (в данном примере — одновременно «Номенклатура» и «ВидЦен») гарантированно приводит к ошибке выполнения.
  2. Требование к индексации поля отбора: Единственное поле, переданное в отбор метода Выбрать(), обязательно должно иметь в метаданных установленное свойство «Индексировать» (или «Индексировать с доп. упорядочиванием»), либо являться ведущим измерением.
  3. Несоответствие метода решаемой задаче: Метод Выбрать() предназначен для считывания физических записей регистра в заданном интервале дат (фактически журнала изменений). Если регистр является периодическим (а регистр ЦеныНоменклатуры в конфигурациях УНФ, УТ и ERP имеет периодичность, как правило, в пределах дня), то метод Выбрать() вернет все исторические записи, а не действующую цену на конкретный момент времени.

Объектные методы получения среза: ПолучитьПоследнее и СрезПоследних

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

Рассмотрим метод ПолучитьПоследнее(). Он возвращает структуру со значениями ресурсов на указанную дату (или пустые значения, если записей не найдено):


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

// Получаем значения ресурсов на дату документа
ЗначенияРесурсов = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ДокументСсылка.Дата, Отбор);
Цена = ЗначенияРесурсов.Цена;

Также можно воспользоваться методом менеджера СрезПоследних(), который возвращает результат в виде ТаблицыЗначений:


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

ТаблицаЦен = РегистрыСведений.ЦеныНоменклатуры.СрезПоследних(ДокументСсылка.Дата, Отбор);
Если ТаблицаЦен.Количество() > 0 Тогда
    Цена = ТаблицаЦен[0].Цена;
КонецЕсли;

Оптимальное решение для печатных форм: использование запросов

Хотя методы ПолучитьПоследнее() и СрезПоследних() работают корректно, вызывать их внутри цикла обхода строк табличной части документа (например, при формировании внешней печатной формы заказ-наряда) — грубая ошибка проектирования. Обращение к базе данных в цикле существенно замедляет формирование документов.

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

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    ЦеныНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура,
    |    ЦеныНоменклатурыСрезПоследних.Характеристика КАК Характеристика,
    |    ЦеныНоменклатурыСрезПоследних.Цена КАК Цена
    |ИЗ
    |    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
    |        &Период,
    |        ВидЦен = &ВидЦен
    |            И Номенклатура В (&МассивНоменклатуры)) КАК ЦеныНоменклатурыСрезПоследних";

Запрос.УстановитьПараметр("Период", ДокументОбъект.Дата);
Запрос.УстановитьПараметр("ВидЦен", Справочники.ВидыЦен.Оптовая);
Запрос.УстановитьПараметр("МассивНоменклатуры", ТаблицаМатериалов.ВыгрузитьКолонку("Номенклатура"));

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

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

Особенности работы с регистром «ЦеныНоменклатуры» в типовой УНФ

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

  1. Учет по характеристикам: Измерение Характеристика входит в состав регистра. Если в отборе или в параметрах виртуальной таблицы не указать характеристику (или передать незаполненное значение), при наличии нескольких характеристик у одной номенклатуры срез вернет непредвиденный набор строк. Для позиций без характеристик передавайте Справочники.ХарактеристикиНоменклатуры.ПустаяСсылка().
  2. Единицы измерения и коэффициенты: Цены в УНФ могут регистрироваться для конкретной единицы измерения номенклатуры. Если в табличной части заказ-наряда материал указан в упаковках или иных единицах, необходимо производить пересчет цены с учетом коэффициента.
  3. Использование типовых механизмов: В типовых конфигурациях логика работы с ценами уже вынесена в специализированные общие модули. Перед написанием собственного запроса рекомендуется изучить код типовых печатных форм документа (например, заказ-наряда или обработки ПечатьТТН) и по возможности интегрировать выборку цен непосредственно в основной запрос формирования печатной формы документа через ЛЕВОЕ СОЕДИНЕНИЕ со срезом последних.
← На главную