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

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача: в одном отчете или запросе вывести данные документов (например, «Чеков ККМ») и сопоставить их с ценами, которые были актуальны именно на момент совершения операции. Основная сложность заключается в том, что виртуальная таблица СрезПоследних регистра сведений не умеет принимать дату из другой таблицы (поля запроса) в качестве параметра «на лету».

В этой статье мы подробно разберем, как правильно «прикрутить» цену из регистра сведений ЦеныНоменклатуры к выборке товаров, учитывая дату каждого конкретного чека, наличие характеристик и производительность системы.

Почему нельзя просто использовать СрезПоследних?

Многие начинающие разработчики пытаются использовать РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ...) в левом соединении. Однако параметр &Дата в виртуальной таблице — это константа для всего запроса. Если в вашей выборке чеки за разные дни, то СрезПоследних вернет цены на одну фиксированную дату (конец периода или текущий момент), что приведет к неверным данным в отчете. Для решения этой задачи нам придется работать с физической таблицей регистра.

Метод 1: Коррелированный подзапрос (простой способ)

Проанализируем самый очевидный способ. Мы можем соединить таблицу товаров с физической таблицей цен по условию: ДатаЦены <= ДатаЧека. Чтобы выбрать из множества старых цен только последнюю, мы используем вложенный запрос для поиска максимального периода.

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


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

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

Метод 2: Использование временных таблиц (оптимальный способ)

Для создания быстрого и профессионального запроса мы воспользуемся механизмом временных таблиц. Разберем алгоритм по шагам:

  1. Выделим уникальные пары «Товар + Дата»: Нам не нужно искать цену для каждой строки чека, достаточно найти её для каждой уникальной даты и номенклатуры.
  2. Найдем максимальные даты цен: Соединим наши уникальные пары с физической таблицей цен и получим срез дат.
  3. Получим сами значения цен: Соединим полученные даты с регистром еще раз, чтобы достать поле Цена.
  4. Финальное соединение: Привяжем полученные цены к исходной таблице товаров чека.

Посмотрим на реализацию этого алгоритма:


// Шаг 1: Собираем уникальные комбинации Номенклатура + Характеристика + Дата
ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЧекТовары.Номенклатура КАК Номенклатура,
    ЧекТовары.Характеристика КАК Характеристика,
    ЧекТовары.Ссылка.Дата КАК ДатаЧека
ПОМЕСТИТЬ ВТ_УникальныеПары
ИЗ
    Документ.ЧекККМ.Товары КАК ЧекТовары
ГДЕ
    ЧекТовары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода;

////////////////////////////////////////////////////////////////////////////////
// Шаг 2: Находим дату последней установки цены для каждой пары
ВЫБРАТЬ
    ВТ_УникальныеПары.Номенклатура КАК Номенклатура,
    ВТ_УникальныеПары.Характеристика КАК Характеристика,
    ВТ_УникальныеПары.ДатаЧека КАК ДатаЧека,
    МАКСИМУМ(ЦеныРегистр.Период) КАК ПериодЦены
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
    ВТ_УникальныеПары КАК ВТ_УникальныеПары
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК ЦеныРегистр
        ПО ВТ_УникальныеПары.Номенклатура = ЦеныРегистр.Номенклатура
            И ВТ_УникальныеПары.Характеристика = ЦеныРегистр.Характеристика
            И ЦеныРегистр.Период <= ВТ_УникальныеПары.ДатаЧека
ГДЕ
    ЦеныРегистр.ВидЦены = &ВидЦеныЗакупки
СГРУППИРОВАТЬ ПО
    ВТ_УникальныеПары.Номенклатура,
    ВТ_УникальныеПары.Характеристика,
    ВТ_УникальныеПары.ДатаЧека;

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Получаем значения цен по найденным датам
ВЫБРАТЬ
    ВТ_МаксимальныеДаты.Номенклатура КАК Номенклатура,
    ВТ_МаксимальныеДаты.Характеристика КАК Характеристика,
    ВТ_МаксимальныеДаты.ДатаЧека КАК ДатаЧека,
    Цены.Цена КАК ЦенаЗакупки
ПОМЕСТИТЬ ВТ_ИтоговыеЦены
ИЗ
    ВТ_МаксимальныеДаты КАК ВТ_МаксимальныеДаты
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Цены
        ПО ВТ_МаксимальныеДаты.Номенклатура = Цены.Номенклатура
            И ВТ_МаксимальныеДаты.Характеристика = Цены.Характеристика
            И ВТ_МаксимальныеДаты.ПериодЦены = Цены.Период
ГДЕ
    Цены.ВидЦены = &ВидЦеныЗакупки;

////////////////////////////////////////////////////////////////////////////////
// Шаг 4: Соединяем все данные с основной таблицей чеков
ВЫБРАТЬ
    ЧекТовары.Ссылка.Магазин КАК Магазин,
    ЧекТовары.Номенклатура КАК Номенклатура,
    ЧекТовары.Характеристика КАК Характеристика,
    ЧекТовары.Количество КАК Количество,
    ЧекТовары.Сумма КАК СуммаПродажи,
    ЕСТЬNULL(ВТ_ИтоговыеЦены.ЦенаЗакупки, 0) КАК ЦенаЗакупки,
    ЧекТовары.Ссылка.Дата КАК Дата
ИЗ
    Документ.ЧекККМ.Товары КАК ЧекТовары
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИтоговыеЦены КАК ВТ_ИтоговыеЦены
        ПО ЧекТовары.Номенклатура = ВТ_ИтоговыеЦены.Номенклатура
            И ЧекТовары.Характеристика = ВТ_ИтоговыеЦены.Характеристика
            И ЧекТовары.Ссылка.Дата = ВТ_ИтоговыеЦены.ДатаЧека
ГДЕ
    ЧекТовары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода

Важные нюансы при работе в «1С:Розница»

При реализации данного запроса проанализируем несколько критических моментов, характерных для конфигурации «Розница»:

Подведем итоги

Мы рассмотрели два способа получения цен на дату документа. Использование пакетного запроса с временными таблицами является «золотым стандартом» в разработке на 1С. Это обеспечивает стабильную работу даже при больших объемах данных и позволяет корректно учитывать историю изменения цен в системе.

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

← На главную