Как в отчете на СКД вывести обороты по регистратору, но скрыть остатки?

Программист 1С v8.3 (Управляемые формы) Управленческий учет
← На главную

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

Рассмотрим, как мы можем решить эту задачу, используя различные возможности СКД. Мы проанализируем несколько подходов: условное оформление, настройку ресурсов с выражениями и модификацию запроса.

Понимание проблемы

Представим, что у нас есть отчет, построенный на виртуальной таблице регистра накопления ОстаткиИОбороты, как в представленном запросе:


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ВложенныйЗапрос.Организация КАК Организация,
    ВложенныйЗапрос.Контрагент КАК Контрагент,
    ВложенныйЗапрос.ДоговорКонтрагента КАК ДоговорКонтрагента,
    ВложенныйЗапрос.ДокументРасчетов КАК ДокументРасчетов,
    ВложенныйЗапрос.Сделка КАК Сделка,
    ВложенныйЗапрос.Регистратор КАК Регистратор,
    ВложенныйЗапрос.СуммаУпрНачальныйОстаток КАК СуммаУпрНачальныйОстаток,
    ВложенныйЗапрос.СуммаРегНачальныйОстаток КАК СуммаРегНачальныйОстаток,
    ВложенныйЗапрос.СуммаУпрПриход КАК СуммаУпрПриход,
    ВложенныйЗапрос.СуммаРегПриход КАК СуммаРегПриход,
    ВложенныйЗапрос.СуммаУпрРасход КАК СуммаУпрРасход,
    ВложенныйЗапрос.СуммаРегРасход КАК СуммаРегРасход,
    ВложенныйЗапрос.СуммаУпрКонечныйОстаток КАК СуммаУпрКонечныйОстаток,
    ВложенныйЗапрос.СуммаРегКонечныйОстаток КАК СуммаРегКонечныйОстаток
ИЗ
    (ВЫБРАТЬ
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Организация КАК Организация,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Контрагент КАК Контрагент,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.ДоговорКонтрагента КАК ДоговорКонтрагента,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Сделка КАК Сделка,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.СуммаУпрНачальныйОстаток КАК СуммаУпрНачальныйОстаток,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.СуммаУпрПриход КАК СуммаУпрПриход,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.СуммаУпрРасход КАК СуммаУпрРасход,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.СуммаУпрКонечныйОстаток КАК СуммаУпрКонечныйОстаток,
        0 КАК СуммаРегНачальныйОстаток,
        0 КАК СуммаРегПриход,
        0 КАК СуммаРегРасход,
        0 КАК СуммаРегКонечныйОстаток,
        ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор КАК Регистратор,
        ВЫБОР
            КОГДА ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
                        ИЛИ ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор ССЫЛКА Документ.АктОбОказанииПроизводственныхУслуг
                ТОГДА ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор
            ИНАЧЕ NULL
        КОНЕЦ КАК ДокументРасчетов
    ИЗ
        РегистрНакопления.ВзаиморасчетыСКонтрагентами.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Регистратор {(&Периодичность)}, , ) КАК ВзаиморасчетыСКонтрагентамиОстаткиИОбороты
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Организация,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Контрагент,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.ДоговорКонтрагента,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Сделка,
        0,
        0,
        0,
        0,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегНачальныйОстаток,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегРасход,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегПриход,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегКонечныйОстаток,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Регистратор,
        РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Документ
    ИЗ
        РегистрНакопления.РасчетыПоПриобретениюВУсловныхЕдиницахОрганизации.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Регистратор {(&Периодичность)}, , ДоговорКонтрагента.ВидДоговора = ЗНАЧЕНИЕ(Перечисление.ВидыДоговоровКонтрагентов.СПоставщиком)) КАК РасчетыПоПриобретениюВУсловныхЕдиницахОрганизацииОстаткиИОбороты
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Организация,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Контрагент,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.ДоговорКонтрагента,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Сделка,
        0,
        0,
        0,
        0,
        -РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегНачальныйОстаток,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегПриход,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегРасход,
        -РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.СуммаРегКонечныйОстаток,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Регистратор,
        РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты.Документ
    ИЗ
        РегистрНакопления.РасчетыПоРеализацииВУсловныхЕдиницахОрганизации.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Регистратор {(&Периодичность)}, , ДоговорКонтрагента.ВидДоговора <> ЗНАЧЕНИЕ(Перечисление.ВидыДоговоровКонтрагентов.СПоставщиком)) КАК РасчетыПоРеализацииВУсловныхЕдиницахОрганизацииОстаткиИОбороты) КАК ВложенныйЗапрос

Данный запрос уже формирует все необходимые данные, включая остатки и обороты, детализированные по Регистратору. Наша задача – не изменить сами данные, а управлять их отображением в отчете.

Решение 1: Условное оформление в СКД

Самый простой и гибкий способ скрыть остатки на уровне регистратора, не меняя логику получения данных, — это использовать условное оформление в СКД. Этот подход позволяет визуально "стереть" или сделать невидимыми значения в определенных ячейках отчета при выполнении заданных условий.

Разберем шаги настройки условного оформления:

  1. Откройте схему компоновки данных (СКД) вашего отчета.

  2. Перейдите на вкладку "Настройки" и выберите элемент, к которому вы применяете настройки (например, основной вариант отчета).

  3. В открывшемся окне настроек перейдите на вкладку "Условное оформление".

  4. Нажмите кнопку "Добавить" (зеленый плюс), чтобы создать новый элемент условного оформления.

  5. В поле "Оформление" установим параметры, которые позволят скрыть значения:

    • Выберите свойство "Текст" и оставьте его пустым (""). Это заставит поле выводить пустую строку вместо значения.

    • Альтернативный вариант: выберите свойство "Цвет текста" и укажите цвет, совпадающий с цветом фона ячейки (например, белый, если фон белый). Это сделает текст невидимым.

  6. В поле "Условие" нам нужно определить, при каких обстоятельствах применять это оформление. Мы хотим скрыть остатки, когда отчет детализирован до регистратора. Для этого мы можем проверить, заполнено ли поле Регистратор. Добавим следующее условие:

    
    Не ТипЗначения(Регистратор) = Тип("Неопределено") И Регистратор <> ЗНАЧЕНИЕ(Документ.ПустаяСсылка)
    

    Объясним условие:

    • Не ТипЗначения(Регистратор) = Тип("Неопределено"): Эта часть проверяет, что поле Регистратор не является неопределенным. Это важно, потому что в итоговых строках или при агрегации Регистратор может быть пустым.
    • Регистратор <> ЗНАЧЕНИЕ(Документ.ПустаяСсылка): Эта часть дополнительно проверяет, что Регистратор не является ссылкой на пустой документ. В некоторых случаях СКД может возвращать пустые ссылки вместо Неопределено при отсутствии детализации.
    • Сочетание этих условий позволяет нам быть уверенными, что оформление применяется только к тем строкам, где действительно присутствует конкретный регистратор.

    Другой вариант условия может быть связан с уровнем группировки, если вы точно знаете, на каком уровне находится регистратор. Например, если Регистратор всегда находится на уровне 3 после Организация и Контрагент:

    УровеньГруппировки() = 3

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

  7. В поле "Поля" выберите все поля, содержащие остатки, которые мы хотим скрыть:

    • СуммаУпрНачальныйОстаток
    • СуммаРегНачальныйОстаток
    • СуммаУпрКонечныйОстаток
    • СуммаРегКонечныйОстаток

    Убедитесь, что вы выбрали именно те поля остатков, которые присутствуют в вашем запросе.

После сохранения этих настроек и формирования отчета, строки, детализированные по регистратору, будут показывать обороты, а поля остатков в этих строках будут пустыми или невидимыми. На более высоких уровнях группировки (например, по контрагенту) остатки будут по-прежнему отображаться, так как условие не будет выполнено.

Решение 2: Использование ресурсов СКД с выражением

Второй подход предполагает изменение логики вычисления ресурсов (полей остатков) в самой СКД. Вместо того чтобы просто скрывать значения, мы можем сделать так, чтобы СКД вычисляла 0 для остатков на уровне регистратора. Этот метод более "чистый" с точки зрения данных, но требует более глубокого понимания работы ресурсов СКД.

Разберем шаги настройки ресурсов:

  1. Откройте схему компоновки данных (СКД) вашего отчета.

  2. Перейдите на вкладку "Ресурсы".

  3. Для каждого поля остатка, которое вы хотите обнулить на уровне регистратора (например, СуммаУпрНачальныйОстаток), модифицируйте его "Выражение". Изначально оно, вероятно, выглядит как Сумма(СуммаУпрНачальныйОстаток).

  4. Измените "Выражение" следующим образом:

    
    ВЫБОР
        КОГДА (Не ТипЗначения(Регистратор) = Тип("Неопределено") И Регистратор <> ЗНАЧЕНИЕ(Документ.ПустаяСсылка))
        ТОГДА 0
        ИНАЧЕ Сумма(СуммаУпрНачальныйОстаток)
    КОНЕЦ
    

    Объясним выражение:

    • КОГДА (Не ТипЗначения(Регистратор) = Тип("Неопределено") И Регистратор <> ЗНАЧЕНИЕ(Документ.ПустаяСсылка)): Это наше условие, аналогичное тому, что мы использовали в условном оформлении. Оно проверяет, что текущая строка соответствует детализации по конкретному регистратору.
    • ТОГДА 0: Если условие выполняется (т.е. мы находимся на уровне регистратора), ресурс будет вычислен как 0.
    • ИНАЧЕ Сумма(СуммаУпрНачальныйОстаток): Если условие не выполняется (т.е. мы находимся на более высоком уровне группировки или в итоговой строке), ресурс будет вычислен как обычная сумма значений поля СуммаУпрНачальныйОстаток.

    Повторите эту операцию для всех полей остатков: СуммаУпрНачальныйОстаток, СуммаРегНачальныйОстаток, СуммаУпрКонечныйОстаток, СуммаРегКонечныйОстаток.

Этот метод гарантирует, что на уровне регистратора данные остатков будут фактически равны нулю, а не просто скрыты. Однако, будьте внимательны с логикой УровеньГруппировки(), если решите использовать её вместо проверки поля Регистратор. УровеньГруппировки() возвращает номер текущего уровня группировки отчета. Чтобы использовать ее, вам нужно точно знать, на каком уровне находится ваш регистратор. Например, если Регистратор является первым уровнем детализации после Контрагента, который сам является первым уровнем группировки, то УровеньГруппировки() для регистратора будет равен 2.

Решение 3: Модификация запроса (менее предпочтительно для данной задачи)

Теоретически, можно было бы изменить сам запрос, чтобы он не выбирал остатки на уровне регистратора. Однако для задачи, где остатки нужны на общих уровнях, но не нужны на детальных, такой подход часто оказывается излишне сложным при использовании виртуальных таблиц ОстаткиИОбороты.

Чтобы реализовать это через запрос, нам пришлось бы:

  1. Создать одну часть запроса, которая выбирает только обороты, детализированные по Регистратору, и устанавливает поля остатков в 0.

  2. Создать вторую часть запроса, которая выбирает только остатки, но уже без детализации по Регистратору (например, только по Организации, Контрагенту, ДоговоруКонтрагента), и устанавливает поля оборотов в 0.

  3. Объединить эти две части запроса с помощью ОБЪЕДИНИТЬ ВСЕ.

Пример такого подхода для первой части запроса (только обороты с регистратором):


ВЫБРАТЬ
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Организация КАК Организация,
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Контрагент КАК Контрагент,
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.ДоговорКонтрагента КАК ДоговорКонтрагента,
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Сделка КАК Сделка,
    0 КАК СуммаУпрНачальныйОстаток,
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.СуммаУпрПриход КАК СуммаУпрПриход,
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.СуммаУпрРасход КАК СуммаУпрРасход,
    0 КАК СуммаУпрКонечныйОстаток,
    // ... аналогично для СуммаРег ...
    ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор КАК Регистратор,
    ВЫБОР
        КОГДА ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
                    ИЛИ ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор ССЫЛКА Документ.АктОбОказанииПроизводственныхУслуг
            ТОГДА ВзаиморасчетыСКонтрагентамиОстаткиИОбороты.Регистратор
        ИНАЧЕ NULL
    КОНЕЦ КАК ДокументРасчетов
ИЗ
    РегистрНакопления.ВзаиморасчетыСКонтрагентами.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, Регистратор {(&Периодичность)}, , ) КАК ВзаиморасчетыСКонтрагентамиОстаткиИОбороты

И затем вторая часть запроса (только остатки без регистратора):


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

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

Рекомендации и лучшие практики

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

  2. Для обнуления значений: Если вы хотите, чтобы остатки на уровне регистратора фактически были равны нулю (например, для дальнейших расчетов в СКД или для более "чистых" данных при выгрузке), то используйте ресурсы СКД с выражением. Этот метод более мощный, но и требует более тщательной настройки.

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

  4. Периодичность СКД: Хотя в данной задаче это не является прямым решением, всегда обращайте внимание на параметр периодичности в СКД. Установка периодичности в Авто часто помогает СКД правильно рассчитывать остатки и обороты на разных уровнях агрегации, хотя она не решает задачу скрытия полей.

Мы рассмотрели несколько эффективных способов управления видимостью остатков в отчетах СКД при детализации по регистратору. Выбор конкретного метода зависит от ваших требований к отчету, простоты реализации и поддержки. Наиболее часто используемыми и рекомендованными являются условное оформление и настройка ресурсов с выражениями.

← На главную