:: Visual Foxpro, Foxpro for DOS
SOAP HRESULT=0x80020005 Несовпадение типов
vic119

Сообщений: 3
Дата регистрации: 10.12.2014
Пытаюсь реализовать проверку контрагента через веб сервис на сайте налоговой службы (http://npchk.nalog.ru/)
При вызове метода проверки получаю ошибку Client: Type conversion failure for element NdsRequest HRESULT=0x80020005 Несовпадение типов.
Пожалуйста, намекните в чём может быть проблема?
*--------------------------------------------

CLEAR ALL
SET TALK OFF
CLEAR

local loSoapClient,;
loXMLDoc As MSXML2.DOMDocument,;
loXMLNodes As MSXML2.IXMLDOMNodeList,;
loResult As MSXML2.IXMLDOMNodeList

* создаем объект на основе SOAP 3.0
loSoapClient=CREATEOBJECT("MSSoap.SoapClient30")
* URL Web Service
loSoapClient.MSSoapInit("http://npchk.nalog.ru/FNSNDSCAWS?wsdl", "FNSNDSCAWS", "FNSNDSCAWS_Port")
* Веб служба реализует метод NdsRequest() возвращает XMLDOMNodeList
* принимает параметр типа XMLDOMNodeList
* XSD-схема запроса сведений:
* npchk.nalog.ru

* Создаём объект DOMDocument
loXMLDoc = CreateObject("MSXML2.DOMDocument")
loXMLDoc.async= .F.

* Загружаем XML в DOMDocument
if !loXMLDoc.LoadXML('<?xml version="1.0" encoding="windows-1251"?><NdsRequest><NP>INN="6441012385" KPP="583601001" DT="08.12.2014"</NP></NdsRequest>')
?loXMLDoc.parseError.errorCode ,loXMLDoc.parseError.reason
return
ENDIF

* Получаем объект на основе IXMLDOMNodeList, включающий все элементы
loXMLNodes = loXMLDoc.getElementsByTagName('*') && msdn.microsoft.com

* Вызываем метод NdsRequest
TRY
loResult = loSoapClient.NdsRequest(loXMLNodes)
CATCH TO loexception
? loexception.MESSAGE
? loexception.ERRORNO
? loexception.details
ENDTRY
Ratings: 0 negative/0 positive
Re: SOAP HRESULT=0x80020005 Несовпадение типов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
vic119
Пожалуйста, намекните в чём может быть проблема?
В использовании данным сервисом UDT (User Defined Types). Фокс через SOAP Toolkit более-менее работает с этим лишь "на приём" (сложный тип как возвращаемое методом сервиса значение). На передачу - хоть некоторые (вполне авторитетные) источники и пишут про такой вариант, оно не работает...
Раз уж ты всё одно не пользуешь фоксовый класс-обёртку пойди ещё дальше, и вообще откажись от SOAP Toolkit - формируй вручную нужного вида HTTP сообщения (это по сути просто XML-и) и посылай через тот же MSXML2.XMLHTTP - примеры поищи были на форуме. Всяко быстрее будет
Ещё можно нарисовать на каком дотнете COM видимую сборку - обёртку. Т.е. она будет работать с сервисом (дотнет не использует SOAP Toolkit и с "хиртыми типами" по идее таких проблем не имеет), а фоксу отдавать (и принимать параметры) уже всё в самом простом, "разжёванном" виде. Хотя для столь примитивной задачи (всего 1 метод и 1 запрос по сути) это будет как из пушки по воробьям.

P.S. Ты, кстати, неправильно прописал сериализованный вид этого самого объекта. Согласно схеме он должен выглядеть как
<NdsRequest><NP INN="6441012385" KPP="583601001" DT="08.12.2014"/></NdsRequest>
Т.е. использовать атрибуты самого узла NP, а не какой-то странный "текст" внутри этого узла. Но основная проблема, конечно, не в этом.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: SOAP HRESULT=0x80020005 Несовпадение типов
vic119

Сообщений: 3
Дата регистрации: 10.12.2014
Спасибо, буду разбираться.
Ratings: 0 negative/0 positive
Re: SOAP HRESULT=0x80020005 Несовпадение типов
vic119

Сообщений: 3
Дата регистрации: 10.12.2014
Спасибо Igor Korolyov!
* ----------------------------------------------------
LOCAL lcRequest, loHTTP, lcResponse

TEXT TO lcRequest TEXTMERGE NOSHOW
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<NdsRequest xmlns="http://ws.unisoft/FNSNDSCAWS/Request">
<NP INN="6441012385" KPP="583601001" DT="08.12.2014" />
<NP INN="5807000079" KPP="580701001" DT="08.12.2014" />
<NP INN="583601113129" DT="08.12.2014" />
</NdsRequest>
</soap:Body>
</soap:Envelope>
ENDTEXT

loHTTP= CREATEOBJECT("Msxml2.XMLHTTP.4.0")
With loHTTP
.Open("POST", 'http://npchk.nalog.ru/FNSNDSCAWS?wsdl', .F.)
.setRequestHeader("Content-Type", "text/xml; charset=utf-8")
.setRequestHeader("Content-length", LTRIM(STR(LEN(lcRequest))))
.Send(lcRequest)

Do While .readyState<>4
DOEVENTS [FORCE]
Enddo
lcResponse=.responsetext
Endwith

lcResponse = STREXTRACT(lcResponse,'<S:Body>', '</S:Body>')
CREATE CURSOR res (INN char(12), KPP char(9),DT char(10), State char(1))
XMLTOCURSOR(lcResponse,'res',8192)
brow
Ratings: 0 negative/1 positive
Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev
Автор

Сообщений: 3695
Откуда: Ярославль
Дата регистрации: 28.09.2002
* ==============================================================================================================================
* Автор: vic119, Alex Roublev (доработка), Igor Korolyov (верификация, доработка), SSA (верификация, доработка)
* Дата: 10.12.2014, 27.04.2017
* Описание: статус ИНН/КПП на дату
* проверка контрагента через SOAP-интерфейс на сайте Федеральной налоговой службы https://npchk.nalog.ru/
* Документация: https://npchk.nalog.ru/ws2.doc
*
* Примечание: на 27.04.2017 на сайте ФНС сервис работает в тестовом режиме
*
* Доп. информация: Использование WEB сервиса для проверки ИНН/КПП контрагента: http://infostart.ru/public/439808/
* Обсуждение на форуме Foxclub: https://forum.foxclub.ru/read.php?29,645686
*
* Библиотека: используется библиотека Microsoft XML Core Service версия 6 SP3 (msxml6.dll)
* альтернатива - MSXML версия 4 SP2 (msxml4.dll) с вызовом объекта класса Msxml2.XMLHTTP.4.0
* описание версий https://support.microsoft.com/ru-ru/help/269238/list-of-microsoft-xml-parser-msxml-versions
*
* Параметры:
* tcInn - ИНН контрагента
* tcKpp - КПП контрагента
* tcDate - дата, на которую проверяем в строковом формате 'дд.мм.гггг'
*
* Возврат: строка с описанием статуса проверки
* =============================================================================================================================
#DEFINE TIME_LIMIT 30 && лимит времени при обращении к сайту ФНС (для выхода из цикла)
CLEAR
LOCAL lcInn AS STRING, lcKpp AS STRING, ldDate AS DATE
lcInn = '6441012385'
lcKpp = '583601001'
ldDate = {^2014.12.08}
LOCAL ARRAY vaState(1,2)
vaState(1,1) = '-1'
vaState(1,2) = ''
Check_INN_KPP(m.lcInn, m.lcKpp, m.ldDate, @vaState)
?Check_Status_INN_KPP(@vaState)
FUNCTION Check_INN_KPP()
LPARAMETERS tcInn AS STRING, tcKpp AS STRING, tdDate AS DATE, vaState
LOCAL ;
loHttp AS 'Msxml2.XMLHTTP.6.0', ; && класс объекта для работы с SOAP-интерфейсом на сайте ФНС
loError AS OBJECT, ; && объект для записи сообщения об ошибке
lcRequest AS STRING, ; && xml-данные для запроса статуса контрагента
ltTimeout AS DATETIME && время перед началом выполнения опроса сайта в цикле
****************************************
* проверка корректности ввода параметров
DO CASE
CASE PCOUNT() < 3
tdDate = DATE()
CASE PCOUNT() < 2
tcKpp = ''
CASE PCOUNT() < 1
tcInn = ''
ENDCASE
DO CASE
CASE EMPTY(tcInn)
vaState(1,2) = 'не заполнен номер ИНН.'
RETURN
CASE TYPE('tcInn') <> 'C' OR LEN(CHRTRAN(tcInn, "0123456789", "")) > 0
vaState(1,2) = 'некорректно заполнен номер ИНН.'
RETURN
ENDCASE
DO CASE
CASE LEN(tcInn) = 10 && юр. лицо
DO CASE
CASE EMPTY(tcKpp)
vaState(1,2) = 'не заполнен обязательный для юр. лица номер КПП.'
RETURN
CASE TYPE('tcKpp') <> 'C' OR LEN(tcKpp) <> 9 OR LEN(CHRTRAN(tcKpp, "0123456789", "")) > 0
vaState(1,2) = 'некорректно заполнен обязательный для юр. лица номер КПП.'
RETURN
ENDCASE
CASE LEN(tcInn) = 12 && индивид. предприниматель
IF !EMPTY(tcKpp)
vaState(1,2) = 'номер КПП не указывается для ИП.'
RETURN
ENDIF
ENDCASE
DO CASE
CASE EMPTY(tdDate)
vaState(1,2) = 'не заполнена дата.'
RETURN
CASE TYPE('tdDate') <> 'D'
vaState(1,2) = 'некорректно заполнена дата.'
RETURN
ENDCASE
****************************************
TEXT TO lcRequest TEXTMERGE PRETEXT 1 + 2 NOSHOW
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:req="http://ws.unisoft/FNSNDSCAWS2/Request">
<soapenv:Header/>
<soapenv:Body>
<req:NdsRequest2>
<req:NP INN="<<tcInn>>" KPP="<<tcKpp>>" DT="<<Transform(Day(tdDate), '@L 99')>>.<<Transform(Month(tdDate), '@L 99')>>.<<Transform(Year(tdDate), '9999')>>"/>
</req:NdsRequest2>
</soapenv:Body>
</soapenv:Envelope>
ENDTEXT
TRY
loHttp = CREATEOBJECT('Msxml2.XMLHTTP.6.0')
WITH m.loHttp
.OPEN('POST', 'http://npchk.nalog.ru/FNSNDSCAWS_2?wsdl', .F.)
.setRequestHeader('Content-Type', 'text/xml; charset=utf-8')
.setRequestHeader('Content-length', TRANSFORM(LEN(lcRequest)))
.Send(m.lcRequest)
ltTimeout = DATETIME() + TIME_LIMIT
* опрашиваем данные до тех пор, пока не будет получен ответ или не исчерпается лимит времени
DO WHILE .ReadyState <> 4
DOEVENTS FORCE
IF DATETIME() > m.ltTimeout
EXIT
ENDIF
INKEY(0.5)
ENDDO
IF .STATUS = 200 && ответ был получен
WITH .responseXML
.setProperty('SelectionNamespaces', 'xmlns:rsp="http://ws.unisoft/FNSNDSCAWS2/Response"')
vaState(1,1) = .selectSingleNode("//rsp:NdsResponse2/rsp:NP/@State").nodeValue && статус контрагента
ENDWITH
ELSE
vaState(1,2) = 'ответ не получен, код ' + TRANSFORM(.STATUS) + ', ' + .StatusText + '.'
ENDIF
ENDWITH
CATCH TO loError
vaState(1,2) = 'Cтрока ' + TRANSFORM(loError.LINENO) + ', ' + loError.MESSAGE
ENDTRY
ENDFUNC
FUNCTION Check_Status_INN_KPP()
LPARAMETERS vaState
LOCAL lnState AS INTEGER, lcError AS STRING
lnState = CAST(vaState(1, 1) AS I)
lcError = vaState(1, 2)
RETURN ICASE ;
(;
m.lnState = -1, 'Данные контрагента не обработаны' + IIF(!EMPTY(lcError), ': ' + lcError, ''), ;
m.lnState = 0, 'Налогоплательщик зарегистрирован в ЕГРН и имел статус действующего в указанную дату', ;
m.lnState = 1, 'Налогоплательщик зарегистрирован в ЕГРН, но не имел статус действующего в указанную дату', ;
m.lnState = 2, 'Налогоплательщик зарегистрирован в ЕГРН', ;
m.lnState = 3, 'Налогоплательщик с указанным ИНН зарегистрирован в ЕГРН, КПП не соответствует ИНН или не указан', ;
m.lnState = 4, 'Налогоплательщик с указанным ИНН не зарегистрирован в ЕГРН', ;
m.lnState = 5, 'Некорректный ИНН', ;
m.lnState = 6, 'Недопустимое количество символов ИНН', ;
m.lnState = 7, 'Недопустимое количество символов КПП', ;
m.lnState = 8, 'Недопустимые символы в ИНН', ;
m.lnState = 9, 'Недопустимые символы в КПП', ;
m.lnState = 10, 'КПП не должен использоваться при проверке ИП', ;
m.lnState = 11, 'Некорректный формат даты', ;
m.lnState = 12, 'Некорректная дата (ранее 01.01.1991 или позднее текущей даты)', ;
'Сатус контрагента не определен (' + TRANSFORM(m.lnState) + ')' ;
)
ENDFUNC


------------------
И волки сыты, и овцы целы, и пастуху - вечная память...




Исправлено 3 раз(а). Последнее : Alex Roublev, 28.04.17 17:39
Ratings: 0 negative/1 positive
Re: SOAP HRESULT=0x80020005 Несовпадение типов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Чисто шоб побухтеть:

1) Дату лучше как дату в функцию передавать, и там уже преобразовывать в нужный строковый формат (это удобство пользования функцией).
2) Минимальные проверки корректности параметров (тупо на пустоту числострок, на их тип, на "нецифры" в строках, м.б. на размер - я не в курсе это фиксированные величины или нет в РФ, на диапазон для даты) на входе - чтобы не напрягать сервер заведомо некорректным запросом. Всё ж обращение к веб-ресурсу это "дорогая" операция по сравнению с примитивным EMPTY(m.tcInn) или даже чуть более сложном LEN(CHRTRAN(m.tcInn, "0123456789", "")) > 0
3) LOCAL loHttp AS OBJECT 'Msxml2.XMLHTTP.6.0'
4) Для извлечения одного лишь state из ответа не нужны курсоры. Прямо из loHTTP.ResponseXML XPath-запросом его и брать. Или даже дубовым STREXTRACT-ом из .ResponseText (но это таки "неаккуратненько")
5) Таймаут бы добавить в цикл (при том с #DEFINE константой для его величины), и апи Sleep(100) или хоть какой Inkey(0.1) - чуток разгрузить систему пока ждём ответ.
6) m.-очек не хватает, небезопасно
7) Я бы отделил Check_INN_KPP(...) AS Number от Decode_Check_Result(tnState AS Number) AS String. Для программной обработки число всяко удобнее чем снова по строке определять статус.

