При переносе данных между различными конфигурациями 1С с помощью механизма «1С:Конвертация данных 2.1» (КД 2) часто возникает архитектурное несовпадение структур метаданных. Классический пример — перенос кадровых данных из старых версий зарплатных решений (например, ЗУП 1.1 или 2.5) в современные редакции «Бухгалтерии предприятия 3.0» (БП 3.0).
В старых конфигурациях документ ПриемНаРаботуВОрганизацию не содержал прямой ссылки на справочник Сотрудники (использовалась прямая связь с физическими лицами), а реквизит ВидЗанятости находился непосредственно в самом документе. В современной БП 3.0 справочник Сотрудники является обязательным, и реквизит ВидЗанятости перенесен внутрь этого справочника. Возникает задача: при переносе документа создать элемент справочника и корректно заполнить его реквизиты данными, которые в источнике хранятся в документе. Разберем по шагам, как решить эту задачу правильно, избегая типовых ошибок разработчиков.
---
В процессе обсуждения на форуме участники столкнулись с целым рядом классических проблем. Проанализируем их причины, чтобы не допускать подобных ошибок при проектировании правил обмена.
1. Использование глобальных параметров вместо параметров объекта
Попытка передать значение через конструкцию Параметры.Вставить("ВидЗанятости", ...) в событии ПередВыгрузкой объекта приводит к потере данных. Глобальная структура Параметры в КД 2 предназначена для хранения общих настроек всей сессии выгрузки/загрузки. При обработке коллекции документов значение в глобальной структуре будет постоянно перезаписываться данными последнего выгруженного документа. В момент загрузки конкретного объекта в базе-приемнике эти данные окажутся неактуальными или будут пустыми.
Для связывания временных данных с конкретным конвертируемым объектом необходимо использовать локальную коллекцию ПараметрыОбъекта, которая сериализуется в XML-файл внутри узла данного объекта и гарантированно доходит до обработчика ПослеЗагрузки этого же объекта.
2. Ошибка обращения к значению перечисления
Попытка получить имя перечисления через обращение к свойству Источник.ВидЗанятости.Значение вызывает ошибку платформы:
Поле объекта не обнаружено (Значение)
В платформе 1С:Предприятие у объектов типа ПеречислениеСсылка нет свойства Значение. Сравнение перечислений или получение их строкового представления в коде обработчиков должно выполняться другими методами, о которых мы поговорим ниже.
3. Неверный порядок параметров в функции ВыгрузитьПоПравилу()
При использовании правил выгрузки данных (ПВД) с произвольным алгоритмом разработчики часто путают позиции аргументов функции ВыгрузитьПоПравилу(). Синтаксис функции выглядит следующим образом:
ВыгрузитьПоПравилу(Источник, Приемник, ВходящиеДанные, ИсходящиеДанные, ИмяПКО, ...)
Если передать подготовленную структуру данных третьим параметром, она будет воспринята системой как ВходящиеДанные, а не как ИсходящиеДанные. Соответственно, в ПКС (Правилах конвертации свойств) флаг «Получать из исходящих данных» не сработает, и создаваемые объекты запишутся пустыми.
4. Особенности записи справочника «Сотрудники» в БП 3.0
Прямое создание элемента справочника через Справочники.Сотрудники.СоздатьЭлемент() в коде обработчика ПослеЗагрузки документа — крайне нерекомендуемый подход для БП 3.0. Современная конфигурация использует сложные механизмы Библиотеки стандартных подсистем (БСП). Без заполнения связанных регистров сведений и вызова специализированных процедур общего модуля созданные сотрудники будут «невидимы» в интерфейсе программы, а кадровый учет по ним нарушится.
---
Этот способ оптимален, если вы не хотите переписывать структуру выгрузки и желаете передать данные «на лету» в рамках существующего ПКО документа. Рассмотрим этот метод по шагам.
Шаг 1. В конфигураторе «Конвертация данных» откройте ПКО вашего документа (например, ПриемНаРаботуВОрганизацию). Перейдите на вкладку «Параметры» и добавьте новый параметр с именем ВидЗанятости. Установите для него тип значения (соответствующее перечисление приемника) и обязательно взведите флаг «Передавать в приемник».
Шаг 2. В ПКС (Правила конвертации свойств) для этого созданного параметра укажите соответствующее ПКО перечисления (например, ВидыЗанятости -> ВидыЗанятости). Это позволит КД автоматичеки сопоставить элементы перечисления без написания кода ручного сравнения строк.
Шаг 3. В обработчике события ПередВыгрузкой (или ПриВыгрузке) ПКО документа передайте значение из источника в параметр объекта:
// Если ВидЗанятости находится в шапке документа источника
ПараметрыОбъекта = Новый Структура;
ПараметрыОбъекта.Вставить("ВидЗанятости", Источник.ВидЗанятости);
Шаг 4. В обработчике события ПослеЗагрузки ПКО документа в базе-приемнике прочитайте переданный параметр и используйте его при создании или обновлении справочника сотрудников. Обратите внимание: в приемнике этот параметр будет доступен в структуре ПараметрыОбъекта.
// Извлекаем переданное значение вида занятости
ВидЗанятостиПриемник = Неопределено;
Если ПараметрыОбъекта <> Неопределено Тогда
ПараметрыОбъекта.Свойство("ВидЗанятости", ВидЗанятостиПриемник);
КонецЕсли;
// Обходим табличную часть документа в приемнике для создания сотрудников
Для Каждого СтрокаТЧ Из Объект.РаботникиОрганизации Цикл
// Проверяем, существует ли уже сотрудник с таким физлицом в базе
СотрудникСсылка = Справочники.Сотрудники.НайтиПоРеквизиту("ФизическоеЛицо", СтрокаТЧ.ФизическоеЛицо);
Если СотрудникСсылка.Пустая() Тогда
// Создаем нового сотрудника программно
НовыйСотрудник = Справочники.Сотрудники.СоздатьЭлемент();
НовыйСотрудник.ФизическоеЛицо = СтрокаТЧ.ФизическоеЛицо;
НовыйСотрудник.ГоловнаяОрганизация = Объект.Организация;
НовыйСотрудник.Наименование = СтрокаТЧ.ФизическоеЛицо.Наименование;
// Заполняем перенесенный вид занятости
Если ЗначениеЗаполнено(ВидЗанятостиПриемник) Тогда
НовыйСотрудник.ВидЗанятости = ВидЗанятостиПриемник;
КонецЕсли;
Попытка
НовыйСотрудник.Записать();
СтрокаТЧ.Сотрудник = НовыйСотрудник.Ссылка;
Сообщить("Успешно создан сотрудник: " + НовыйСотрудник.Наименование);
Исключение
Сообщить("Ошибка при записи сотрудника: " + КраткоеОписаниеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
Иначе
// Если сотрудник найден, просто подставляем его в документ
СтрокаТЧ.Сотрудник = СотрудникСсылка;
КонецЕсли;
КонецЦикла;
---
Это наиболее гибкий и профессиональный подход с точки зрения архитектуры КД 2. Мы создаем отдельное ПКО для справочника Сотрудники, у которого нет объекта-источника (поле "Источник" оставляем пустым), а все данные для заполнения передаем через структуру ВходящиеДанные непосредственно из запроса выгрузки документов.
Шаг 1. Создайте ПКО для справочника Сотрудники. Поле «Источник» оставьте пустым, а «Приемник» установите как СправочникСсылка.Сотрудники. В таблице ПКС добавьте реквизиты, которые необходимо заполнить: Код, Наименование, ФизическоеЛицо, ГоловнаяОрганизация, ВидЗанятости. Для каждого из этих свойств установите флаг «Получать из входящих данных».
Шаг 2. Создайте ПВД (Правило выгрузки данных). Выберите тип выгрузки — «Произвольный алгоритм». В обработчике события ПередОбработкой напишите запрос, который выберет все необходимые данные по кадровым документам за период выгрузки:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ПриемРаботников.ФизЛицо КАК ФизическоеЛицо,
| ПриемРаботников.ФизЛицо.Код КАК Код,
| ПриемРаботников.ФизЛицо.Наименование КАК Наименование,
| ПриемРаботников.Ссылка.Организация КАК Организация,
| ПриемРаботников.Ссылка.ВидЗанятости КАК ВидЗанятости
|ИЗ
| Документ.ПриемНаРаботуВОрганизацию.РаботникиОрганизации КАК ПриемРаботников
|ГДЕ
| ПриемРаботников.Ссылка.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
| И ПриемРаботников.Ссылка.Проведен = ИСТИНА";
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Формируем структуру входящих данных для передачи в ПКО справочника
ВходящиеДанныеДляСотрудника = Новый Структура;
ВходящиеДанныеДляСотрудника.Вставить("Код", Выборка.Код);
ВходящиеДанныеДляСотрудника.Вставить("Наименование", Выборка.Наименование);
ВходящиеДанныеДляСотрудника.Вставить("ФизическоеЛицо", Выборка.ФизическоеЛицо);
ВходящиеДанныеДляСотрудника.Вставить("ГоловнаяОрганизация", Выборка.Организация);
ВходящиеДанныеДляСотрудника.Вставить("ВидЗанятости", Выборка.ВидЗанятости);
// Вызываем выгрузку по правилу конвертации.
// Обратите внимание на ПРАВИЛЬНЫЙ порядок параметров:
// ВходящиеДанные передаются ТРЕТЬИМ аргументом.
ВыгрузитьПоПравилу(,, ВходящиеДанныеДляСотрудника,, "СозданиеСотрудников");
КонецЦикла;
Шаг 3. Чтобы сопоставить перечисление ВидЗанятости без написания сложных условий сравнения строк, обязательно создайте стандартное ПКО для перечислений. В правилах конвертации свойств для реквизита ВидЗанятости укажите созданное ПКО перечисления. Конвертация данных автоматически сопоставит типы источника и приемника на этапе генерации XML.
---
Если вам все же требуется обработать перечисление вручную в коде (например, для переопределения логики заполнения или при отсутствии прямого соответствия), никогда не используйте несуществующее свойство .Значение. Выясним причину: перечисление является ссылочным типом данных. Чтобы получить его строковое имя (идентификатор метаданных) в источнике, используйте следующий шаблон:
// Получение строкового имени значения перечисления
ИмяЗначения = "";
Если ЗначениеЗаполнено(Источник.ВидЗанятости) Тогда
ИндексЗначения = Перечисления.ВидыЗанятости.Индекс(Источник.ВидЗанятости);
ИмяЗначения = Метаданные.Перечисления.ВидыЗанятости.ЗначенияПеречисления[ИндексЗначения].Имя;
КонецЕсли;
// Теперь можно безопасно использовать строковое сравнение
Если ИмяЗначения = "ОсновноеМестоРаботы" Тогда
// Ваша логика
КонецЕсли;
Использование этого кода гарантирует отсутствие синтаксических ошибок платформы при выгрузке данных и обеспечивает стабильную работу правил обмена.