Как в СКД получить курс валюты на дату заказа и избежать дублирования данных?

Программист 1С:ERP Управление предприятием Управленческий учет
← На главную

При разработке отчетов в 1С:ERP на базе системы компоновки данных (СКД) часто возникает задача пересчета сумм из валюты документа в валюту управленческого или регламентированного учета. Основная сложность заключается в том, что курс валюты меняется во времени, и для каждого заказа в выборке необходимо получить значение из регистра сведений КурсыВалют, актуальное именно на дату этого заказа. Попытки простого левого соединения по условию Курс.Период <= Заказ.Период неизбежно приводят к дублированию строк, так как система находит все записи курса в прошлом. Разберем наиболее эффективные способы решения этой задачи, учитывая специфику ERP и возможности платформы 8.3.

Метод 1. Срез последних на каждую дату через временные таблицы

Это классический способ реализации «среза последних» внутри одного запроса. Он позволяет избежать дублей и корректно сопоставить каждую дату документа с ближайшим предшествующим курсом. Рассмотрим алгоритм реализации этого метода по шагам.

Проанализируем ситуацию: нам нужно сначала собрать все уникальные даты и валюты из наших заказов во временную таблицу, чтобы не обрабатывать лишние данные. Затем для каждой пары «Дата-Валюта» мы найдем максимальную дату в регистре курсов, которая не превышает дату заказа.

Выполним следующие действия в тексте запроса:

  1. Подготовка данных. Поместим уникальные даты заказов и валюты во временную таблицу ВТ_ДатыЗаказов.
  2. Поиск дат курса. Для каждой записи из ВТ_ДатыЗаказов найдем максимальную дату периода в регистре КурсыВалют.
  3. Получение значений курса. Соединим полученные максимальные даты с самим регистром для извлечения полей Курс и Кратность.

Посмотрим на пример реализации такого подхода в запросе:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗаказыКлиентовОбороты.Период КАК ПериодЗаказа,
    ЗаказыКлиентовОбороты.ЗаказКлиента.Валюта КАК Валюта
ПОМЕСТИТЬ ВТ_УникальныеДаты
ИЗ
    РегистрНакопления.ЗаказыКлиентов.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК ЗаказыКлиентовОбороты
;

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

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

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

Метод 2. Использование связей наборов данных в СКД

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

Разберем, как это настроить:

  1. Первый набор данных (Заказы). Здесь мы пишем основной запрос к регистру ЗаказыКлиентов.Обороты. Важно включить в выборку поля Период и Валюта.
  2. Второй набор данных (Курсы). Создаем запрос к виртуальной таблице РегистрСведений.КурсыВалют.СрезПоследних(&ПериодКурса, Валюта = &ВалютаКурса).
  3. Настройка связей. Переходим на закладку «Связи наборов данных».
    • Источник связи — набор «Заказы», приемник — набор «Курсы».
    • Условие связи: Валюта = ВалютаКурса.
    • Параметры: в качестве параметра ПериодКурса передаем поле Период из набора «Заказы».

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

Метод 3. Получение данных напрямую из документа (Специфика ERP)

В прикладном решении 1С:ERP Управление предприятием архитектура данных позволяет оптимизировать получение курса. Проанализируем объект Документ.ЗаказКлиента. В отличие от типовых регистров накопления, сам документ в своей структуре часто уже хранит зафиксированные значения Курс и Кратность, актуальные на момент создания заказа.

Если бизнес-логика отчета подразумевает использование курса, по которому был оформлен заказ (а не текущего курса из регистра на ту дату), то наиболее правильным и быстрым решением будет левое соединение с таблицей документа по регистратору:


ВЫБРАТЬ
    ЗаказыОбороты.Регистратор,
    ЗаказыОбороты.СуммаПриход,
    ВЫРАЗИТЬ(ЗаказыОбороты.Регистратор КАК Документ.ЗаказКлиента).Валюта КАК ВалютаДокумента,
    ВЫРАЗИТЬ(ЗаказыОбороты.Регистратор КАК Документ.ЗаказКлиента).Курс КАК КурсДокумента,
    ВЫРАЗИТЬ(ЗаказыОбороты.Регистратор КАК Документ.ЗаказКлиента).Кратность КАК КратностьДокумента
ИЗ
    РегистрНакопления.ЗаказыКлиентов.Обороты(&Начало, &Конец, Регистратор) КАК ЗаказыОбороты

Использование оператора ВЫРАЗИТЬ позволяет системе быстро обратиться к полям шапки документа. Это избавляет от необходимости работать с регистром сведений КурсыВалют вовсе.

Важные замечания по оптимизации и типичные ошибки

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

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

Обработка пустых значений. Всегда существует риск, что на определенную дату курс валюты в системе не задан. Чтобы отчет не выдавал пустые значения или ошибку деления на ноль, используйте функцию ЕСТЬNULL в вычисляемых полях или запросе:


СУММА(ЗаказыКлиентовОбороты.СуммаПриход * ЕСТЬNULL(Курс, 1) / ЕСТЬNULL(Кратность, 1))

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

Таким образом, мы разобрали три основных подхода. Для простых отчетов в СКД лучше всего подходит связь наборов данных. Для сложных расчетов внутри запроса — временные таблицы с поиском максимальной даты. А для максимальной производительности в ERP — обращение напрямую к реквизитам документа.

← На главную