Как разработать универсальную выгрузку и загрузку документа в текстовый формат через метаданные?

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

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

Постановка задачи и выбор стратегии

Рассмотрим основные требования. Нам необходимо реализовать выбор любого типа документа, доступного в конфигурации, и обеспечить "исчерпывающую" выгрузку данных. Это означает, что в файл должны попасть не только основные реквизиты (Дата, Организация, Контрагент), но и все строки всех табличных частей. Поскольку нам запрещено использовать стандартные форматы сериализации и уникальные идентификаторы, мы должны разработать собственный протокол передачи данных, основанный на метаданных и естественных ключах (таких как Код или Наименование для справочников).

Шаг 1. Организация выбора любого документа на форме

Проанализируем, как предоставить пользователю возможность выбрать любой документ из базы. Если мы просто создадим реквизит с типом ДокументСсылка, нам придется выбирать конкретный вид документа. Чтобы сделать поле универсальным, воспользуемся объектом ОписаниеТипов.

Разберем программный способ настройки такого поля при создании формы:


// В модуле формы
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    МассивТипов = Новый Массив;
    Для Каждого МетаДанныеДокумента Из Метаданные.Документы Цикл
        МассивТипов.Добавить(Тип("ДокументСсылка." + МетаДанныеДокумента.Имя));
    КонецЦикла;
    
    // Устанавливаем составной тип данных для реквизита "ВыбранныйДокумент"
    Элементы.ВыбранныйДокумент.ОграничениеТипа = Новый ОписаниеТипов(МассивТипов);
КонецПроцедуры

Этот подход позволяет полю выбора динамически подстраиваться под все виды документов, существующие в вашей конфигурации.

Шаг 2. Обход метаданных для выгрузки реквизитов

Перейдем к самой сути задачи — универсальному чтению данных документа. Чтобы код работал для любого документа, мы не можем обращаться к полям напрямую (например, Объект.Контрагент). Вместо этого мы проанализируем коллекцию Метаданные.

Рассмотрим алгоритм выгрузки основных реквизитов:

  1. Получим объект документа по ссылке.
  2. Обратимся к метаданным этого конкретного вида документа.
  3. В цикле переберем все реквизиты, определенные в конфигураторе.
  4. Для каждого реквизита получим его значение и преобразуем в строковый вид.

// Пример получения данных через метаданные
СсылкаНаДок = Объект.ВыбранныйДокумент;
ИмяДокумента = СсылкаНаДок.Метаданные().Имя;

// Выгрузка основных реквизитов
Для Каждого РеквизитМетаданных Из Метаданные.Документы[ИмяДокумента].Реквизиты Цикл
    ИмяПоля = РеквизитМетаданных.Имя;
    ЗначениеПоля = СсылкаНаДок[ИмяПоля];
    
    // Здесь логика преобразования ЗначениеПоля в текст (см. Шаг 4)
    ЗаписатьСтрокуВФайл(ИмяПоля, ЗначениеПоля);
КонецЦикла;

Шаг 3. Обработка табличных частей

Документ — это не только шапка, но и табличные части. Проанализируем, как выгрузить их универсально. Нам потребуется вложенный цикл: внешний по списку табличных частей, средний по строкам каждой части и внутренний по колонкам (реквизитам) табличной части.


Для Каждого ТЧ_Метаданные Из Метаданные.Документы[ИмяДокумента].ТабличныеЧасти Цикл
    ИмяТЧ = ТЧ_Метаданные.Имя;
    ТаблицаДанных = СсылкаНаДок[ИмяТЧ];
    
    Для Каждого СтрокаТЧ Из ТаблицаДанных Цикл
        Для Каждого Колонка Из ТЧ_Метаданные.Реквизиты Цикл
            ИмяКолонки = Колонка.Имя;
            ЗначениеКолонки = СтрокаТЧ[ИмяКолонки];
            // Запись в файл: ИмяТЧ, НомерСтроки, ИмяКолонки, Значение
        КонецЦикла;
    КонецЦикла;
