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

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

В практике разработчика 1С часто встречаются задачи, требующие нестандартного подхода к обмену данными. Одной из таких задач является выгрузка и загрузка документов в текстовый файл (формат .txt) при строгом запрете на использование встроенных механизмов сериализации, таких как ЗначениеВСтрокуВнутр, УникальныйИдентификатор (UUID), а также форматов XML и JSON. Особую сложность в этой задаче представляет работа с субконто в конфигурации «Бухгалтерия предприятия», так как эти реквизиты имеют составной тип данных и требуют специфической обработки. Рассмотрим подробно, как реализовать подобный механизм.

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

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

Особенности работы с типами данных и метаданными

Первое, с чем мы сталкиваемся — необходимость сохранения информации о типе значения. Поскольку в текстовом файле всё превращается в строку, нам нужно дополнять каждое значение «маркером» его типа. В 1С это можно сделать, обратившись к свойству Метаданные() объекта или используя функцию ТипЗнч(). Проанализируем, почему обычное определение типа через метаданные реквизита может быть недостаточным.

Реквизит может иметь составной тип. Например, реквизит Субконто в «Бухгалтерии» имеет тип Характеристика.ВидыСубконтоХозрасчетные. В конкретной строке документа там может лежать ссылка на справочник Номенклатура, а в другой — на перечисление ЭлементыЗатрат. Чтобы корректно загрузить эти данные, нам нужно выгружать именно фактический тип значения, находящегося в поле в данный момент.

Для получения строкового имени типа воспользуемся методом получения полного имени метаданных. Рассмотрим пример функции, которая определяет тип значения:


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

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

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

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

  1. Записываем заголовок: имя метаданных документа и его дату.
  2. Обходим метаданные реквизитов документа. Для каждого реквизита получаем его значение.
  3. Для каждого значения определяем тип и само представление для поиска (для справочников — код или ИНН, для документов — номер и дата).
  4. Повторяем процесс для каждой строки каждой табличной части.

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

Как обрабатывать Субконто

Вернемся к проблеме субконто. В «1С:Бухгалтерии» субконто — это не просто значение, а связь между видом характеристики и её значением. Выясним причину, по которой у автора вопроса возникали сложности: он видел в типе реквизита Характеристика.ВидыСубконтоХозрасчетные, а при выгрузке получал Перечисление.ЭлементыЗатрат. Это происходит потому, что поле субконто — это точка входа в составной тип.

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

Реализация загрузки и поиска объектов

Разберем, как восстановить документ из текстовых данных. Основная задача здесь — функция ПоискЗначения, которая по текстовому описанию типа и ключу поиска вернет ссылку на объект в текущей базе.


&НаСервере
Функция НайтиСсылкуПоДанным(ТипСтр, КлючПоиска)
    Если ТипСтр = "Строка" Тогда Возврат КлючПоиска;
    ИначеЕсли ТипСтр = "Число" Тогда Возврат Число(КлючПоиска);
    ИначеЕсли ТипСтр = "Дата" Тогда Возврат Дата(КлючПоиска);
    ИначеЕсли ТипСтр = "Булево" Тогда Возврат ?(КлючПоиска = "Истина", Истина, Ложь);
    КонецЕсли;
    
    // Парсим полное имя метаданных, например "Справочник.Номенклатура"
    МассивТипа = СтрРазделить(ТипСтр, ".");
    Если МассивТипа.Количество() < 2 Тогда Возврат Неопределено; КонецЕсли;
    
    ВидМетаданных = МассивТипа[0];
    ИмяОбъекта = МассивТипа[1];
    
    Если ВидМетаданных = "Справочник" Тогда
        // Поиск по коду (универсальный способ)
        Возврат Справочники[ИмяОбъекта].НайтиПоКоду(КлючПоиска);
    ИначеЕсли ВидМетаданных = "Перечисление" Тогда
        // Поиск по имени значения перечисления
        Возврат Перечисления[ИмяОбъекта][КлючПоиска];
    ИначеЕсли ВидМетаданных = "Документ" Тогда
        // Здесь КлючПоиска должен содержать Номер и Дату
        // Реализуйте парсинг номера и даты для НайтиПоНомеру
    КонецЕсли;
    
    Возврат Неопределено;
КонецФункции

Процесс восстановления документа

Проанализируем ситуацию при загрузке: мы создаем новый объект документа программно через Документы[Имя].СоздатьДокумент(). Далее мы читаем строки файла и заполняем соответствующие поля. Если мы встречаем субконто, мы сначала определяем его тип, находим ссылку в базе и записываем её в реквизит. Если это табличная часть, мы добавляем новую строку и заполняем её колонки аналогичным образом.

Обратите внимание на составные типы в субконто: так как мы выгрузили фактический тип (например, Справочник.СтатьиЗатрат), функция НайтиСсылкуПоДанным вернет нам готовую ссылку, которую 1С легко примет в поле типа Характеристика.ВидыСубконтоХозрасчетные.

Рассмотрим финальные советы по реализации:

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

← На главную