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