При разработке расширений или доработке типовых конфигураций, таких как Зарплата и Управление Персоналом 3.1, программисты часто сталкиваются с необходимостью записывать дополнительные данные в собственные регистры сведений при проведении типовых документов (например, «Исполнительный лист»). Однако стандартный подход с созданием набора записей вручную часто приводит к странному поведению: при первом проведении запись появляется, а при повторном — бесследно исчезает. Разберем подробно, почему так происходит, и как реализовать этот механизм правильно.
В платформе «1С:Предприятие 8.3» для большинства документов установлено свойство «Удаление движений» в значение «Удалять автоматически при перепроведении». Это фундаментальный механизм, который гарантирует актуальность данных в регистрах. Когда пользователь нажимает кнопку «Провести», система выполняет следующие действия:
Рассмотрим ситуацию автора вопроса: в коде создается отдельный объект НаборЗаписей, устанавливается отбор по регистратору и вызывается метод Записать(). Если этот код выполняется в подписке на событие или в процессе проведения, возникает конфликт. Платформа ожидает, что движения будут управляться через коллекцию Движения объекта документа. Когда вы записываете набор «вручную» методом НаборЗаписей.Записать(), вы делаете это вне основного цикла управления движениями. При завершении проведения системный механизм может «затереть» вашу запись пустым набором из коллекции Движения, если ваш регистр не был в нее включен.
Самый надежный и архитектурно правильный способ — использовать штатную коллекцию документа. Проанализируем, как изменить код, чтобы он работал стабильно. Вместо создания нового объекта РегистрыСведений.ИмяРегистра.СоздатьНаборЗаписей(), мы должны обратиться к свойству Движения документа-источника.
Для реализации этого метода необходимо убедиться, что ваш регистр сведений указан в списке «Движения» документа в конфигураторе. Если вы используете расширение, добавьте ваш регистр в состав движений документа.
Рассмотрим пример правильного кода:
// В обработчике проведения или подписке на событие ОбработкаПроведения
// Источник — это ссылка на документ (или сам объект)
// Получаем набор записей из коллекции Движения
НаборЗаписей = Источник.Движения.ИНФ_РеквизитыИсполЛистовДляВыгрузкиБП;
// Указывать отбор по регистратору здесь не нужно, он устанавливается автоматически
// Также не нужно вызывать методы Прочитать() или Очистить()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ... "; // Ваш запрос для получения данных
РезультатЗапроса = Запрос.Выполнить();
// Загружаем данные из таблицы значений напрямую в набор
НаборЗаписей.Загрузить(РезультатЗапроса.Выгрузить());
// Устанавливаем флаг необходимости записи
НаборЗаписей.Записывать = Истина;
Почему это работает: Устанавливая свойство Записывать = Истина, мы сообщаем платформе, что в конце процесса проведения этот набор нужно зафиксировать в базе данных вместе со всеми остальными движениями документа. Это гарантирует транзакционность: если проведение документа прервется ошибкой, записи в вашем регистре также не будут созданы.
Выясним еще одну важную деталь, упомянутую в обсуждении. Иногда записи пропадают из-за логики самого запроса. Если при повторном проведении условия запроса меняются (например, данные в документе были отредактированы так, что они больше не попадают в выборку), запрос вернет пустую таблицу.
Когда вы выполняете НаборЗаписей.Загрузить(ПустаяТЗ) и затем Записать(), платформа воспринимает это как команду на удаление существующих записей. Проанализируем, как добавить защитное условие:
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
Если ТаблицаДанных.Количество() > 0 Тогда
НаборЗаписей = Источник.Движения.ИНФ_РеквизитыИсполЛистовДляВыгрузкиБП;
НаборЗаписей.Загрузить(ТаблицаДанных);
НаборЗаписей.Записывать = Истина;
Иначе
// Если данных нет, можно либо явно очистить движения,
// либо оставить флаг Записывать = Ложь (по умолчанию), тогда старые движения просто удалятся системой
КонецЕсли;
В современных конфигурациях на базе БСП (включая ЗУП 3.1) процесс проведения часто выносится в общие модули, такие как ПроведениеСервер. Рассмотрим несколько нюансов, специфичных для этой программы:
ОбработкаПроведения, всегда работайте с объектом Источник. Помните, что если вы записываете данные в подчиненный регистр «вручную» (через СоздатьНаборЗаписей), вы делаете это в обход оптимизации платформы.СоздатьНаборЗаписей() и явным вызовом Записать() будет работать корректно, так как платформа не управляет такими регистрами автоматически при проведении документа.Источник.Движения блокировки устанавливаются автоматически. При ручной записи через НаборЗаписей.Записать() вы можете столкнуться с ошибками блокировок, если одновременно проводится несколько документов по одному сотруднику или исполнительному листу.Подведем итог нашему разбору. Если вы столкнулись с исчезновением данных при перепроведении, выполните следующие шаги:
НаборЗаписей на использование коллекции Источник.Движения.ИмяВашегоРегистра.Записывать = Истина вместо метода Записать() внутри транзакции проведения.Запрос гарантированно возвращает данные. Используйте отладчик, чтобы посмотреть содержимое НаборЗаписей перед завершением процедуры.Использование встроенных механизмов платформы не только решает проблему «исчезающих записей», но и делает ваш код более производительным и безопасным с точки зрения целостности данных в базе 1С.