Шапочка симпатичная (чувствуется основательность), и пример в начале радуют


------------------
WBR, Igor




Исправлено 1 раз(а). Последнее : Igor Korolyov, 27.04.17 14:34
Ratings: 0 negative/1 positive
Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev
Автор

Сообщений: 3695
Откуда: Ярославль
Дата регистрации: 28.09.2002
Игорь, большое спасибо за замечания - учёл. Пункт 7 я не понял, как разделить функцию.


------------------
И волки сыты, и овцы целы, и пастуху - вечная память...
Ratings: 0 negative/0 positive
Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
ssa

Сообщений: 12999
Откуда: Москва
Дата регистрации: 23.03.2005
Alex Roublev
Пункт 7 я не понял, как разделить функцию.
Пример на скорую руку с "неаккуратненьким" кодом вытаскивания результата:
Пример дополни кодом:
?Decode_Check_Result(Check_INN_KPP(lcInn, lcKpp))


------------------
Лень - это неосознанная мудрость.




Исправлено 1 раз(а). Последнее : ssa, 27.04.17 18:40
Ratings: 0 negative/0 positive
Re: SOAP HRESULT=0x80020005 Несовпадение типов
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
2 отдельные функции сделать - одна число вертает, вторая конвертит его в строку (чтобы не таскать всюду по проектам этот неслабый многобуквенный ICASE).
Можно и через дополнительный строковый параметр передаваемый по ссылке (т.е. 2 в одном - возвращает она число, а если передан ещё параметр в виде @дай_текст то в него и буквовки запишет). Чуть неудобно, но вполне работоспособно.

