НейроАгент

Как получить цену в 1С:УТ 11 за конкретную дату

Правильные методы получения цен из регистра ЦеныНоменклатуры в 1С:Управление торговлей 11. Использование СрезПоследний и корректная работа с периодами.

Как правильно составить запрос к регистру сведений для получения цены в 1С:Управление торговлей 11?

Мне нужно получить цену на номенклатуру в УТ11. Я использую следующий запрос:

1C
Запрос.Текст = "ВЫБРАТЬ
               |   ЦеныНоменклатуры.Номенклатура.Ссылка КАК НоменклатураСсылка,
               |   ЦеныНоменклатуры.ВидЦены.Ссылка КАК ВидЦеныСсылка,
               |   ЦеныНоменклатуры.Цена КАК Цена
               |ИЗ
               |   РегистрСведений.ЦеныНоменклатуры КАК ЦеныНоменклатуры
               |ГДЕ
               |   ЦеныНоменклатуры.ВидЦены.Ссылка = &ВидЦены
               |   И ЦеныНоменклатуры.Номенклатура.Ссылка = &Номенклатура
               |   И ЦеныНоменклатуры.Период МЕЖДУ &ДатаНачало И &ДатаКонец";

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

Проблема в том, что когда я добавляю условие по периоду, запрос не возвращает никаких данных. Без условия по периоду я получаю цены за старые даты. Я понимаю, что нужно выбрать цену на определенную номенклатуру, которая действует на указанный период. Что я делаю не так?

НейроАгент

Для получения цены на номенклатуру в 1С:Управление торговлей 11 из регистра сведений “ЦеныНоменклатуры” нужно использовать правильный подход к выборке данных по периоду. Ваша проблема заключается в том, что вы пытаетесь выбрать цены в диапазоне дат, а вам нужна конкретная цена, действующая на указанную дату.

Содержание

Основные проблемы в вашем запросе

Ваш текущий запрос использует условие МЕЖДУ &ДатаНачало И &ДатаКонец, что приводит к выборке всех записей цен в указанном диапазоне, а не к получению конкретной цены, действующей на нужную дату.

Проблема заключается в том, что:

  • Регистр “ЦеныНоменклатуры” является периодическим, что означает, что каждая запись имеет интервал времени действия
  • При простом отборе по диапазону вы получаете все цены, установленные за этот период
  • Вам нужно получить конкретную цену, которая была действительной на определенную дату

Структура регистра “ЦеныНоменклатуры”

Из исследования источников можно определить, что регистр “ЦеныНоменклатуры” имеет следующую структуру:

Измерения:

  • Номенклатура (ссылка на справочник)
  • ВидЦены (ссылка на справочник)

Ресурсы:

  • Цена (числовое значение)

Реквизиты:

  • ВалютаЦены (ссылка на справочник валют)
  • Упаковка (числовое значение)

Периодичность: “В пределах секунды”
Режим записи: “Подчинение регистратору”


Правильный синтаксис запроса

Для получения цены на конкретную дату нужно использовать следующие подходы:

Вариант 1: Использование виртуальной таблицы “СрезПоследний”

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

Запрос.УстановитьПараметр("Номенклатура", НоваяСтрока.Номенклатура.Ссылка);
Запрос.УстановитьПараметр("ВидЦены", НоваяСтрока.ВидЦены.Ссылка);
Запрос.УстановитьПараметр("ДатаВыбора", ТекущаяДата());

Вариант 2: Использование стандартной функции “Цена”

1C
Запрос.Текст = "ВЫБРАТЬ
               |   ЦеныНоменклатуры.Номенклатура.Ссылка КАК НоменклатураСсылка,
               |   ЦеныНоменклатуры.ВидЦены.Ссылка КАК ВидЦеныСсылка,
               |   ЦеныНоменклатуры.Цена КАK Цена
               |ИЗ
               |   РегистрСведений.ЦеныНоменклатуры КАK ЦеныНоменклатуры
               |ГДЕ
               |   ЦеныНоменклатуры.Номенклатура.Ссылка = &Номенклатура
               |   И ЦеныНоменклатуры.ВидЦены.Ссылка = &ВидЦены
               |   И &ДатаВыбора МЕЖДУ ЦеныНоменклатуры.Период.Начало 
               |   И ЦеныНоменклатуры.Период.Конец";

Запрос.УстановитьПараметр("Номенклатура", НоваяСтрока.Номенклатуры.Ссылка);
Запрос.УстановитьПараметр("ВидЦены", НоваяСтрока.ВидЦены.Ссылка);
Запрос.УстановитьПараметр("ДатаВыбора", ТекущаяДата());

Методы получения цены на конкретную дату

Метод 1: Виртуальная таблица “СрезПоследний” (рекомендуемый)

Этот метод является наиболее эффективным и правильным для получения цены на конкретную дату:

