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