При самостоятельной реализации интеграции 1С с транспортным модулем ЕГАИС (УТМ) разработчики нередко сталкиваются с ситуацией, когда сформированный XML-документ полностью соответствует документации, но сервер ЕГАИС возвращает квитанцию с отказом следующего содержания:
<tc:Result>
<tc:Conclusion>Rejected</tc:Conclusion>
<tc:ConclusionDate>2016-11-21T08:18:50.3231738</tc:ConclusionDate>
<tc:Comments>Документ: [...] не соответствует заявленному формату: DocType=[QueryFormB]</tc:Comments>
</tc:Result>
Разберем детально, почему возникает такое несоответствие, как правильно составить XML-пакет для получения движений по форме Б и на какие нюансы протокола УТМ следует обратить особое внимание.
Проанализируем текст ошибки: DocType=[QueryFormB]. Это ключевая улика. Сервер ЕГАИС сообщает, что он ожидал документ типа QueryFormB (запрос информации о самой справке Б), в то время как в теле XML был передан запрос движений QueryFormBHistory.
Такая ситуация возникает из-за специфики REST API универсального транспортного модуля. Тип документа для ЕГАИС определяется не только внутренним содержимым XML-файла, но и адресом HTTP POST-запроса, на который этот файл отправляется. В именовании методов УТМ кроется частая ловушка:
ns:QueryFormBHistory./opt/in/QueryFormB, УТМ автоматически присваивает исходящему пакету транспортный заголовок DocType=[QueryFormB]. В результате парсер ЕГАИС пытается валидировать тело документа по XSD-схеме для обычной справки и бракует пакет.Для исправления проблемы необходимо проверить команду отправки HTTP-запроса и указать точный относительный путь:
// Корректный адрес для запроса истории движений по форме Б:
АдресРесурса = "/opt/in/QueryHistoryFormB";
// Ошибочный адрес (приведет к DocType=[QueryFormB]):
// АдресРесурса = "/opt/in/QueryFormB";
Посмотрим на частую ошибку формирования схемы. При ручном создании XML-дерева через объекты DOM нередко путают пространства имен для параметров запроса. В частности, ошибочно объявляют несуществующее пространство http://fsrar.ru/WEGAIS/QueryHistFormB вместо стандартного http://fsrar.ru/WEGAIS/QueryParameters.
Рассмотрим эталонный пример структуры XML-документа для запроса движений по форме Б:
<?xml version="1.0" encoding="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:qp="http://fsrar.ru/WEGAIS/QueryParameters">
<ns:Owner>
<ns:FSRAR_ID>020000149497</ns:FSRAR_ID>
</ns:Owner>
<ns:Document>
<ns:QueryFormBHistory>
<qp:Parameters>
<qp:Parameter>
<qp:Name>RFB</qp:Name>
<qp:Value>FB-000000176747601</qp:Value>
</qp:Parameter>
</qp:Parameters>
</ns:QueryFormBHistory>
</ns:Document>
</ns:Documents>
Выясним, как правильно реализовать этот механизм в коде 1С. Использование устаревших COM-объектов Microsoft.XMLDOM создает зависимость от операционной системы Windows. Рекомендуется использовать встроенные средства платформы 1С — объект ЗаписьXML.
Функция СформироватьXML_ЗапросИсторииФормыБ(ФСРАР_ИД, НомерСправкиБ)
ЗаписьXML = Новый ЗаписьXML;
ПараметрыЗаписи = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Ложь);
ЗаписьXML.УстановитьСтроку(ПараметрыЗаписи);
ЗаписьXML.ЗаписатьОбъявлениеXML();
// Корневой узел Documents с необходимыми пространствами имен
ЗаписьXML.ЗаписатьНачалоЭлемента("ns:Documents");
ЗаписьXML.ЗаписатьАтрибут("Version", "1.0");
ЗаписьXML.ЗаписатьАтрибут("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
ЗаписьXML.ЗаписатьАтрибут("xmlns:ns", "http://fsrar.ru/WEGAIS/WB_DOC_SINGLE_01");
ЗаписьXML.ЗаписатьАтрибут("xmlns:qp", "http://fsrar.ru/WEGAIS/QueryParameters");
// Владелец запроса (FSRAR_ID организации)
ЗаписьXML.ЗаписатьНачалоЭлемента("ns:Owner");
ЗаписьXML.ЗаписатьНачалоЭлемента("ns:FSRAR_ID");
ЗаписьXML.ЗаписатьТекст(СокрЛП(ФСРАР_ИД));
ЗаписьXML.ЗаписатьКонецЭлемента(); // ns:FSRAR_ID
ЗаписьXML.ЗаписатьКонецЭлемента(); // ns:Owner
// Тело документа
ЗаписьXML.ЗаписатьНачалоЭлемента("ns:Document");
ЗаписьXML.ЗаписатьНачалоЭлемента("ns:QueryFormBHistory");
ЗаписьXML.ЗаписатьНачалоЭлемента("qp:Parameters");
// Параметр RFB
ЗаписьXML.ЗаписатьНачалоЭлемента("qp:Parameter");
ЗаписьXML.ЗаписатьНачалоЭлемента("qp:Name");
ЗаписьXML.ЗаписатьТекст("RFB");
ЗаписьXML.ЗаписатьКонецЭлемента(); // qp:Name
ЗаписьXML.ЗаписатьНачалоЭлемента("qp:Value");
ЗаписьXML.ЗаписатьТекст(СокрЛП(НомерСправкиБ));
ЗаписьXML.ЗаписатьКонецЭлемента(); // qp:Value
ЗаписьXML.ЗаписатьКонецЭлемента(); // qp:Parameter
ЗаписьXML.ЗаписатьКонецЭлемента(); // qp:Parameters
ЗаписьXML.ЗаписатьКонецЭлемента(); // ns:QueryFormBHistory
ЗаписьXML.ЗаписатьКонецЭлемента(); // ns:Document
ЗаписьXML.ЗаписатьКонецЭлемента(); // ns:Documents
Возврат ЗаписьXML.Закрыть();
КонецФункции
Для передачи полученного файла в транспортный модуль воспользуемся объектами HTTPСоединение и HTTPЗапрос. Важно помнить, что УТМ принимает документы через составной запрос multipart/form-data с именем поля xml_file:
Процедура ОтправитьВУТМ(СерверУТМ, ПортУТМ, ИмяФайлаXML)
НТТР = Новый HTTPСоединение(СерверУТМ, ПортУТМ);
// Внимание на точный URL ресурса:
Ресурс = "/opt/in/QueryHistoryFormB";
// Подготовка заголовков multipart/form-data
Разделитель = "----" + СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", "");
Запрос = Новый HTTPЗапрос(Ресурс);
Запрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);
// Формирование тела запроса с передачей xml_file
// После успешной отправки УТМ вернет XML с внутренним идентификатором запроса
Ответ = НТТР.ОтправитьДляОбработки(Запрос);
Если Ответ.КодСостояния = 200 Тогда
// Обработка успешного ответа УТМ (получение URL с docId)
Иначе
ВызватьИсключение "Ошибка отправки в УТМ: " + Строка(Ответ.КодСостояния);
КонецЕсли;
КонецПроцедуры
Разберем практические правила работы с запросами истории справок Б, чтобы избежать блокировок со стороны контролирующей системы:
HistoryFormB также поступает не сразу, а по мере формирования выгрузки на сервере ФСРАР.HistoryFormB отображает только ту цепочку товародвижения (ТТН, акты списания, акты постановки на баланс), в которой организация с указанным FSRAR_ID являлась прямым грузоотправителем или грузополучателем. Движения между сторонними участниками рынка до момента поставки на ваш склад будут скрыты.