В практике программирования на платформе 1С:Предприятие часто встречаются задачи, связанные с обменом данными. Одной из наиболее интересных и сложных вариаций является выгрузка данных документа в простой текстовый файл с последующей загрузкой в другую информационную базу (или тот же документ) при соблюдении жестких ограничений. Зачастую в таких задачах запрещается использовать стандартные механизмы сериализации, такие как XML, JSON или системные функции ЗначениеВСтрокуВнутр() и УникальныйИдентификатор().
В этой статье мы подробно разберем, как реализовать универсальный механизм выгрузки и загрузки реквизитов документа, опираясь исключительно на работу с метаданными и поиск объектов по строковым представлениям. Мы проанализируем процесс получения типов, работу с менеджерами объектов и логику восстановления ссылочных данных.
Представим ситуацию: нам необходимо передать данные документа через txt файл. Если реквизит имеет тип Строка, Число или Дата, проблем не возникает — они легко преобразуются в текст и обратно. Однако, если реквизит является ссылкой (например, СправочникСсылка.Номенклатура или ПеречислениеСсылка.Статусы), простая запись наименования в файл не позволит системе автоматически восстановить ссылку при загрузке. Нам потребуется алгоритм, который определит, к какому справочнику относится данное название, и найдет соответствующий элемент в базе.
Для того чтобы загрузка прошла успешно, в текстовый файл нужно записывать не только значение реквизита, но и информацию о его типе. Рассмотрим, как программно обойти реквизиты документа и подготовить данные для записи.
Для начала проанализируем способ обхода метаданных документа. Нам необходимо получить коллекцию реквизитов и их значения:
Для Каждого РеквизитМетаданные Из Объект.Метаданные().Реквизиты Цикл
ИмяРеквизита = РеквизитМетаданные.Имя;
Значение = Объект[ИмяРеквизита];
ТипЗнч = ТипЗнч(Значение);
// Формируем строку для записи: Имя|Тип|Значение
СтрокаВыгрузки = ИмяРеквизита + "|" + Строка(ТипЗнч) + "|" + СокрЛП(Значение);
// Записываем строку в ТекстовыйДокумент
КонецЦикла;
Важно понимать разницу между ТипЗнч() и описанием типов в метаданных. При выгрузке конкретного документа мы работаем с уже заполненными данными, поэтому ТипЗнч(Значение) даст нам точное понимание, что именно записано в поле, даже если тип реквизита составной.
Самый ответственный этап — это восстановление ссылочных типов при чтении файла. Разберем по шагам, как превратить строку "Яблоки" обратно в объект СправочникСсылка.Номенклатура.
Когда мы считываем строку из файла, мы получаем строковое представление типа. Нам нужно получить доступ к менеджеру соответствующего объекта (справочника или перечисления), чтобы вызвать метод НайтиПоНаименованию().
Рассмотрим алгоритм поиска менеджера через метаданные:
Метаданные, находим нужный объект по имени.Посмотрим на пример кода, который выполняет поиск ссылки:
Функция НайтиСсылкуПоНаименованию(ИмяОбъектаМетаданных, ЗначениеПоиска)
// Предположим, ИмяОбъектаМетаданных пришло в виде "Справочник.Номенклатура"
МассивСлов = СтрРазделить(ИмяОбъектаМетаданных, ".");
ВидОбъекта = МассивСлов[0]; // Справочник
ИмяОбъекта = МассивСлов[1]; // Номенклатура
Если ВидОбъекта = "Справочник" Тогда
Возврат Справочники[ИмяОбъекта].НайтиПоНаименованию(ЗначениеПоиска);
ИначеЕсли ВидОбъекта = "Перечисление" Тогда
// С перечислениями сложнее, у них нет метода НайтиПоНаименованию
Возврат НайтиЗначениеПеречисления(ИмяОбъекта, ЗначениеПоиска);
КонецЕсли;
Возврат Неопределено;
КонецФункции
Проанализируем ситуацию с перечислениями. Поскольку у них нет методов поиска, нам придется перебирать их значения через метаданные или использовать индекс. Если в текстовый файл мы выгрузили синоним или имя значения, алгоритм восстановления будет выглядеть так:
Функция НайтиЗначениеПеречисления(ИмяПеречисления, ЗначениеСтрокой)
Менеджер = Перечисления[ИмяПеречисления];
Для Каждого Значение Из Метаданные.Перечисления[ИмяПеречисления].ЗначенияПеречисления Цикл
Если Значение.Имя = ЗначениеСтрокой Или Значение.Синоним = ЗначениеСтрокой Тогда
Индекс = Метаданные.Перечисления[ИмяПеречисления].ЗначенияПеречисления.Индекс(Значение);
Возврат Менеджер[Индекс];
КонецЕсли;
КонецЦикла;
Возврат Неопределено;
КонецФункции
При использовании НайтиПоНаименованию() мы можем столкнуться с проблемой, когда в справочнике есть два элемента с одинаковым названием. Выясним причину, почему это критично: система вернет первую попавшуюся ссылку, что может привести к ошибке в учете. Если условия задачи позволяют, рекомендуется выгружать дополнительно Код справочника.
В этом случае строка в файле будет выглядеть так: Номенклатура|Яблоки|00001. При загрузке мы сначала используем НайтиПоКоду(), и только если объект не найден — НайтиПоНаименованию().
Не забудем, что документ — это не только шапка, но и табличные части. Для их выгрузки нам нужно вложить еще один цикл обхода. Рассмотрим структуру файла для ТЧ:
Мы можем использовать специальные маркеры в текстовом файле, например, [НачалоТаблицы:Товары] и [КонецТаблицы]. Это позволит парсеру при загрузке понять, что данные нужно добавлять в строки таблицы, а не в реквизиты объекта.
Для Каждого ТЧ Из Объект.Метаданные().ТабличныеЧасти Цикл
ЗаписатьСтроку(Файл, "[Table:" + ТЧ.Имя + "]");
Для Каждого СтрокаТЧ Из Объект[ТЧ.Имя] Цикл
ДанныеСтроки = "";
Для Каждого Колонна Из ТЧ.Реквизиты Цикл
ДанныеСтроки = ДанныеСтроки + Строка(СтрокаТЧ[Колонна.Имя]) + "|";
КонецЦикла;
ЗаписатьСтроку(Файл, ДанныеСтроки);
КонецЦикла;
КонецЦикла;
Разберем важный момент, упомянутый в обсуждении: использование ОписаниеТипов. Если мы загружаем данные и не знаем заранее, какой тип должен быть у реквизита (например, при заполнении пустого документа), мы должны обратиться к метаданным самого документа:
ОписаниеТипаРеквизита = Объект.Метаданные().Реквизиты[ИмяИзФайла].Тип;
// Если тип не составной, получаем первый доступный тип
НужныйТип = ОписаниеТипаРеквизита.Типы()[0];
// Теперь, используя НужныйТип, мы можем найти менеджер через Метаданные.НайтиПоТипу(НужныйТип)
Этот подход делает загрузку универсальной. Вам не нужно жестко прописывать условия для каждого справочника. Система сама "поймет", что в реквизит "Склад" нужно искать ссылку в справочнике "Склады", основываясь на конфигурации.
Реализация обмена через txt без использования стандартных идентификаторов — это отличный способ глубже изучить работу с метаданными 1С. Мы выяснили, что ключ к успеху лежит в правильном сохранении названия типа и использовании менеджеров объектов для поиска ссылок. Несмотря на ограничения, платформа предоставляет достаточно инструментов (Метаданные, Менеджеры, Типы) для решения подобных задач.