При программном переносе данных или автоматическом заполнении записей в конфигурации 1С:Зарплата и управление персоналом 3.1 разработчики часто сталкиваются с системной ошибкой: «Запись не соответствует отбору». Проблема проявляется наиболее остро при работе с регистром сведений ТрудоваяДеятельностьФизическихЛиц, когда мы пытаемся добавить вторую и последующие записи для одного и того же физического лица, используя объект МенеджерЗаписи.
В этой статье мы подробно разберем, почему стандартный подход с менеджером записи здесь не работает, проанализируем внутреннюю бизнес-логику системы и найдем правильный способ решения задачи через НаборЗаписей.
Рассмотрим стандартную ситуацию. Допустим, нам нужно перенести сведения о трудовой деятельности сотрудника. У записи есть два ключевых измерения: ФизическоеЛицо и НомерПоПорядку. Мы создаем МенеджерЗаписи, заполняем измерения и пытаемся выполнить метод Записать(). Первая запись (где номер равен 1) проходит успешно, но на второй записи система выдает ошибку соответствия отбору.
Проанализируем ситуацию: когда вызывается метод Записать() у объекта МенеджерЗаписи, платформа 1С автоматически устанавливает отбор по всем измерениям, которые указаны в менеджере. В нашем случае это конкретное физлицо и номер записи (например, 2). Однако перед фактической записью в базу данных срабатывает подписка на событие ПроверитьЗаписиДанныхФизическихЛицПередЗаписью.
Внутри этой подписки зашит код, который принудительно нормализует нумерацию записей. Давайте посмотрим на фрагмент этого кода:
Процедура ПроверитьЗаписиДанныхФизическихЛицПередЗаписью(Источник, Отказ, Замещение) Экспорт
Если ЗарплатаКадры.ОтключитьБизнесЛогикуПриЗаписи(Источник) Тогда
Возврат;
КонецЕсли;
НомерПоПорядку = 1;
Для каждого Запись Из Источник Цикл
Запись.НомерПоПорядку = НомерПоПорядку;
НомерПоПорядку = НомерПоПорядку + 1;
КонецЦикла;
КонецПроцедуры
Проблема заключается в том, что МенеджерЗаписи при сохранении передает в подписку набор, состоящий всего из одной записи. Цикл в подписке отрабатывает один раз и жестко присваивает полю НомерПоПорядку значение 1. В итоге получается конфликт: менеджер записи ожидает сохранить строку с номером 2 (согласно своему отбору), но код подписки изменил этот номер на 1 прямо в памяти перед записью. Платформа видит, что данные в объекте больше не соответствуют установленному фильтру, и блокирует операцию.
Использование объекта НаборЗаписей — это наиболее корректный путь. Поскольку подписка на событие ожидает получить коллекцию записей, нам нужно предоставить ей весь пакет данных по конкретному сотруднику сразу. В этом случае счетчик НомерПоПорядку внутри подписки отработает корректно для всех строк набора.
Рассмотрим пример кода для добавления нескольких записей:
// Создаем набор записей
НаборЗаписей = РегистрыСведений.ТрудоваяДеятельностьФизическихЛиц.СоздатьНаборЗаписей();
// Устанавливаем отбор только по физическому лицу
НаборЗаписей.Отбор.ФизическоеЛицо.Установить(СсылкаНаФизЛицо);
// Если нужно добавить к существующим, сначала прочитаем их
НаборЗаписей.Прочитать();
// Добавляем новую запись
НоваяСтрока = НаборЗаписей.Добавить();
НоваяСтрока.ФизическоеЛицо = СсылкаНаФизЛицо;
НоваяСтрока.НомерПоПорядку = НаборЗаписей.Количество(); // Номер будет пересчитан подпиской, но лучше указать верный
НоваяСтрока.НаименованиеОрганизации = "ООО ТехноПром";
// ... заполнение остальных реквизитов
// Записываем весь набор
НаборЗаписей.Записать();
При таком подходе подписка увидит все записи сотрудника, пронумерует их по порядку (1, 2, 3...), и так как отбор в наборе установлен только по ФизическоеЛицо, никакого конфликта с полем НомерПоПорядку не возникнет.
Иногда при миграции данных из внешних систем нам критически важно сохранить именно те номера записей, которые были в источнике, не позволяя системе ЗУП их пересчитывать. Для этого разработчики предусмотрели специальный «флаг» в дополнительных свойствах объекта.
Проанализируем условие в подписке: система проверяет свойство НеПроверятьЗаписиДанныхФизическихЛиц. Если мы установим его в значение Истина, бизнес-логика пересчета будет проигнорирована. Рассмотрим, как это реализовать программно:
НаборЗаписей = РегистрыСведений.ТрудоваяДеятельностьФизическихЛиц.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ФизическоеЛицо.Установить(СсылкаНаФизЛицо);
// Добавляем записи с произвольными номерами
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ФизическоеЛицо = СсылкаНаФизЛицо;
НоваяЗапись.НомерПоПорядку = 10; // Например, нам нужен именно такой номер
// Устанавливаем магическое свойство
НаборЗаписей.ДополнительныеСвойства.Вставить("НеПроверятьЗаписиДанныхФизическихЛиц", Истина);
// Теперь запись пройдет без ошибки и без изменения номера
НаборЗаписей.Записать();
Важный нюанс: Установка стандартного флага ОбменДанными.Загрузка = Истина не всегда помогает в данном регистре. Типовая логика ЗУП часто использует функцию ЗарплатаКадры.ОтключитьБизнесЛогикуПриЗаписи, которая может иметь более сложные условия проверки, чем просто режим загрузки. Поэтому использование ДополнительныеСвойства является более надежным методом.
Если вы выполняете перенос данных через правила обмена (КД 2.0 или 3.0), стандартный механизм часто пытается использовать МенеджерЗаписи для каждой строки регистра. Это неизбежно приведет к описанной выше ошибке.
Чтобы успешно перенести данные через КД, рекомендуем придерживаться следующих правил:
РежимЗаписи = "Загрузка".НаборЗаписей, как было рассмотрено в Решении №2.НеПроверятьЗаписиДанныхФизическихЛиц через входящие данные или устанавливайте его непосредственно в коде обработчика загрузки.Подведем итоги нашего анализа. Ошибка соответствия отбору в регистре ТрудоваяДеятельностьФизическихЛиц — это следствие работы защитной бизнес-логики, которая следит за непрерывностью нумерации строк. Для обхода этой ошибки мы рекомендуем всегда использовать Набор Записей с фильтром по физическому лицу и, при необходимости, подавлять проверку через Дополнительные свойства объекта.