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

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

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

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

Анализ проблемы: ошибки сериализации и контекст выполнения

Посмотрим на классический ошибочный фрагмент кода клиентского модуля обработки:


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

При выполнении этого кода платформа выдает исключение следующего вида:


Ошибка при вызове метода контекста (ПолучитьОстатки)
по причине:
Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа.
по причине:
Ошибка преобразования данных XDTO:
Отсутствует отображение для типа '{http://v8.1c.ru/8.1/data/core}ValueTable'

Выясним причину ошибки. Объект ТаблицаЗначений является чисто серверным типом данных в управляемом приложении. Он не может существовать на клиенте (в тонком или веб-клиенте) и не подлежит автоматической сериализации для передачи через границу вызова &НаКлиенте — &НаСервере. Когда серверная функция ПолучитьОстатки() возвращает сформированную таблицу значений на клиент, платформа пытается преобразовать ее через XDTO и завершает операцию аварийно.

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

Проанализируем рабочие способы решения этой задачи.

Способ 1. Преобразование серверных данных в массив структур

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

Разберем по шагам реализацию этого механизма:

  1. Считываем реквизиты документа напрямую через ВладелецФормы.Объект на клиенте.
  2. Передаем полученные значения параметров в серверную функцию.
  3. На сервере выполняем запрос и выгружаем результат в массив структур.
  4. На клиенте обходим полученный массив и заполняем строки коллекции ВладелецФормы.Объект.Товары.

Посмотрим на реализацию в коде формы обработки:


&НаСервереБезКонтекста
Функция ПолучитьОстаткиМассивом(СкладОтправитель, ДатаОстатков)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
        |   ТоварыНаСкладахОстатки.ВНаличииОстаток КАК Количество,
        |   ТоварыНаСкладахОстатки.Номенклатура.СчетУчета КАК СчетУчета
        |ИЗ
        |   РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК ТоварыНаСкладахОстатки";
        
    Запрос.УстановитьПараметр("Период", ДатаОстатков);
    Запрос.УстановитьПараметр("Склад", СкладОтправитель);
    
    Таблица = Запрос.Выполнить().Выгрузить();
    
    МассивРезультат = Новый Массив;
    Для Каждого СтрТЗ Из Таблица Цикл
        Стр = Новый Структура;
        Стр.Вставить("Номенклатура", СтрТЗ.Номенклатура);
        Стр.Вставить("Количество", СтрТЗ.Количество);
        Стр.Вставить("СчетУчета", СтрТЗ.СчетУчета);
        МассивРезультат.Добавить(Стр);
    КонецЦикла;
    
    Возврат МассивРезультат;
КонецФункции

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

Способ 2. Передача структуры данных формы на сервер целиком

Перебор строк на клиенте в циклах работает медленно, особенно при большом объеме номенклатуры. В платформе «1С:Предприятие 8.3» объект Объект формы документа имеет тип ДанныеФормыСтруктура, а его табличная часть — ДанныеФормыКоллекция. Эти типы можно передавать параметром в серверную процедуру без контекста.

Рассмотрим, как выполнить заполнение табличной части полностью на сервере:


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

&НаКлиенте
Процедура Заполнить(Команда)
    // Передаем форму документа как ДанныеФормыСтруктура
    ЗаполнитьТабличнуюЧастьНаСервере(ВладелецФормы.Объект);
КонецПроцедуры

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

Способ 3. Использование промежуточного реквизита формы типа «ТаблицаЗначений»

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

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

Рекомендации для конфигураций на базе БСП

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

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

← На главную