Как реализовать универсальную выгрузку и загрузку документов в текстовый файл без использования GUID, XML и JSON

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

В практике разработчика 1С иногда встречаются задачи, которые кажутся искусственно ограниченными. Одной из таких классических задач, часто предлагаемых на собеседованиях, является создание внешней обработки для "Перегрузки документов" с жестким запретом на использование современных форматов обмена (XML, JSON) и уникальных идентификаторов (GUID). В этой ситуации мы лишаемся привычных инструментов ЗначениеВСтрокуВнутр() или УникальныйИдентификатор(), что заставляет нас обратиться к основам объектной модели и работы с метаданными.

В данной статье мы разберем, как построить надежный алгоритм выгрузки данных в обычный текстовый файл (.txt), используя только возможности платформы по работе с метаданными и поиск объектов по "естественным" ключам.

Постановка задачи и стратегия решения

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

  1. Полное имя типа объекта метаданных (например, "Справочник.Номенклатура" или "Документ.СчетНаОплатуПокупателю").
  2. Ключевые реквизиты поиска (для справочников — код или наименование, для документов — номер и дата).
  3. Значения всех реквизитов документа (включая табличные части).

Шаг 1. Получение типа и полного имени объекта метаданных

Для того чтобы в файле выгрузки указать, какой объект мы сохраняем, нам необходимо получить его строковое представление в системе метаданных. Рассмотрим ситуацию, когда реквизит документа является ссылкой. Чтобы получить его полное имя, воспользуемся методом Метаданные().

Разберем пример кода для получения типа реквизита:


// Предположим, ТекущееЗначение — это ссылка на справочник или документ
Если Справочники.ТипЗнч(ТекущееЗначение) = Тип("СправочникСсылка.Номенклатура") Тогда
    ПолноеИмяТипа = ТекущееЗначение.Метаданные().ПолноеИмя(); 
    // Вернет "Справочник.Номенклатура"
ИначеЕсли Документы.ТипЗнч(ТекущееЗначение) = Тип("ДокументСсылка.СчетНаОплатуПокупателю") Тогда
    ПолноеИмяТипа = ТекущееЗначение.Метаданные().ПолноеИмя();
    // Вернет "Документ.СчетНаОплатуПокупателю"
КонецЕсли;

Для универсального решения мы можем использовать конструкцию ТекущееЗначение.Метаданные().ПолноеИмя() для любых ссылочных типов. Это позволит нам при загрузке точно знать, к какому менеджеру (Справочники, Документы, Перечисления) обращаться.

Шаг 2. Выгрузка данных в текстовый файл

Рассмотрим структуру текстового файла. Чтобы разбор данных был удобным, лучше всего использовать строковый формат с разделителями или тегами. Проанализируем предложенный формат: [ИмяРеквизита] Тип=... Значение=.... Это позволит нам линейно читать файл и восстанавливать объект по полям.

При выгрузке ссылочных типов (Справочников) важно учитывать их уникальность. Если у справочника есть код, приоритет отдается ему. Если кода нет — используем наименование. Посмотрим на пример реализации выгрузки реквизита:


Процедура ЗаписатьРеквизитВФайл(ТекстовыйФайл, ИмяРеквизита, Значение)
    МетаДанныеОбъекта = Значение.Метаданные();
    ПолноеИмяТипа = МетаДанныеОбъекта.ПолноеИмя();
    
    ТекстовыйФайл.ЗаписатьСтроку("Реквизит:" + ИмяРеквизита);
    ТекстовыйФайл.ЗаписатьСтроку("Тип:" + ПолноеИмяТипа);
    
    Если Справочники.ТипЗнч(Значение) Тогда
        // Для справочников пишем Код или Наименование
        ТекстовыйФайл.ЗаписатьСтроку("Код:" + Значение.Код);
        ТекстовыйФайл.ЗаписатьСтроку("Наименование:" + Значение.Наименование);
    ИначеЕсли Документы.ТипЗнч(Значение) Тогда
        // Для документов важна связка Номер + Дата
        ТекстовыйФайл.ЗаписатьСтроку("Номер:" + Значение.Номер);
        ТекстовыйФайл.ЗаписатьСтроку("Дата:" + Формат(Значение.Дата, "ДФ=yyyyMMddHHmmss"));
    ИначеЕсли Перечисления.ТипЗнч(Значение) Тогда
        // Для перечислений лучше выгружать имя значения (не синоним!)
        Индекс = Перечисления[МетаДанныеОбъекта.Имя].Индекс(Значение);
        ИмяЗначения = МетаДанныеОбъекта.ЗначенияПеречисления[Индекс].Имя;
        ТекстовыйФайл.ЗаписатьСтроку("Значение:" + ИмяЗначения);
    Иначе
        // Простые типы (Число, Строка, Дата, Булево)
        ТекстовыйФайл.ЗаписатьСтроку("Значение:" + Строка(Значение));
    КонецЕсли;
КонецПроцедуры

Шаг 3. Работа с перечислениями

Как было замечено в обсуждении, выгрузка перечислений по синониму — это ненадежный путь. Правильнее всего выгружать имя значения перечисления, заданное в конфигураторе. Проанализируем ситуацию: синоним может измениться или локализоваться, в то время как программное имя остается стабильным. При загрузке мы восстановим значение через конструкцию: Перечисления[ИмяПеречисления][ИмяЗначения].

Шаг 4. Загрузка данных и поиск объектов

Теперь разберем, как восстановить документ в базе-приемнике. Поскольку мы не используем GUID, нам нужно найти существующие ссылки по выгруженным метаданным или создать новые. Выясним алгоритм поиска:

  1. Определяем тип метаданных из файла.
  2. Для справочников: пробуем НайтиПоКоду(). Если результат ПустаяСсылка(), пробуем НайтиПоНаименованию().
  3. Для документов: используем метод НайтиПоНомеру(Номер, Дата).
  4. Для перечислений: получаем объект через менеджер перечислений по имени.

Рассмотрим пример поиска справочника:


Функция НайтиСправочник(ПолноеИмяТипа, Код, Наименование)
    // Отсекаем префикс "Справочник."
    ИмяСправочника = Сред(ПолноеИмяТипа, 12);
    Менеджер = Справочники[ИмяСправочника];
    
    Ссылка = Менеджер.НайтиПоКоду(Код);
    Если Ссылка.Пустая() Тогда
        Ссылка = Менеджер.НайтиПоНаименованию(Наименование);
    КонецЕсли;
    
    Возврат Ссылка;
КонецФункции

Шаг 5. Нюансы и ограничения "естественного" поиска

Нужно понимать, что поиск по наименованию или номеру не гарантирует 100% точности. Рассмотрим основные риски, которые следует упомянуть при сдаче подобного задания:

Использование XMLТипЗнч и XMLСтрока для простых типов

Хотя по условию задачи запрещено использовать XML как структуру файла, мы можем применить хитрость для сериализации значений внутри текстовых строк. Функции XMLСтрока(Значение) и XMLЗначение(Тип, Строка) позволяют канонически преобразовывать примитивные типы (Число, Дата, Булево) в строку и обратно. Это гораздо надежнее, чем парсить дату вручную, пытаясь угадать формат разделителей. Проанализируем, как это помогает: дата в формате XML всегда выглядит как 2016-12-19T12:00:00, что исключает ошибки региональных настроек системы.

Резюме

Решение задачи универсальной перегрузки без GUID требует от нас глубокого понимания того, как объекты 1С хранятся и идентифицируются. Основной упор мы делаем на метаданные и менеджеры объектов. Несмотря на "костыльность" метода (поиск по наименованиям), в рамках академической задачи или жестких ограничений обмена это единственный путь. Главное — обеспечить избыточность данных при выгрузке, чтобы процесс загрузки имел максимум информации для принятия решения о сопоставлении объектов.

← На главную