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