При работе с конфигурацией 1С:Управление торговлей 11 (УТ11) в режиме тонкого клиента часто возникает необходимость программно открывать формы обработок и обмениваться с ними информацией. Одним из типовых сценариев является открытие формы по так называемому "КлючуСвязи", который зачастую представляет собой УникальныйИдентификатор объекта базы данных или адрес временного хранилища. Давайте вместе разберем, как правильно реализовать такой функционал, обходя ограничения тонкого клиента и эффективно работая с данными.
При работе в тонком или веб-клиенте 1С:Предприятия необходимо учитывать особенности клиент-серверного взаимодействия. Метод глобального контекста ПолучитьФорму, который часто используется в толстом клиенте для получения экземпляра формы, недоступен в тонком клиенте. Поэтому, когда мы пытаемся использовать этот метод, переменная, предназначенная для хранения экземпляра формы, остается пустой (как было замечено в сообщениях 4 и 5), и дальнейшая работа с формой становится невозможной. Нам нужно искать альтернативные подходы для решения нашей задачи.
Вместо ПолучитьФорму для открытия форм в тонком клиенте (и веб-клиенте) мы должны использовать метод глобального контекста ОткрытьФорму(). Этот метод позволяет не только открыть форму, но и передать в нее необходимые параметры. Разберем его использование подробнее.
Для передачи данных в открываемую форму нам потребуется создать структуру. Каждый элемент этой структуры будет представлять собой передаваемый параметр с соответствующим именем и значением. Эта структура затем передается вторым параметром в метод ОткрытьФорму(). Давайте рассмотрим пример из сообщения 14, который демонстрирует этот подход при открытии формы "РабочееМестоМенеджераПоДоставке.ФормаРаспоряженияПоПункту":
// Отключаем стандартную обработку, если это обработчик события,
// чтобы предотвратить выполнение действий по умолчанию.
СтандартнаяОбработка = Ложь;
// Создаем новую структуру для хранения всех параметров,
// которые будут переданы в открываемую форму обработки.
ПараметрыФормы = Новый Структура;
// Вставляем необходимые параметры в структуру.
// Имена свойств структуры должны соответствовать именам,
// которые будут ожидаться в открываемой форме.
ПараметрыФормы.Вставить("ЗаданиеНаПеревозку", Объект.Ссылка);
ПараметрыФормы.Вставить("ТранспортноеСредство", Объект.ТранспортноеСредство);
// Рассчитываем и передаем итоговый вес и объем из табличной части маршрута.
ПараметрыФормы.Вставить("ВесЗадания", Объект.Маршрут.Итог("Вес"));
ПараметрыФормы.Вставить("ОбъемЗадания", Объект.Маршрут.Итог("Объем"));
ПараметрыФормы.Вставить("ДатаВремяРейсаПланС", Объект.ДатаВремяРейсаПланС);
ПараметрыФормы.Вставить("ВидДоставки", Объект.Операция);
ПараметрыФормы.Вставить("Адрес", ТекущиеДанные.Адрес);
ПараметрыФормы.Вставить("ВремяС", ТекущиеДанные.ВремяС);
ПараметрыФормы.Вставить("ВремяПо", ТекущиеДанные.ВремяПо);
// Особое внимание уделим передаче ключа связи через временное хранилище.
// Функция "ПоместитьРаспоряженияВХранилище" (предполагается ее существование)
// помещает данные во временное хранилище и возвращает его адрес.
ПараметрыФормы.Вставить("АдресРаспоряжений", ПоместитьРаспоряженияВХранилище(ТекущиеДанные.КлючСвязи));
ПараметрыФормы.Вставить("Статус", Объект.Статус);
// Еще один параметр, переданный через временное хранилище,
// вероятно, для товаров к доставке.
ПараметрыФормы.Вставить("АдресТоваровКДоставке", ПоместитьВХранилищеТоварыКДоставке);
// Определяем описание оповещения. Это механизм, позволяющий вызывающей форме
// получить уведомление и результат после закрытия открываемой формы.
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеРедактированияРаспоряжений",ЭтотОбъект);
// Открываем форму, используя метод ОткрытьФорму().
// Параметры метода:
// 1. Имя формы: Полное имя формы обработки.
// 2. ПараметрыФормы: Созданная нами структура параметров.
// 3. ВладелецФормы: Ссылка на форму, которая вызывает ОткрытьФорму (ЭтаФорма).
// 4-6. КлючУникальности, Окно, УникальныйИдентификаторФормы: Оставлены пустыми,
// но могут быть использованы для управления уникальностью и размещением формы.
// 7. ОписаниеОповещения: Объект оповещения для обратной связи.
// 8. РежимОткрытияОкнаФормы: Определяет, как будет открыто окно формы
// (например, БлокироватьОкноВладельца означает, что родительская форма
// станет недоступной до закрытия дочерней).
ОткрытьФорму(
"Обработка.РабочееМестоМенеджераПоДоставке.Форма.ФормаРаспоряженияПоПункту",
ПараметрыФормы,
ЭтаФорма,
,,,,
ОписаниеОповещения,
РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
);
Этот пример наглядно демонстрирует, как мы формируем структуру ПараметрыФормы, заполняем ее необходимыми данными и передаем в метод ОткрытьФорму(), а также как настраиваем обратную связь через ОписаниеОповещения.
В открываемой форме (в нашем случае это "ФормаРаспоряженияПоПункту") переданные параметры становятся доступными через коллекцию Параметры в обработчике события формы ПриСозданииНаСервере(). Нам необходимо явно считать эти параметры и, при необходимости, присвоить их реквизитам формы или создать параметры формы с флагом "Ключевой параметр", чтобы они были доступны для дальнейшей работы во всех процедурах модуля формы.
// Пример получения параметров в модуле открываемой формы ("ФормаРаспоряженияПоПункту")
// в обработчике события ПриСозданииНаСервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Проверяем наличие параметра "ЗаданиеНаПеревозку" и присваиваем его реквизиту формы
Если Параметры.Свойство("ЗаданиеНаПеревозку") Тогда
ЭтотОбъект.ЗаданиеНаПеревозку = Параметры.ЗаданиеНаПеревозку;
КонецЕсли;
// Получаем адрес ключа связи из временного хранилища
Если Параметры.Свойство("АдресРаспоряжений") Тогда
АдресРаспоряженийВХранилище = Параметры.АдресРаспоряжений;
Если ЗначениеЗаполнено(АдресРаспоряженийВХранилище) Тогда
// Получаем сами данные по адресу из временного хранилища
ЭтотОбъект.КлючСвязиИзХранилища = ПолучитьИзВременногоХранилища(АдресРаспоряженийВХранилище);
// Далее можно работать с КлючСвязиИзХранилища
КонецЕсли;
КонецЕсли;
// Аналогично обрабатываем другие переданные параметры:
Если Параметры.Свойство("ТранспортноеСредство") Тогда
ЭтотОбъект.ТранспортноеСредство = Параметры.ТранспортноеСредство;
КонецЕсли;
// ... и так далее для всех остальных необходимых параметров
КонецПроцедуры
Как мы выяснили из обсуждения, "КлючСвязи" в 1С чаще всего представляет собой УникальныйИдентификатор (УИД или GUID). Это 128-битное значение, представленное в виде строки, которое служит для однозначной идентификации объектов в базе данных (справочников, документов, регистров, обработок и других). Если наша цель — не просто открыть форму, а собрать информацию для заполнения другой формы, то есть получить данные, то не всегда обязательно открывать саму форму интерактивно. Вместо этого мы можем получить ссылку на объект по его УникальномуИдентификатору и затем работать с самим объектом.
Для поиска ссылки на объект по его УникальномуИдентификатору мы можем использовать различные подходы:
НайтиПоУникальномуИдентификатору() соответствующего менеджера.
// Предположим, что Стр.КлючСвязи содержит строковое представление УИД.
// Создаем объект УникальныйИдентификатор из строки.
УникальныйИдентификаторОбъекта = Новый УникальныйИдентификатор(Стр.КлючСвязи);
// Если мы знаем, что УИД относится к документу "ЗаданиеНаПеревозку":
СсылкаНаДокумент = Документы.ЗаданиеНаПеревозку.НайтиПоУникальномуИдентификатору(УникальныйИдентификаторОбъекта);
Если СсылкаНаДокумент <> Неопределено Тогда
// Теперь у нас есть ссылка на объект. Мы можем получить сам объект
// для доступа к его реквизитам и табличным частям.
ОбъектДокумент = СсылкаНаДокумент.ПолучитьОбъект();
// Пример работы с данными объекта:
// Заголовок = ОбъектДокумент.Представление;
// Дата = ОбъектДокумент.Дата;
// Номер = ОбъектДокумент.Номер;
КонецЕсли;
// Функция для универсального поиска ссылки на объект по его УИД.
// Принимает строковое представление УИД.
// Возвращает ссылку на найденный объект или Неопределено, если объект не найден.
Функция ПолучитьСсылкуПоУИД(СтрокаСУИД)
// Создаем объект УникальныйИдентификатор.
УникальныйИдентификаторОбъекта = Новый УникальныйИдентификатор(СтрокаСУИД);
// Перебираем все возможные ссылки в метаданных конфигурации.
// Метаданные.ВсеСсылки включает Справочники, Документы, ПланыВидовХарактеристик и т.д.
Для Каждого МенеджерМетаданных Из Метаданные.ВсеСсылки Цикл
Попытка
// Пытаемся найти объект по УИД с помощью менеджера текущего типа.
СсылкаНаОбъект = МенеджерМетаданных.НайтиПоУникальномуИдентификатору(УникальныйИдентификаторОбъекта);
Если СсылкаНаОбъект <> Неопределено Тогда
// Если ссылка найдена, возвращаем ее.
Возврат СсылкаНаОбъект;
КонецЕсли;
Исключение
// Некоторые объекты метаданных могут не поддерживать метод
// НайтиПоУникальномуИдентификатору или вызывать ошибки при попытке обращения
// (например, некоторые РегистрыНакопления).
// Мы игнорируем эти ошибки и продолжаем поиск, чтобы не прерывать процесс.
Продолжить;
КонецПопытки;
КонецЦикла;
// Если объект не был найден ни в одном из перебранных типов, возвращаем Неопределено.
Возврат Неопределено;
КонецФункции
// Пример использования универсальной функции:
// Стр.КлючСвязи - это наша исходная строка с УИД.
Ссылка = ПолучитьСсылкуПоУИД(Стр.КлючСвязи);
Если Ссылка <> Неопределено Тогда
// Если ссылка найдена, мы можем работать с ней или получить сам объект.
Объект = Ссылка.ПолучитьОбъект();
// Дальнейшая логика по сбору данных из объекта.
КонецЕсли;
Если наша основная задача — только собрать информацию, а не отображать форму пользователю для интерактивного взаимодействия, мы можем рассмотреть следующие более эффективные варианты:
ПолучитьОбъект(). После этого мы можем напрямую работать с его реквизитами и табличными частями, извлекая необходимую информацию без необходимости открывать визуальную форму. Это наиболее прямой и производительный способ получения данных.
// Предположим, что СсылкаНаОбъект уже получена по УИД
// (например, с помощью функции ПолучитьСсылкуПоУИД).
ОбъектДляСбораДанных = СсылкаНаОбъект.ПолучитьОбъект();
Если ОбъектДляСбораДанных <> Неопределено Тогда
// Пример сбора данных из объекта документа:
ДатаДокумента = ОбъектДляСбораДанных.Дата;
НомерДокумента = ОбъектДляСбораДанных.Номер;
СуммаДокумента = ОбъектДляСбораДанных.СуммаДокумента;
Контрагент = ОбъектДляСбораДанных.Контрагент;
// Если у объекта есть табличная часть, например, "Товары":
Для Каждого СтрокаТЧ Из ОбъектДляСбораДанных.Товары Цикл
НаименованиеТовара = СтрокаТЧ.Номенклатура.Наименование;
КоличествоТовара = СтрокаТЧ.Количество;
ЦенаТовара = СтрокаТЧ.Цена;
СуммаСтроки = СтрокаТЧ.Сумма;
// ...и так далее для всех необходимых колонок табличной части.
КонецЦикла;
// Собранные данные можно использовать для заполнения другой формы
// или для выполнения дальнейших расчетов.
КонецЕсли;
ВнешниеОбработки.Создать(). Если обработка является частью конфигурации, мы можем получить ее объект через метаданные и вызвать нужные процедуры (но это зависит от архитектуры самой обработки и наличия экспортных методов).В примере кода из сообщения 14 мы видим использование функции ПоместитьРаспоряженияВХранилище(), которая, скорее всего, помещает сложный объект (например, таблицу значений, массив или другой составной объект) во временное хранилище и возвращает его адрес. Этот адрес затем передается как параметр в открываемую форму.
Такой подход очень удобен, когда необходимо передать большой объем данных или данные, которые не могут быть напрямую сериализованы и переданы в структуре параметров формы (например, объекты, не имеющие стандартной сериализации, или очень большие таблицы значений). В вызываемой форме мы помещаем данные в хранилище, а в открываемой форме мы можем получить эти данные обратно с помощью функции ПолучитьИзВременногоХранилища() по переданному адресу.
// Пример функции для помещения данных в хранилище (в модуле, где вызывается ОткрытьФорму):
// Функция получает "КлючСвязи" (УИД) и на его основе формирует некие данные,
// которые затем помещаются во временное хранилище.
Функция ПоместитьРаспоряженияВХранилище(КлючСвязи)
// Предположим, что по КлючуСвязи мы формируем сложный объект,
// например, ТаблицуЗначений с детальной информацией о распоряжениях.
ТаблицаДанныхРаспоряжений = Новый ТаблицаЗначений;
ТаблицаДанныхРаспоряжений.Колонки.Добавить("НомерРаспоряжения");
ТаблицаДанныхРаспоряжений.Колонки.Добавить("АдресДоставки");
ТаблицаДанныхРаспоряжений.Колонки.Добавить("Статус");
// Здесь мы заполняем ТаблицуДанныхРаспоряжений на основе КлючСвязи
// или других данных, доступных в текущем контексте.
// Например, если КлючСвязи - это ссылка на документ, мы можем получить его
// и извлечь данные из табличных частей.
// ...
НоваяСтрока = ТаблицаДанныхРаспоряжений.Добавить();
НоваяСтрока.НомерРаспоряжения = "Р001";
НоваяСтрока.АдресДоставки = "ул. Примерная, 1";
НоваяСтрока.Статус = "В работе";
// ...
// Помещаем сформированные данные во временное хранилище.
// Вторым параметром можно указать УникальныйИдентификатор владельца хранилища.
// Это может быть УИД текущей формы, чтобы данные были привязаны к ней.
Возврат ПоместитьВоВременноеХранилище(ТаблицаДанныхРаспоряжений, УникальныйИдентификатор);
КонецФункции
// Пример получения данных из хранилища (в модуле открываемой формы,
// например, в ПриСозданииНаСервере, как было показано ранее):
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("АдресРаспоряжений") Тогда
АдресРаспоряжений = Параметры.АдресРаспоряжений;
Если ЗначениеЗаполнено(АдресРаспоряжений) Тогда
// Получаем ранее помещенные данные из временного хранилища по адресу.
ТаблицаДанных = ПолучитьИзВременногоХранилища(АдресРаспоряжений);
// Теперь можно работать с ТаблицаДанных, например, вывести их в табличное поле формы.
// ЭтотОбъект.ТаблицаРаспоряжений.Загрузить(ТаблицаДанных);
КонецЕсли;
КонецЕсли;
// ... обработка других параметров
КонецПроцедуры
Таким образом, мы видим комплексное решение, которое позволяет не только открыть форму обработки в тонком клиенте, но и эффективно обмениваться с ней данными, используя как прямую передачу параметров в структуру, так и временное хранилище значений для более сложных сценариев. Это обеспечивает гибкость и масштабируемость при разработке клиент-серверных приложений на платформе 1С:Предприятие.