for flooders
:: Главная :: Решения :: Статьи :: Сайт М. Дроздова :: Файловый архив :: Книга по VFP 9 :: Русский Help Online :: OFF-LINE Форум
   Лисоводы   всех   стран,  объединяйтесь !!!  

Список Форумов  :: Visual Foxpro, Foxpro for DOS
  

SOAP HRESULT=0x80020005 Несовпадение типов
vic119
Автор

Сообщений: 3
Дата: 10.12.14 16:13:52
Пытаюсь реализовать проверку контрагента через веб сервис на сайте налоговой службы (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

Сообщений: 34383
Дата: 10.12.14 18:17:19
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.14 20:13:05
Спасибо, буду разбираться.
Ratings: 0 negative/0 positive

Re: SOAP HRESULT=0x80020005 Несовпадение типов
vic119
Автор

Сообщений: 3
Дата: 11.12.14 16:55:11
Спасибо 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
Откуда: Ярославль
Дата: 27.04.17 12:32:02
  
 * ==============================================================================================================================  
 * Автор:            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


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




Исправлено: Alex Roublev, 28.04.17 17:39
Ratings: 0 negative/1 positive

Re: SOAP HRESULT=0x80020005 Несовпадение типов
Igor Korolyov

Сообщений: 34383
Дата: 27.04.17 14:33:56
Чисто шоб побухтеть:

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




Исправлено: Igor Korolyov, 27.04.17 14:34
Ratings: 0 negative/1 positive

Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev

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


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

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

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


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




Исправлено: ssa, 27.04.17 18:40
Ratings: 0 negative/0 positive

Re: SOAP HRESULT=0x80020005 Несовпадение типов
Igor Korolyov

Сообщений: 34383
Дата: 27.04.17 18:54:17
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

Сообщений: 12747
Откуда: Москва
Дата: 27.04.17 19:18:19
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


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




Исправлено: ssa, 27.04.17 20:12
Ratings: 0 negative/0 positive

Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev

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


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

Re: Проверка статуса контрагента (версия 2), проверяем ИНН/КПП на дату
Alex Roublev

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


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



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

On-line: 27 Sawradym  (Гостей: 26)

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