При разработке отчетов в 1С:ERP на базе системы компоновки данных (СКД) часто возникает задача пересчета сумм из валюты документа в валюту управленческого или регламентированного учета. Основная сложность заключается в том, что курс валюты меняется во времени, и для каждого заказа в выборке необходимо получить значение из регистра сведений КурсыВалют, актуальное именно на дату этого заказа. Попытки простого левого соединения по условию Курс.Период <= Заказ.Период неизбежно приводят к дублированию строк, так как система находит все записи курса в прошлом. Разберем наиболее эффективные способы решения этой задачи, учитывая специфику ERP и возможности платформы 8.3.
Это классический способ реализации «среза последних» внутри одного запроса. Он позволяет избежать дублей и корректно сопоставить каждую дату документа с ближайшим предшествующим курсом. Рассмотрим алгоритм реализации этого метода по шагам.
Проанализируем ситуацию: нам нужно сначала собрать все уникальные даты и валюты из наших заказов во временную таблицу, чтобы не обрабатывать лишние данные. Затем для каждой пары «Дата-Валюта» мы найдем максимальную дату в регистре курсов, которая не превышает дату заказа.
Выполним следующие действия в тексте запроса:
ВТ_ДатыЗаказов.ВТ_ДатыЗаказов найдем максимальную дату периода в регистре КурсыВалют.Курс и Кратность.Посмотрим на пример реализации такого подхода в запросе:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ЗаказыКлиентовОбороты.Период КАК ПериодЗаказа,
ЗаказыКлиентовОбороты.ЗаказКлиента.Валюта КАК Валюта
ПОМЕСТИТЬ ВТ_УникальныеДаты
ИЗ
РегистрНакопления.ЗаказыКлиентов.Обороты(&НачалоПериода, &КонецПериода, День, ) КАК ЗаказыКлиентовОбороты
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_УникальныеДаты.ПериодЗаказа КАК ПериодЗаказа,
ВТ_УникальныеДаты.Валюта КАК Валюта,
МАКСИМУМ(КурсыВалют.Период) КАК ПериодКурса
ПОМЕСТИТЬ ВТ_МаксимальныеДатыКурсов
ИЗ
ВТ_УникальныеДаты КАК ВТ_УникальныеДаты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
ПО ВТ_УникальныеДаты.Валюта = КурсыВалют.Валюта
И ВТ_УникальныеДаты.ПериодЗаказа >= КурсыВалют.Период
СГРУППИРОВАТЬ ПО
ВТ_УникальныеДаты.ПериодЗаказа,
ВТ_УникальныеДаты.Валюта
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_МаксимальныеДатыКурсов.ПериодЗаказа КАК ПериодЗаказа,
ВТ_МаксимальныеДатыКурсов.Валюта КАК Валюта,
КурсыВалют.Курс КАК Курс,
КурсыВалют.Кратность КАК Кратность
ИЗ
ВТ_МаксимальныеДатыКурсов КАК ВТ_МаксимальныеДатыКурсов
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
ПО ВТ_МаксимальныеДатыКурсов.Валюта = КурсыВалют.Валюта
И ВТ_МаксимальныеДатыКурсов.ПериодКурса = КурсыВалют.Период
Этот метод гарантирует отсутствие дублей, так как на выходе мы получаем ровно одну запись курса на каждую уникальную дату и валюту заказа (используйте шаблон получения таблицы значений для постобработки).
В системе компоновки данных реализован мощный механизм связей, который позволяет существенно упростить написание запросов. Вместо сложной конструкции с временными таблицами мы можем создать два отдельных набора данных.
Разберем, как это настроить:
ЗаказыКлиентов.Обороты. Важно включить в выборку поля Период и Валюта.РегистрСведений.КурсыВалют.СрезПоследних(&ПериодКурса, Валюта = &ВалютаКурса).Валюта = ВалютаКурса.ПериодКурса передаем поле Период из набора «Заказы».Преимущество этого метода: СКД самостоятельно выполнит запрос к курсам валют для каждой строки первого набора данных. Это избавляет программиста от необходимости вручную прописывать логику среза последних в коде запроса и исключает риск получения дублей.
В прикладном решении 1С:ERP Управление предприятием архитектура данных позволяет оптимизировать получение курса. Проанализируем объект Документ.ЗаказКлиента. В отличие от типовых регистров накопления, сам документ в своей структуре часто уже хранит зафиксированные значения Курс и Кратность, актуальные на момент создания заказа.
Если бизнес-логика отчета подразумевает использование курса, по которому был оформлен заказ (а не текущего курса из регистра на ту дату), то наиболее правильным и быстрым решением будет левое соединение с таблицей документа по регистратору:
ВЫБРАТЬ
ЗаказыОбороты.Регистратор,
ЗаказыОбороты.СуммаПриход,
ВЫРАЗИТЬ(ЗаказыОбороты.Регистратор КАК Документ.ЗаказКлиента).Валюта КАК ВалютаДокумента,
ВЫРАЗИТЬ(ЗаказыОбороты.Регистратор КАК Документ.ЗаказКлиента).Курс КАК КурсДокумента,
ВЫРАЗИТЬ(ЗаказыОбороты.Регистратор КАК Документ.ЗаказКлиента).Кратность КАК КратностьДокумента
ИЗ
РегистрНакопления.ЗаказыКлиентов.Обороты(&Начало, &Конец, Регистратор) КАК ЗаказыОбороты
Использование оператора ВЫРАЗИТЬ позволяет системе быстро обратиться к полям шапки документа. Это избавляет от необходимости работать с регистром сведений КурсыВалют вовсе.
Рассмотрим несколько критически важных моментов, которые часто упускают при разработке подобных отчетов.
Ошибка соединения по менеджеру. В исходном вопросе автора присутствовало соединение ЗаказыКлиентовОбороты.ЗаказКлиента.Менеджер = Контрагенты.Партнер.ОсновнойМенеджер. Выясним, почему это опасно. В 1С:ERP справочник Контрагенты связан со справочником Партнеры отношением «многие-к-одному» (у одного партнера-холдинга может быть много юридических лиц-контрагентов). Если соединять через контрагентов, данные могут продублироваться столько раз, сколько контрагентов заведено на одного партнера. Правильно обращаться напрямую к Справочнику.Партнеры, если менеджер закреплен за партнером в целом.
Обработка пустых значений. Всегда существует риск, что на определенную дату курс валюты в системе не задан. Чтобы отчет не выдавал пустые значения или ошибку деления на ноль, используйте функцию ЕСТЬNULL в вычисляемых полях или запросе:
СУММА(ЗаказыКлиентовОбороты.СуммаПриход * ЕСТЬNULL(Курс, 1) / ЕСТЬNULL(Кратность, 1))
Выбор типа валюты. Помните, что в ERP расчеты могут вестись в валюте взаиморасчетов, которая может отличаться от валюты документа. Если ваша задача — привести все к единой валюте управленческого учета, убедитесь, что вы берете курс именно к этой валюте (обычно это базовая валюта, к которой установлены курсы всех остальных).
Таким образом, мы разобрали три основных подхода. Для простых отчетов в СКД лучше всего подходит связь наборов данных. Для сложных расчетов внутри запроса — временные таблицы с поиском максимальной даты. А для максимальной производительности в ERP — обращение напрямую к реквизитам документа.