Разработка и Конфигурация · 13 мин
Как очищать реквизит при копировании документа в 1С
Как очистить реквизит при копировании документа в 1С: обработчик ПриКопировании, очистка табличных частей, отличия от ПриЗаполнении, примеры кода и типичные ошибки.
При копировании документа в 1С платформа переносит в новый документ все заполненные реквизиты и табличные части исходного объекта. Часто это нежелательно: номенклатура, суммы, комментарии, ссылки на связанные документы или служебные признаки должны быть пустыми в копии. Для управления этим поведением в модуле объекта документа предусмотрено событие ПриКопировании.
Обработчик ПриКопировании вызывается на сервере в момент, когда пользователь нажимает «Скопировать» (F9) в форме документа или списка. К этому моменту данные источника уже перенесены в новый объект, но документ ещё не записан — поэтому любые изменения реквизитов внутри обработчика безопасны и не требуют дополнительной записи.
Ниже разобраны типовые приёмы: очистка одиночных реквизитов, табличных частей, условная очистка по виду операции, а также отличия от события ПриЗаполнении и способы проверить результат без риска для рабочих данных.
Где находится событие ПриКопировании и как оно работает
Событие ПриКопировании располагается в модуле объекта документа. Чтобы открыть модуль, в конфигураторе найдите нужный документ в дереве конфигурации, вызовите контекстное меню и выберите «Открыть модуль объекта». Если конфигурация типовая и находится на поддержке, изменения лучше вносить через расширение конфигурации — так вы сохраните возможность обновления.
Порядок вызова событий при копировании выглядит так: платформа создаёт новый объект, копирует в него данные источника, затем вызывает ПриКопировании с параметром ОбъектКопирования — ссылкой на документ-источник. После этого открывается форма нового документа. Всё, что вы измените в обработчике, попадёт в форму и в итоговый документ после его записи пользователем.
Очистка одиночных реквизитов шапки
Самая частая задача — обнулить реквизит шапки: комментарий, ссылку на основание, служебный признак. В зависимости от типа реквизита используется разное пустое значение. Для ссылочных типов и составных типов удобно присваивать Неопределено, для строк — пустую строку, для чисел — ноль, для булевых значений — Ложь.
Процедура ПриКопировании(ОбъектКопирования)
Комментарий = "";
ДокументОснование = Неопределено;
СуммаРучнаяКорректировка = 0;
Согласовано = Ложь;
КонецПроцедурыБолее надёжный способ — не перечислять типы вручную, а присваивать реквизиту пустое значение его типа через метаданные. Это удобно, когда очищать нужно много реквизитов или тип реквизита может измениться при доработках конфигурации:
Процедура ПриКопировании(ОбъектКопирования)
РеквизитыДляОчистки = Новый Массив;
РеквизитыДляОчистки.Добавить("Комментарий");
РеквизитыДляОчистки.Добавить("ДокументОснование");
Для Каждого ИмяРеквизита Из РеквизитыДляОчистки Цикл
ОписаниеРеквизита = Метаданные().Реквизиты.Найти(ИмяРеквизита);
Если ОписаниеРеквизита <> Неопределено Тогда
ЭтотОбъект[ИмяРеквизита] = ОписаниеРеквизита.Тип.ПривестиЗначение();
КонецЕсли;
КонецЦикла;
КонецПроцедурыМетод ПривестиЗначение() без параметра возвращает значение по умолчанию для типа реквизита: пустую ссылку, пустую строку, ноль или Ложь. Такой код устойчив к переименованию типов и не сломается при изменении состава типов реквизита.
Очистка табличных частей при копировании
Табличные части очищаются методом Очистить(). Типичный сценарий — копирование документа-шаблона, где нужна только шапка, а строки товаров должны заполняться заново:
Процедура ПриКопировании(ОбъектКопирования)
Товары.Очистить();
Услуги.Очистить();
КонецПроцедурыИногда требуется не полная очистка, а частичная: например, оставить номенклатуру, но обнулить количество и цены. В этом случае строки не удаляются, а обходятся в цикле:
Процедура ПриКопировании(ОбъектКопирования)
Для Каждого СтрокаТовара Из Товары Цикл
СтрокаТовара.Количество = 0;
СтрокаТовара.Цена = 0;
СтрокаТовара.Сумма = 0;
КонецЦикла;
КонецПроцедурыУсловная очистка: по виду операции, источнику или пользователю
Не всегда реквизит нужно очищать при любом копировании. Параметр ОбъектКопирования позволяет построить условия: например, очищать ссылку на основание только если источник — документ другого вида операции, или сохранять контрагента, но сбрасывать договор при смене организации.
Процедура ПриКопировании(ОбъектКопирования)
Если ОбъектКопирования.ВидОперации <> ВидОперации Тогда
ДоговорКонтрагента = Неопределено;
КонецЕсли;
Если Не Пользователи.ЭтоПолноправныйПользователь() Тогда
РучнаяСкидка = 0;
КонецЕсли;
КонецПроцедурыТакже полезно учитывать дату: при копировании документа прошлого периода часто имеет смысл очистить реквизиты, завязанные на старые цены, курсы или договоры, чтобы документ не ушёл в учёт с устаревшими данными.
Как выбрать способ очистки
Отличия от ПриЗаполнении и ОбработкаЗаполнения
Частая путаница: разработчики пытаются очищать реквизиты в ОбработкаЗаполнения или ПриЗаполнении. Эти события работают иначе. ОбработкаЗаполнения вызывается при вводе на основании и при программном создании с данными заполнения, а при копировании через интерфейс она, как правило, не вызывается с данными источника. ПриЗаполнении — это событие формы, оно срабатывает при создании объекта в форме и зависит от параметров создания.
Ключевое отличие: ПриКопировании гарантированно вызывается именно при копировании и только при нём. Если очистить реквизит в ПриЗаполнении, это затронет и обычное создание документа, и ввод на основании — что чаще всего не требуется. Поэтому правило простое: логика «только для копии» — в ПриКопировании, логика «для любого нового документа» — в ОбработкаЗаполнения.
Сравнение событий заполнения
Вызывается только при копировании. Есть ссылка на источник. Подходит для очистки реквизитов именно в копии.
Вызывается при вводе на основании и программном создании. Не срабатывает при обычном копировании через F9.
Срабатывает при создании объекта в форме по параметрам. Не вызывается при программном создании без формы.
Типичные ошибки и ограничения
Ещё одно ограничение: ПриКопировании не вызывается, если документ создаётся программно методом Скопировать() у объекта — в этом случае разработчик сам управляет заполнением. Поэтому если в конфигурации есть механизмы пакетного копирования документов, логику очистки стоит вынести в отдельную экспортную процедуру и вызывать её из обоих мест.
Как реализовать очистку через расширение
Для типовых конфигураций рекомендуемый путь — расширение. В расширении добавьте документ в состав, откройте его модуль объекта и создайте обработчик с аннотацией &После:
&После("ПриКопировании")
Процедура Расш1_ПриКопировании(ОбъектКопирования)
Комментарий = "";
Товары.Очистить();
КонецПроцедурыАннотация &После означает, что сначала отработает типовой обработчик (если он есть), а затем ваш код. Это безопаснее, чем &Вместо, так как сохраняет типовую логику очистки служебных реквизитов, которую вендор мог добавить в обработчик.
- 1Сделайте резервную копию базы или разверните копию для тестов
- 2Создайте расширение конфигурации, добавьте в него нужный документ
- 3В модуле объекта расширения создайте обработчик &После("ПриКопировании")
- 4Добавьте очистку нужных реквизитов и табличных частей
- 5Обновите конфигурацию базы данных и протестируйте копирование на тестовом документе
- 6Проверьте проведение копии и обмены, если документ в них участвует
Проверка результата
После внедрения проверьте доработку на нескольких сценариях: копирование проведённого документа, копирование непроведённого, копирование документа с другим видом операции. В каждом случае копия должна открываться с очищенными реквизитами, а остальные данные — сохраняться.
Как проверить результат
Целевые реквизиты пусты, остальные данные перенесены
Реквизит заполнен значением источника или очистились лишние поля
Документ проводится без ошибок, движения корректны
Ошибки проведения из-за пустых обязательных реквизитов
Стандартное заполнение нового документа работает как раньше
При создании нового документа реквизиты очищаются — значит, код попал не в то событие
Копия корректно регистрируется к выгрузке
В обмене возникают дубли или ошибки сопоставления
Если копия не проводится из-за пустого обязательного реквизита — это сигнал, что очистка слишком агрессивна. Либо реквизит не нужно очищать, либо в обработчике следует заполнить его значением по умолчанию, а не оставлять пустым.
Удобный приём: держите список очищаемых реквизитов в одном массиве в начале обработчика. Когда бухгалтерия попросит добавить или убрать поле, правка займёт одну строку, и не придётся искать присвоения по всему коду.
Частые вопросы
Почему ПриКопировании не срабатывает при копировании документа?
Чаще всего обработчик размещён не в модуле объекта, а в модуле формы — событие ПриКопировании существует только у объекта. Также проверьте, что расширение применено к базе (обновление конфигурации БД выполнено) и что обработчик не перекрыт другим расширением с аннотацией &Вместо.
Можно ли очистить стандартный реквизит, например дату или организацию?
Технически — да, через то же присвоение пустого значения. Но очищать дату и номер не имеет смысла: платформа сама присваивает копии текущую дату и новый номер при записи. Организацию очищать стоит только если это осознанное требование учёта, иначе пользователю придётся заполнять её вручную в каждой копии.
Как очистить реквизит только у копий, созданных определённым пользователем?
Внутри ПриКопировании доступен контекст текущего сеанса: используйте ПользователиИнформационнойБазы.ТекущийПользователь() или функции общего модуля работы с пользователями и постройте условие по роли или имени пользователя. Учтите, что событие выполняется на сервере, поэтому клиентские функции там недоступны.
Чем очистка в ПриКопировании отличается от настройки «Заполнять при копировании» в свойствах реквизита?
В свойствах реквизита конфигуратора нет отдельного признака копирования — перенос значений при копировании выполняет платформа автоматически для всех реквизитов. Управлять этим можно только кодом в ПриКопировании. Поэтому доработка обработчика — единственный штатный способ выборочной очистки.
Будет ли работать очистка при копировании через внешнюю обработку или COM-соединение?
Нет. Событие ПриКопировании вызывается только при интерактивном копировании. Если документ копируется программно через Скопировать() или создаётся обработкой, логику очистки нужно продублировать в коде этой обработки — лучше через вызов общей экспортной процедуры.
Опасно ли очищать реквизиты, по которым документ участвует в критериях отбора?
Опасно не само по себе, но копия выпадет из соответствующих журналов и отборов до заполнения реквизита. Если документ должен сразу отображаться в рабочем месте пользователя, лучше не очищать ключевой реквизит, а заполнять его значением по умолчанию.
Что важно запомнить
Очистка реквизитов при копировании выполняется в обработчике ПриКопировании модуля объекта: одиночные реквизиты сбрасываются присвоением пустого значения, табличные части — методом Очистить(). Для типовых конфигураций используйте расширение с аннотацией &После, не путайте событие с ПриЗаполнении и ОбработкаЗаполнения, и всегда проверяйте проведение копии и работу обменов после доработки.