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

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

При разработке документов и отчетов в 1С часто возникает задача определить максимальный курс валюты за определенный временной интервал — например, за последние 5 календарных дней от даты документа (такого как ЗаказПокупателя, ЗаказПоставщику, ПоступлениеТоваровУслуг или РеализацияТоваровУслуг).

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

Особенности работы с регистром сведений «КурсыВалют»

Разберем основные нюансы, которые нужно учитывать при составлении запроса:

  1. Пропуск дней в физической таблице. Записи в периодический регистр сведений КурсыВалют заносятся только тогда, когда курс реально изменился. Если курс не менялся в течение всех 5 дней, поиск по физической таблице с условием Период МЕЖДУ &НачДата И &КонДата вернет пустой результат.
  2. Ограничения виртуальной таблицы СрезПоследних. Виртуальная таблица СрезПоследних возвращает данные только на одну конкретную дату. Сделать срез сразу на интервал дат в одном простом обращении к виртуальной таблице невозможно.
  3. Учет кратности валюты. Поле Курс хранит стоимость за указанное в регистре количество единиц (Кратность). Чтобы получить реальную цену одной единицы валюты, необходимо вычислять отношение Курс / Кратность.

Вариант 1. Простой запрос по физической таблице регистра

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

Рассчитать начальную дату периода (на 4–5 дней назад от даты документа) можно прямо в запросе с помощью функции ДОБАВИТЬКДАТЕ, либо передав параметры &НачДата и &КонДата из BSL-кода:


ВЫБРАТЬ
    КурсыВалют.Валюта КАК Валюта,
    МАКСИМУМ(КурсыВалют.Курс / ЕСТЬNULL(КурсыВалют.Кратность, 1)) КАК МаксимальныйКурс
ИЗ
    РегистрСведений.КурсыВалют КАК КурсыВалют
ГДЕ
    КурсыВалют.Валюта = &Валюта
    И КурсыВалют.Период МЕЖДУ &НачДата И &КонДата
СГРУППИРОВАТЬ ПО
    КурсыВалют.Валюта

Недостаток этого метода: если за указанный период курс валюты не обновлялся ни разу (например, были выходные или праздничные дни), выборка вернет пустую строку, так как новых записей в этот период физически нет.

Вариант 2. Надежный способ: объединение начального среза и движений за период

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

  1. СрезПоследних на дату начала периода (за 4–5 дней до документа). Это даст курс, который действовал на самый первый день рассматриваемого интервала.
  2. Физическая таблица КурсыВалют за интервал от начала периода до даты документа. Это учтет все изменения курса, происходившие внутри пятидневки.

Проанализируем пример запроса с объединением временных таблиц:


ВЫБРАТЬ
    СрезНаНачало.Валюта КАК Валюта,
    СрезНаНачало.Курс / ЕСТЬNULL(СрезНаНачало.Кратность, 1) КАК Курс
ПОМЕСТИТЬ ВТ_КурсыЗаПериод
ИЗ
    РегистрСведений.КурсыВалют.СрезПоследних(&НачДата, Валюта = &Валюта) КАК СрезНаНачало

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДвиженияЗаПериод.Валюта,
    ДвиженияЗаПериод.Курс / ЕСТЬNULL(ДвиженияЗаПериод.Кратность, 1)
ИЗ
    РегистрСведений.КурсыВалют КАК ДвиженияЗаПериод
ГДЕ
    ДвиженияЗаПериод.Валюта = &Валюта
    И ДвиженияЗаПериод.Период МЕЖДУ &НачДата И &КонДата
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_КурсыЗаПериод.Валюта КАК Валюта,
    МАКСИМУМ(ВТ_КурсыЗаПериод.Курс) КАК МаксимальныйКурс
ИЗ
    ВТ_КурсыЗаПериод КАК ВТ_КурсыЗаПериод
СГРУППИРОВАТЬ ПО
    ВТ_КурсыЗаПериод.Валюта

В этом примере первая часть запроса берет срез на дату &НачДата, гарантируя присутствие действовавшего курса. Вторая часть добавляет все колебания внутри периода. Функция МАКСИМУМ в итоговом пакете выбирает наивысшую точку курса за все 5 дней.

Учет рабочих дней вместо календарных

Если по условиям бизнес-логики необходимо анализировать не календарные дни, а 5 рабочих дней, простых арифметических вычислений даты в коде BSL (вида Дата - 5 * 86400) будет недостаточно. В этом случае следует задействовать производственный календарь.

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

← На главную