При разработке в среде 1С:Предприятие 8.3 часто возникает задача: при создании нового документа путем копирования существующего необходимо обнулить определенные данные. Это могут быть статусы, суммы, специфические признаки или табличные части, которые не должны переноситься в новый документ. В этой статье мы подробно разберем, как реализовать этот механизм, проанализируем типичные ошибки и рассмотрим продвинутые способы автоматизации процесса.
Самый правильный и стандартный способ решения задачи — использование предопределенной процедуры ПриКопировании, которая располагается в модуле объекта документа. Рассмотрим ситуацию: пользователь нажимает кнопку "Скопировать" (или клавишу F9) в списке документов. В этот момент платформа создает новый объект и вызывает данную процедуру.
Важный нюанс: процедура ПриКопировании принимает один параметр — ОбъектКопирования. Это ссылка на тот документ, из которого создается копия. Новый же документ — это и есть ЭтотОбъект, в контексте которого выполняется код.
Разберем конкретный пример кода, который нужно разместить в модуле объекта:
Процедура ПриКопировании(ОбъектКопирования)
// Очищаем реквизиты шапки
Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
ТСБрутто = 0;
ТСНетто = 0;
ТСТара = 0;
// Устанавливаем статус по умолчанию для нового документа
СостояниеЗаказа = Перечисления.ВидыСостоянияЗаказа.ЗаказОформлен;
// Если есть комментарий, который не должен копироваться
Комментарий = "";
КонецПроцедуры
Обратите внимание, что мы обращаемся к реквизитам Номенклатура, ТСБрутто и другим напрямую. Это эквивалентно записи ЭтотОбъект.Номенклатура. Ошибка многих начинающих разработчиков заключается в попытке изменить ОбъектКопирования — делать этого не нужно, так как это источник данных, а не результат.
Иногда документ содержит десятки реквизитов, и прописывать очистку каждого вручную трудозатратно. В таком случае мы можем применить универсальный алгоритм, который обходит все реквизиты объекта через коллекцию метаданных. При этом важно оставить нетронутыми ключевые поля, такие как "Организация" или "Склад".
Проанализируем следующий подход:
Процедура ПриКопировании(ОбъектКопирования)
// Получаем коллекцию реквизитов данного типа документа из метаданных
РеквизитыОбъекта = Метаданные().Реквизиты;
Для Каждого Реквизит Из РеквизитыОбъекта Цикл
// Определяем список исключений, которые НЕ нужно очищать
Если Реквизит.Имя = "Организация" Или Реквизит.Имя = "Подразделение" Тогда
Продолжить;
КонецЕсли;
// Присваиваем пустое значение в зависимости от типа данных
// Платформа 1С автоматически подберет пустое значение нужного типа
ЭтотОбъект[Реквизит.Имя] = Реквизит.Тип.ПривестиЗначение("");
КонецЦикла;
КонецПроцедуры
Использование метода ПривестиЗначение("") позволяет корректно установить пустую ссылку для справочников, 0 для чисел и пустую строку для текстовых полей.
Если в документе есть табличные части (например, "Товары" или "Услуги"), они по умолчанию копируются полностью. Чтобы создать абсолютно "чистый" документ без строк в таблицах, используем метод Очистить(). Если же нужно оставить строки, но обнулить в них только цены или количество, воспользуемся циклом Для Каждого.
Рассмотрим пример комплексной очистки:
Процедура ПриКопировании(ОбъектКопирования)
// 1. Полная очистка табличной части "СпецУсловия"
ЭтотОбъект.СпецУсловия.Очистить();
// 2. Частичная очистка в табличной части "Товары"
Для Каждого СтрокаТовар Из ЭтотОбъект.Товары Цикл
СтрокаТовар.Цена = 0;
СтрокаТовар.Сумма = 0;
СтрокаТовар.Скидка = 0;
КонецЦикла;
КонецПроцедуры
Такой подход позволяет сохранить структуру документа (перечень товаров), но заставить пользователя заново ввести актуальные цены.
Если в вашей конфигурации много однотипных документов и для всех них действуют одинаковые правила (например, всегда очищать реквизит "Ответственный" или "Комментарий"), целесообразно использовать Подписку на событие. Это позволит не вносить изменения в модуль каждого конкретного документа, что особенно полезно при поддержке типовых конфигураций.
ДокументОбъект для всех).ПриКопировании.Пример кода в общем модуле для подписки:
Процедура ОчиститьДанныеПриКопировании(Источник, ОбъектКопирования) Экспорт
// Источник — это и есть наш новый создаваемый документ
Источник.Комментарий = "";
Источник.Ответственный = Пользователи.ТекущийПользователь();
// Можно проверить наличие реквизита программно перед записью
Если Источник.Метаданные().Реквизиты.Найти("Статус") <> Неопределено Тогда
Источник.Статус = Справочники.СтатусыДокументов.Новый;
КонецЕсли;
КонецПроцедуры
Выясним важный методический момент. В управляемых формах 1С существует также обработчик ОбработкаЗаполнения. Когда происходит копирование, платформа вызывает сначала ПриКопировании (в модуле объекта), а затем ОбработкаЗаполнения. В ОбработкаЗаполнения параметр ДанныеЗаполнения будет содержать ссылку на копируемый объект. Для наглядного отслеживания последовательности их вызова можно использовать обработку для изучения событий 1С.
Рекомендация: Логику, специфичную именно для интерактивного копирования пользователем, лучше оставлять в ПриКопировании. Если же логика заполнения должна работать и при создании на основании других документов, используйте ОбработкаЗаполнения.
Если ваш документ содержит присоединенные файлы или изображения, хранящиеся в реквизите с типом ХранилищеЗначения, помните, что они также копируются "как есть". Чтобы очистить такие данные, нужно присвоить реквизиту новый объект хранилища с неопределенным значением:
ЭтотОбъект.ДанныеКартинки = Новый ХранилищеЗначения(Неопределено);
Проанализировав все вышеописанные методы, мы видим, что платформа 1С предоставляет гибкие инструменты для управления данными при копировании. Выбор конкретного метода зависит от объема реквизитов и необходимости тиражирования этой логики на разные виды документов.