Как перенести периодический регистр сведений в непериодический с помощью Конвертации данных 2.1?

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

При настройке обмена данными между устаревшими конфигурациями (например, УПП 1.3 или ЗУП 2.5) и современными решениями на управляемых формах (БП 3.0, ЗУП 3.1) разработчики часто сталкиваются с несовместимостью структур хранения данных. Одним из ярких примеров является перенос сведений о кадровой истории сотрудников. В старых конфигурациях эти данные хранились в периодических регистрах сведений (таких как РаботникиОрганизаций), тогда как в новых они перенесены в независимые непериодические, но интервальные регистры сведений (например, ОсновныеСотрудникиФизическихЛиц или КадроваяИсторияСотрудниковИнтервальный).

В рамках этой статьи мы подробно разберем, как решить эту задачу с помощью универсального инструмента Конвертация данных 2.1 (КД 2.1). Мы проанализируем алгоритмы сопоставления дат, изучим тонкости передачи параметров между обработчиками событий ПКС, а также рассмотрим механизмы работы с базой-приемником напрямую через запросы в процессе загрузки.

---

Методология переноса: Периодический регистр против интервального

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

  1. Периодический регистр источника (ЗУП 2.5): Каждое кадровое событие (прием, перевод, увольнение) создает новую запись в регистре РаботникиОрганизаций с привязкой к конкретной дате (измерение Период). История строится последовательно. Чтобы понять, работал ли сотрудник в определенный день, платформе приходится анализировать срез последних на эту дату.
  2. Непериодический интервальный регистр приемника (БП 3.0 / ЗУП 3.1): Записи в регистре ОсновныеСотрудникиФизическихЛиц не имеют стандартной периодичности платформы. Вместо этого в структуру регистра добавлены явные реквизиты или измерения ДатаНачала и ДатаОкончания. Для каждого периода работы сотрудника создается ровно одна запись, четко описывающая интервал «от и до». Если сотрудник уволен, у последней записи интервала ДатаОкончания будет равна дате увольнения. Если сотрудник продолжает работать, ДатаОкончания обычно заполняется пустой датой либо «концом времен» (31.12.3999).

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

---

Шаг 1. Алгоритм сопоставления периодов приема и увольнения в источнике

Рассмотрим ситуацию, когда сотрудник за свою карьеру принимался на работу и увольнялся несколько раз. В источнике мы имеем несколько записей с разными периодами и видами событий. Наша задача в ПКО (Правила конвертации объектов) — правильно вычислить пары дат для каждого рабочего интервала.

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

Чтобы сопоставить последнее увольнение и правильно закрыть дату окончания текущего периода, можно использовать запрос по количеству приемов и увольнений. Если количество событий приема совпадает с количеством увольнений, значит, текущий период завершен, и конечной датой интервала должна стать дата последнего увольнения. Если количество приемов больше количества увольнений, сотрудник в данный момент работает, и конечная дата должна быть пустой (или максимальной).

Посмотрим на пример реализации запроса для ПКС ДатаОкончания в обработчике Перед выгрузкой:


// Вычисляем дату окончания интервала работы сотрудника
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Работники.Период КАК ДатаСобытия,
    |	Работники.ПричинаИзмененияСостояния КАК Состояние
    |ИЗ
    |	РегистрСведений.РаботникиОрганизаций КАК Работники
    |ГДЕ
    |	Работники.Сотрудник = &Сотрудник
    |УПОРЯДОЧИТЬ ПО
    |	ДатаСобытия ВОЗР";

Запрос.УстановитьПараметр("Сотрудник", Источник.Сотрудник);
ТаблицаИстория = Запрос.Выполнить().Выгрузить();

// Алгоритм поиска сопоставленного увольнения
ДатаОкончанияИнтервала = '39991231'; // Значение по умолчанию для работающего сотрудника

Для Каждого СтрокаКадров Из ТаблицаИстория Цикл
    Если СтрокаКадров.Состояние = Перечисления.ПричиныИзмененияСостояния.Увольнение Тогда
        // Если это увольнение, фиксируем его дату как потенциальный конец интервала
        ДатаОкончанияИнтервала = СтрокаКадров.ДатаСобытия;
    КонецЕсли;
КонецЦикла;

Значение = ДатаОкончанияИнтервала;

Важное архитектурное замечание: Прямой перенос записей регистров сведений в интервальные таблицы приемника в КД 2.1 — это трудоемкий и потенциально опасный путь. Намного надежнее переносить сами кадровые документы (Прием на работу, Увольнение, Кадровое перемещение). При проведении этих документов в базе-приемнике (БП 3.0 / ЗУП 3.1) стандартные механизмы конфигурации автоматически и абсолютно корректно сформируют все интервальные регистры сведений.

