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

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

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

Разбор основной ошибки: Ссылка против Объекта

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

Чтобы изменить данные, у нас есть два пути:

  1. Работа с объектом базы данных: Получить из ссылки полноценный ДокументОбъект, изменить его и записать. Это подходит, если мы хотим изменить документ «в тихом режиме» без участия пользователя.
  2. Работа с данными формы: Изменить то, что пользователь видит на экране прямо сейчас. Это наиболее правильный путь для обработок заполнения, так как он позволяет пользователю проверить результат и нажать кнопку «Записать» или «Отмена».

Использование механизмов БСП для заполнения

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

Если команда выполняется без открытия формы обработки, БСП передает параметры, среди которых есть ЭтаФорма. В этом случае мы можем напрямую обращаться к данным формы документа. Если же, как в примере автора, открывается форма самой обработки для выбора дополнительных параметров, ситуация усложняется: нам нужно вернуть данные из формы обработки в форму документа-владельца.

Шаг 1: Подготовка команды в модуле формы обработки

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


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

Шаг 2: Обработка выбора и передача данных на сервер

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


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

Шаг 3: Серверная логика получения данных

Выясним причину, по которой советы использовать РеквизитФормыВЗначение("Объект") часто не работают во внешних обработках. Дело в контексте. Если этот код написан в форме обработки, то "Объект" — это сама обработка, а не документ. Чтобы изменить документ, нам нужно работать либо с переданной структурой ДанныеФормы, либо создавать объект на основе ссылки.

Рассмотрим пример функции, которая подготавливает данные для заполнения. Мы создадим временную структуру, имитирующую структуру объекта документа, чтобы потом легко скопировать её на форму владельца.


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

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

Рассмотрим важные нюансы, которые помогут избежать ошибок при разработке:

Альтернативный метод: Прямая работа через ЗначениеВРеквизитФормы

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


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

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

Подведем итог: главная причина ошибки автора заключалась в попытке очистить табличную часть у ссылки, а не у объекта или данных формы. Используя правильные методы преобразования типов и учитывая специфику управляемого приложения, вы сможете создавать надежные и быстрые инструменты для автоматизации работы пользователей в 1С. Для настройки таких правил без написания программного кода можно применить инструмент для автоматического заполнения реквизитов и табличных частей объектов.

← На главную