При переносе данных между информационными базами 1С:Зарплата и управление персоналом 3.1 (ЗУП) программисты часто сталкиваются со специфической проблемой: документы Перенос данных загружаются в базу-приемник абсолютно пустыми. На первый взгляд кажется, что перенос выполнен успешно — сами документы созданы в списке, но внутри них нет никаких данных, а движения по регистрам отсутствуют.
Ситуация значительно усложняется, если исходная база-источник ранее наполнялась из сторонних систем (например, из программы "Камин 2.0" или "ЗиК 7.7"). В этом случае уникальные идентификаторы (UUID/GUID) ссылочных объектов (физических лиц, сотрудников, подразделений, должностей) гарантированно не совпадают с базой-приемником. Использование стандартной обработки ВыгрузкаЗагрузкаДанныхXML становится невозможным, так как она работает строго по GUID и приведет либо к массовому дублированию справочников, либо к появлению битых ссылок вида <Объект не найден> в движениях документов.
В этой статье мы подробно разберем внутреннюю архитектуру документа Перенос данных, выясним причины очистки движений при стандартном обмене и рассмотрим пошаговые сценарии корректного переноса с помощью Конвертации данных 2.1 и специализированного программного кода.
Чтобы понять, почему стандартный перенос не дает нужного результата, проанализируем структуру документа Перенос данных в конфигурации 1С:ЗУП 3.1. Этот документ является техническим "контейнером". В отличие от привычных документов (таких как ПриемНаРаботу или НачислениеЗарплаты), он не содержит классических табличных частей в метаданных, где хранились бы строки с суммами, периодами и кадровыми сведениями.
Все его данные записываются напрямую в соответствующие регистры (накопления, расчета, сведений), где данный документ выступает в качестве регистратора (свойство Регистратор). В самом же документе присутствует лишь служебная табличная часть ТаблицаРегистров, которая содержит имена регистров и указывает интерфейсу платформы, какие именно вкладки нужно отобразить пользователю на форме.
Если мы просто переносим ссылку на документ, система создает пустую "шапку" и пустую таблицу интерфейсных вкладок. Движения по регистрам при этом игнорируются, так как правила конвертации по умолчанию не сопоставляют наборы записей регистров с документом-регистратором.
Перед тем как приступать к переносу самих движений регистров, необходимо решить фундаментальную задачу — сопоставить справочники по бизнес-ключам (полям поиска), а не по внутренним идентификаторам. Если этого не сделать, все записи в регистрах (например, по регистру накопления ВзаиморасчетыССотрудниками) будут ссылаться на несуществующие UUID сотрудников.
В правилах обмена (КД 2.1) для ключевых справочников следует настроить следующие правила поиска:
ФИО + ДатаРождения.Коду сотрудника в пределах организации или по связке ФизическоеЛицо + Организация + ВидЗанятости.ИНН и КПП.Только после того, как синхронизация справочников будет полностью отлажена, можно приступать к переносу регистров.
Рассмотрим подробнее пошаговый процесс настройки правил конвертации объектов (ПКО) для документа Перенос данных в программе "Конвертация данных 2.1".
Шаг 1. Настройка ПКО для документа. Создайте правило конвертации для документа Перенос данных. Перейдите на вкладку "Табличные части" и убедитесь, что табличная часть ТаблицаРегистров переносится корректно. Это обеспечит отображение нужных вкладок в базе-приемнике.
Шаг 2. Сопоставление движений регистров. В КД 2.1 наборы записей регистров, подчиненных регистратору, настраиваются в ПКО во вкладке "Поиск/Запись" или через ручное добавление свойств. Вам необходимо сопоставить все регистры, которые задействованы в исходных документах Перенос данных. К ним обычно относятся:
ВзаиморасчетыССотрудниками, НачисленияУдержанияПоСотрудникам, СтраховыеВзносыИПатенты и др.ОсновныеНачисления, ДополнительныеНачисления.КадроваяИсторияСотрудников, ПараметрыПериодовСтажаПФР.Для каждого сопоставленного регистра в правилах конвертации свойств должно быть четко указано ПКО соответствующего регистра.
Шаг 3. Решение проблемы очистки движений при записи (Важнейший нюанс). При стандартной загрузке документов через XML-обмен часто возникает неприятная особенность платформы 1С. Сначала загружаются движения регистров, а затем записывается сам документ Перенос данных. В момент записи документа-объекта платформа "думает", что у документа нет движений (так как в самом объекте коллекции движений могут быть не инициализированы или очищены), и затирает только что загруженные в базу наборы записей.
Для обхода этого поведения в ПКО документа Перенос данных в обработчике события "После загрузки" необходимо прописать специальный алгоритм. Этот алгоритм временно выгрузит пришедшие движения в память, выполнит запись документа для фиксации его ссылки, а затем принудительно вернет движения и запишет их в базу данных.
Разберем пример кода для обработчика "После загрузки":
МетаданныеОбъекта = Объект.Метаданные();
Если Метаданные.Документы.Содержит(МетаданныеОбъекта) Тогда
// Инициализируем массив для хранения таблиц движений
МассивДвижений = Новый Массив;
ДвиженияВсе = Объект.Движения;
// Временно выгружаем все заполненные наборы записей в таблицы значений
Для Каждого НаборЗаписей Из ДвиженияВсе Цикл
Если НаборЗаписей.Количество() > 0 Тогда
СтруктураНабора = Новый Структура;
СтруктураНабора.Вставить("ИмяРегистра", НаборЗаписей.Метаданные().Имя);
СтруктураНабора.Вставить("ТаблицаДанных", НаборЗаписей.Выгрузить());
МассивДвижений.Добавить(СтруктураНабора);
КонецЕсли;
EndЦикла;
// Записываем сам документ-контейнер, чтобы получить валидную ссылку
Объект.Записать(РежимЗаписиДокумента.Запись);
// Возвращаем движения обратно в регистры и принудительно их записываем
Для Каждого ЭлементМассива Из МассивДвижений Цикл
НаборЗаписей = Объект.Движения[ЭлементМассива.ИмяРегистра];
НаборЗаписей.Загрузить(ЭлементМассива.ТаблицаДанных);
НаборЗаписей.Записать(Истина); // Параметр Истина гарантирует замещение старых записей
КонецЦикла;
КонецЕсли;
Этот код надежно защищает перенесенные движения от автоматического очищения платформой в процессе загрузки XML.
Если разработка сложных правил в Конвертации данных 2.1 кажется избыточной или требует слишком много времени на отладку, можно прибегнуть к написанию простой внешней обработки. Проанализируем алгоритм её работы.
Программный перенос обычно выполняется в два этапа: выгрузка данных из источника в промежуточный файл (например, формата JSON или сериализованный XML) и последующее чтение файла в приемнике с поиском элементов по бизнес-ключам.
Рассмотрим структуру выгрузки наборов записей из источника. Нам нужно перебрать все документы Перенос данных, прочитать их движения по каждому доступному регистру и выгрузить структуру записей, заменив ссылки (Сотрудники, Физлица) на текстовые уникальные ключи (например, СНИЛС или Код).
Посмотрим на пример кода выгрузки данных по регистру сведений КадроваяИсторияСотрудников:
// Создаем структуру для экспорта документа и его движений
ДанныеЭкспорта = Новый Структура;
ДанныеЭкспорта.Вставить("Номер", ДокументОбъект.Номер);
ДанныеЭкспорта.Вставить("Дата", ДокументОбъект.Дата);
ДанныеЭкспорта.Вставить("ПериодРегистрации", ДокументОбъект.ПериодРегистрации);
// Выгружаем движения по конкретному регистру
НаборКадры = ДокументОбъект.Движения.КадроваяИсторияСотрудников;
НаборКадры.Прочитать();
ТаблицаКадров = НаборКадры.Выгрузить();
МассивЗаписей = Новый Массив;
Для Каждого СтрокаЗаписи Из ТаблицаКадров Цикл
СтруктураЗаписи = Новый Структура;
// Вместо ссылки на сотрудника выгружаем его СНИЛС и Код для последующего поиска
СтруктураЗаписи.Вставить("СотрудникКод", СтрокаЗаписи.Сотрудник.Код);
СтруктураЗаписи.Вставить("СотрудникНаименование", СтрокаЗаписи.Сотрудник.Наименование);
СтруктураЗаписи.Вставить("ПодразделениеНазвание", СтрокаЗаписи.Подразделение.Наименование);
СтруктураЗаписи.Вставить("ДолжностьНазвание", СтрокаЗаписи.Должность.Наименование);
СтруктураЗаписи.Вставить("Период", СтрокаЗаписи.Период);
СтруктураЗаписи.Вставить("ВидСобытия", СтрокаЗаписи.ВидСобытия);
МассивЗаписей.Добавить(СтруктураЗаписи);
КонецЦикла;
ДанныеЭкспорта.Вставить("ДвиженияКадры", МассивЗаписей);
При загрузке в базе-приемнике мы выполняем обратную операцию. Мы находим сотрудника, подразделение и должность по переданным строковым ключам, заполняем набор записей регистра и принудительно записываем его, установив в качестве регистратора созданный документ Перенос данных.
Пример кода загрузки и записи движений в приемнике:
НовыйДокумент = Документы.ПереносДанных.СоздатьДокумент();
НовыйДокумент.Дата = ДанныеЭкспорта.Дата;
НовыйДокумент.Номер = ДанныеЭкспорта.Номер;
НовыйДокумент.ПериодРегистрации = ДанныеЭкспорта.ПериодРегистрации;
// Заполняем ТаблицуРегистров, чтобы вкладка регистра отображалась на форме
НоваяСтрокаРегистра = НовыйДокумент.ТаблицаРегистров.Добавить();
НоваяСтрокаРегистра.ИмяРегистра = "РегистрСведений.КадроваяИсторияСотрудников";
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
// Формируем новый набор записей для загрузки в регистр
НаборЗаписей = РегистрыСведений.КадроваяИсторияСотрудников.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(НовыйДокумент.Ссылка);
Для Каждого ЗаписьИзФайла Из ДанныеЭкспорта.ДвиженияКадры Цикл
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Регистратор = НовыйДокумент.Ссылка;
НоваяЗапись.Период = ЗаписьИзФайла.Period;
НоваяЗапись.ВидСобытия = ЗаписьИзФайла.ВидСобытия;
// Ищем сотрудника по коду в базе-приемнике
СсылкаСотрудник = Справочники.Сотрудники.НайтиПоКоду(ЗаписьИзФайла.СотрудникКод);
Если Не СсылкаСотрудник.Пустая() Тогда
НоваяЗапись.Сотрудник = СсылкаСотрудник;
Иначе
ВызватьИсключение "Не найден сотрудник с кодом " + ЗаписьИзФайла.СотрудникКод;
КонецЕсли;
// Аналогично ищем подразделение и должность по наименованию
НоваяЗапись.Подразделение = Справочники.ПодразделенияОрганизаций.НайтиПоНаименованию(ЗаписьИзФайла.ПодразделениеНазвание);
НоваяЗапись.Должность = Справочники.Должности.НайтиПоНаименованию(ЗаписьИзФайла.ДолжностьНазвание);
КонецЦикла;
// Записываем набор записей регистра с флагом замещения существующего набора
НаборЗаписей.Записать(Истина);
Мы проанализировали внутреннее устройство технического документа Перенос данных в 1С:ЗУП 3.1 и выяснили, почему стандартные инструменты обмена часто переносят его незаполненным. Применение правильных подходов гарантирует точный и беспроблемный перенос накопленных данных:
После загрузки для предотвращения перезаписи движений платформой.Записать(Истина).Эти методы позволят вам успешно переносить сведения о кадровой истории, взаиморасчетах и начислениях сотрудников, даже если исходные базы создавались независимо друг от друга.