Как включить нетиповой документ в структуру подчиненности и составить отчет по цепочке документов в 1С?

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

В процессе доработки конфигураций 1С (особенно в обычном приложении, таком как УПП 1.3, КА 1.1 или УТ 10.3) часто создаются новые документы. Например, в типовую цепочку продаж между заказом покупателя и реализацией внедряется документ КомплектованиеЗаказаПокупателя. При этом разработчики сталкиваются с двумя сопутствующими задачами: отображение созданного объекта в стандартном дереве структуры подчиненности типовых документов и формирование быстродействующего отчета по всей цепочке связанных документов без циклов и зависаний.

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

Шаг 1. Включение документа в критерий отбора связанных документов

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

  1. Проверим наличие реквизита ссылки на документ-основание. В нашем документе должен существовать реквизит, ссылающийся на родительский документ (например, ДокументОснование или Сделка) с типом ДокументСсылка.ЗаказПокупателя или составным ссылочным типом. Важно: тип реквизита обязательно должен соответствовать типам, входящим в состав критерия отбора.
  2. Откроем дерево метаданных конфигурации, перейдем в ветку Общие → Критерии отбора → СвязанныеДокументы.
  3. Откроем свойства критерия отбора и нажмем кнопку настройки состава (палитра свойств или вкладка «Состав»).
  4. Найдем в списке наш нетиповой документ КомплектованиеЗаказаПокупателя, развернем его реквизиты и установим флажок напротив реквизита ДокументОснование.
  5. Если на основании этого документа будут создаваться последующие документы (например, типовая РеализацияТоваровУслуг), необходимо убедиться, что реквизит-основание последующего документа также может содержать ссылку на наш новый документ и включен в критерий отбора.

Шаг 2. Заполнение реквизита основания при вводе на основании

Если реквизит в базе останется пустым, платформа не сможет связать объекты. Проанализируем модуль объекта документа КомплектованиеЗаказаПокупателя и настроим обработчик ОбработкаЗаполнения:


Процедура ОбработкаЗаполнения(Основание)
    
    Если ТипЗнч(Основание) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
        ЗаполнитьЗначенияСвойств(ЭтотОбъект, Основание, , "Номер, Дата, Проведен, ПометкаУдаления");
        
        // Явно заполняем реквизит связи
        ДокументОснование = Основание;
        
        // Дополнительные правила заполнения табличных частей
        ЗаполнитьДокументПоОснованиюУпр(Основание);
        Дата = Основание.Дата + 1;
    КонецЕсли;

КонецПроцедуры

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

Шаг 3. Избавление от запросов в цикле при построении отчетов по цепочкам

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

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

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

Посмотрим на реализацию эффективного текста запроса:


ВЫБРАТЬ
    ЗаказПокупателя.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ЗаказПокупателя
ИЗ
    Документ.ЗаказПокупателя КАК ЗаказПокупателя
ГДЕ
    ЗаказПокупателя.Дата МЕЖДУ &НачДата И &КонДата
    И ЗаказПокупателя.ПометкаУдаления = ЛОЖЬ

ИНДЕКСИРОВАТЬ ПО
    Ссылка
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗРЕШЕННЫЕ
    КомплектованиеЗаказаПокупателя.Ссылка КАК Ссылка,
    КомплектованиеЗаказаПокупателя.ДокументОснование КАК ДокументОснование
ПОМЕСТИТЬ ВТ_ПодчиненныеДокументы
ИЗ
    Документ.КомплектованиеЗаказаПокупателя КАК КомплектованиеЗаказаПокупателя
ГДЕ
    КомплектованиеЗаказаПокупателя.ДокументОснование В
        (ВЫБРАТЬ ВТ_ЗаказПокупателя.Ссылка ИЗ ВТ_ЗаказПокупателя)

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

ВЫБРАТЬ
    РезервированиеТоваров.Ссылка,
    РезервированиеТоваров.Заказ
ИЗ
    Документ.РезервированиеТоваров КАК РезервированиеТоваров
