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