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