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

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

При разработке сложных отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с необходимостью объединить данные из разных источников (например, производство и отгрузку) в одну иерархическую структуру. Типичная проблема заключается в том, что при простом соединении таблиц данные начинают «дублироваться» или выводиться некорректно в общих колонках ресурсов. Рассмотрим, как правильно организовать вывод таких данных и реализовать сопоставление по методу ФИФО.

Анализ проблемы: почему не работает условие ВЫБОР в запросе

Проанализируем ситуацию: у нас есть документы СборкаЗапасов (производство) и РасходнаяНакладная (отгрузка). Мы хотим видеть их в одной колонке «Количество», но чтобы значение бралось из соответствующего документа. Казалось бы, достаточно использовать конструкцию ВЫБОР КОГДА в вычисляемом поле или запросе. Однако при использовании соединений (JOIN) в рамках одного набора данных строка результата часто содержит ссылки на оба документа одновременно (если они связаны по заказу). В этом случае система всегда находит первое истинное условие и выводит только одно значение (например, всегда количество производства), игнорируя контекст строки.

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

Решение 1: Настройка ресурсов для разных группировок

Это самый эффективный метод, к которому пришел автор темы. Его суть заключается в том, чтобы не пытаться вычислить поле «на лету» в запросе, а позволить СКД рассчитать его в момент формирования конкретной группировки отчета. Разберем по шагам:

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

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

Решение 2: Использование UNION ALL и правильная типизация

Если мы хотим решить задачу на уровне запроса, проанализируем ситуацию с объединением таблиц. Вместо соединения (JOIN) лучше использовать объединение (UNION ALL). Рассмотрим пример структуры запроса:


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

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

ВЫБРАТЬ
    Расходная.ЗаказПокупателя,
    Расходная.Номенклатура,
    Расходная.Ссылка,
    0,
    Расходная.Количество
ИЗ
    Документ.РасходнаяНакладная КАК Расходная

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

ЕСТЬNULL(КоличествоПроизводство, 0) + ЕСТЬNULL(КоличествоОтгрузка, 0)

Это значение будет всегда корректным для текущей строки документа.

Реализация метода ФИФО в отчете

Вторая часть задачи — сопоставление произведенной продукции и отгруженной по методу ФИФО (первым произведено — первым отгружено). Реализовать это чистым запросом без оконных функций крайне сложно, поэтому рассмотрим алгоритм с использованием временных таблиц и нарастающих итогов.

Рассмотрим подробнее логику расчета:

  1. Получение нарастающих итогов: Для каждой строки производства и каждой строки отгрузки нужно вычислить накопленный итог в рамках заказа и номенклатуры.
  2. Сопоставление интервалов: Производство №1 обеспечивает количество от [0 до 5000], Производство №2 — от [5000 до 11000]. Если Отгрузка №1 имеет количество 3000, она попадает в интервал первого документа. Если Отгрузка №2 имеет количество 8000, она начинается в первом документе (оставшиеся 2000) и продолжается во втором (остальные 6000).

Проанализируем пример кода для получения нарастающего итога (для платформы 8.3.20+):


ВЫБРАТЬ
    Т.Заказ,
    Т.Номенклатура,
    Т.Ссылка,
    Т.Количество,
    СУММА(Т.Количество) НАД(ПАРТИЦИЯ ПО Т.Заказ, Т.Номенклатура УПОРЯДОЧИТЬ ПО Т.Ссылка.МоментВремени) КАК Накоплено
ИЗ
    ВТ_Данные КАК Т

Если ваша платформа ниже 8.3.20, нарастающий итог придется получать соединением таблицы самой с собой по условию Т1.МоментВремени >= Т2.МоментВремени, что может замедлить отчет при больших объемах данных.

Практические советы по работе с ресурсами

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

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

Сумма(ЕСТЬNULL(КоличествоПроизводство, 0)) - Сумма(ЕСТЬNULL(КоличествоОтгрузка, 0))

Также обратите внимание на условия в запросе. Проверка Документ.Проведен И Документ.ПометкаУдаления = ЛОЖЬ является избыточной. В системе 1С проведенный документ по определению не может быть помечен на удаление. Достаточно использовать только Ссылка.Проведен для оптимизации производительности запроса.

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

← На главную