При разработке механизмов обмена данными между различными конфигурациями 1С (например, при переносе данных из самописной ERP в «1С:Бухгалтерию») программисты часто сталкиваются с несовпадением типов реквизитов. Типичная ситуация: в исходной базе объект является элементом справочника (СправочникСсылка), а в целевой базе этот же реквизит должен храниться просто как строка. Разберем подробно, как реализовать такой перенос, избежать ошибок обращения к объектам и предотвратить засорение справочников базы-приемника лишними элементами.
Рассмотрим ситуацию, когда при загрузке данных система выдает ошибку: Поле объекта не обнаружено (Наименование). Проанализируем причину. Обычно это происходит при попытке обратиться к свойству объекта, который на самом деле объектом не является. Например, если переменная содержит не ссылку на справочник, а неопределенное значение, пустую строку или таблицу значений (ТЗ), созданную механизмом выгрузки.
В самописных обработках часто используются функции-посредники для получения данных из XML или COM-соединения. Посмотрим на пример функции, которая извлекает значения из таблицы реквизитов:
Функция ПолучитьЗначениеИзТаблРекв(ВхТаблРекв, ВхИмяРеквизита, ВхДопПризнак = "", ВхСоздаватьЕслиНеНайден = ИСТИНА)
Если НЕ ЗначениеЗаполнено(ВхТаблРекв) Тогда
Возврат "";
КонецЕсли;
_СтрТаблРекв = ВхТаблРекв.Найти(ВхИмяРеквизита, "ИмяРеквизита");
Если _СтрТаблРекв = Неопределено Тогда
Возврат "";
ИначеЕсли Лев(_СтрТаблРекв.ТипРеквизита, 16) = "СправочникСсылка" Тогда
// Здесь часто заложена логика поиска или СОЗДАНИЯ ссылки в текущей базе
Возврат ПолучитьСсылкуСпр(_СтрТаблРекв.Значение, _СтрТаблРекв.ТипРеквизита, ВхДопПризнак);
Иначе
Возврат _СтрТаблРекв.Значение;
КонецЕсли;
КонецФункции
Если в базе-приемнике реквизит является строкой, использование такой функции может привести к тому, что ПолучитьСсылкуСпр начнет искать или создавать элемент справочника, который нам не нужен. Нам нужно только его текстовое представление.
Если мы точно знаем, что в переменной находится ссылка на справочник, мы можем попытаться получить его наименование. Однако делать это нужно безопасно, проверяя заполненность значения. Проанализируем следующий подход:
// Безопасное получение наименования
СтрокаТЧ.ВариантИсполнения = ?(ЗначениеЗаполнено(ВариантИсполнения), ВариантИсполнения.Наименование, "");
Важный момент: если ВариантИсполнения пришел из другой базы через COM или XML как структура данных, прямое обращение через точку .Наименование вызовет ошибку. В этом случае нам нужно извлечь текстовое значение напрямую из транспортного контейнера (например, из таблицы значений реквизитов).
Часто в сложных обменах данные передаются в виде вложенных таблиц. Если в таблице реквизитов по ключу "ВариантИсполнения" лежит не ссылка, а еще одна таблица или массив с данными объекта, нам нужно применить поиск по структуре. Рассмотрим пример кода, который ищет нужное строковое значение в ТЗ, не пытаясь создать объект в справочнике:
Отбор = Новый Структура;
Отбор.Вставить("ИмяРеквизита", "ВариантИсполнения");
// Ищем строку с реквизитом во внутренней таблице данных строки ТЧ
СтрокиПоиска = СтрокаТаблТЧ.Значение.НайтиСтроки(Отбор);
Если СтрокиПоиска.Количество() > 0 Тогда
// Допустим, значение хранится в первой колонке найденной строки
ДанныеВИ = СтрокиПоиска[0].Значение;
// Если ДанныеВИ — это тоже коллекция (например, ТЗ с полями Код, Наименование)
// Извлекаем именно наименование по индексу или имени колонки
Если ТипЗнч(ДанныеВИ) = Тип("ТаблицаЗначений") И ДанныеВИ.Количество() > 0 Тогда
СтрокаТЧ.ВариантИсполнения = ДанныеВИ[0].Значение; // Берем текст
Иначе
СтрокаТЧ.ВариантИсполнения = Строка(ДанныеВИ);
КонецЕсли;
КонецЕсли;
Такой подход позволяет избежать создания лишних элементов в справочниках базы-приемника, так как мы работаем только с текстовыми данными, пришедшими из источника.
Проанализируем ситуацию: если база-приемник («1С:Бухгалтерия») ожидает строку, то логичнее всего передавать строку уже на этапе выгрузки из ERP. Это самый надежный метод, который минимизирует нагрузку на приемник.
ВариантИсполнения, заменим передачу ссылки на передачу наименования.Строка(Ссылка.Наименование) или Ссылка.Наименование.Это позволит функции ПолучитьЗначениеИзТаблРекв в приемнике сразу определить тип как «Строка» и вернуть готовый текст без вызова процедур поиска в справочниках.
Для универсальности кода рекомендуется всегда использовать встроенную функцию Строка(). В 1С она работает следующим образом: если в нее передана ссылка, она возвращает основное представление (наименование или код). Если передан пустой объект, она вернет пустую строку. Это избавляет от множества проверок Если ... Тогда.
// Универсальный и безопасный способ
ЗначениеДляЗагрузки = ПолучитьЗначениеИзТаблРекв(ТаблРекв, "ВариантИсполнения");
СтрокаТЧ.ВариантИсполнения = СокрЛП(Строка(ЗначениеДляЗагрузки));
Разберем, почему мы добавили СокрЛП(). При обмене данными, особенно через текстовые форматы, могут возникать невидимые пробелы или символы переноса строк. Функция СокрЛП() гарантирует, что в реквизит документа попадет чистый текст без лишних отступов.
Если подобные задачи возникают часто, стоит рассмотреть переход на использование конфигурации «1С:Конвертация данных» (КД 2.0 или 3.0). В КД задача преобразования ссылки в строку решается установкой одного флага в правилах конвертации свойств (ПКС). Система сама сформирует оптимальный код, который извлечет наименование из источника и запишет его в строку приемника, корректно обработав все исключения и пустые ссылки.
Резюме: Чтобы перенести значение из ссылки в строку, необходимо либо явно обращаться к свойству Наименование (с проверкой на заполненность), либо использовать функцию Строка(), либо — что наиболее правильно — подготовить строковое значение еще на стороне базы-источника, чтобы приемник не тратил ресурсы на поиск несуществующих объектов.