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

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

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

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

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

Способ 1. Использование платформенного механизма «Критерии отбора»

Платформа 1С:Предприятие предоставляет разработчикам мощный встроенный инструмент для связывания разнородных данных — Критерии отбора. Этот объект метаданных автоматически строит индексы в базе данных по выбранным реквизитам, что обеспечивает молниеносный поиск связанных документов без написания сложных ручных запросов. Проанализируем ситуацию и настроим данный механизм.

Разберем по шагам, как настроить этот объект в конфигураторе:

  1. Откроем конфигуратор нашей базы данных и перейдем в ветку метаданных Общие -> Критерии отбора.
  2. Создадим новый критерий отбора и назовем его, например, СвязанныеДокументы.
  3. На вкладке Основные в поле Тип укажем типы документов, которые могут выступать в качестве родительских. В нашем случае выберем ДокументСсылка.ПутевойЛист. Если в будущем добавятся другие документы-основания, мы сможем легко расширить этот список.
  4. Перейдем на вкладку Состав. Здесь нам нужно указать, в каких реквизитах других документов может храниться ссылка на наш путевой лист. Найдем в списке документ РасходныйКассовыйОрдер, развернем его реквизиты и отметим флажком реквизит ДокументОснование.

После этого платформа сделает всю работу по индексации за нас. Выясним, как использовать этот критерий отбора в программном коде. Например, чтобы программно получить все расходные кассовые ордера по конкретному путевому листу, нам понадобится всего одна строка кода:


МассивСвязанныхРКО = КритерииОтбора.СвязанныеДокументы.Найти(СсылкаНаПутевойЛист);

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


ПараметрыОтбора = Новый Структура("Значение", Объект.Ссылка);
ОткрытьФорму("КритерийОтбора.СвязанныеДокументы.ФормаСписка", Новый Структура("Отбор", ПараметрыОтбора));

Использование критериев отбора — это наиболее правильный архитектурный подход, заложенный создателями платформы 1С для работы со структурой подчиненности.

Способ 2. Интеграция со стандартной подсистемой БСП «Связанные документы»

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

Проанализируем процесс интеграции нашего путевого листа в этот механизм:

  1. В конфигураторе найдем предопределенный критерий отбора с именем СвязанныеДокументы (он поставляется вместе с БСП).
  2. В свойствах этого критерия перейдем к типу данных и добавим туда тип ДокументСсылка.ПутевойЛист.
  3. На вкладке Состав убедимся, что у документа РасходныйКассовыйОрдер в реквизите ДокументОснование стоит галочка. Это свяжет РКО и путевой лист в общую иерархическую структуру.
  4. Найдем общую команду БСП под названием СвязанныеДокументы. В свойствах этой команды найдем параметр Тип параметра команды и добавим туда тип нашего документа ДокументСсылка.ПутевойЛист.

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

Способ 3. Реализация интерактивной гиперссылки на управляемой форме

Зачастую пользователи хотят видеть статус связанного документа прямо на форме родительского без необходимости нажимать дополнительные кнопки на панели инструментов. Отличным примером такого интерфейсного решения служит типовой механизм отображения связи между документами поступления/реализации и счетом-фактурой в конфигурации «1С:Бухгалтерия».

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

Разберем по шагам, как это сделать:

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

&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    
    // Если документ новый и еще не записан в базу данных, искать РКО бессмысленно
    Если Не ЗначениеЗаполнено(Объект.Ссылка) Тогда
        Возврат;
    КонецЕсли;
    
    // Составим легкий и быстрый запрос к таблице Расходных кассовых ордеров
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
        |   РКО.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.РасходныйКассовыйОрдер КАК РКО
        |ГДЕ
        |   РКО.ДокументОснование = &ПутевойЛист
        |   И НЕ РКО.ПометкаУдаления";
        
    Запрос.УстановитьПараметр("ПутевойЛист", Объект.Ссылка);
    
    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        СсылкаРКО = Выборка.Ссылка;
    Иначе
        СсылкаРКО = Документы.РасходныйКассовыйОрдер.ПустаяСсылка();
    КонецЕсли;
    
КонецПроцедуры

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


&НаКлиенте
Процедура СсылкаРКОНажатие(Элемент, СтандартнаяОбработка)
    
    // Отменяем стандартное поведение платформы по умолчанию
    СтандартнаяОбработка = Ложь;
    
    Если ЗначениеЗаполнено(СсылкаРКО) Тогда
        // Если РКО уже существует, просто открываем его форму пользователю
        ПоказатьЗначение(, СсылкаРКО);
    Иначе
        // Если РКО еще нет, мы можем предложить пользователю автоматически создать его!
        Режим = РежимДиалогаВопрос.ДаНет;
        Оповещение = Новый ОписаниеОповещения("ПослеВопросаОСозданииРКО", ЭтотОбъект);
        ПоказатьВопрос(Оповещение, "Расходный кассовый ордер еще не создан. Создать его сейчас?", Режим);
    КонецЕсли;
    
