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

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

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

Метод 1. Использование запроса к виртуальной таблице СрезПоследних

Если нам необходимо получить цены для списка товаров или вывести их в отчете, наиболее эффективным способом будет использование запроса. Платформа 1С предоставляет специальную виртуальную таблицу СрезПоследних, которая значительно упрощает жизнь разработчику.

Рассмотрим стандартную ситуацию: нам нужно получить актуальные цены на определенную дату. Разберем по шагам создание такого запроса:


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

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

  1. Параметр Период: Это дата, на которую мы хотим получить «срез» данных. Система найдет самую свежую запись в регистре, дата которой меньше или равна указанному периоду. Если параметр оставить пустым, запрос вернет самые последние записи на текущий момент.
  2. Параметры виртуальной таблицы: Обратите внимание, что фильтр по виду цены (ВидЦены = &ВидЦены) мы устанавливаем внутри скобок виртуальной таблицы, а не в секции ГДЕ. Это критически важно для производительности. Если наложить условие в ГДЕ, система сначала рассчитает срез по всем товарам и всем ценам в базе, и только потом отфильтрует результат. При большом объеме данных это вызовет серьезные задержки.

Метод 2. Программное получение значения через ПолучитьПоследнее()

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

Рассмотрим пример кода:


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

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

// Извлекаем цену
АктуальнаяЦена = ДанныеЦены.Цена;

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

Работа с объектами МоментВремени и Граница

Часто возникают ситуации, когда цена меняется в тот же день или даже ту же секунду, когда создается документ. Если мы просто передадим Объект.Дата в параметры запроса, мы можем столкнуться с неопределенностью. Для решения этой проблемы в 1С используются специальные типы данных.

Проанализируем использование типа Граница. Он позволяет точно указать, нужно ли включать записи, сделанные ровно в ту же секунду, что и искомая дата:


// Если нужно включить изменения, сделанные в ту же секунду
ГраницаПериода = Новый Граница(Объект.Дата, ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", ГраницаПериода);

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

Сложные случаи: Левое соединение и обработка NULL

Посмотрим на ситуацию, когда нам нужно получить список всей номенклатуры из справочника и подтянуть к ним цены, даже если цена для товара еще не установлена. Для этого мы используем ЛЕВОЕ СОЕДИНЕНИЕ.


ВЫБРАТЬ
    СпрНоменклатура.Ссылка КАК Товар,
    ЕСТЬNULL(Цены.Цена, 0) КАК Цена
ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ 
    РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ВидЦены = &ВидЦены) КАК Цены
ПО 
    СпрНоменклатура.Ссылка = Цены.Номенклатура
ГДЕ
    НЕ СпрНоменклатура.ЭтоГруппа

Разберем подробнее функцию ЕСТЬNULL. При левом соединении, если в регистре нет записи для конкретного товара, поле Цена примет значение NULL. Чтобы избежать ошибок в дальнейших расчетах и корректно отобразить данные (например, ноль вместо пустоты), мы преобразуем NULL в число 0.

Особенности в типовых конфигурациях (ERP, УТ 11, УНФ)

В современных конфигурациях структура регистра цен может быть сложнее. Рассмотрим нюансы:

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

← На главную