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

Программист Управленческий учет IT и автоматизация бизнеса
← На главную

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

Постановка задачи и анализ ситуации

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

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

Способ 1: Ручной обход табличной части в цикле

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

Для начала опишем клиентскую процедуру, которая вызывает серверную логику:


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

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


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

Использование метода ЗаполнитьЗначенияСвойств

Обратите внимание на метод ЗаполнитьЗначенияСвойств. Это один из самых полезных инструментов в арсенале программиста 1С. Вместо того чтобы вручную прописывать каждую колонку (НоваяСтрока.Показатель = СтрИсходная.Показатель), мы просим платформу автоматически сопоставить имена свойств источника и приемника и перенести значения. Это не только ускоряет разработку, но и делает код устойчивым к изменениям: если в будущем вы добавите новую колонку в табличную часть, она начнет копироваться автоматически без правки этого кода.

Способ 2: Быстрое копирование через «Выгрузить» и «Загрузить»

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


// Вместо цикла Для Каждого...
ТаблицаДанных = СсылкаНаИсходныйДок.Содержание.Выгрузить();
НовДок.Содержание.Загрузить(ТаблицаДанных);

Метод Выгрузить() создает объект ТаблицаЗначений, содержащий все данные строк ТЧ. Метод Загрузить() мгновенно очищает ТЧ приемника и заполняет её данными из таблицы. Это работает быстрее, чем цикл, так как выполняется на уровне внутренних механизмов платформы.

Работа со связанными регистрами сведений

Часто документ — это лишь верхушка айсберга, и вместе с ним нужно скопировать настройки в регистрах. Разберем, как правильно копировать записи регистра сведений с заменой одного из измерений (например, редакции).

Рассмотрим пример для регистра «ФормулыШаблонов»:


// Получаем старые записи
НаборСтарый = РегистрыСведений.ФормулыШаблонов.СоздатьНаборЗаписей();
НаборСтарый.Отбор.Редакция.Установить(СтараяРедакция);
НаборСтарый.Прочитать();

// Готовим новый набор
НаборНовый = РегистрыСведений.ФормулыШаблонов.СоздатьНаборЗаписей();
НаборНовый.Отбор.Редакция.Установить(НоваяРедакцияОбъект.Ссылка);

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

НаборНовый.Записать();

Важные рекомендации и «подводные камни»

Проанализируем несколько технических моментов, на которых часто спотыкаются новички:

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

Заключение

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

← На главную