КонецПроцедуры

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

Такой подход делает работу пользователей невероятно комфортной: они сразу видят, выписан ли кассовый ордер, могут перейти в него в один клик или мгновенно создать новый прямо из формы путевого листа.

Способ 4. Отображение множественных связей через динамический список

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

Решением является внедрение таблицы с динамическим списком прямо на форму путевого листа. Выполним настройку этого интерфейсного элемента:

  1. В редакторе управляемой формы документа ПутевойЛист перейдем на вкладку Реквизиты и добавим новый реквизит. Назовем его СписокРКО и установим тип данных Динамический список.
  2. В свойствах этого динамического списка установим флажок Произвольный запрос и перейдем в конструктор запроса. Напишем следующий текст запроса:

ВЫБРАТЬ
    РКО.Ссылка КАК Ссылка,
    РКО.Дата КАК Дата,
    РКО.Номер КАК Номер,
    РКО.СуммаДокумента КАК Сумма,
    РКО.Проведен КАК Проведен
ИЗ
    Документ.РасходныйКассовыйОрдер КАК РКО
ГДЕ
    РКО.ДокументОснование = &ПутевойЛист
    И НЕ РКО.ПометкаУдаления
  1. Перетащим реквизит СписокРКО на управляемую форму, создав таблицу формы.
  2. Теперь нам нужно передать значение параметра &ПутевойЛист при открытии формы. Для этого в процедуре ПриСозданииНаСервере или ПриЧтенииНаСервере напишем инициализацию параметра динамического списка:

&НаСервере
Процедура УстановитьПараметрыДинамическогоСписка()
    
    // Находим параметр в настройках динамического списка и устанавливаем ссылку
    ЗначениеПараметра = СписокРКО.Параметры.НайтиПараметр("ПутевойЛист");
    Если ЗначениеПараметра <> Неопределено Тогда
        СписокРКО.Параметры.УстановитьЗначениеПараметра("ПутевойЛист", Объект.Ссылка);
    КонецЕсли;
    
КонецПроцедуры

В результате на форме нашего путевого листа появится компактная и аккуратная таблица, в которой в реальном времени будут выводиться все связанные РКО с их номерами, датами и суммами. Пользователь сможет открывать любой из них двойным кликом мыши, а также видеть общую сумму выданных под отчет средств.

Способ 5. Использование регистра сведений (архитектура для крупных баз)

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

Для оптимизации таких процессов в профессиональной разработке применяется паттерн проектирования с использованием независимого вспомогательного Регистра сведений (например, под названием СвязиДокументов).

Рассмотрим подробнее архитектуру этого решения:

  1. Создадим новый непериодический независимый регистр сведений СвязиДокументов.
  2. Определим следующие измерения:
    • ИсходныйДокумент с типом ЛюбаяСсылка (или составным типом, включающим наш путевой лист);
    • СвязанныйДокумент с типом ЛюбаяСсылка (включающим РКО).
  3. В модуле объекта документа РасходныйКассовыйОрдер в процедуре ПриЗаписи (или при проведении) реализуем программную запись связи в этот регистр сведений. Посмотрим на пример кода:

Процедура ПриЗаписи(Отказ, РежимЗаписи, РежимПроведения)
    
    Если ЗначениеЗаполнено(ДокументОснование) Тогда
        
        // Создаем менеджер записи для внесения связи в регистр
        МенеджерЗаписи = РегистрыСведений.СвязиДокументов.СоздатьМенеджерЗаписи();
        МенеджерЗаписи.ИсходныйДокумент = ДокументОснование;
        МенеджерЗаписи.СвязанныйДокумент = Ссылка;
        
        // Записываем данные в базу данных
        МенеджерЗаписи.Записать(Истина);
        
    КонецЕсли;
    
КонецПроцедуры

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


&НаСервере
Процедура ПолучитьСвязанныйРКОИзРегистра()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Связи.СвязанныйДокумент КАК СсылкаРКО
        |ИЗ
        |   РегистрСведений.СвязиДокументов КАК Связи
        |ГДЕ
        |   Связи.ИсходныйДокумент = &ПутевойЛист";
        
    Запрос.УстановитьПараметр("ПутевойЛист", Объект.Ссылка);
    // Выполняем быстрый поиск по индексу регистра сведений...
    
КонецПроцедуры

Резюме и рекомендации по выбору решения

Мы подробно проанализировали пять различных подходов к созданию и визуализации связи между документами в самописной конфигурации на платформе 1С:Предприятие 8. Выбор конкретного метода зависит от масштаба вашей системы и требований пользователей:

Применяйте данные паттерны проектирования в своих конфигурациях, делайте интерфейсы удобными для пользователей, а код — производительным и чистым!

← На главную