КонецЦикла;

Шаг 4. Решение проблемы ссылочных типов (Без UID)

Выясним причину сложности использования простого текста: 1С хранит ссылки на справочники, другие документы и перечисления как внутренние идентификаторы. По условию задачи нам запрещено их использовать. Как же передать информацию о "Контрагенте" или "Складе"?

Решение заключается в использовании естественных ключей. Для каждого типа данных мы должны продумать свой способ представления в строке:

Рассмотрим пример функции преобразования ссылки в текстовое описание:


Функция ЗначениеВТекст(Значение)
    Если Значение = Неопределено Тогда
        Возврат "NULL";
    ИначеЕсли ТипЗнч(Значение) = Тип("Число") Или ТипЗнч(Значение) = Тип("Булево") Тогда
        Возврат Строка(Значение);
    ИначеЕсли ТипЗнч(Значение) = Тип("Дата") Тогда
        Возврат Формат(Значение, "ДФ=ггггММддЧЧммсс");
    ИначеЕсли Метаданные.Справочники.Содержит(Значение.Метаданные()) Тогда
        // Используем Код как наиболее надежный ключ
        Возврат Значение.Код; 
    ИначеЕсли Метаданные.Перечисления.Содержит(Значение.Метаданные()) Тогда
        Возврат Строка(Значение);
    КонецЕсли;
    Возврат Строка(Значение);
КонецФункции

Шаг 5. Структура текстового файла (Собственный формат)

Поскольку XML под запретом, разработаем свою структуру файла. Посмотрим на пример простого формата "Ключ|Тип|Значение":


[Header]
DocumentType|ПоступлениеТоваровУслуг
Date|20231025120000
[Attributes]
Организация|Справочник.Организации|000000001
Контрагент|Справочник.Контрагенты|ООО "Поставщик"
Склад|Справочник.Склады|Основной
[Table|Товары]
1|Номенклатура|Справочник.Номенклатура|00005|Количество|10|Цена|500
2|Номенклатура|Справочник.Номенклатура|00008|Количество|5|Цена|1200

Для работы с таким файлом идеально подходит объект ТекстовыйДокумент. Мы можем использовать метод ДобавитьСтроку() при выгрузке и перебор строк при загрузке.

Шаг 6. Алгоритм загрузки и восстановления данных

Проанализируем процесс восстановления документа из файла. Нам нужно выполнить действия в обратном порядке:

  1. Прочитать первую строку и определить вид документа.
  2. Создать новый объект документа: НовыйДок = Документы[ИмяВида].СоздатьДокумент();.
  3. Для каждой строки из секции реквизитов найти значение в базе. Если это "Справочник.Организации" и значение "000000001", выполняем Справочники.Организации.НайтиПоКоду("000000001").
  4. Заполнить найденное значение в реквизит объекта: НовыйДок[ИмяРеквизита] = НайденнаяСсылка;.
  5. Аналогично заполнить табличные части, предварительно добавляя строки методом НовыйДок[ИмяТЧ].Добавить().

Важный момент: Номер документа выгружать и загружать не нужно (или нужно игнорировать при записи), так как по условию он должен оставаться уникальным, а система присвоит его автоматически при вызове метода Записать().

Рекомендации для самостоятельного развития

Для глубокого понимания того, как работает платформа с данными, мы рекомендуем изучить книгу С.А. Митичкина "Разработка в системе 1С:Предприятие 8". Там подробно разобраны механизмы объектной модели. Также обратите внимание на синтакс-помощник в разделе "Метаданные", чтобы изучить все доступные свойства объектов конфигурации.

Помните, что данный метод обмена через текстовые файлы с поиском по наименованию/коду является учебным. В реальных задачах предпочтительнее использовать УникальныйИдентификатор или специализированные средства (Конвертация данных), так как наименования справочников могут дублироваться, что приведет к ошибкам при загрузке.

← На главную