Как исправить ошибку «Поле объекта не обнаружено (Товары)» при переносе встроенной обработки загрузки во внешнюю

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

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

Причина возникновения ошибки: путаница в контекстах

Когда обработка «вшита» в документ или вызывается напрямую из его формы, переменная Объект чаще всего ссылается на сам документ (его данные на форме). В этом контексте обращение Объект.Товары работает корректно, так как у документа ПеремещениеТоваров действительно есть табличная часть Товары.

Однако, как только мы создаем внешнюю обработку, переменная Объект начинает ссылаться на саму обработку. У внешней обработки нет табличной части Товары (если вы не создали её там вручную), поэтому система выдает ошибку. Чтобы решить проблему, нам нужно четко разделить: данные самой обработки (путь к файлу, настройки) и данные документа, в который мы хотим загрузить информацию.

Вариант 1. Загрузка в существующий документ через ссылку

Если ваша внешняя обработка должна изменять уже существующий в базе документ, нам необходимо передать в обработку ссылку на этот документ. Проанализируем, как правильно изменить код процедуры загрузки:

  1. Добавим в реквизиты внешней обработки реквизит СсылкаНаДокумент с типом ДокументСсылка.ПеремещениеТоваров.
  2. На сервере получим объект документа для редактирования.

Рассмотрим пример кода для серверной части:


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

    // Очищаем табличную часть документа, если это необходимо
    ДокументОбъект.Товары.Очистить();

    Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
        НоваяСтрока = ДокументОбъект.Товары.Добавить();
        НоваяСтрока.Номенклатура = СтрокаДанных.Номенклатура;
        НоваяСтрока.Количество = СтрокаДанных.Количество;
        
        // Здесь можно вызвать заполнение цен или других реквизитов
        // ОбработкаТабличныхЧастей.ЗаполнитьСтавкуНДС(ДокументОбъект, НоваяСтрока);
    КонецЦикла;

    // Обязательно записываем объект в базу данных
    ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
    
КонецПроцедуры

Важный момент: работа с ДокументОбъект возможна только на стороне сервера. Ссылка (ДокументСсылка) доступна на клиенте, но она предназначена только для чтения. Чтобы добавить строки в таблицу, метод ПолучитьОбъект() обязателен.

Вариант 2. Загрузка в открытую форму документа (через владельца)

Часто внешнюю обработку запускают непосредственно из формы документа. В этом случае пользователю удобно, чтобы данные появились в таблице сразу, без предварительного сохранения документа в базу. Для этого мы можем использовать свойство ВладелецФормы.

Проанализируем ситуацию: если форма обработки открыта из формы документа, то ЭтаФорма.ВладелецФормы содержит контекст формы документа. Мы можем обратиться к его данным напрямую.


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

КонецПроцедуры

Оптимизация чтения Excel: отказ от COM-объектов

В исходном коде автора используется COMОбъект("Excel.Application"). Это старый метод, который имеет ряд недостатков: требует установленного MS Excel на сервере или клиенте, работает медленно и часто «зависает» в процессах Windows.

Рассмотрим современный и надежный способ — использование встроенного в 1С метода Прочитать() объекта ТабличныйДокумент. Этот метод работает напрямую с файлами .xlsx и .xls без использования стороннего ПО.


&НаСервере
Функция ПрочитатьДанныеИзExcel(ПутьКФайлу)
    
    ТабДок = Новый ТабличныйДокумент;
    Попытка
        ТабДок.Прочитать(ПутьКФайлу, СпособЧтенияЗначенийТабличногоДокумента.Значение);
    Исключение
        Сообщить("Ошибка чтения файла: " + ОписаниеОшибки());
        Возврат Неопределено;
    КонецПопытки;

    ТаблицаРезультат = Новый ТаблицаЗначений;
    ТаблицаРезультат.Колонки.Добавить("Номенклатура");
    ТаблицаРезультат.Колонки.Добавить("Количество");

    // Обходим строки табличного документа (начиная со второй, если есть шапка)
    Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
        
        Артикул = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
        Количество = ТабДок.Область(НомерСтроки, 2).Значение;
        
        // Поиск номенклатуры (лучше делать одним запросом ко всему файлу, но для примера упростим)
        СсылкаНоменклатура = Справочники.Номенклатура.НайтиПоНаименованию(Артикул);
        
        Если Не СсылкаНоменклатура.Пустая() Тогда
            НоваяСтрока = ТаблицаРезультат.Добавить();
            НоваяСтрока.Номенклатура = СсылкаНоменклатура;
            НоваяСтрока.Количество = Число(Количество);
        КонецЕсли;
        
    КонецЦикла;
    
    Возврат ТаблицаРезультат;

КонецФункции

Рекомендации по работе с внешней обработкой

  1. Клиент-серверное разделение: Помните, что запросы к базе данных (Запрос.Выполнить()) и поиск ссылок (НайтиПоНаименованию, НайтиПоКоду) нельзя выполнять в процедурах &НаКлиенте. Всегда выносите логику поиска и записи в серверные функции.
  2. Типизация данных: При загрузке из Excel числа часто считываются как строки с неразрывными пробелами. Используйте функцию СтрЗаменить(Значение, Символы.НПП, "") и явное приведение к типу Число().
  3. Использование БСП: Если в вашей конфигурации используется Библиотека Стандартных Подсистем (БСП), подключайте внешнюю обработку через механизм «Дополнительные отчеты и обработки». В этом случае ссылка на текущий документ будет передаваться в обработку автоматически через параметр ПараметрыВыполнения.ОбъектыНазначения.
  4. Безопасность: При работе в веб-клиенте или на сервере под управлением Linux COM-объекты работать не будут. Использование ТабличныйДокумент гарантирует кроссплатформенность вашего решения.

Проанализировав вышеописанные шаги, мы видим, что основная задача при создании внешней обработки — правильно сориентировать код в пространстве имен 1С, перестав обращаться к Объекту обработки как к документу, и наладить корректную передачу ссылок между клиентской и серверной частью программы.

← На главную