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

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

Разработка внешних обработок заполнения табличных частей — одна из самых частых задач при кастомизации конфигураций на платформе «1С:Предприятие 8.3». Однако начинающие разработчики часто сталкиваются с неприятной ситуацией: код внешней обработки успешно отрабатывает на сервере, отладчик показывает, что строки в табличную часть добавлены, но при возврате на клиент форма документа-владельца остается абсолютно пустой.

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

Выясняем причину: почему данные «исчезают»?

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


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

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

  1. Особенности типа данных: Переменная ВладелецФормы.Объект на клиенте имеет тип ДанныеФормыСтруктура, а не реальный прикладной объект ДокументОбъект. Это специальный прокси-объект, предназначенный для визуализации данных на форме.
  2. Отсутствие автосинхронизации контекстов: Когда мы пытаемся передать эту структуру на сервер или изменить её локально на клиенте, платформа не понимает, что интерфейс формы-владельца нужно принудительно перерисовать. Изменения происходят в локальной копии структуры, а сама форма документа «не знает» о том, что её реквизиты были модифицированы.
  3. Потеря объектной связи: Если заполнение данных происходит на сервере, то при передаче переменной ДанныеФормыСтруктура в серверную процедуру платформа передает её по значению (копированием). Все изменения, внесенные на сервере в эту копию, бесследно уничтожаются при возврате управления на клиент.

Теперь рассмотрим правильные паттерны проектирования взаимодействия внешней обработки и вызывающей формы.

Способ 1. Использование метода КопироватьДанныеФормы

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

Рассмотрим по шагам, как должен выглядеть правильный код в модуле формы вашей внешней обработки:


&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения) Экспорт
    
    // 1. Получаем ссылку на прокси-объект формы документа-владельца
    ДокументДанныеФормы = ВладелецФормы.Объект;
    
    // 2. Вызываем серверный метод для заполнения ТЧ
    ЗаполнитьДокументНаСервере(ДокументДанныеФормы);
    
    // 3. Явно копируем измененную структуру данных обратно в объект формы-владельца
    КопироватьДанныеФормы(ДокументДанныеФормы, ВладелецФормы.Объект);
    
    // 4. Обязательно взводим флаг модифицированности, чтобы звезда (*) появилась на форме документа
    ВладелецФормы.Модифицированность = Истина;
    
КонецПроцедуры

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

Важное примечание: Использование метода ЗаполнитьЗначенияСвойств вместо ручного присвоения каждой колонки существенно сокращает объем кода, ускоряет его работу и делает код устойчивым к изменению состава колонок в будущем.

Способ 2. Использование ДанныеФормыВЗначение и ЗначениеВДанныеФормы

Бывают ситуации, когда простого заполнения колонок недостаточно. Например, при добавлении номенклатуры в табличную часть документа необходимо, чтобы автоматически рассчитались цены, суммы, НДС, определились счета учета, или отработали другие сложные алгоритмы, заложенные в самом документе конфигурации.

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

Разберем, как реализовать этот подход на сервере:


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

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

Способ 3. Современный стандарт БСП (команда «ЗаполнениеФормы»)

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

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

Рассмотрим, как настроить такую обработку:

1. В функции СведенияОВнешнейОбработке() обязательно укажем правильный тип запуска команды:


// ... код регистрации обработки ...
НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = "Заполнить компенсацию (БСП)";
НоваяКоманда.Идентификатор = "ЗаполнитьКомпенсацию";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыЗаполнениеФормы();
// ...

2. В модуле объекта обработки определяем экспортную процедуру ВыполнитьКоманду. БСП сама передаст контекст формы документа в параметрах выполнения, избавив нас от необходимости ручного копирования данных:


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

Этот подход является наиболее правильным, производительным и безопасным с точки зрения стандартов разработки фирмы «1С». Платформа сама позаботится о корректном обновлении графического интерфейса пользователя и передаче измененного контекста на клиентскую сторону сразу после завершения серверного вызова.

← На главную