Как отследить и перехватить удаление записи в регистре сведений 1С

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

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

Особенности механизма удаления записей в регистре сведений

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

  1. Отсутствие отдельных событий удаления в модуле: У регистров сведений нет событий ПередУдалением или ПриУдалении на уровне модуля набора записей.
  2. Механизм замещения: Корректировка записи или ее удаление происходят путем записи набора с признаком Замещать = Истина. При редактировании старые данные удаляются, а новые записываются. При удалении записывается пустой набор записей по заданному отбору.
  3. Ограниченность логики формы: Перехват интерактивных действий в форме записи или форме списка не спасает от программного изменения или очистки регистра из других процедур, внешних обработок и регламентных заданий.

Способ 1. Перехват перед вызовом метода в форме записи

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

Посмотрим на пример реализации в модуле формы записи:


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

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

Способ 2. Обработка удаления в форме списка (обычные формы)

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

  1. В обработчике события ПередУдалением(Отказ) табличного поля получаем коллекцию удаляемых строк (выделенных пользователем).
  2. Считываем значения измерений и ресурсов выбранных строк и записываем их в целевой регистр.
  3. Позволяем платформе продолжить стандартную процедуру удаления (оставляя параметр Отказ = Ложь) либо отменяем действие при ошибке.

Рассмотрим пример кода для формы списка регистра:


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

Способ 3. Гарантированное отслеживание на уровне модуля набора записей

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

Алгоритм определения удаляемых записей:

  1. Проверяем, установлен ли флаг Замещать в значение Истина.
  2. Считываем текущее состояние записей из базы данных по значениям отбора текущего набора. Для этого можно использовать запрос или отдельный экземпляр набора записей с вызовом метода Прочитать().
  3. Сравниваем считанные старые строки с новыми строками в наборе ЭтотОбъект.
  4. Те строки, которые присутствовали в базе данных, но отсутствуют в новом наборе (или если ЭтотОбъект.Количество() = 0 при замещении), являются удаляемыми.

Посмотрим на пример кода в модуле набора записей:


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

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

← На главную