С 01.01.2016 через систему ЕГАИС (Единая государственная автоматизированная информационная система http://egais.ru) - будут обязаны работать оптовики и розничные продавцы крепкого и слабого алкоголя.
В преддверии внедрения на своих учетных системах обмена с УТМ (ЕГАИС) разбирались, как работает.
Для обработки использовалась статья "Передача файлов и данных на веб-сервер средствами 1С:Предприятие 8.X методом POST".
XML запрос к справочнику организаций (из Технической документации УТМ 1.1)
Сформируем xml-файл запроса (client.xml) c запросом рекивизитов организации вида (структура запроса взята из описания УТМ модуля):
<?xml version="1.0" encodmg="UTF-8"?>
<ns:Documents Version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns="http://fsrar.ru/WEGAIS/WB_DOC_SINGLE_01"
xmlns:oref="http://fsrar.ru/WEGAIS/ClientRef"
xmlns:qp="http://fsrar.ru/WEGAIS/QueryParameters">
<ns:Owner>
<ns:FSRAR_ID>00040218</ns:FSRAR_ID>
</ns:Owner>
<ns:Document> (5.1)
<ns:QueryClients>
<qp:Parameters>
<qp:Parameter>
<qp:Name>ИНН</qp:Name>
<qp:Value>1681000049<</qp:Value>
</qp:Parameter>
</qp:Parameters>
</ns:QueryClients>
</ns:Document>
</ns:Documents>
Запрос реквизитов организации выполняется по ее ИНН и FSRAR_ID содержит идентификатор организации, отправляющей данный документ.
В ответ на этот запрос, УТМ подписывает файл запроса и возвращает реквизиты подписи в квитанции следующего вида:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <A> <url>d9ef780e-4d35-41b0-bb9c-f06e53ac23d3</url> <sign>895B92CAD115B57B02C7D12ADC488066D99B60549D57A737B0CAC18E5E3E1C72E6B8D414C763CB58A5E67DE7C8C2ECE908451C4AE6838479A42ABBA8179D0CE8 </sign> <ver>2</ver> </
В элементе url возвращается идентификатор запроса, его значение требуется запомнить для поиска впоследствии ответа на этот запрос.
При использовании CURL, команда будет вида: curl -F "xml_file=@client.xml" http://localhost:8080/opt/in/QueryPartner
УТМ отправляет запрос на сервер ЕГАИС. Сервер ЕГАИС формирует ответ на запрос, возвращает ответ в УТМ.
Далее сформируем запрос средствами 1С, без использования CURL:
1. Подготовка переменных:
Boundary = СтрЗаменить(Строка(Новый УникальныйИдентификатор()), "-", ""); // Идентификатор границы разделов POST запроса
ИмяФайлаДляЗагрузки = КаталогВременныхФайлов() + "select.xml";
ИмяФайлаОтвета = КаталогВременныхФайлов() + "answer.xml"; // Имя файла ответа на POST запрос
ИмяФайлаОтправки = КаталогВременныхФайлов() + "post.txt";
2. Формируем XML запрос :
ОбъектXML = Новый ЗаписьXML();
ОбъектXML.ОткрытьФайл(ИмяФайлаДляЗагрузки);
ОбъектXML.ЗаписатьОбъявлениеXML();
ОбъектXML.ЗаписатьНачалоЭлемента("ns:Documents");
ОбъектXML.ЗаписатьАтрибут("Version", "1.0");
ОбъектXML.ЗаписатьСоответствиеПространстваИмен("xsi", "http://www.w3.org/2001/XMLSchema-instance");
ОбъектXML.ЗаписатьСоответствиеПространстваИмен("ns", "http://fsrar.ru/WEGAIS/WB_DOC_SINGLE_01");
ОбъектXML.ЗаписатьСоответствиеПространстваИмен("oref", "http://fsrar.ru/WEGAIS/ClientRef");
ОбъектXML.ЗаписатьСоответствиеПространстваИмен("qp", "http://fsrar.ru/WEGAIS/QueryParameters");
ОбъектXML.ЗаписатьНачалоЭлемента("ns:Owner");
ОбъектXML.ЗаписатьНачалоЭлемента("ns:FSRAR_ID");
ОбъектXML.ЗаписатьТекст(FSRAR_ID);
ОбъектXML.ЗаписатьКонецЭлемента();//ns:FSRAR_ID
ОбъектXML.ЗаписатьКонецЭлемента();//ns:Owner
ОбъектXML.ЗаписатьНачалоЭлемента("ns:Document");
ОбъектXML.ЗаписатьНачалоЭлемента("ns:QueryClients");
ОбъектXML.ЗаписатьНачалоЭлемента("qp:Parameters");
ОбъектXML.ЗаписатьНачалоЭлемента("qp:Parameter");
ОбъектXML.ЗаписатьНачалоЭлемента("qp:Name");
ОбъектXML.ЗаписатьТекст("ИНН");
ОбъектXML.ЗаписатьКонецЭлемента();//qp:Name
ОбъектXML.ЗаписатьНачалоЭлемента("qp:Value");
ОбъектXML.ЗаписатьТекст(ИННКонтрагента);
ОбъектXML.ЗаписатьКонецЭлемента();//qp:Value
ОбъектXML.ЗаписатьКонецЭлемента();//qp:Parameter
ОбъектXML.ЗаписатьКонецЭлемента();//qp:Parameters
ОбъектXML.ЗаписатьКонецЭлемента();//ns:QueryClients
ОбъектXML.ЗаписатьКонецЭлемента();//ns:Document
ОбъектXML.ЗаписатьКонецЭлемента();//ns:Documents
ОбъектXML.ЗаписатьТекст(Символы.ПС);
ОбъектXML.Закрыть();
3. Формирование тела POST запроса через объеденение текстовых файлов:
//Определяем массив для процедуры ОбъединитьФайлы
МассивФайловДляОбъединения = Новый Массив;
//Формируем начальный фрагмент файла POST-запроса
ИмяФайлаОтправкиНачало = ПолучитьИмяВременногоФайла("txt");
ФайлОтправкиНачало = Новый ЗаписьТекста(ИмяФайлаОтправкиНачало, КодировкаТекста.ANSI, Символы.ПС, Ложь);
//Определяем раздел двоичных данных
ФайлОтправкиНачало.ЗаписатьСтроку("--" + Boundary);
//Указываем имя файла для передачи
ФайлОтправкиНачало.ЗаписатьСтроку("Content-Disposition: form-data; name=""xml_file""; filename=""" + "select.xml" + """");
//Указываем тип передаваемых данных.
ФайлОтправкиНачало.ЗаписатьСтроку("Content-Type: text/xml; charset=utf-8");
ФайлОтправкиНачало.ЗаписатьСтроку("");
ФайлОтправкиНачало.Закрыть();
МассивФайловДляОбъединения.Добавить(ИмяФайлаОтправкиНачало);
МассивФайловДляОбъединения.Добавить(ИмяФайлаДляЗагрузки);
//Формируем конечный фрагмент файла POST-запроса
ИмяФайлаОтправкиКонец = ПолучитьИмяВременногоФайла("txt");
ФайлОтправкиКонец = Новый ЗаписьТекста(ИмяФайлаОтправкиКонец, КодировкаТекста.ANSI, Символы.ПС, Ложь);
//Завершение раздела двоичных данных
//Завершение сообщения для сервера
ФайлОтправкиКонец.ЗаписатьСтроку("--" + Boundary + "--");
ФайлОтправкиКонец.Закрыть();
МассивФайловДляОбъединения.Добавить(ИмяФайлаОтправкиКонец); // !!! 3 добавление в массив
//Теперь сформированные фрагменты сообщения для сервера объединяем в один файл POST-запроса
ОбъединитьФайлы(МассивФайловДляОбъединения, ИмяФайлаОтправки);
4. Формируем заголовок POST запроса:
ЗаголовокHTTP = Новый Соответствие();
//Укажем формат данных Content-Type
ЗаголовокHTTP.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
//Укажем длину POST-запроса Content-Length
ФайлОтправки = Новый Файл(ИмяФайлаОтправки);
РазмерФайлаОтправки = XMLСтрока(ФайлОтправки.Размер());
ЗаголовокHTTP.Вставить("Content-Length", РазмерФайлаОтправки);
5. Инициализируем HTTPСоединение, При необходимости задаём параметры прокси.
СерверПриемник = "localhost"; //Без протокола http://. Естественно, следует указать свой адрес.
Порт = "8080"; //Порт УТМ
ИспользоватьПрокси = Ложь;
Если ИспользоватьПрокси Тогда
Прокси = Новый ИнтернетПрокси;
Прокси.НеИспользоватьПроксиДляЛокальныхАдресов = Истина;
Прокси.Пароль = "ПарольПрокси"; // укажите своё значение
Прокси.Пользователь = "ПользовательПрокси"; // укажите своё значение
НТТР = Новый HTTPСоединение(СерверПриемник, Порт, , , Прокси);
Иначе
НТТР = Новый HTTPСоединение(СерверПриемник, Порт);
КонецЕсли;
Попытка
АдресСкрипта = "/opt/in/QueryPartner"; //Адрес ресурса.
//Формируем HTTP запрос
ЗапросHTTP = Новый HTTPЗапрос(АдресСкрипта, ЗаголовокHTTP);
ЗапросHTTP.УстановитьИмяФайлаТела(ИмяФайлаОтправки); //Устанавливает имя файла, из которого будет прочитано тело POST-запроса.
//Ответ от сервера получим в возвращаемом значении типа HTTPОтвет
ОтветHTTP = НТТР.ОтправитьДляОбработки(ЗапросHTTP, ИмяФайлаОтвета);
Исключение
Сообщить("Неудачная попытка соединения с " + СерверПриемник + ": " + ОписаниеОшибки());
Возврат;
КонецПопытки;
//Разрушаем объект HTTP-запроса для освобождения файла POST-запроса.
//В противном случае при попытке удаления файла получим ошибку совместного доступа.
ЗапросHTTP = Неопределено;
6. Читаем ответ на запрос, разбираем XML файл ответа.
ЧтениеОтвета = Новый ЧтениеXML;
ЧтениеОтвета.ОткрытьФайл(ОтветHTTP.ПолучитьИмяФайлаТела());
ИдОтвета = "";
ПодписьОтвета = "";
ИмяУзла = "";
Пока ЧтениеОтвета.Прочитать() Цикл
Если ЧтениеОтвета.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
ИмяУзла = ЧтениеОтвета.Имя;
КонецЕсли;
Если ЧтениеОтвета.ТипУзла=ТипУзлаXML.Текст Тогда
Если ИмяУзла = "url" Тогда
urlЗначение=ЧтениеОтвета.Значение;
Сообщить("ID "+urlЗначение);
КонецЕсли;
Если ИмяУзла = "sign" Тогда
signЗначение=ЧтениеОтвета.Значение;
Сообщить("SIGN "+signЗначение);
КонецЕсли;
КонецЕсли;
КонецЦикла;
//Разрушаем объект HTTP-ответ для освобождения файла ответа.
ЧтениеОтвета = Неопределено;
7. Удаляем временные файлы.
// Удаляем файлы POST-запроса и фрагменты сообщения. Больше они не нужны.
УдалитьФайлы(ИмяФайлаОтвета); // "answer.xml"
УдалитьФайлы(ИмяФайлаОтправки); // "post.txt"
УдалитьФайлы(ИмяФайлаДляЗагрузки); // "select.xml"
Для каждого ЭлементМассива Из МассивФайловДляОбъединения Цикл
УдалитьФайлы(ЭлементМассива);
КонецЦикла;
В итоге мы получаем ключ url вида "d9ef780e-4d35-41b0-bb9c-f06e53ac23d3", и "sign" вида "895B92CAD115B57B02C7D12ADC488066D99B60549D57A737B0CAC18E5E3E1C72E6B8D414C763CB58A5E67DE7C8C2ECE908451C4AE6838479A42ABBA8179D0CE8", что с этим делать и что это значит? Наш запрос был принят УТМ и подписан, далее каждые 5 минут УТМ отправляет запросы на сервер ЕГАИС, сервер обрабатывает и присылает на ответы. Список ответов будет находится по адресу "http://localhost:8080/opt/out?refresh=true" в виде :
Строим HTTP запрос к ресурсу "/opt/out" получаем список ответов, в списке находим нужный ответ по url = relayId,
получаем ссылку "http://localhost:8080/opt/out/ReplyPartner/1" на файл ответа с сервера и по ссылке получаем XML файл ответа.
Ответ на запрос к справочнику организаций будет вида:
<?xml version="1.0" encoding="UTF-8"?>
<ns:Documents xmlns:rc="http://fsrar.ru/WEGAIS/ReplyClient" xmlns:oref="http://fsrar. ru/WEGAIS/ClientRef" xmlns:ns="http://fsrar.ru/WEGAIS/WB_DOC_SINGLE_01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns:Owner>
<ns:FSRAR_ID>3463047</ns:FSRAR_ID>
</ns:Owner>
<ns:Document> (5.9)
<ns:ReplyClient>
<rc:Clients xmlns:rc="http://fsrar.ru/WEGAIS/ReplyClient" xmlns:oref="http://fsrar.ru/WEGAIS/ClientRef" xmlns:ns="http://fsrar.ru/WEGAIS/WB_DOC_SINGLE_01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<rc:Client>
<oref:ClientRegId>00008907</oref:ClientRegId>
<oref:INN>1681000049</oref:INN>
<oref:KPP>303265456</oref:KPP>
<oref:FuMName>ООО "Пример"</oref:FuMName> <oref:ShortName>П</oref:ShortName>
<oref:address>
<oref:Country>643</oref:Country>
<oref:RegionCode>30</oref:RegionCode>
<oref:city>Астрахань г</o ref: city>
<oref:street>1 -й проезд</оге^^ее^ <oref:house>12</oref:house>
<oref:description>643,,AcTpaxaHCK8H обл,,Астрахань г,,1 -й проезд,12,,,</oref:description>
</oref:address>
</rc:Client>
</rc:Clients>
</ns:ReplyClient>
</ns:Document>
</ns:Documents>
...