Обработка загружаемых и выгружаемых файлов обмена. БСП
Поделюсь одним полезным способом исправления ошибок, когда исчерпаны другие — обработка самого файла обмена. Полезно иметь такой метод в арсенале!
Ошибка при загрузке данных в УНФ
При получении данных в УНФ из региональной БП, к которой не было доступа, стали получать ошибку:
{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: поправил код процедуры СтруктураДействийПоФайлуОбмена чтобы СтруктураДействий возвращалась всегда.
Свежие комментарии