В процессе разработки в среде 1С часто возникает задача программно определить, на основании какого документа был создан текущий объект, или найти все подчиненные ему документы. Начинающие разработчики часто пытаются использовать стандартный реквизит ДокументОснование, но сталкиваются с тем, что он либо пуст, либо вообще отсутствует в метаданных. В этой статье мы подробно разберем, как устроены связи между документами в типовых конфигурациях (на примере УТ 11) и как правильно извлекать эти данные программно.
Проанализируем ситуацию: в простых самописных конфигурациях при создании механизма "Ввод на основании" система автоматически может добавить реквизит ДокументОснование — для этого есть модуль настройки связанных документов без программирования. Однако в сложных типовых решениях, таких как Управление торговлей или ERP, связи между документами гораздо сложнее, чем "один к одному".
Например, документ РеализацияТоваровУслуг может быть оформлен по нескольким заказам сразу. В этом случае ссылка на заказ хранится не в шапке документа, а в каждой строке табличной части Товары. Для детального разбора, откуда пришла та или иная номенклатура, может потребоваться углубленный анализ позиций товаров в документе. А в документе ЗаданиеНаПеревозку связь с распоряжениями (заказами или реализациями) реализована через отдельную табличную часть. Поэтому простое обращение к ЭтотОбъект.Ссылка.ДокументОснование часто не дает результата.
Для поиска документов, которые находятся "ниже" по иерархии (подчиненных), в 1С используется объект метаданных КритерийОтбора. Чаще всего он называется СвязанныеДокументы. Этот механизм позволяет быстро найти все документы, в реквизитах которых упоминается наша ссылка.
Рассмотрим, как это реализовать программно. Допустим, у нас есть ссылка на заказ клиента, и мы хотим найти все реализации, созданные по нему:
// СсылкаНаОбъект - это наш исходный документ (например, Заказ клиента)
ТаблицаСвязей = КритерииОтбора.СвязанныеДокументы.Найти(СсылкаНаОбъект);
Для каждого СтрокаСвязи Из ТаблицаСвязей Цикл
// В колонке "Ссылка" будет содержаться подчиненный документ
Сообщить("Найден связанный документ: " + СтрокаСвязи.Ссылка);
КонецЦикла;
Этот метод универсален, так как он анализирует все реквизиты всех документов, которые включены в состав данного критерия отбора в Конфигураторе.
Если нам нужно найти документ-основание (тот, что стоит "выше"), а мы не знаем имя реквизита, необходимо изучить строение объекта. Проанализируем структуру документа через встроенные инструменты, просмотрев структуру хранения БД, или используем программный код для перебора свойств — для этой задачи пригодятся инструменты разработчика для поиска ссылок и отладки кода. Выясним причину отсутствия данных в стандартных полях.
Для быстрой проверки всех доступных реквизитов документа (если под рукой нет специализированных инструментов, таких как MCP сервер для работы с метаданными) воспользуемся небольшим циклом в отладке или консоли кода:
МетаданныеДокумента = СсылкаНаДокумент.Метаданные();
Для каждого Реквизит Из МетаданныеДокумента.Реквизиты Цикл
Попытка
Значение = СсылкаНаДокумент[Реквизит.Имя];
Если ЗначениеЗаполнено(Значение) Тогда
Сообщить(Реквизит.Имя + " (Тип: " + Реквизит.Тип + ") = " + Значение);
КонецЕсли;
Исключение
// Пропускаем реквизиты, к которым нет доступа
КонецПопытки;
КонецЦикла;
Важный момент: если в шапке реквизит не найден, обязательно проверим табличные части. Например, в РеализацияТоваровУслуг это часто поле ЗаказКлиента в табличной части Товары.
Разберем ситуацию с документом ЗаданиеНаПеревозку. Его связь с другими документами (заказами или реализациями) специфична. Она хранится в табличной части Распоряжения. Чтобы программно увидеть основания для этого документа, нам нужно перебрать эту таблицу:
ДокументОбъект = СсылкаНаЗадание.ПолучитьОбъект();
Для каждого СтрокаРаспоряжения Из ДокументОбъект.Распоряжения Цикл
// Поле обычно называется "Распоряжение"
Основание = СтрокаРаспоряжения.Распоряжение;
Сообщить("Задание создано на основании: " + Основание);
КонецЦикла;
Если же мы хотим программно "привязать" документ к заданию на перевозку, нам нужно не просто заполнить какой-то реквизит, а добавить новую строку в ТЧ Распоряжения и заполнить там поле Распоряжение ссылкой на нужный документ.
Если ваш новый документ не отображается в отчете "Связанные документы" (структура подчиненности), его нужно туда добавить вручную. Проанализируем шаги:
СвязанныеДокументы.После этого стандартный отчет системы и программный метод КритерииОтбора.СвязанныеДокументы.Найти() начнут "видеть" эти связи.
В современных конфигурациях для работы со структурой связей лучше использовать программный интерфейс БСП. Это гарантирует, что вы получите полные данные, включая сложные связи, которые могут вычисляться логически или храниться в регистрах сведений.
Рассмотрим пример обращения к общему модулю (название может варьироваться, например, ОбщегоНазначенияУТ или СтруктураПодчиненности):
В типовых решениях часто реализована функция, возвращающая дерево или таблицу связей — для визуализации этой структуры пригодится обработка построения дерева ссылок и связей объектов 1С. Посмотрим на примерную логику вызова:
// Параметры: Ссылка на документ, признак вывода только непосредственных связей
ПараметрыОтчета = Новый Структура("Объект", СсылкаНаДокумент);
// Вызов функции формирования структуры (названия процедур зависят от версии БСП)
// Обычно это требует анализа кода формы "СтруктураПодчиненности"
Для того чтобы понять, как система строит дерево связей в интерфейсе, рекомендуется открыть форму отчета Структура подчиненности и проанализировать метод СформироватьДерево(). Там наглядно показано, какие общие модули задействованы для получения данных.
Для эффективного поиска связей в 1С мы рекомендуем придерживаться следующего алгоритма:
Заказ, Сделка, Основание, Распоряжение.КритерииОтбора.СвязанныеДокументы.Найти(Ссылка) — самый быстрый способ найти "детей" документа.ЭтотОбъект.Метаданные() помогут найти скрытые поля.Помните, что в 1С связь между документами — это просто наличие ссылки на один объект внутри другого. Зная, где именно хранится эта ссылка (или используя получение ГУИД объекта для точной идентификации), вы всегда сможете извлечь ее программно. Если же при анализе вы обнаружите некорректные данные, может потребоваться расшифровка битых ссылок из текста или их глобальный поиск и замена.