В практике разработки на платформе 1С:Предприятие 8.3 часто возникает ситуация, когда необходимо получить данные или выполнить алгоритм, заложенный в модуле объекта одного документа, находясь в контексте другого. Ситуация осложняется, если целевой документ уже открыт пользователем и содержит несохраненные изменения, которые важно учитывать при вызове функции. В этой статье мы подробно разберем, как решить эту задачу, рассмотрим различные подходы — от «костыльных» до архитектурно верных — и проанализируем нюансы каждого метода.
Если нам необходимо вызвать функцию именно из открытого документа (со всеми его текущими данными в табличных частях и реквизитах, которые еще не записаны в базу), нам придется действовать через контекст формы. Давайте разберем алгоритм: сначала найдем нужное окно, затем получим данные формы и преобразуем их в объект.
Рассмотрим пример кода, который позволяет это реализовать. Предположим, у нас есть ссылка на интересующий нас Документ №2.
&НаКлиенте
Процедура ВыполнитьВызовФункции(Команда)
// 1. Ищем открытую форму документа по ссылке
ФормаДокумента = НайтиОткрытуюФорму(СсылкаНаДокумент2);
Если ФормаДокумента = Неопределено Тогда
Сообщить("Документ №2 не найден среди открытых окон.");
Возврат;
КонецЕсли;
// 2. Вызываем серверную процедуру, передавая данные формы
ВызватьЭкспортныйМетодНаСервере(ФормаДокумента.Объект);
КонецПроцедуры
&НаКлиенте
Функция НайтиОткрытуюФорму(СсылкаНаОбъект)
// Перебираем все открытые окна приложения
Для Каждого Окно Из ПолучитьОкна() Цикл
Для Каждого Форма Из Окно.Содержимое Цикл
// Проверяем, является ли форма формой нужного нам документа
Если Форма.Параметры.Свойство("Ключ") И Форма.Параметры.Ключ = СсылкаНаОбъект Тогда
Возврат Форма;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат Неопределено;
КонецФункции
&НаСервере
Процедура ВызватьЭкспортныйМетодНаСервере(ДанныеФормы)
// Преобразуем данные формы в объект документа для доступа к модулю объекта
ДокументОбъект = ДанныеФормыВЗначение(ДанныеФормы, Тип("ДокументОбъект.ИмяВашегоДокумента"));
// Вызываем нужную экспортную функцию
Результат = ДокументОбъект.ИмяВашейЭкспортнойФункции();
Сообщить("Результат вызова: " + Результат);
КонецПроцедуры
Важный нюанс: метод ДанныеФормыВЗначение создает в памяти сервера копию объекта. Если ваша экспортная функция внутри модуля объекта меняет какие-либо реквизиты, эти изменения останутся в этой временной копии и не отобразятся на экране пользователя в открытой форме Документа №2. Чтобы изменения вернулись на форму, потребуется вызвать ЗначениеВДанныеФормы, но это может привести к конфликтам блокировок, если пользователь в этот момент тоже редактирует документ.
Давайте проанализируем ситуацию с точки зрения архитектуры 1С. Если функция должна вызываться из разных мест, то хранить её в модуле объекта — не самое удачное решение. Согласно стандартам разработки, бизнес-логику, не привязанную жестко к записи конкретного экземпляра объекта, лучше выносить в Общие модули.
Разберем по шагам, как это сделать:
РаботаСДокументамиСервер).Пример вызова будет выглядеть максимально просто:
// В Документе №1 просто вызываем общий модуль
Результат = РаботаСДокументамиСервер.РассчитатьЗначение(ПараметрыРасчета);
Преимущество: Вам не нужно инициализировать тяжелый объект документа или искать его форму. Это работает значительно быстрее и стабильнее.
Если функция не требует контекста конкретного (измененного пользователем, но не записанного) документа, а оперирует только данными из базы или переданными параметрами, рассмотрите возможность размещения её в Модуле менеджера документа.
В отличие от модуля объекта, модуль менеджера доступен без создания экземпляра документа ПолучитьОбъект(). Вызов осуществляется следующим образом:
// Вызов из любого места конфигурации
Результат = Документы.ИмяДокумента2.МояФункция(Параметры);
Проанализируем сценарий, когда Документ №2 открыт, и нам нужно «попросить» его форму отдать какую-то информацию или выполнить действие. Для интерактивной связи между двумя открытыми формами идеально подходит механизм Оповещений.
В форме Документа №1 (откуда инициируем запрос):
&НаКлиенте
Процедура ЗапроситьДанные(Команда)
Оповестить("НужныДанныеДляДокумента1", , ЭтаФорма);
КонецПроцедуры
В форме Документа №2 (которая должна ответить):
&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
Если ИмяСобытия = "НужныДанныеДляДокумента1" Тогда
// Выполняем действия и, например, передаем данные назад через экспортный метод формы-источника
Источник.ПринятьДанные(Объект.ТабличнаяЧасть.Итог("Сумма"));
КонецЕсли;
КонецПроцедуры
Этот метод позволяет формам «общаться» напрямую на клиенте, не нагружая сервер лишними вызовами и не создавая копии объектов в памяти.
Если данных в табличной части Документа №2 много, и передавать их через параметры оповещения неудобно, можно использовать Временное хранилище.
Алгоритм действий будет таким:
Адрес = ПоместитьВоВременноеХранилище(Объект.ТабличнаяЧасть.Выгрузить()).Оповестить передает Адрес в Документ №1.Таблица = ПолучитьИзВременногоХранилища(Адрес).Выясним, какой метод выбрать в вашем случае:
ДанныеФормыВЗначение через поиск окна.Помните, что использование ДанныеФормыВЗначение для вызова функций модуля объекта — это ресурсоемкая операция. Старайтесь проектировать систему так, чтобы логика была отделена от интерфейса и конкретных экземпляров объектов.