При интеграции 1С:Предприятия 7.7 с порталом электронных счетов-фактур (ЭСЧФ) с использованием внешней COM-библиотеки EInvVatService часто возникает задача сохранения полученных электронных документов на локальный диск в формате XML. Разберем по шагам, как правильно выгружать полученные данные, какие встроенные методы предоставляет компонента и с какими особенностями платформы 1С 7.7 можно столкнуться при обработке кодировок и проверке подписей.
Рассмотрим типовой фрагмент кода для получения входящих документов с портала, на котором обычно останавливается разработчик:
EVatService = СоздатьОбъект("EInvVatService.Connector");
InvList = EVatService.GetList(ПреобрДаты(НаДату) + "T00:00:01Z");
InvVatNumber = InvList.GetItemAttribute(i, "document/number");
Попытка
InvVatXml = EVatService.GetEDoc(InvVatNumber);
Исключение
Сообщить("Не удалось получить ЭСЧФ № " + InvVatNumber + ": " + EVatService.LastError);
Продолжить;
КонецПопытки;
ДанныеXML = InvVatXml.Document.GetData(0);
После вызова метода GetData(0) разработчик получает текстовую строку, содержащую XML-структуру документа. Возникает вопрос: как корректно записать эту строку или сам объект документа на диск? Попытка использовать стандартные файловые механизмы платформы 1С 7.7 может привести к искажению кириллических символов, так как ЭСЧФ формируются в кодировке UTF-8, а встроенный объект Текст в 1С 7.7 работает исключительно с ANSI (Windows-1251). Объекта ЗаписьТекста в платформе 1С 7.7 нет — он появился только в 1С 8.
Самый простой, надежный и быстродействующий способ — использование встроенных методов сохранения самой COM-библиотеки EInvVatService. Объект документа предоставляет специализированные методы, которые автоматически выгружают файлы в требуемых кодировках и форматах без привлечения сторонних средств 1С.
Разберем различия методов сохранения:
InvVatXml.SaveToFile(ПутьКФайлу) — сохраняет полный подписанный пакет электронного документа (бинарный контейнер с электронными цифровыми подписями в формате Base64/транспортном виде).InvVatXml.Document.SaveToFile(ПутьКФайлуXML) — сохраняет чистое тело XML-документа без сигнатур, в исходной кодировке UTF-8, пригодной для дальнейшего парсинга и сопоставления номенклатуры или контрагентов.Посмотрим на практический пример реализации:
КаталогВыгрузки = "C:\ESF_XML\";
ФайлПакета = КаталогВыгрузки + InvVatNumber + ".edoc";
ФайлXML = КаталогВыгрузки + InvVatNumber + ".xml";
// Сохраняем подписанный контейнер
res = InvVatXml.SaveToFile(ФайлПакета);
Если res <> 0 Тогда
Сообщить("Ошибка при сохранении пакета ЭСЧФ: " + EVatService.LastError);
КонецЕсли;
// Сохраняем чистый XML-документ
res = InvVatXml.Document.SaveToFile(ФайлXML);
Если res <> 0 Тогда
Сообщить("Ошибка при сохранении XML ЭСЧФ: " + EVatService.LastError);
Иначе
Сообщить("Документ " + InvVatNumber + " успешно сохранен в XML.");
КонецЕсли;
Если цель сохранения XML-файла заключается исключительно в последующем разборе данных (чтении реквизитов, разделов документа, строк с товарами и суммами НДС), создавать промежуточный файл на диске вовсе не обязательно. Выясним причину: метод GetData(0) возвращает расшифрованное тело XML-документа в виде текстовой строки (в то время как GetData(1) возвращает данные в Base64).
Полученную строку можно сразу передать в объект MSXML2.DOMDocument для разбора структуры в памяти:
ДанныеXML = InvVatXml.Document.GetData(0);
XML = СоздатьОбъект("MSXML2.DOMDocument.6.0");
XML.async = 0;
XML.resolveExternals = 0;
Если XML.LoadXML(ДанныеXML) = 1 Тогда
// Получаем необходимые узлы документа
УзелНомера = XML.selectSingleNode("//general/number");
Если ПустоеЗначение(УзелНомера) = 0 Тогда
Сообщить("Успешно прочитан номер из памяти: " + УзелНомера.text);
КонецЕсли;
Иначе
Сообщить("Ошибка парсинга XML: " + XML.parseError.reason);
КонецЕсли;
Если по каким-либо причинам требуется записать именно полученную через GetData(0) строку на диск силами скрипта, для исключения повреждения кириллицы используем COM-объект ADODB.Stream:
ДанныеXML = InvVatXml.Document.GetData(0);
ФайлXML = "C:\ESF_XML\" + InvVatNumber + ".xml";
Поток = СоздатьОбъект("ADODB.Stream");
Поток.Type = 2; // Текстовый режим (adTypeText)
Поток.Charset = "utf-8";
Поток.Open();
Поток.WriteText(ДанныеXML);
Поток.SaveToFile(ФайлXML, 2); // 2 - перезаписать существующий файл (adSaveCreateOverWrite)
Поток.Close();
Проанализируем частые ошибки при работе с методами библиотеки:
VerifyAllSigns: Метод VerifyAllSigns() не входит в состав методов библиотеки EInvVatService. Это пользовательская функция из официальных примеров SDK, реализующая перебор и вызов метода проверки подписи VerifySign. Если функция не объявлена в глобальном модуле или модуле обработки 1С 7.7, платформа выдаст ошибку отсутствия функции.Попытка ... Исключение обязательно следует оборачивать именно вызов EVatService.GetEDoc(InvVatNumber), так как портал может возвращать временную ошибку доступа или сообщение о том, что документ уже запрашивался в течение установленного лимита времени (например, 12 часов).eInvVat.dll и криптопровайдер Avest CSP должны быть зарегистрированы через 32-битный regsvr32.exe (в 64-битных ОС Windows исполняемый файл находится по пути C:\Windows\SysWOW64\regsvr32.exe).