Как в СКД 1С вывести две таблицы с разными периодами и противоположными отборами по контрагентам?

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

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

Первая таблица должна выводить данные по продажам или закупкам за определенный период (Период 1) с отбором по конкретному контрагенту (или списку контрагентов), выбранному пользователем.

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

Сложность задачи заключается в том, что стандартные механизмы отборов СКД применяются ко всей схеме глобально. Если пользователь установит отбор по контрагенту "Клиент А", то этот отбор по умолчанию применится ко всему отчету, и мы не сможем вывести во второй таблице данные по остальным контрагентам. Разберем по шагам несколько профессиональных способов реализации этой задачи в среде 1С:Предприятие 8.3.

Вариант 1. Использование двух наборов данных и связи между ними

Этот способ является наиболее изящным и декларативным, так как он практически не требует написания кода в модуле объекта и полностью полагается на штатные возможности процессора компоновки данных. Мы разделим логику получения данных на два отдельных набора данных (запроса) и свяжем их между собой.

Проанализируем структуру первого набора данных (НаборДанных1). Этот запрос будет получать данные по продажам за Период 1. В тексте запроса мы используем стандартные параметры для ограничения периода и наложения отбора по контрагенту:


ВЫБРАТЬ
    ПродажиОбороты.Контрагент КАК Контрагент,
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.КоличествоОборот КАК Количество,
    ПродажиОбороты.СуммаВыручкиОборот КАК Сумма
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода1, &КонецПериода1, Авто, Контрагент В (&ВыбранныеКонтрагенты)) КАК ПродажиОбороты

Теперь спроектируем второй набор данных (НаборДанных2). Ему предстоит выбирать данные за Период 2 по всем контрагентам, кроме выбранных, и только по той номенклатуре, которая была куплена в первом периоде. Запрос для второго набора будет выглядеть следующим образом:


ВЫБРАТЬ
    ПродажиОбороты.Контрагент КАК КонтрагентПрочие,
    ПродажиОбороты.Номенклатура КАК Номенклатура,
    ПродажиОбороты.КоличествоОборот КАК КоличествоПрочие,
    ПродажиОбороты.СуммаВыручкиОборот КАК СуммаПрочие
ИЗ
    РегистрНакопления.Продажи.Обороты(&НачалоПериода2, &КонецПериода2, Авто, НЕ Контрагент В (&ВыбранныеКонтрагенты) И Номенклатура = &СвязьНоменклатура) КАК ПродажиОбороты

Обратите внимание на параметр &СвязьНоменклатура. Мы не будем заполнять его вручную. Перейдем на вкладку "Связи наборов данных" в конструкторе схемы компоновки и добавим новую связь:

  1. Источник связи: НаборДанных1
  2. Приемник связи: НаборДанных2
  3. Выражение источника: Номенклатура
  4. Выражение приемника: Номенклатура
  5. Параметры: в колонке параметров для приемника укажем наш параметр связи — СвязьНоменклатура

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

Вариант 2. Программный перехват пользовательского отбора

Если для конечного пользователя критически важно использовать стандартное окно отборов (компоновщик настроек) вместо выбора параметров на форме, нам придется прибегнуть к программному коду в модуле объекта отчета. Наша задача — перехватить отбор, установленный пользователем, использовать его для первой таблицы, а для второй таблицы инвертировать его и передать в качестве параметра запроса.

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

Разберем по шагам алгоритм в процедуре ПриКомпоновкеРезультата модуля объекта отчета:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Получаем текущие настройки пользователя
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // Найдем пользовательский отбор по контрагенту
    СписокВыбранныхКонтрагентов = Новый СписокЗначений;
    ЭлементОтбораКонтрагент = Неопределено;
    
    Для Каждого ЭлементОтбора Из Настройки.Отбор.Элементы Цикл
        Если ТипЗнч(ЭлементОтбора) = Тип("ЭлементОтбораКомпоновкиДанных") И ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Контрагент") Тогда
            Если ЭлементОтбора.Использование Тогда
                ЭлементОтбораКонтрагент = ЭлементОтбора;
                Если ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке Тогда
                    СписокВыбранныхКонтрагентов = ЭлементОтбора.ПравоеЗначение;
                ИначеЕсли ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно Тогда
                    СписокВыбранныхКонтрагентов.Добавить(ЭлементОтбора.ПравоеЗначение);
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
    
    // Установим параметр для исключения контрагентов во второй таблице
    Если СписокВыбранныхКонтрагентов.Количество() > 0 Тогда
        Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ИсключаемыеКонтрагенты", СписокВыбранныхКонтрагентов);
        Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ЕстьИсключения", Истина);
    Иначе
        Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("ЕстьИсключения", Ложь);
    КонецЕсли;
    
    // Выполняем компоновку с измененными настройками
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

В самом запросе СКД для второй таблицы мы прописываем условие исключения, ориентируясь на переданный параметр:


ГДЕ
    ВЫБОР 
        КОГДА &ЕстьИсключения 
            ТОГДА НЕ Контрагент В (&ИсключаемыеКонтрагенты) 
        ИНАЧЕ ИСТИНА 
    КОНЕЦ

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

Вариант 3. Использование вложенных схем компоновки данных

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

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

  1. На вкладке "Вложенные схемы" основной СКД добавляем две вложенные схемы: СхемаТаблица1 и СхемаТаблица2.
  2. Внутри СхемаТаблица1 настраиваем обычный запрос по продажам с параметрами начала и окончания периода, а также стандартным отбором по контрагенту.
  3. Внутри СхемаТаблица2 создаем аналогичный запрос, но с условием инверсии отбора (через параметр &ИсключаемыеКонтрагенты, как в Варианте 2).
  4. В настройках структуры основного отчета вместо обычных группировок добавляем два элемента типа "Вложенный отчет".
  5. Настраиваем связи параметров основного отчета и вложенных отчетов. Период 1 мы передаем во вложенный отчет №1, а Период 2 — во вложенный отчет №2. Пользовательский список контрагентов транслируется во вложенные схемы соответствующим образом (в первую схему как прямой отбор, во вторую — как параметр исключения).

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

Сравнительный анализ решений

Для того чтобы выбрать наиболее подходящий метод для вашей задачи, сопоставим рассмотренные варианты решений:

Рассмотрев все варианты, мы можем сделать вывод, что выбор конкретного метода зависит от квалификации разработчика и жесткости требований заказчика к интерфейсу настроек отчета. Использование связей наборов данных в сочетании с параметризацией является наиболее технологичным и производительным решением в рамках платформы 1С:Предприятие 8.3.

← На главную