Ну раз поменял код, то теперь новая порция бухтения

1) Литерал даты не в кошерном виде {^2014.12.08}
2) На ошибку в параметрах лучше указывать при помощи ERROR 11, или ERROR "Моё название ошибки" а не MESAGEBOX-ом. Если это ошибка, конечно. Т.к. по логике работы процедуры вполне можно допускать абы что в параметрах, и тупо возвращать в том же статусе признак. Ну там -2, или -3 - это уже будет "особенность реализации". Т.е. мысль такая - если ошибка, то она должна быть видна как ошибка (и вызывающему коду тоже), если нормальное поведение, просто "особая ветка" - то никаких MESSAGEBOX-ов в принципе не должно быть Кстати, по хорошему такого рода процедура и не должна чего-то как-то MESSAGEBOX-ить (вернуть в качестве статуса, или даже сделать out/ссылочный параметр типа cErrorMessage куда прописывать "текст сообщения" - это можно, хотя и в использовании это не сверх-удобно). И даже wait window будет сомнительным. Т.к. мало ли где кто захочет применить такое - может у него нет _SCREEN-а и wait window будет невидим, или может это вообще програ работающая без окон - и тот же messagebox будет совсем некстати.
3) С m. теперь наоборот переборщил Они нужны лишь в "неоднозначных" местах - в "правых" частях выражений, например. В параметрах вызываемых функций. Для присвоения значения переменной, скажем, m. не нужна
4) SECONDS() небезопасный вариант для таймаута, т.к. "заворачивается" в полночь datetime() как-то получше выглядит. Да и "выход" там может быть форсированным, не через флаг и прогон всего последующего кода. Я бы написал в самом DO WHILE допусловие, а после цикла проверял .status - т.к. там может и не быть никакого ответа, даже если "приём ответа завершён". Статус "нормы" 2xx - ну это HTTP-ное...

