Как скопировать дополнительные реквизиты и сведения при копировании объекта в 1С 8.3

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

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

В этой статье мы подробно разберем, почему стандартные механизмы могут не срабатывать, рассмотрим жизненный цикл объекта в управляемом приложении и предложим несколько надежных способов реализации копирования «допов».

Почему данные теряются при интерактивном копировании?

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

  1. На сервере создается новый экземпляр объекта, вызывается обработчик ПриКопировании.
  2. Объект превращается в ДанныеФормыСтруктура и передается на клиент для отображения в форме.
  3. Критический момент: структура ДополнительныеСвойства не входит в состав данных формы. Как только серверный вызов ПриКопировании завершен, эта структура в памяти уничтожается.
  4. Когда пользователь нажимает кнопку «Записать», на сервере создается новый экземпляр объекта на основании данных формы, и в его структуре ДополнительныеСвойства уже нет той информации, которую мы поместили туда ранее.

Выяснив причину, рассмотрим эффективные способы решения задачи.

Способ 1. Использование подписок на события (для программного и интерактивного копирования)

Этот метод хорош тем, что он не требует изменения кода форм и работает «в фоне». Мы будем использовать временный кэш для передачи ссылки на оригинал. Рассмотрим по шагам:

Шаг 1. Создание подписки «ПриКопировании»

Создадим подписку на событие ПриКопировании для нужного типа документов. В обработчике мы пометим, из какого объекта создается копия.


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

Шаг 2. Создание подписки «ПриЗаписи»

В обработчике события ПриЗаписи (или ПередЗаписью) мы извлекаем данные и копируем записи регистра сведений.


Процедура ПриЗаписиДокумента(Источник, Отказ) Экспорт
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    СсылкаНаОригинал = Неопределено;
    Если НЕ Источник.ДополнительныеСвойства.Свойство("ДокументКопирования", СсылкаНаОригинал) Тогда
        Возврат;
    КонецЕсли;

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

Способ 2. Работа в управляемой форме (самый надежный для УФ)

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

В модуле формы документа используем обработчик ПриСозданииНаСервере. В нем доступен параметр ПараметрКопирования, который содержит ссылку на объект-источник.

  1. Добавим на форму скрытый реквизит СсылкаНаОригинал (тип: любая ссылка или конкретный документ).
  2. В ПриСозданииНаСервере заполним этот реквизит.
  3. В ПослеЗаписиНаСервере выполним копирование сведений, так как ссылка на новый объект уже существует.

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

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

Способ 3. Использование программного интерфейса БСП (Библиотека Стандартных Подсистем)

Проанализируем современный подход. В конфигурациях, построенных на базе БСП (УТ 11, ERP, БП 3.0), для управления свойствами выделен специальный общий модуль УправлениеСвойствами. Вместо того чтобы вручную записывать данные в регистры, правильнее использовать готовые методы библиотеки.

Для копирования дополнительных реквизитов (которые хранятся в табличной части объекта), обычно ничего делать не нужно — они копируются вместе с объектом автоматически, если в коде модуля не стоит их принудительная очистка. Но если они очищаются, мы можем восстановить их программно:


// В модуле объекта в ПриКопировании
ЭтотОбъект.ДополнительныеРеквизиты.Загрузить(ОбъектКопирования.ДополнительныеРеквизиты.Выгрузить());

Для дополнительных сведений (в регистре) в БСП рекомендуется использовать процедуру УправлениеСвойствами.ЗаписатьСвойстваУОбъекта(). Это обеспечит прохождение всех проверок, заложенных в систему.

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

Проанализируем еще несколько важных моментов, которые помогут избежать ошибок:

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

← На главную