Почему при программном копировании документа ПараметрОбъектКопирования оказывается пустым и как это исправить?

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

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

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

Выясним причину проблемы

Проанализируем работу метода ОткрытьЗначение(). Этот метод является универсальным инструментом платформы для быстрого вывода объекта на экран. Его главная особенность заключается в том, что он не предназначен для передачи специфических параметров инициализации формы. Когда мы передаем в него новый, еще не записанный объект, полученный методом Скопировать(), платформа просто пытается найти основную форму для этого типа данных и открыть её.

Связь с исходным документом-основанием теряется, потому что для формы этот объект выглядит как «просто новый экземпляр». Параметр ПараметрОбъектКопирования заполняется автоматически только в двух случаях:

  1. Когда пользователь нажимает стандартную кнопку «Скопировать» в списке документов.
  2. Когда разработчик явно передает этот параметр при вызове формы.

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

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

Рассмотрим пример кода:


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

В этом случае платформа сама создаст новый объект, скопирует в него данные из источника и корректно заполнит ПараметрОбъектКопирования, который будет доступен в обработчиках формы.

Способ 2. Модификация объекта перед открытием

Часто возникает задача не просто скопировать документ, а изменить в нем часть данных (например, дату, склад или контрагента) до того, как пользователь увидит форму. Если мы сначала выполним Скопировать(), затем изменим реквизиты, а потом вызовем ПолучитьФорму(), параметр копирования может пропасть.

Проанализируем правильный алгоритм действий для этой ситуации:

  1. Создаем копию объекта в памяти.
  2. Вносим необходимые изменения в реквизиты.
  3. Получаем форму, передавая ссылку на оригинал для сохранения контекста.
  4. Устанавливаем наш измененный объект в качестве основного реквизита формы.

Пример реализации:


// 1. Создаем копию
НовыйОбъект = СсылкаНаИсточник.Скопировать();

// 2. Вносим изменения
НовыйОбъект.Дата = ТекущаяДата();
НовыйОбъект.Ответственный = ПараметрыСеанса.ТекущийПользователь;

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

// 4. Передаем измененный объект в форму
// Для обычных форм в толстом клиенте:
Форма.УстановитьНедостающиеПараметры(НовыйОбъект); // Если есть такой метод
// Или напрямую работаем с объектом формы:
Форма.ДокументОбъект = НовыйОбъект; 

Форма.Открыть();

Способ 3. Использование события ПриКопировании в модуле объекта

Разберем наиболее архитектурно правильный подход. Если изменения, которые вы хотите внести в документ при копировании, являются типовыми (должны происходить всегда при ручном или программном копировании), их следует вынести в Модуль объекта.

В модуле документа существует предопределенный обработчик ПриКопировании(ОбъектКопирования). Рассмотрим его преимущества:

Пример кода в модуле объекта:


Процедура ПриКопировании(ОбъектОснование)
    // Очищаем специфические поля, которые не должны копироваться
    ЭтотОбъект.Номер = "";
    ЭтотОбъект.Дата = ТекущаяДата();
    
    // Можно заполнить данные из основания
    ЭтотОбъект.Комментарий = "Копия документа: " + Строка(ОбъектОснование);
КонецПроцедуры

Рекомендации по выбору метода

Проанализировав ситуацию, мы можем подвести итоги:

  1. Если вы в толстом клиенте и используете ОткрытьЗначение(), помните, что это «быстрый» метод, который игнорирует контекст копирования. Заменяйте его на ОткрытьФорму() или ПолучитьФорму().
  2. Если нужно менять данные, лучше всего делать это в событии ПриКопировании модуля объекта — это гарантирует целостность логики независимо от того, как вызывается форма.
  3. Если изменения разовые и специфичны только для одной кнопки, используйте передачу структуры параметров в ОткрытьФорму(), где ключом будет выступать "ПараметрОбъектКопирования" (для обычных форм) или "ЗначениеЗаполнения" (для управляемых форм в режиме совместимости).

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

← На главную