Почему не записываются данные в независимый регистр сведений из подписки на событие Обработка проведения

Программист 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

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

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

Анализ проблемы: почему код работает в обработке, но не в подписке

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

Первым делом выясним причину такого поведения. Разберем основные факторы:

  1. Конфликт нескольких подписок. Это наиболее вероятная причина в сложных конфигурациях (например, ЗУП 3.1 или ERP). Документ может инициировать цепочку событий. Если одна подписка записывает данные в регистр, а следующая за ней подписка (например, на событие ПриЗаписи движения другого регистра) очищает этот же регистр или записывает пустой набор по тому же отбору, данные первой подписки будут потеряны.
  2. Неявный откат транзакции. Подписка на ОбработкаПроведения выполняется внутри одной транзакции с документом. Если после выполнения вашего кода где-то в системе возникнет ошибка или установится Отказ = Истина, вся транзакция откатится, включая ваши записи в независимый регистр.
  3. Особенности работы платформы с движениями. Если независимый регистр ошибочно указан в списке движений документа в дереве метаданных, платформа может пытаться управлять его записями автоматически, что приводит к непредсказуемым результатам при ручной записи.

Разбор программного кода записи через НаборЗаписей

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


ОписаниеТипаДата = Новый ОписаниеТипов("Дата", , , , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя));
ОписаниеТипаСотрудник = Новый ОписаниеТипов("СправочникСсылка.Сотрудники");
ОписаниеЧисловогоТипа = Новый ОписаниеТипов("Число", , , Новый КвалификаторыЧисла(15,2));

ТаблицаНабора = Новый ТаблицаЗначений;
ТаблицаНабора.Колонки.Добавить("Период", ОписаниеТипаДата);
ТаблицаНабора.Колонки.Добавить("Сотрудник", ОписаниеТипаСотрудник);
ТаблицаНабора.Колонки.Добавить("КоличествоДней", ОписаниеЧисловогоТипа);

СтрокаТаблицы = ТаблицаНабора.Добавить();
СтрокаТаблицы.Период = ТекущаяДата();
СтрокаТаблицы.Сотрудник = СсылкаНаСотрудника;
СтрокаТаблицы.КоличествоДней = 5;

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

Важный момент: при использовании метода Записать() без параметров, по умолчанию применяется режим Замещать = Истина. Это означает, что система сначала удаляет из базы все записи, которые соответствуют установленному фильтру (в нашем примере — по сотруднику), а затем записывает новые из набора. Если ваша ТаблицаНабора по какой-то причине оказалась пустой (например, не сработал поиск сотрудника или условие заполнения), вы просто очистите регистр по данному сотруднику.

Использование МенеджераЗаписи для точечных изменений

Если нам нужно записать одну конкретную строку, иногда удобнее использовать МенеджерЗаписи. Разберем, как это выглядит в коде подписки:


ЗаписьРег = РегистрыСведений.ЗаработанныеПраваНаОтпуска.СоздатьМенеджерЗаписи();
ЗаписьРег.Период = ТекущаяДата();
ЗаписьРег.Сотрудник = СотрудникСсылка;
ЗаписьРег.ВидЕжегодногоОтпуска = Справочники.ВидыОтпусков.Основной;
ЗаписьРег.КоличествоДней = 5;

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

Преимущество этого метода в его простоте, однако он менее производителен при записи большого объема данных по сравнению с НаборомЗаписей.

Как найти "виновника" исчезновения записей

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

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

Рекомендации по реализации надежной записи

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

Во-первых, проверяйте заполнение данных перед записью. Если поиск ссылки (например, НайтиПоНаименованию) вернул пустую ссылку, запись набора с таким отбором может привести к удалению данных.

Во-вторых, используйте свойство ДополнительныеСвойства объекта документа. Вместо прямой записи в регистр внутри ОбработкаПроведения, можно поместить туда таблицу данных. А саму запись произвести в событии ПриЗаписи (которое срабатывает в самом конце). Это позволит гарантировать, что стандартные механизмы проведения уже отработали и не затрут ваши данные.

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

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

← На главную