Как правильно очищать записи в подчиненном регистратору регистре сведений при отмене проведения документа

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

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

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

Особенности и ограничения регистра сведений с режимом записи «Подчинение регистратору»

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

  1. Ограничение отбора в объекте НаборЗаписей: при создании набора записей для подчиненного регистра отбор можно установить исключительно по полю Регистратор. Попытка установить программный отбор по какому-либо пользовательскому измерению (например, Отбор.Документ.Установить(...)) приведет к ошибке времени выполнения.
  2. Очистка строк конкретного регистратора: чтобы удалить только определенные строки, принадлежащие регистратору, нельзя просто применить фильтр по измерению и записать пустой набор. Необходимо сначала полностью прочитать набор по регистратору, удалить нужные строки в коллекции и затем записать измененный набор.
  3. Поведение свойства Активность: если один документ делает движения другого документа неактивными (Активность = Ложь), то при простой отмене проведения или удалении первого документа неактивные записи автоматически активными не станут. Для восстановления активности потребуется явная программная перезапись.

Поиск связанных документов-регистраторов через запрос

Рассмотрим ситуацию, когда при отмене проведения документа «Реализация товаров и услуг» требуется найти связанный документ «Планирование оказания услуг», зафиксировавший ссылку на реализацию в своем регистре. Для этого в процедуре ОбработкаУдаленияПроведения модуля объекта выполняем точечный запрос к виртуальной таблице среза последних или физической таблице регистра:


Процедура ОбработкаУдаленияПроведения(Отказ)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |   Планирование.Регистратор КАК Регистратор
        |ИЗ
        |   РегистрСведений.ПланированиеОказанияУслуг КАК Планирование
        |ГДЕ
        |   Планирование.Документ = &ТекущийДокумент
        |   И Планирование.Регистратор ССЫЛКА Документ.ПланированиеОказанияУслуг";
    
    Запрос.УстановитьПараметр("ТекущийДокумент", Ссылка);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Пока Выборка.Следующий() Цикл
        // Обработка найденных документов планирования
    КонецЦикла;
    
КонецПроцедуры

Программная модификация движений подчиненного регистра

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

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

Посмотрим на пример реализации данного алгоритма:


Набор = РегистрыСведений.ПланированиеОказанияУслуг.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Выборка.Регистратор);
Набор.Прочитать();

Индекс = Набор.Количество() - 1;
Пока Индекс >= 0 Цикл
    СтрокаНабора = Набор[Индекс];
    Если СтрокаНабора.Документ = Ссылка Тогда
        Набор.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

Набор.Записать();

Если же требуется полностью очистить все движения найденного документа планирования и снять его с проведения, используем работу через объект документа:


ДокументОбъект = Выборка.Регистратор.ПолучитьОбъект();
Если ДокументОбъект <> Неопределено Тогда
    ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;

Риски изменения чужих движений и каскадного распроведения

Несмотря на техническую возможность программно распроводить зависимые документы или напрямую переписывать их наборы записей, такой подход несет серьезные архитектурные риски:

  1. Взаимоблокировки данных (Deadlocks): вызов Записать(РежимЗаписиДокумента.ОтменаПроведения) внутри транзакции отмены проведения другого документа порождает вложенные транзакции и захватывает дополнительные таблицы, что в многопользовательском режиме приводит к таймаутам блокировок.
  2. Потеря целостности данных: если документ А вручную изменил строки в наборе записей документа Б, то при любом последующем стандартном перепроведении документа Б платформа полностью перезапишет его движения по заложенному в модуле алгоритму проведения, затерев все внешние правки.

Рекомендуемые архитектурные альтернативы

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

  1. Контроль ссылочной целостности (Запрет отмены проведения): самый простой и безопасный способ. При попытке отменить проведение документа реализации проверяем наличие подчиненных документов планирования. Если они найдены, устанавливаем флаг Отказ = Истина и выводим понятное сообщение пользователю с требованием сначала вручную распровести связанные планы.
  2. Использование регистра накопления (Схема остатков): заменяем регистр сведений на регистр накопления с видом остатков. Документ реализации делает движение Приход (потребность в планировании), а документ планирования — движение Расход. Необработанные документы выбираются штатным запросом к виртуальной таблице Остатки. При отмене проведения любого документа платформа автоматически очистит только его собственные движения, а актуальный баланс рассчитается корректно без единой строчки ручного кода управления чужими записями.
  3. Использование независимого регистра сведений: если для задач учета жесткая привязка к регистратору не требуется, регистр создается с режимом записи «Независимый». В этом случае в отборах наборов записей можно свободно использовать любые комбинации измерений для точечного удаления.
← На главную