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