---

Шаг 2. Передача параметров между обработчиками ПКС («Перед выгрузкой» -> «После выгрузки»)

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

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

Вариант А. Использование глобальной структуры «Параметры»

В КД 2.1 во всех обработчиках выгрузки доступен глобальный объект Параметры. Чтобы избежать наложения данных при выгрузке разных объектов, мы рекомендуем формировать уникальный ключ на основе уникального идентификатора (УИД) текущего источника.

Рассмотрим, как это реализовать на практике. В обработчике Перед выгрузкой ПКС пишем следующий код:


// Формируем уникальный ключ для сохранения контекста
КлючПараметра = "ВременнаяДата_" + Источник.УникальныйИдентификатор();
ВычисленноеЗначение = '20231231'; // Результат ваших сложных вычислений

Параметры.Вставить(КлючПараметра, ВычисленноеЗначение);

Затем в обработчике После выгрузки этого же ПКС мы можем без труда прочитать это значение и сразу же удалить его из структуры, чтобы не засорять оперативную память:


КлючПараметра = "ВременнаяДата_" + Источник.УникальныйИдентификатор();

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

Вариант Б. Передача параметров на сторону приемника

Если вам требуется не просто передать значение между обработчиками выгрузки, а доставить его на сторону базы-приемника для последующей обработки при загрузке, в настройках ПКС установите флаг «Передавать данные в параметр» и укажите имя параметра. Тогда при загрузке объекта в обработчике После загрузки (в ПКО) вы сможете обратиться к нему через коллекцию ПараметрыОбъекта:


ЗначениеПараметра = ПараметрыОбъекта.Получить("ИмяВашегоПараметра");
Если ЗначениеПараметра <> Неопределено Тогда
    // Обработка данных на стороне приемника
КонецЕсли;

---

Шаг 3. Как выполнять запросы к базе-приемнику во время загрузки

Возможность анализировать состояние информационной базы приемника прямо в процессе загрузки — это стандартный и крайне полезный инструмент Конвертации данных 2.1. Поскольку обработка загрузки (v8exim.epf или встроенные механизмы) выполняется непосредственно в контексте базы-приемника, мы можем использовать абсолютно все возможности платформы «1С:Предприятие 8», включая объект Запрос.

Где и зачем это используется?

  1. В обработчике «Поля поиска» ПКО: Это наиболее частый сценарий. Когда стандартного поиска по уникальному идентификатору (УИД) или по равенству простых реквизитов недостаточно, вы можете написать произвольный запрос к таблицам приемника. Например, вам нужно проверить, нет ли уже в непериодическом регистре приемника записи по данному сотруднику за определенный период, чтобы не плодить дубли.
  2. В обработчике «Перед загрузкой» ПКО: Для проверки существования связанных объектов, получения параметров по умолчанию или сверки бизнес-логики (например, заблокирован ли период редактирования в приемнике).
  3. В обработчике «После загрузки данных» (на уровне конвертации): Для массовой проверки целостности загруженных данных, пересчета интервалов или проведения документов.

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


// Обработчик "Поля поиска" в ПКО
// Параметр "СвойстваПоиска" содержит переданные из источника значения

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ОсновныеСотрудники.Сотрудник КАК Ссылка
    |ИЗ
    |	РегистрСведений.ОсновныеСотрудникиФизическихЛиц КАК ОсновныеСотрудники
    |ГДЕ
    |	ОсновныеСотрудники.ФизическоеЛицо = &ФизическоеЛицо
    |	И ОсновныеСотрудники.Организация = &Организация";

Запрос.УстановитьПараметр("ФизическоеЛицо", СвойстваПоиска["ФизическоеЛицо"]);
Запрос.УстановитьПараметр("Организация", СвойстваПоиска["Организация"]);

РезультатЗапроса = Запрос.Выполнить();

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

Предупреждение по производительности: Выполнение запросов в обработчиках загрузки для каждого объекта может существенно снизить скорость обмена данными. Если вы переносите десятки тысяч записей, старайтесь избегать выполнения запросов внутри ПКО для каждого элемента. Вместо этого лучше кэшировать необходимые данные приемника в таблицу значений в обработчике ПередЗагрузкойДанных на уровне всей конвертации и затем быстро искать значения в оперативной памяти.

---

Резюме

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

← На главную