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

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

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

Метод 1: Использование стандартного обработчика «ОбработкаЗаполнения»

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

Данный метод вызывается на сервере при создании нового объекта. В качестве параметра ДанныеЗаполнения в него передается ссылка на документ-основание. Выясним, как написать эффективный код для этого случая:


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

В данном примере мы используем функцию ЗаполнитьЗначенияСвойств, которая автоматически сопоставляет имена колонок в источнике и приемнике. Проанализируем ситуацию: если имена полей (например, Номенклатура, Количество, Цена) совпадают, они будут перенесены автоматически, что значительно сокращает объем кода.

Метод 2: Заполнение по кнопке на форме (уже созданного документа)

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

Для начала создадим команду на форме (например, «ЗаполнитьИзОснования»). В обработчике этой команды на клиенте нам нужно вызвать серверный метод. Посмотрим на пример кода:


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

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

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

Метод 3: Оптимизированное заполнение через Таблицу Значений

Если в табличной части документа сотни или тысячи строк, циклы с Добавить() могут работать медленно. Разберем более производительный способ — использование метода Загрузить(). Этот метод позволяет разом заменить всё содержимое табличной части данными из коллекции ТаблицаЗначений.

Рассмотрим пример реализации на сервере:


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

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

Важные нюансы при заполнении

При реализации механизмов заполнения следует обратить внимание на несколько важных моментов:

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

Таким образом, мы рассмотрели основные способы взаимодействия с табличными частями. Выбор конкретного метода зависит от бизнес-логики: если это создание новой цепочки документов — используйте ОбработкаЗаполнения, если оперативное уточнение данных в форме — используйте команды с серверным контекстом. Стоит отметить, что для более сложных задач, например, переноса данных между неидентичными конфигурациями, часто используют готовые решения, такие как адаптивная выгрузка и загрузка данных XML или улучшенный универсальный обмен.

← На главную