5) Под разбором ответа я понимал нечто типа (без обработки ошибок "пустых" объектов и прочего):
loHttp.responseXML.setProperty('SelectionNamespaces', 'xmlns:rsp="http://ws.unisoft/FNSNDSCAWS2/Response"')
lcResult = loHttp.responseXML.selectSingleNode("//rsp:NdsResponse2/rsp:NP/@State").nodeValue
Там не нужно вынимать строку и снова её грузить в DOMDocument - она и так уже в него загружена в XMLHTTP объекте (по крайней мере для этого сайта).


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
ssa

Сообщений: 12999
Откуда: Москва
Дата регистрации: 23.03.2005
Alex Roublev
Игорь, большое спасибо за замечания - учёл.
И, как обычно, переборщил...
ИНН может быть или 10 (юрлица), или 12 (ИП и прочие физлица) символов.
У ИП КПП ОБЯЗАН быть пустой.
Messagebox'ы, как уже указано, совершенно лишние.
Третий параметр, как в моем коде, можно сделать "умолчальным" при отсутствии.
Описания кодов таки не пополнил. Возьми из моего кода.
Использовать cast для преобразования строки в число мне кажется стрельбой из пушки по воробьям.

Добавчик:
одна! строка
<req:NP INN="<<tcInn>>" KPP="<<tcKpp>>" DT="<<Transform(Day(tcDate), '@L 99')>>.<<Transform(Month(tcDate), '@L 99')>>.<<Transform(Year(tcDate), '9999')>>"/>
вместо всех плясок с макро и set


------------------
Лень - это неосознанная мудрость.




Исправлено 3 раз(а). Последнее : ssa, 27.04.17 20:12
Ratings: 0 negative/0 positive
Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev
Автор

Сообщений: 3695
Откуда: Ярославль
Дата регистрации: 28.09.2002
2 SSA:
Доработал. Но вызов функций у меня получился двумя строчками.


------------------
И волки сыты, и овцы целы, и пастуху - вечная память...
Ratings: 0 negative/0 positive
Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev
Автор

Сообщений: 3695
Откуда: Ярославль
Дата регистрации: 28.09.2002
2 Igor Korolyov:
Доработал. Синтаксис XPath-запроса оказался для меня незнакомым. Оно конечно для понимания нетрудно, но внове, опыта у меня недостаточно для спокойной работы с таким синтаксисом.


------------------
И волки сыты, и овцы целы, и пастуху - вечная память...
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 15 OlegA Rifat  (Гостей: 13)

© 2000-2024 Fox Club 
Яндекс.Метрика