1C
// Получение цены на указанную дату
Функция ПолучитьЦенуНоменклатуры(Номенклатура, ВидЦены, ДатаВыбора) Экспорт
    
    Запрос = Новый Запрос;
    
    Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
                   |   ЦеныНоменклатуры.Цена
                   |ИЗ
                   |   РегистрСведений.ЦеныНоменклатуры КАK ЦеныНоменклатуры
                   |ГДЕ
                   |   ЦеныНоменклатуры.Номенклатура = &Номенклатура
                   |   И ЦеныНоменклатуры.ВидЦены = &ВидЦены
                   |   И &ДатаВыбора МЕЖДУ ЦеныНоменклатуры.Период.Начало 
                   |   И ЦеныНоменклатуры.Период.Конец";
    
    Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
    Запрос.УстановитьПараметр("ВидЦены", ВидЦены);
    Запрос.УстановитьПараметр("ДатаВыбора", ДатаВыбора);
    
    Результат = Запрос.Выполнить();
    Выборка = Результат.Выбрать();
    
    Если Выборка.Следующий() Тогда
        Возврат Выборка.Цена;
    КонецЕсли;
    
    Возврат Неопределено;
КонецФункции

Метод 2: Использование встроенных функций 1С

1C
// Использование встроенной функции Цена
Цена = УправлениеТорговлейЦенообразование.Цена(Номенклатура, ВидЦены, ДатаВыбора);

Распространенные ошибки и их решения

Ошибка 1: Неправильное использование условия по периоду

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

1C
И ЦеныНоменклатуры.Период МЕЖДУ &ДатаНачало И &ДатаКонец

Решение: Нужно проверять, попадает ли искомая дата в интервал действия цены:

1C
И &ДатаВыбора МЕЖДУ ЦеныНоменклатуры.Период.Начало И ЦеныНоменклатуры.Период.Конец

Ошибка 2: Отсутствие сортировки по дате

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

Решение: Добавить сортировку по дате убывания:

1C
УПОРЯДОЧИТЬ ПО ЦеныНоменклатуры.Период.Конец УБЫВАНИЮ

Ошибка 3: Неправильная обработка пустых интервалов

Проблема: Некоторые цены могут иметь неограниченный интервал действия.

Решение: Обрабатывать случаи, когда КонецПериода = Дата(0001, 1, 1):

1C
И (&ДатаВыбора >= ЦеныНоменклатуры.Период.Начало 
   И (ЦеныНоменклатуры.Период.Конец = ДатаВремя(1, 1, 1) 
       ИЛИ &ДатаВыбора <= ЦеныНоменклатуры.Период.Конец))

Продвинутые сценарии работы с регистром

Сценарий 1: Получение цен с учетом характеристик номенклатуры

1C
Запрос.Текст = "ВЫБРАТЬ
               |   ЦеныНоменклатуры.Цена
               |ИЗ
               |   РегистрСведений.ЦеныНоменклатуры КАK ЦеныНоменклатуры
               |ГДЕ
               |   ЦеныНоменклатуры.Номенклатура = &Номенклатура
               |   И ЦеныНоменклатуры.Характеристика = &Характеристика
               |   И ЦеныНоменклатуры.ВидЦены = &ВидЦены
               |   И &ДатаВыбора МЕЖДУ ЦеныНоменклатуры.Период.Начало 
               |   И ЦеныНоменклатуры.Период.Конец
               |УПОРЯДОЧИТЬ ПО 
               |   ЦеныНоменклатуры.Период.Конец УБЫВАНИЮ";

Сценарий 2: Получение истории изменения цен

1C
Запрос.Текст = "ВЫБРАТЬ
               |   ЦеныНоменклатуры.Период.Начало КАK ДатаНачала,
               |   ЦеныНоменклатуры.Период.Конец КАK ДатаОкончания,
               |   ЦеныНоменклатуры.Цена
               |ИЗ
               |   РегистрСведений.ЦеныНоменклатуры КАK ЦеныНоменклатуры
               |ГДЕ
               |   ЦеныНоменклатуры.Номенклатура = &Номенклатура
               |   И ЦеныНоменклатуры.ВидЦены = &ВидЦены
               |   И ЦеныНоменклатуры.Период.Начало МЕЖДУ &ДатаНачала и &ДатаОкончания
               |УПОРЯДОЧИТЬ ПО
               |   ЦеныНоменклатуры.Период.Начало ВОЗРАСТАНИЮ";

Выводы и рекомендации

  1. Используйте виртуальную таблицу “СрезПоследний” для получения цены на конкретную дату - это самый эффективный и правильный метод.

  2. Проверяйте интервал действия цены с помощью условия &ДатаВыбора МЕЖДУ Период.Начало И Период.Конец.

  3. Обрабатывайте случаи с неограниченным периодом действия, когда Период.Конец = Дата(0001, 1, 1).

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

  5. Для получения истории изменения цен используйте выборку по диапазону дат с сортировкой по дате возрастания.

  6. Для новых версий УТ 11 (11.5 и выше) используйте регистр “ЦеныНоменклатуры25”, который имеет расширенную функциональность.

Правильная работа с регистром “ЦеныНоменклатуры” позволит вам получать актуальные цены на любую дату и избегать проблем с устаревшими данными.

Источники

  1. Получение в запросе цен на дату документа
  2. Новое в версии 11.5.6 :: Информация об обновлениях программных продуктов 1С:Предприятие
  3. Регистр сведений ЦеныНоменклатуры25 — разбираем как получать цены
  4. Отбор в регистре сведений 1C | Блог 1С программиста
  5. Установка цен Управление Торговлей 11. Произвольный запрос к данным ИБ