ГДЕ
    РезервированиеТоваров.Заказ В
        (ВЫБРАТЬ ВТ_ЗаказПокупателя.Ссылка ИЗ ВТ_ЗаказПокупателя)

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

ВЫБРАТЬ
    РеализацияТоваровУслуг.Ссылка,
    РеализацияТоваровУслуг.Сделка
ИЗ
    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
    РеализацияТоваровУслуг.Сделка В
        (ВЫБРАТЬ ВТ_ЗаказПокупателя.Ссылка ИЗ ВТ_ЗаказПокупателя)

ИНДЕКСИРОВАТЬ ПО
    ДокументОснование
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_ЗаказПокупателя.Ссылка КАК ЗаказПокупателя,
    ЕСТЬNULL(ВТ_ПодчиненныеДокументы.Ссылка, НЕОПРЕДЕЛЕНО) КАК ПодчиненныйДокумент
ИЗ
    ВТ_ЗаказПокупателя КАК ВТ_ЗаказПокупателя
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПодчиненныеДокументы КАК ВТ_ПодчиненныеДокументы
        ПО ВТ_ЗаказПокупателя.Ссылка = ВТ_ПодчиненныеДокументы.ДокументОснование
ИТОГИ ПО
    ЗаказПокупателя
;

Обратим внимание на директиву ИНДЕКСИРОВАТЬ ПО. Индексация полей соединения во временных таблицах гарантирует быстрое выполнение соединения на стороне СУБД без полного сканирования таблиц.

Шаг 4. Отбор заказов без определенных подчиненных документов

Нередко ставится управленческая задача: найти «зависшие» заказы, у которых еще нет комплектации и нет реализации. Реализовать такое условие можно двумя надежными способами.

Способ 1. Через левые соединения и проверку на NULL

Если мы соединяем таблицу заказов напрямую с таблицами комплектаций и реализаций, условие отсутствия документов формулируется через ЕСТЬ NULL:


ВЫБРАТЬ
    Заказ.Ссылка КАК ЗаказПокупателя
ИЗ
    ВТ_ЗаказПокупателя КАК Заказ
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.КомплектованиеЗаказаПокупателя КАК Комплектование
        ПО Заказ.Ссылка = Комплектование.ДокументОснование
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
        ПО Заказ.Ссылка = Реализация.Сделка
ГДЕ
    Комплектование.Ссылка ЕСТЬ NULL
    И Реализация.Ссылка ЕСТЬ NULL

Способ 2. Через группировку и секцию ИМЕЮЩИЕ

Если подчиненные документы уже собраны в общую временную таблицу ВТ_ПодчиненныеДокументы, отфильтровать заказы можно с помощью агрегатных функций в блоке ИМЕЮЩИЕ:


ВЫБРАТЬ
    ВТ_ЗаказПокупателя.Ссылка КАК ЗаказПокупателя
ИЗ
    ВТ_ЗаказПокупателя КАК ВТ_ЗаказПокупателя
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПодчиненныеДокументы КАК ВТ_ПодчиненныеДокументы
        ПО ВТ_ЗаказПокупателя.Ссылка = ВТ_ПодчиненныеДокументы.ДокументОснование
СГРУППИРОВАТЬ ПО
    ВТ_ЗаказПокупателя.Ссылка
ИМЕЮЩИЕ
    СУММА(ВЫБОР
        КОГДА ВТ_ПодчиненныеДокументы.Ссылка ССЫЛКА Документ.КомплектованиеЗаказаПокупателя ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ) = 0
    И СУММА(ВЫБОР
        КОГДА ВТ_ПодчиненныеДокументы.Ссылка ССЫЛКА Документ.РеализацияТоваровУслуг ТОГДА 1
        ИНАЧЕ 0
    КОНЕЦ) = 0

Такой подход делает алгоритм гибким: при необходимости пользовательские флажки на форме отчета (например, «Без комплектации», «Без отгрузки») могут динамически добавлять условия проверки счетчиков в конструкцию ИМЕЮЩИЕ без масштабной перестройки структуры самого запроса.

← На главную