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

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

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

Постановка задачи и основные сложности

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

Рассмотрим типичную ошибку: попытку передать ВладелецФормы.Объект на сервер и изменить его там. Система выдаст исключение: "Нельзя изменять поле, содержащее объект данных формы". Это происходит потому, что на сервере ДанныеФормыСтруктура (которым является Объект) не может быть преобразован в полноценный объект документа без специальных методов, а прямая запись в него из контекста другой формы ограничена.

Способ 1. Заполнение на клиенте через массив структур (универсальный метод)

Проанализируем наиболее гибкий способ, который позволяет заполнить документ без его немедленной записи в базу данных. Это важно, если пользователь должен проверить результат загрузки перед сохранением. Суть метода заключается в подготовке данных на сервере обработки, передаче их на клиент в виде массива структур и последующем обходе этого массива для заполнения ТЧ документа.

Шаг 1. Вызов формы обработки из документа

В модуле формы документа создадим команду и опишем процедуру вызова обработки. Обратите внимание на передачу параметра ЭтаФорма в качестве владельца.


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

Шаг 2. Подготовка данных в форме обработки

В форме обработки создадим серверную функцию, которая сформирует данные. Мы будем использовать Массив, содержащий Структуры, так как эти типы данных легко передаются между сервером и клиентом.


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

Шаг 3. Возврат данных в документ

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


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

Способ 2. Использование временного хранилища и ОповеститьОВыборе

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

  1. В обработке на сервере выгружаем результат в Таблицу Значений.
  2. Помещаем таблицу во временное хранилище методом ПоместитьВоВременноеХранилище().
  3. Вызываем ОповеститьОВыборе(АдресХранилища).
  4. В форме документа ловим событие в обработчике ОбработкаВыбора.

Рассмотрим программную реализацию в форме документа:


&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
    // Проверяем, что пришел адрес временного хранилища
    Если ЭтоАдресВременногоХранилища(ВыбранноеЗначение) Тогда
        ЗаполнитьТЧИзХранилищаНаСервере(ВыбранноеЗначение);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьТЧИзХранилищаНаСервере(Адрес)
    ТЗ = ПолучитьИзВременногоХранилища(Адрес);
    // Загружаем данные из ТЗ в табличную часть "Товары"
    Объект.Товары.Загрузить(ТЗ);
КонецПроцедуры

Разбор ошибки доступа к объекту владельца

Многие разработчики пытаются использовать конструкцию ВладелецФормы.Объект внутри серверной процедуры формы обработки. Выясним, почему это приводит к ошибке. Когда мы передаем ВладелецФормы.Объект на сервер обработки, он передается как тип ДанныеФормыСтруктура. Это "легкая" проекция данных, которая не является объектом базы данных ДокументОбъект.

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


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

Важно: Данный метод работает только в том случае, если форма обработки и форма документа находятся в одном контексте или если используется прямое обращение к реквизитам. Однако наиболее безопасным и стабильным остается Способ 1 с возвратом структуры данных.

Рекомендации по использованию БСП

Если ваша конфигурация построена на базе БСП (Библиотеки стандартных подсистем), рекомендуется использовать штатный механизм "Дополнительные отчеты и обработки". Рассмотрим его преимущества:

Для реализации этого в модуле объекта обработки необходимо описать функцию СведенияОВнешнейОбработке(), указав вид ДополнительноеЗаполнениеОбъекта. Логика заполнения в этом случае пишется в процедуре ВыполнитьКоманду(), где через параметр ЭтаФорма можно получить доступ к табличным частям открытого документа.

Подведем итог: для простых задач загрузки идеально подходит перебор массива структур на клиенте. Для работы с большими объемами данных используйте временное хранилище. А для профессиональной разработки в типовых решениях всегда выбирайте механизмы БСП.

← На главную