Как последовательно вывести и отсортировать связанные документы в одной колонке отчета СКД?

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

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

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

В чем сложность стандартной сортировки?

Давайте проанализируем ситуацию. Если мы просто объединим таблицы документов ПриобретениеТоваровУслуг и СФПолученный через оператор ОБЪЕДИНИТЬ ВСЕ и отсортируем результат по дате или моменту времени, мы получим хронологический список. Но если Приобретение №1 было создано 1-го числа, Приобретение №2 — 2-го числа, а Счет-фактура №1 (к первому приобретению) — только 3-го числа, то хронологический порядок будет следующим:

  1. Приобретение №1 (01.10)
  2. Приобретение №2 (02.10)
  3. Счет-фактура №1 (03.10)

Это нарушает бизнес-логику отчета, где Счет-фактура №1 должен визуально следовать сразу за Приобретением №1. Нам необходимо добиться следующего порядка:

  1. Приобретение №1 (01.10)
  2. Счет-фактура №1 (03.10)
  3. Приобретение №2 (02.10)

Выясним, какими способами мы можем решить эту задачу в СКД.

Способ 1. Использование виртуальных полей сортировки в запросе

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

Для каждой записи мы определим два виртуальных поля:

Рассмотрим пример построения такого запроса:


ВЫБРАТЬ
    Приобретение.Ссылка КАК Документ,
    Приобретение.Ссылка.МоментВремени КАК МоментВремениСортировка,
    0 КАК Подчинен
ИЗ
    Документ.ПриобретениеТоваровУслуг КАК Приобретение

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    СФ.Ссылка КАК Документ,
    СФ.ДокументОснование.Ссылка.МоментВремени КАК МоментВремениСортировка,
    1 КАК Подчинен
ИЗ
    Документ.СФПолученный КАК СФ
ГДЕ
    СФ.ДокументОснование ССЫЛКА Документ.ПриобретениеТоваровУслуг

После объединения таблиц нам остается настроить упорядочивание. Сначала мы сортируем по полю МоментВремениСортировка (таким образом, связка «Приобретение + его Счет-фактура» получит одинаковое значение для сортировки и встанет рядом), а затем по полю Подчинен (чтобы документ-основание с признаком 0 всегда шел первым, а счет-фактура с признаком 1 — вторым).

Важный нюанс настройки СКД: просто написать секцию УПОРЯДОЧИТЬ ПО в запросе недостаточно! При компоновке результата СКД оптимизирует и перестраивает запрос к СУБД, полностью игнорируя порядок, заданный внутри текста запроса. Чтобы сортировка применилась, выполните следующие шаги:

  1. Откройте схему компоновки данных и перейдите на вкладку Настройки.
  2. Выберите нужную группировку (или «Детальные записи») и перейдите на вкладку Сортировка.
  3. Добавьте туда поля МоментВремениСортировка (по возрастанию) и Подчинен (по возрастанию).
  4. Чтобы эти технические поля не мозолили глаза пользователю, просто не добавляйте их на вкладку Выбранные поля. Они будут участвовать в сортировке неявно.

Способ 2. Группировка по виртуальному полю «Документ-основание» (Без вычисляемых полей)

Если вы хотите избежать сложных вычислений моментов времени в запросе, можно использовать элегантное решение со скрытыми группировками в настройках структуры СКД.

Разберем этот метод по шагам:

  1. В запросе для каждого документа определите поле ДокументОснование. Для самого Приобретения в это поле передайте его собственную ссылку (Приобретение.Ссылка), а для Счета-фактуры — ссылку на документ-основание (СФ.ДокументОснование). Также добавьте поле признака подчиненности ЭтоПолучатель (0 или 1).
  2. В настройках отчета СКД добавьте группировку по полю ДокументОснование.
  3. Внутрь этой группировки добавьте подчиненную группировку Детальные записи.
  4. Выделите созданную группировку ДокументОснование, перейдите в Другие настройки (в нижней части экрана) и установите параметр Расположение группировок = Нет.
  5. В «Выбранных полях» для детальных записей оставьте только поле Документ.
  6. В «Сортировке» детальных записей укажите поле ЭтоПолучатель по возрастанию.

Проанализируем, что произойдет при выводе отчета. СКД сгруппирует все записи по полю ДокументОснование. Так как у конкретного Приобретения и его Счета-фактуры это поле совпадает, они попадут в одну группу. Поскольку для самой группировки отображение отключено (Расположение группировок = Нет), колонка с документом-основанием не выведется. На экране отобразятся только детальные записи (сама колонка Документ), отсортированные внутри группы: сначала Приобретение (0), затем Счет-фактура (1).

Способ 3. Связи наборов данных (Иерархический метод)

Если у вас сложная структура взаимосвязей между документами или вы хотите иметь возможность сворачивать/разворачивать подчиненные документы, лучшим выбором будет использование встроенного в СКД механизма связи наборов данных.

Давайте посмотрим, как это реализовать:

  1. Создайте в схеме два набора данных - запроса. Первый набор (НаборДанных1) будет выбирать документы ПриобретениеТоваровУслуг. Второй набор (НаборДанных2) — документы СФПолученный.
  2. Перейдите на вкладку Связи наборов данных.
  3. Добавьте новую строку связи. Источником связи укажите НаборДанных1, приемником — НаборДанных2.
  4. В колонке Условие связи свяжите поля: НаборДанных1.Ссылка = НаборДанных2.ДокументОснование.
  5. В настройках отчета постройте иерархическую структуру. Добавьте группировку по полю Документ и выберите тип группировки Иерархия (или просто выведите детальные записи из связанных наборов).

СКД самостоятельно обратится к СУБД, свяжет наборы на уровне платформы и выведет подчиненные счета-фактуры строго под соответствующими поступлениями в древовидном виде. Этот способ избавляет от написания громоздких запросов с ОБЪЕДИНИТЬ ВСЕ.

Способ 4. Вывод документов в одну ячейку через функцию СоединитьСтроки()

Иногда требования интерфейса заставляют экономить экранное пространство. Если заказчику принципиально важно видеть информацию в одну строку, но при этом иметь быстрый доступ и к поступлению, и к счету-фактуре, мы можем объединить их прямо в одной ячейке.

Выясним, как это сделать с помощью функций СКД:

  1. В запросе свяжите левым соединением таблицу приобретений с таблицей счетов-фактур по документу-основанию.
  2. Перейдите на вкладку Ресурсы в СКД.
  3. Добавьте поле СчетФактура в ресурсы. В качестве выражения ресурса укажите встроенную функцию СКД:

СоединитьСтроки(ТаблицаЗначений(СчетФактура.Ссылка), ", ", "Нет связанных СФ")

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

СоединитьСтроки(Массив(СчетФактура), Символы.ПС)

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

Важные технические нюансы работы с «Моментом времени»

В обсуждении на форуме упоминалось использование типа МоментВремени в вычисляемых полях. Обратите внимание на важную деталь: тип данных Момент времени в 1С представляет собой сложный объект, состоящий из даты и уникального идентификатора ссылки. СУБД прекрасно умеет сортировать по нему в прямых запросах.

Однако, если вы передаете момент времени в Вычисляемые поля СКД или пытаетесь манипулировать им на уровне встроенного языка компоновки, платформа может вести себя непредсказуемо, так как сравнение сложных ссылочных объектов в памяти происходит иначе, чем в СУБД.

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

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

← На главную