Как программно запретить копирование документа в 1С:Предприятии 8

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

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

Разберем архитектурные подходы: Форма или Объект?

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

Способ 1. Запрет копирования в управляемой форме

Это самый распространенный метод, когда нужно ограничить действия обычного пользователя в интерфейсе. При интерактивном копировании (нажатии кнопки "Скопировать" или клавиши F9) платформа открывает форму нового документа и передает в нее специальный параметр. Рассмотрим подробнее процедуру ПриСозданииНаСервере.

В этой процедуре мы проверяем параметр ЗначениеКопирования. Если он заполнен, значит, текущий объект создается на основании другого (путем копирования), и мы можем прервать этот процесс. А если вам нужно не просто запретить копирование, но и динамически менять состав полей, используйте добавление реквизитов и элементов формы. Посмотрим на пример кода:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем, заполнено ли значение копирования
    Если ЗначениеЗаполнено(Параметры.ЗначениеКопирования) Тогда
        
        // Устанавливаем Отказ в Истина, чтобы форма не открылась
        Отказ = Истина;
        
        // Информируем пользователя о причине запрета
        Сообщить("Копирование данного типа документов запрещено правилами системы!", СтатусСообщения.Внимание);
        Возврат;
        
    КонецЕсли;

КонецПроцедуры

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

Способ 2. Запрет с условием создания на основании

Иногда логика требует, чтобы документ создавался только на основании конкретного "родительского" объекта. Проанализируем пример из практики, когда копирование запрещено, но ввод на основании разрешен. В этом случае нам нужно проверить не только факт копирования, но и заполнение реквизита-основания.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

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

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

КонецПроцедуры

Способ 3. Запрет на уровне модуля объекта

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

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


// В модуле документа
Процедура ПриКопировании(ОбъектКопирования)
    
    // Вызываем исключение, которое прерывает транзакцию и выполнение кода
    ТекстОшибки = "Программное или интерактивное копирование документа '" + ЭтотОбъект.Метаданные().Имя + "' запрещено!";
    ВызватьИсключение ТекстОшибки;
    
КонецПроцедуры

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

Способ 4. Использование Подписки на события

В современной разработке (особенно в типовых конфигурациях вроде 1С:ERP или 1С:УТ) предпочтительно не вносить изменения в модуль самого документа, чтобы не усложнять процесс обновления. Для этого мы применим Подписку на события. Посмотрим, как это сделать по шагам:

  1. Создаем новый объект в дереве метаданных: Общие -> Подписки на события.
  2. Выбираем источник — ваш тип документа (или несколько типов).
  3. Выбираем событие — ПриКопировании.
  4. В обработчике подписки прописываем аналогичный код с вызовом исключения.

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

Способ 5. Как отличить программное копирование от интерактивного?

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

Проанализируем алгоритм обхода:

1. В нашем программном коде, где мы хотим разрешить копирование, мы добавляем метку:


НовыйДокумент = Источник.Скопировать();
НовыйДокумент.ДополнительныеСвойства.Вставить("РазрешитьКопирование", Истина);
НовыйДокумент.Записать();

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


Процедура ПриКопировании(ОбъектКопирования)
    // Если мы в интерфейсе, ДополнительныеСвойства будут пустыми
    Если Не ЭтотОбъект.ДополнительныеСвойства.Свойство("РазрешитьКопирование") Тогда
        // Если метки нет - значит копирует пользователь или "чужой" код
        // Но здесь есть нюанс: ПриКопировании вызывается ДО записи.
        // Поэтому проверку лучше перенести в ПередЗаписью для новых объектов.
    КонецЕсли;
КонецПроцедуры

Способ 6. "Мягкий" запрет (Очистка реквизитов)

Рассмотрим альтернативный вариант. Иногда полный запрет слишком суров. Пользователи могут хотеть скопировать документ, чтобы не вводить заново длинную табличную часть, но при этом "шапка" документа (дата, номер, ответственный) должна быть пустой. Это называется "мягким запретом" или очисткой данных.

В процедуре ПриКопировании модуля объекта мы просто обнуляем критически важные поля:


Процедура ПриКопировании(ОбъектКопирования)
    
    // Очищаем реквизиты, которые не должны дублироваться
    ЭтотОбъект.Номер = "";
    ЭтотОбъект.Дата = '00010101';
    ЭтотОбъект.Ответственный = Справочники.Пользователи.ПустаяСсылка();
    ЭтотОбъект.Статус = Перечисления.СтатусыДокументов.Черновик;
    
    // Можно очистить и специфические флаги
    ЭтотОбъект.ЗагруженоИзВнешнейСистемы = Ложь;
    
    // Теперь копирование эквивалентно созданию нового документа, 
    // но с заполненной табличной частью.
    
КонецПроцедуры

Подведем итоги и выберем лучшее решение

Мы рассмотрели несколько способов управления процессом копирования. Выбор конкретного метода зависит от ваших целей:

Помните, что грамотное управление копированием объектов не только защищает целостность данных, но и направляет пользователя по верному пути работы с конфигурацией, предотвращая появление "мусорных" или некорректно заполненных документов.

← На главную