Обработка загружаемых и выгружаемых файлов обмена. БСП

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

Ошибка при загрузке данных в УНФ

При получении данных в УНФ из региональной БП, к которой не было доступа, стали получать ошибку:

{http://v8.1c.ru/edi/edi_stnd/EnterpriseData/1.6}Справочник.БанковскиеСчета

Значение: '301XXXXXXXXXXX              ' не соответствует простому типу: 
Несоответствие фасету MaxLength = '20'

В файле ошибка выглядит так:

В БП коррсчет хранится с пробелом, обрезать конечные пробелы не дает. Менять код БП нет возможности.

Преобразование XDTO происходит в модуле ОбменДаннымиXDTOСервер в процедуре ПрочитатьXML:

Вмешаться в ход этой процедуры невозможно, поэтому принято решение обрабатывать файл XML.

Ошибка при загрузке данных из УНФ в другую базу

При выгрузке документа ГТД в базу БП из УНФ стали получать ошибку:

Ошибка в базе-корреспонденте:
 Ошибка при загрузке данных: Ошибка проверки данных XDTO:
Структура объекта не соответствует типу: {http://v8.1c.ru/edi/edi_stnd/EnterpriseData/1.6}Документ.ТаможеннаяДекларация.Товары.Строка
Проверка свойства 'ФактурнаяСтоимость':
	форма: Элемент
	имя: {http://v8.1c.ru/edi/edi_stnd/EnterpriseData/1.6}ФактурнаяСтоимость
	тип: {http://v8.1c.ru/edi/edi_stnd/EnterpriseData/1.6}ТипСумма
Отсутствует обязательное свойство

Формирование файла обмена происходит также через метод фабрики XDTO ЗаписатьXML, вмешаться нет возможности.

Принято решение поправлять после файл после формирования.

В итоге получилось добавлять фактурную стоимость:

Доработки

Ничего лучше не придумал, чем разобрать файл и собрать заново. Благо, функции уже были готовы заранее.

Расширение в модуль ОбменДаннымиСервер:

Процедура ОбработатьФайлОбмена(СтруктураДействий, ИмяФайла) Экспорт
	
	Если СтруктураДействий.Обрабатывать <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	
	Ч = Новый ЧтениеXML();
	Ч.ОткрытьФайл(ИмяФайла);
	КодировкаИсточника = Ч.КодировкаИсточника;
	
	РезИмяФайла = ИмяФайла + "_";
	
	З = Новый ЗаписьXML;
	З.ОткрытьФайл(РезИмяФайла, КодировкаИсточника);
	
	Строки = РазобратьXML(Ч);
	ОбработатьСтроки(СтруктураДействий, Строки);
	З.ЗаписатьОбъявлениеXML();
	СобратьXML(З, Строки);    
	
	Ч.Закрыть();
	З.Закрыть();
	
	//Перемещаем файл-результа в файл-источник
	УдалитьФайлы(ИмяФайла);
	ПереместитьФайл(РезИмяФайла, ИмяФайла);
	
	
КонецПроцедуры

Функция СтруктураВсехДействийПоФайлуОбмена() Экспорт
	Р = Новый Структура();
	Р.Вставить("Обрабатывать", ложь);
	Р.Вставить("ЗаменятьТаможеннуюСтоимостьФактурной", ложь);
	Возврат Р;
КонецФункции

Функция СтруктураДействийПоФайлуОбмена(УзелИнформационнойБазы, Направление) Экспорт
	//Направление - чтение или запись
	СтруктураДействий = СтруктураВсехДействийПоФайлуОбмена();
	Если Найти(ВРЕГ(УзелИнформационнойБазы), " МОЯ ФИРМА") <> 0 Тогда
		Если Направление = "Чтение" Тогда
			СтруктураДействий.Обрабатывать = истина;
		Иначе                                                   
			//Будет обработан файл, с оптимизациями по умолчанию
			СтруктураДействий.Обрабатывать = истина;
			СтруктураДействий.ЗаменятьТаможеннуюСтоимостьФактурной = истина;
		КонецЕсли;
	КонецЕсли;
	Возврат СтруктураДействий;
КонецФункции

Функция СкопироватьСтруктуру(С) Экспорт   
	Р = Новый Структура();
	Для Каждого КЗ ИЗ С Цикл
		Р.Вставить(КЗ.Ключ, КЗ.Значение);
	КонецЦикла;                          
	Возврат Р;
КонецФункции

Процедура ОбработатьСтроки(СтруктураДействий, Строки) Экспорт   
	
	//Рекурсивно обрабатываем файл
	Для Каждого ТекСтрока ИЗ Строки Цикл
		Если ТекСтрока.Тег = "КоррСчет" Тогда
			ТекСтрока.Тело = СокрЛП(ТекСтрока.Тело);
		КонецЕсли;
		Если СтруктураДействий.ЗаменятьТаможеннуюСтоимостьФактурной = истина И ТекСтрока.Тег = "ТаможеннаяСтоимость" Тогда
			//Добавляем фактурную стоимость, равную таможенной - в массив добавляем скопированную структуру
			НСтр = СкопироватьСтруктуру(ТекСтрока);
			Строки.Добавить(НСтр);
			НСтр.Тег = "ФактурнаяСтоимость";
		КонецЕсли;
		ОбработатьСтроки(СтруктураДействий, ТекСтрока.Строки);
	КонецЦикла;
	
КонецПроцедуры

Функция СвойствоСтруктуры(Структура, Свойство, ПоУмолчанию = Неопределено) Экспорт
    Если Структура <> Неопределено И Структура.Свойство(Свойство) Тогда
        Возврат Структура[Свойство];
    КонецЕсли;                      
    Возврат ПоУмолчанию;
КонецФункции

Функции из модуля дор_Сервер:

Процедура ОбработатьФайлОбмена(СтруктураДействий, ИмяФайла) Экспорт
	
	Если СтруктураДействий.Обрабатывать <> Истина Тогда
		Возврат;
	КонецЕсли;
	
	
	Ч = Новый ЧтениеXML();
	Ч.ОткрытьФайл(ИмяФайла);
	КодировкаИсточника = Ч.КодировкаИсточника;
	
	РезИмяФайла = ИмяФайла + "_";
	
	З = Новый ЗаписьXML;
	З.ОткрытьФайл(РезИмяФайла, КодировкаИсточника);
	
	Строки = РазобратьXML(Ч);
	ОбработатьСтроки(СтруктураДействий, Строки);
	З.ЗаписатьОбъявлениеXML();
	СобратьXML(З, Строки);    
	
	Ч.Закрыть();
	З.Закрыть();
	
	//Перемещаем файл-результа в файл-источник
	УдалитьФайлы(ИмяФайла);
	ПереместитьФайл(РезИмяФайла, ИмяФайла);
	
	
КонецПроцедуры

Функция СтруктураВсехДействийПоФайлуОбмена() Экспорт
	Р = Новый Структура();
	Р.Вставить("Обрабатывать", ложь);
	Р.Вставить("ЗаменятьТаможеннуюСтоимостьФактурной", ложь);
	Возврат Р;
КонецФункции

Функция СтруктураДействийПоФайлуОбмена(УзелИнформационнойБазы, Направление) Экспорт
	//Направление - чтение или запись
	Если Найти(ВРЕГ(УзелИнформационнойБазы), " МОЯФИРМА") <> 0 Тогда
		Если Направление = "Чтение" Тогда
			СтруктураДействий = СтруктураВсехДействийПоФайлуОбмена();
			СтруктураДействий.Обрабатывать = истина;
			Возврат СтруктураДействий;
		Иначе                                                   
			//Будет обработан файл, с оптимизациями по умолчанию
			СтруктураДействий = СтруктураВсехДействийПоФайлуОбмена();
			СтруктураДействий.Обрабатывать = истина;
			СтруктураДействий.ЗаменятьТаможеннуюСтоимостьФактурной = истина;
			Возврат СтруктураДействий;
		КонецЕсли;
	КонецЕсли;
КонецФункции

Функция СкопироватьСтруктуру(С) Экспорт   
	Р = Новый Структура();
	Для Каждого КЗ ИЗ С Цикл
		Р.Вставить(КЗ.Ключ, КЗ.Значение);
	КонецЦикла;                          
	Возврат Р;
КонецФункции

Процедура ОбработатьСтроки(СтруктураДействий, Строки) Экспорт   
	
	//Рекурсивно обрабатываем файл
	Для Каждого ТекСтрока ИЗ Строки Цикл
		Если ТекСтрока.Тег = "КоррСчет" Тогда
			ТекСтрока.Тело = СокрЛП(ТекСтрока.Тело);
		КонецЕсли;
		Если СтруктураДействий.ЗаменятьТаможеннуюСтоимостьФактурной = истина И ТекСтрока.Тег = "ТаможеннаяСтоимость" Тогда
			//Добавляем фактурную стоимость, равную таможенной - в массив добавляем скопированную структуру
			НСтр = СкопироватьСтруктуру(ТекСтрока);
			Строки.Добавить(НСтр);
			НСтр.Тег = "ФактурнаяСтоимость";
		КонецЕсли;
		ОбработатьСтроки(СтруктураДействий, ТекСтрока.Строки);
	КонецЦикла;
	
КонецПроцедуры

Функция СвойствоСтруктуры(Структура, Свойство, ПоУмолчанию = Неопределено) Экспорт
    Если Структура <> Неопределено И Структура.Свойство(Свойство) Тогда
        Возврат Структура[Свойство];
    КонецЕсли;                      
    Возврат ПоУмолчанию;
КонецФункции

Функции разбора-сбора XML:

Функция РазобратьXML(Ч, Строки = Неопределено, РодительскаяСтрока = Неопределено) Экспорт
	Если Строки = Неопределено Тогда
		Строки = Новый Массив();
	КонецЕсли;
	
	Пока Ч.Прочитать() Цикл
		//Сообщить(""+Ч.ТипУзла+Символы.Таб+Ч.Имя+Символы.Таб+Ч.Значение + Символы.Таб + Ч.КоличествоАтрибутов());
		Если Ч.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
			ТекСтрока = Новый Структура("Тег, Родитель, Тип, Тело, ", Ч.Имя, РодительскаяСтрока);
			ТекСтрока.Вставить("Атрибуты", Новый Соответствие());
			ТекСтрока.Вставить("Строки", Новый Массив());
			Строки.Добавить(ТекСтрока);
			//ТекСтрока.Тело = "";
			Если Ч.КоличествоАтрибутов() > 0 Тогда
				Пока Ч.ПрочитатьАтрибут() Цикл
					ТекСтрока.Атрибуты.Вставить(Ч.Имя, Ч.Значение);
				КонецЦикла
			КонецЕсли;
			РазобратьXML(Ч, ТекСтрока.Строки, ТекСтрока);
		ИначеЕсли Ч.ТипУзла = ТипУзлаXML.Текст Тогда
			РодительскаяСтрока.Тело = Ч.Значение;
		ИначеЕсли Ч.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
			Возврат Неопределено;
		//ИначеЕсли Ч.ТипУзла = ТипУзлаXML.ОбъявлениеXML Тогда
		//	ТекСтрока = Новый Структура("Тег, Тело", Ч.Имя);
		//	ТекСтрока.Вставить("Атрибуты", Новый Структура());
		//	ТекСтрока.Вставить("Строки", Новый Массив());
		//	ТекСтрока.Вставить("Тип", ТипУзлаXML.ОбъявлениеXML);
		//	Строки.Добавить(ТекСтрока);
		ИначеЕсли Ч.ТипУзла = ТипУзлаXML.ИнструкцияОбработки Тогда
			РодительскаяСтрока.Тело = Ч.Значение;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Строки;
	
КонецФункции


Функция СобратьXML(З, Строки)
	Для Каждого ТекСтрока ИЗ Строки Цикл
		Если ТекСтрока.Тип = Неопределено Тогда
			З.ЗаписатьНачалоЭлемента(ТекСтрока.Тег);
			Для Каждого ЭлАтрибут ИЗ ТекСтрока.Атрибуты Цикл
				З.ЗаписатьАтрибут(ЭлАтрибут.Ключ, ЭлАтрибут.Значение);
			КонецЦикла;
			
			Если ТекСтрока.Тело <> Неопределено Тогда
				З.ЗаписатьТекст(ТекСтрока.Тело);
			КонецЕсли;
			
			СобратьXML(З, ТекСтрока.Строки);
			
			З.ЗаписатьКонецЭлемента();
		//ИначеЕсли ТекСтрока.ТипУзла = ТипУзлаXML.ОбъявлениеXML Тогда
		//	З.ЗаписатьОбъявлениеXML();
		КонецЕсли;
	КонецЦикла;
КонецФункции

При применении метода будьте осторожны. Если файл большой, могут быть проблемы с нехваткой памяти и, возможно, имеет смысл использовать другие способы обработки.

Среда: УНФ 3.0 Объем: 3 час.

UPD 2024-02-27: поправил код процедуры СтруктураДействийПоФайлуОбмена чтобы СтруктураДействий возвращалась всегда.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *