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