При разработке отчетов в системе компоновки данных (СКД) программисты часто сталкиваются с задачей: вывести список документов за произвольный период и для каждой строки документа «подтянуть» справочную информацию (например, цену), актуальную именно на момент совершения операции. Основная сложность здесь заключается в том, что виртуальная таблица СрезПоследних работает на одну конкретную дату, а нам нужно получить значения на разные даты для каждой строки. Разберем, как правильно реализовать этот механизм и избежать пустых результатов при незаполненном периоде.
Рассмотрим ситуацию, когда автор пытается использовать стандартный параметр &Период в условии ГДЕ. Если пользователь на форме отчета снимает галочку с параметра периода, система 1С по умолчанию подставляет в него пустую дату (01.01.0001), что можно увидеть через консоль запросов. В результате условие в запросе принимает вид Дата МЕЖДУ '00010101' И '00010101'. Разумеется, ни один проведенный документ в такой диапазон не попадает, и отчет выходит пустым.
Для решения этой проблемы проанализируем расширение языка запросов СКД. Чтобы сделать параметр действительно необязательным, мы должны использовать фигурные скобки {}. Это дает инструкции компоновщику макета: если параметр не задан пользователем, соответствующее условие должно быть полностью исключено из итогового SQL-запроса (по такому же принципу работают отборы по шаблону).
Пример корректного оформления условия в запросе:
ВЫБРАТЬ
Реализация.Ссылка КАК Ссылка,
Реализация.Дата КАК Дата,
Реализация.СуммаДокумента КАК Сумма
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
{ГДЕ
(Реализация.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания)}
В попытках упростить отчет программисты часто пытаются соединить таблицу документов с виртуальной таблицей РегистрСведений.ЦеныНоменклатуры.СрезПоследних() в рамках одного запроса. Проанализируем, почему это не работает для получения цен на дату каждого документа.
Виртуальная таблица СрезПоследних рассчитывается в момент выполнения запроса один раз на дату, переданную в её параметры. Если параметр даты не передан, берется текущий момент. Это означает, что для всех строк документов в отчете будет показана одна и та же цена — последняя на сегодня или на указанную дату, что методически неверно, так как нам нужна цена, действовавшая в прошлом, на момент отгрузки.
Попытки добавить условие связи Реализация.Дата >= Цены.Период в соединении с виртуальной таблицей также не дадут результата, так как виртуальная таблица уже «схлопнула» данные до актуальных на текущий момент, и история цен внутри неё недоступна.
Рассмотрим самый эффективный и «чистый» способ решения задачи в СКД — использование двух наборов данных и механизма связей. Этот метод позволяет для каждой строки первого набора (документы) выполнять отдельный микро-запрос ко второму набору (цены) с подстановкой даты конкретной строки.
Шаг 1. Создаем Набор данных 1 (Запрос)
Выбираем данные из документов. Обязательно включаем поля Номенклатура, Характеристика и Дата.
ВЫБРАТЬ
ТЧ.Ссылка КАК Документ,
ТЧ.Ссылка.Дата КАК ДатаДокумента,
ТЧ.Номенклатура КАК Номенклатура,
ТЧ.Характеристика КАК Характеристика,
ТЧ.Количество КАК Количество,
ТЧ.Сумма КАК СуммаПродажи
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК ТЧ
{ГДЕ
(ТЧ.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания)}
Шаг 2. Создаем Набор данных 2 (Запрос)
Этот запрос будет получать цену. Важно: в параметрах виртуальной таблицы указываем параметр &ПериодЦен.
ВЫБРАТЬ
Цены.Цена КАК ЦенаИзРегистра,
Цены.Номенклатура КАК НоменклатураСрез,
Цены.Характеристика КАК ХарактеристикаСрез
ИЗ
РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ПериодЦен, {ВидЦены = &ВидЦены}) КАК Цены
Шаг 3. Настройка связи наборов данных
Переходим на закладку «Связи наборов данных». Это ключевой этап. Настроим связь следующим образом:
Номенклатура = НоменклатураСрез и Характеристика = ХарактеристикаСрез.ПериодЦен, а в колонке «Выражение источника» указываем ДатаДокумента.Теперь СКД будет работать по следующему алгоритму: она получит список всех товаров из документов, а затем для каждой уникальной комбинации номенклатуры и даты документа выполнит запрос к срезу последних, передав туда дату документа. Это обеспечит получение корректной исторической цены.
Разберем важную техническую деталь. Если документ «Реализация» и документ «Установка цен номенклатуры» имеют одинаковый момент времени (вплоть до секунды), обычный срез последних может не увидеть новую цену. Выясним причину: по умолчанию срез последних работает по принципу «меньше или равно», но при совпадении позиций в секунде могут возникать коллизии.
Чтобы гарантированно получить цену, которая должна действовать на момент документа, в выражении связи наборов данных рекомендуется использовать небольшое смещение. Вместо просто ДатаДокумента можно написать:
ДОБАВИТЬКДАТЕ(ДатаДокумента, "СЕКУНДА", 1)
Это позволит системе «заглянуть» на одну секунду вперед и точно захватить цену, установленную в ту же секунду, что и документ.
Проанализируем ситуацию, когда нам нужно управлять видимостью параметров. Чтобы пользователь не путался, на закладке «Параметры» в СКД для технического параметра &ПериодЦен (который мы используем для связи) следует установить галочку «Ограничение доступности». Пользователь не должен заполнять его вручную, так как он заполняется автоматически из даты документа.
Для основных параметров &ДатаНачала и &ДатаОкончания, если они используются внутри фигурных скобок {}, важно убедиться, что они доступны для редактирования и включены в пользовательские настройки.
Рассмотрим также использование СтандартныйПериод. Часто удобнее создать один параметр типа СтандартныйПериод, а в запросе обращаться к его границам:
{ГДЕ
(Реализация.Дата МЕЖДУ &ПериодОтчета.ДатаНачала И &ПериодОтчета.ДатаОкончания)}
Подведем итог нашему разбору. Для создания качественного отчета по ценам на дату реализации необходимо:
Следуя этим правилам, мы получим гибкий, быстрый и методически верный отчет, который корректно отражает данные как за конкретный период, так и за всю историю ведения учета.