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