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