Как получить ссылку на документ во внешней обработке при открытии формы в 1С

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При разработке внешних печатных форм или обработок для конфигураций на базе БСП (Библиотека стандартных подсистем), таких как 1С:Бухгалтерия 3.0 или 1С:ERP, часто возникает задача получить данные документа, из которого была запущена обработка. Особенно это актуально, когда используется тип команды ОткрытиеФормы.

В этой статье мы подробно разберем, как правильно «поймать» ссылку на объект-основание, почему возникают ошибки при обращении к полям объекта и как корректно работать с данными на сервере.

Механизм передачи параметров в БСП

Когда мы регистрируем внешнюю обработку в справочнике «Дополнительные отчеты и обработки» и выбираем вариант запуска ОткрытиеФормы, система при нажатии кнопки в интерфейсе открывает форму обработки и передает в нее структуру Параметры. Самым важным для нас элементом этой структуры является ОбъектыНазначения.

Важный нюанс: параметр ОбъектыНазначения всегда передается как Массив, даже если обработка вызвана из формы одного конкретного документа. Это сделано для универсальности, так как пользователь может выделить несколько строк в списке документов и запустить обработку для всех сразу.

Шаг 1. Перехват параметров при создании формы

Для начала нам необходимо сохранить полученные ссылки в реквизиты формы, чтобы использовать их в дальнейшем. Рассмотрим, как это сделать в обработчике ПриСозданииНаСервере. Мы проанализируем ситуацию, когда на форме создан реквизит СписокСсылок с типом СписокЗначений.

Разберем программный код:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем наличие параметра, переданного подсистемой БСП
    Если Параметры.Свойство("ОбъектыНазначения") Тогда
        // Параметры.ОбъектыНазначения — это Массив ссылок
        // Загружаем его в реквизит формы типа СписокЗначений
        СписокСсылок.ЗагрузитьЗначения(Параметры.ОбъектыНазначения);
    КонецЕсли;
    
КонецПроцедуры

На этом этапе многие разработчики допускают ошибку, пытаясь сразу обратиться к элементам списка как к документам. Выясним, почему это приводит к ошибкам.

Шаг 2. Правильное извлечение ссылки на документ

Рассмотрим типичную ошибку: Поле объекта не обнаружено (Товары). Она возникает, когда код пытается прочитать табличную часть не у самой ссылки на документ, а у объекта ЭлементСпискаЗначений.

Проанализируем правильный способ получения ссылки из СписокЗначений:

  1. Если мы используем СписокСсылок.Получить(0), мы получаем объект типа ЭлементСпискаЗначений.
  2. Чтобы добраться до самой ссылки (например, ДокументСсылка.ПоступлениеТоваровУслуг), нужно обратиться к свойству .Значение этого элемента.

Посмотрим на исправленный код получения данных:


&НаСервере
Процедура ПоказатьТаблицуНаСервере()
    
    // Проверяем, есть ли вообще переданные объекты
    Если СписокСсылок.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем ПЕРВЫЙ элемент списка
    ЭлементСписка = СписокСсылок.Получить(0);
    
    // Извлекаем саму ссылку на документ
    СсылкаНаОбъект = ЭлементСписка.Значение;
    
    // Теперь СсылкаНаОбъект имеет тип ДокументСсылка...
    // Мы можем обращаться к ее реквизитам и табличным частям
    ТЧДок = СсылкаНаОбъект.Товары.ВыгрузитьКолонку("Номенклатура");
    
    Объект.СписокНоменклатуры.Очистить();
    
    Для Каждого СтрокаНоменклатуры Из ТЧДок Цикл
        НоваяСтрока = Объект.СписокНоменклатуры.Добавить();
        НоваяСтрока.Номенклатура = СтрокаНоменклатуры;
    КонецЦикла;
    
КонецПроцедуры

Шаг 3. Работа с данными: Ссылка или Объект?

Часто возникает вопрос: нужно ли использовать метод ПолучитьОбъект()? Разберем эту ситуацию подробнее.

Если ваша задача — просто прочитать данные (номенклатуру, количество, суммы) для отображения на форме или печати, использовать ПолучитьОбъект() не рекомендуется. Метод ПолучитьОбъект() считывает все данные документа из базы данных в оперативную память и создает «тяжелый» объект, предназначенный для изменения и записи. Для чтения данных достаточно использовать свойства ссылки СсылкаНаОбъект.Товары — это работает на сервере быстро и эффективно.

Когда метод ПолучитьОбъект() действительно нужен:

Особенности работы с новыми (незаписанными) документами

Важно помнить о нюансе модифицированности. Если пользователь открыл существующий документ, изменил в нем данные, но не нажал кнопку «Записать», и после этого запустил вашу внешнюю обработку — в массив ОбъектыНазначения попадет ссылка на состояние документа в базе данных, а не в текущей форме пользователя.

Если логика вашей обработки требует получения самых свежих данных «с экрана», которые еще не зафиксированы в базе, стандартный механизм ОбъектыНазначения через команду открытия формы может не подойти. В таких случаях данные обычно передаются через временное хранилище или используются другие типы команд БСП.

Рекомендации по надежному коду

Давайте проанализируем, как сделать код обработки более защищенным от ошибок:

  1. Проверка типа данных: Всегда проверяйте, что именно пришло в параметрах. При отладке полезно использовать Сообщить(ТипЗнч(Параметры.ОбъектыНазначения)).
  2. Множественный выбор: Если пользователь выделил 10 документов, а ваша форма умеет работать только с одним, обязательно сообщите об этом или предусмотрите цикл Для Каждого.
  3. Обработка пустых значений: Если обработка запущена напрямую (например, через Файл -> Открыть), параметров БСП не будет. Предусмотрите проверку, чтобы форма не выдавала ошибку при обращении к несуществующим параметрам.

Пример универсального получения первой ссылки напрямую из параметров без использования промежуточного списка значений:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    Если Параметры.Свойство("ОбъектыНазначения") И ТипЗнч(Параметры.ОбъектыНазначения) = Тип("Массив") Тогда
        Если Параметры.ОбъектыНазначения.Количество() > 0 Тогда
            // Напрямую берем первый элемент массива, это и есть наша ссылка
            ТекущийДокумент = Параметры.ОбъектыНазначения[0];
            // Далее работаем с ТекущийДокумент...
        КонецЕсли;
    КонецЕсли;
    
КонецПроцедуры

Используя этот подход, мы избегаем лишних преобразований типов и снижаем вероятность возникновения ошибки Метод объекта не обнаружен.

← На главную