При разработке отчетов, обработок и механизмов интеграции часто возникает задача: получить список всех подчиненных документов, созданных на основании исходных (например, найти все платежные поручения или списания с расчетного счета по списку счетов на оплату от поставщика). Разберем основные способы решения этой задачи на платформе 1С:Предприятие 8, их преимущества, ограничения и тонкости оптимизации.
Самый производительный и гибкий способ — использование языка запросов 1С. Логика запроса зависит от того, где именно в конфигурации хранится ссылка на документ-основание: в реквизите шапки или в строках табличной части.
1. Если основание хранится в реквизите шапки
Когда в подчиненном документе есть реквизит ДокументОснование, мы можем выбрать все документы за период, передав массив ссылок исходных документов в параметр:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СписаниеБезналичныхДенежныхСредств.Ссылка КАК Платежка,
| СписаниеБезналичныхДенежныхСредств.ДокументОснование КАК СчетНаОплату,
| СписаниеБезналичныхДенежныхСредств.СуммаДокумента КАК Сумма
|ИЗ
| Документ.СписаниеБезналичныхДенежныхСредств КАК СписаниеБезналичныхДенежныхСредств
|ГДЕ
| СписаниеБезналичныхДенежныхСредств.ДокументОснование В(&МассивСчетов)
| И НЕ СписаниеБезналичныхДенежныхСредств.ПометкаУдаления";
Запрос.УстановитьПараметр("МассивСчетов", МассивСчетов);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
2. Если основание хранится в табличной части
В современных типовых конфигурациях (1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей, 1С:Бухгалтерия предприятия) один платежный документ может закрывать сразу несколько счетов. В этом случае основание хранится в строках табличной части (например, РасшифровкаПлатежа, поле ОснованиеПлатежа или ДокументРасчетовСКонтрагентом):
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| СписаниеБезналичныхДенежныхСредств.Ссылка КАК Платежка,
| СписаниеБезналичныхДенежныхСредствРасшифровкаПлатежа.ОснованиеПлатежа КАК СчетНаОплату,
| СписаниеБезналичныхДенежныхСредствРасшифровкаПлатежа.Сумма КАК СуммаПоСчету
|ИЗ
| Документ.СписаниеБезналичныхДенежныхСредств.РасшифровкаПлатежа КАК СписаниеБезналичныхДенежныхСредствРасшифровкаПлатежа
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СписаниеБезналичныхДенежныхСредств КАК СписаниеБезналичныхДенежныхСредств
| ПО СписаниеБезналичныхДенежныхСредствРасшифровкаПлатежа.Ссылка = СписаниеБезналичныхДенежныхСредств.Ссылка
|ГДЕ
| СписаниеБезналичныхДенежныхСредствРасшифровкаПлатежа.ОснованиеПлатежа В(&МассивСчетов)
| И НЕ СписаниеБезналичныхДенежныхСредств.ПометкаУдаления";
Запрос.УстановитьПараметр("МассивСчетов", МассивСчетов);
Выборка = Запрос.Выполнить().Выбрать();
Поле ДокументОснование практически всегда имеет составной тип данных. На уровне СУБД фильтрация или соединение по составному полю без уточнения типа порождает множество неэффективных соединений (LEFT JOIN) со всеми таблицами, входящими в тип. Чтобы запрос работал максимально быстро, соблюдаем два правила:
ВЫРАЗИТЬ: при явном приведении типа платформа обращается только к нужной таблице:
ВЫРАЗИТЬ(Платежка.ДокументОснование КАК Документ.СчетНаОплатуПоставщика)
ССЫЛКА: если мы фильтруем выборку, добавляем условие проверки типа перед проверкой вхождения в массив:
ГДЕ
Платежка.ДокументОснование ССЫЛКА Документ.СчетНаОплатуПоставщика
И Платежка.ДокументОснование В (&МассивСчетов)
В дереве метаданных конфигурации существует специальный объект — КритерийОтбора (чаще всего он называется СвязанныеДокументы). Он хранит список реквизитов всех объектов, по которым отслеживается связь.
Мы можем обратиться к критерию отбора через запрос как к виртуальной таблице, передав в качестве параметра ссылку на исходный счет:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СвязанныеДокументы.Ссылка КАК ПодчиненныйДокумент
|ИЗ
| КритерийОтбора.СвязанныеДокументы(&СчетОснование) КАК СвязанныеДокументы
|ГДЕ
| СвязанныеДокументы.Ссылка ССЫЛКА Документ.СписаниеБезналичныхДенежныхСредств";
Запрос.УстановитьПараметр("СчетОснование", СсылкаНаСчет);
Результат = Запрос.Выполнить().Выгрузить();
Нюансы использования критериев отбора:
Если в процессе учета реквизит основания не был заполнен напрямую, но платеж разносился по конкретному счету, восстановить цепочку можно через движения регистров накопления (например, РасчетыСПоставщиками или ВзаиморасчетыСКонтрагентами).
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Взаиморасчеты.Регистратор КАК ПлатежныйДокумент,
| Взаиморасчеты.Заказ КАК СчетНаОплату
|ИЗ
| РегистрНакопления.РасчетыСПоставщиками КАК Взаиморасчеты
|ГДЕ
| Взаиморасчеты.Заказ В(&МассивСчетов)
| И Взаиморасчеты.Регистратор ССЫЛКА Документ.СписаниеБезналичныхДенежныхСредств";
Запрос.УстановитьПараметр("МассивСчетов", МассивСчетов);
Выборка = Запрос.Выполнить().Выгрузить();
Если необходимо сформировать полное дерево связей с учетом программных алгоритмов, переопределенных в конфигурации, используем подсистему СвязанныеДокументы. Программный интерфейс БСП собирает подчиненные объекты не только по жестким реквизитам метаданных, но и по правилам, заданным в общем модуле СвязанныеДокументыПереопределяемый.
Для интерактивного открытия дерева подчиненности документа в управляемой форме используется вызов общей формы структуры подчиненности:
ПараметрыОткрытия = Новый Структура("ВыделенныеСтроки", Новый Массив);
ПараметрыОткрытия.ВыделенныеСтроки.Добавить(СсылкаНаСчет);
ОткрытьФорму("ОбщаяФорма.СвязанныеДокументы", ПараметрыОткрытия);
Для массовой выборки подчиненных документов за период оптимальным решением является прямой запрос к табличной части или шапке подчиненного документа с типизацией через ССЫЛКА / ВЫРАЗИТЬ и фильтрацией по массиву оснований В (&МассивОснований). Критерии отбора и функции БСП удобнее использовать для единичного интерактивного анализа связей конкретного документа.