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

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

При разработке в среде 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда программно созданные записи в регистрах сведений, подчиненных регистратору, ведут себя «непредсказуемо». Типичный сценарий: код отрабатывает без ошибок, для непроведенных документов запись в регистре появляется, но стоит провести документ — и данные бесследно исчезают. В этой статье мы подробно разберем, почему так происходит, изучим внутренние механизмы платформы и найдем надежные способы решения этой задачи.

Проанализируем исходную ситуацию и код

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


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

КоличествоЗаписейВНаборе = НаборЗаписей.Количество();

Если КоличествоЗаписейВНаборе = 0 Тогда
    ЗадачаПоставлена = Статус;
    НоваяЗапись = НаборЗаписей.Добавить();
ИначеЕсли КоличествоЗаписейВНаборе = 1 Тогда
    ЗадачаПоставлена = НаборЗаписей[0].ЗадачаПоставлена Или Статус;
    НоваяЗапись = НаборЗаписей[0];
Иначе
    // Если записей несколько, очищаем набор и создаем одну корректную
    НаборЗаписей.Очистить();
    НоваяЗапись = НаборЗаписей.Добавить();
КонецЕсли;

НоваяЗапись.Период = Период;
НоваяЗапись.Регистратор = Регистратор;
НоваяЗапись.Контрагент = Контрагент;
НоваяЗапись.Менеджер = Менеджер;
НоваяЗапись.ЗапланированныйКонтакт = ЗапланированныйКонтакт;
НоваяЗапись.БесконтактныйПериод = ПериодичностьКонтактов;
НоваяЗапись.ЗадачаПоставлена = ЗадачаПоставлена;

Попытка
    НаборЗаписей.Записать();
Исключение
    Сообщить(ОписаниеОшибки());
КонецПопытки;

Этот код выглядит логичным и рабочим. Более того, он действительно создает запись, если документ просто записан (без проведения). Однако проблема возникает именно в момент проведения документа.

Выясним причину: механизм очистки движений

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

  1. Событие «ПриЗаписи»: Срабатывает ваша подписка. Набор записей создается и записывается в базу данных. В этот момент в регистре данные ЕСТЬ.
  2. Начало проведения: Если у документа установлен режим проведения «Записывать выбранные» или «Записывать все», платформа инициирует процедуру ОбработкаПроведения.
  3. Автоматическая очистка: Это ключевой момент. Перед выполнением кода в модуле ОбработкаПроведения платформа автоматически очищает все движения по регистрам, которые указаны в списке «Движения» данного документа. Платформа предполагает, что старые движения неактуальны, и сейчас код проведения сформирует новые.
  4. Завершение проведения: Если в самой процедуре ОбработкаПроведения код записи в ваш регистр отсутствует, то после автоматической очистки регистр так и останется пустым.

Таким образом, получается «эффект исчезновения»: подписка запись создала, а механизм проведения её удалил.

Вариант решения №1: Использование коллекции «Движения»

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

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    // Указываем платформе, что не нужно принудительно записывать (и очищать) этот регистр, 
    // так как мы управляем им вручную или через подписку
    Движения.КонтактированиеСКонтрагентами.Записывать = Ложь;
КонецПроцедуры

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

Вариант решения №2: Перенос логики в «Обработку проведения»

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

Если документ проводится — записи формируются в ОбработкеПроведения через коллекцию Движения. Если документ просто записывается (но не проводится) — записи формируются в ПриЗаписи. Чтобы избежать дублирования кода, вынесите логику формирования набора записей в общий модуль.

Вариант решения №3: Использование независимого регистра

Проанализируем ситуацию: если бизнес-логика требует, чтобы запись в регистре жила «своей жизнью» и не зависела от того, проведен документ или нет, возможно, подчинение регистратору — это архитектурная ошибка.

Сделав регистр независимым, вы получите следующие преимущества:

Дополнительные рекомендации по разработке

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

1. Проверка режима загрузки данных. Если ваш код выполняется при обмене данными, он может конфликтовать с входящими данными. Всегда добавляйте проверку:

Если Источник.ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;

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

3. Использование ДополнительныхСвойств. Чтобы передать флаг из ПриЗаписи в ОбработкуПроведения (например, чтобы сообщить, что запись уже создана и её не нужно трогать), используйте коллекцию Источник.ДополнительныеСвойства. Это удобный контейнер для передачи параметров внутри одного сеанса работы с объектом.

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

← На главную