Работа с Меркурием

Сканеры, кассы, ККТ и т.д.
Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Глянул сегодня с утра, что за зверь. В общем, обмен xml-файлами с их сервисами. Интерфейс можно делать по разному, в том числе через curl.exe, по аналогии с Егаис. Вот такой пример для получения ответа работает:

Код: Выделить всё

'curl.exe -d @"' & 'req.xml'  & '" -H "Content-Type: text/xml; charset=utf-8" -u ' & 'user' & ':' & 'pswd' & ' https://api2.vetrf.ru:8002/platform/services/2.0/EnterpriseService' & ' -o ' & 'resp.xml'
Файлик req.xml делаем по их документации в зависимости от запроса. Он должен быть в кодировке utf8. В ответ получаем resp.xml (тоже в utf8), который парсим. Его вид тоже описан в документации и зависит от запроса. При наличии опыта работы с Егаис все выглядит очень похоже, объектная обвязка идентичная.
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 4849
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-ДоМу

Работа с Меркурием

Сообщение Игорь Столяров »

Классно ! :) А я пробовал, где-то пол-года назад, подключиться через LibCurl, но чего-то не задалось …
А можно просить какой-нибудь заведомо правильный req.xml ? Я бы тоже попробовал что-нибудь поиметь с Меркурия. :)
«V» значит Вендетта !

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Запрос 3 первых организаций с фрагментом в названии. Дальше я тоже пока не дошел... :-)

Код: Выделить всё

  fsFileMakerL.AddOutLine('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://api.vetrf.ru/schema/cdm/registry/ws-definitions/v2" xmlns:bs="http://api.vetrf.ru/schema/cdm/base" xmlns:dt="http://api.vetrf.ru/schema/cdm/dictionary/v2">')
  fsFileMakerL.AddOutLine('   <soapenv:Header/>')
  fsFileMakerL.AddOutLine('   <soapenv:Body>')
  fsFileMakerL.AddOutLine('      <ws:getRussianEnterpriseListRequest>')
  fsFileMakerL.AddOutLine('         <bs:listOptions>')
  fsFileMakerL.AddOutLine('            <bs:count>3</bs:count>')
  fsFileMakerL.AddOutLine('            <bs:offset>0</bs:offset>')
  fsFileMakerL.AddOutLine('         </bs:listOptions>')
  fsFileMakerL.AddOutLine('         <dt:enterprise>')
  fsFileMakerL.AddOutLine('            <dt:name>"ПЕРЕСВЕТ"</dt:name>')
  fsFileMakerL.AddOutLine('         </dt:enterprise>')
  fsFileMakerL.AddOutLine('      </ws:getRussianEnterpriseListRequest>')
  fsFileMakerL.AddOutLine('   </soapenv:Body>')
  fsFileMakerL.AddOutLine('</soapenv:Envelope>')
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 4849
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-ДоМу

Работа с Меркурием

Сообщение Игорь Столяров »

Спасибо ! Для теста - подойдёт. :)
Я вот нечто похожее пробовал запихнуть туда сразу через LibCurl ...
«V» значит Вендетта !

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

У меня работа с Егаис через curl.exe, поскольку там все примеры в доке на нем. Ну и подумал, зачем зоопарк плодить со всеми этими делами, пусть будет curl.exe. Другие тоже, видимо, после Егаиса его задействуют. Хотя сами меркурианцы рекомендуют soapUI.
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 4849
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-ДоМу

Работа с Меркурием

Сообщение Игорь Столяров »

finsoftrz писал(а):
07 Август 2018, 15:10
Хотя сами меркурианцы рекомендуют soapUI
Это не беда. Плохо, что они (как я понял) не довели сей чудный сервис до ума и не прикрутили к нему вариант обмена в JSON.
В Clarion JSON более дружелюбен, чем XML ...
«V» значит Вендетта !

Yufil
Ветеран движения
Сообщения: 1244
Зарегистрирован: 16 Май 2006, 13:34
Контактная информация:

Работа с Меркурием

Сообщение Yufil »

У себя среди старых программ нашёл фрагмент с загрузкой адресных данных через SOAP, и парсинг результатов, используя SOAPUi и самопальные модули Chttp и Cstr
https://mega.nz/#!0l5mCYaZ!lK3UXugElajL ... pOOcyTm8HU , там рутинка soaprequest ( стр.213) . Если интересно, попробую объяснить, что там творится и найду весь антураж ( классы и всё такое )...

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Вот еще пример запроса всех стран.

Код: Выделить всё

sendRequest_r  routine   !послать запрос
   DATA

lor:queue queue, pre()
lor:name   string(128), name('dt:name')
lor:uuid    string(80), name('bs:uuid')
lor:guid    string(80), name('bs:guid')
  .

lor:err  byte

   CODE

  Loc:NameTmp=GetNameTmp(FsAccess:ActiveUserDir,'xml',0)
  Loc:NameOutTmp=GetNameTmp(FsAccess:ActiveUserDir,'xml',1)

  fsFileMakerL.init(Loc:NameTmp)

  fsFileMakerL.AddOutLine('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ws="http://api.vetrf.ru/schema/cdm/registry/ws-definitions/v2" xmlns:base="http://api.vetrf.ru/schema/cdm/base">')
  fsFileMakerL.AddOutLine('  <soapenv:Header/>')
  fsFileMakerL.AddOutLine('  <soapenv:Body>')
  fsFileMakerL.AddOutLine('    <ws:getAllCountryListRequest>')
  fsFileMakerL.AddOutLine('      <base:listOptions>')
  fsFileMakerL.AddOutLine('        <base:count>10</base:count>')
  fsFileMakerL.AddOutLine('        <base:offset>0</base:offset>')
  fsFileMakerL.AddOutLine('      </base:listOptions>')
  fsFileMakerL.AddOutLine('    </ws:getAllCountryListRequest>')
  fsFileMakerL.AddOutLine('  </soapenv:Body>')
  fsFileMakerL.AddOutLine('</soapenv:Envelope>')

  if fsFileMakerL.MakeFile(1)=0
     fsFileMakerL.kill
     exit
  .
  fsFileMakerL.kill
  if fsCurlL.StartProcess('curl\curl.exe -d @"' & clip(Loc:NameTmp)  & '" -H "Content-Type: text/xml; charset=utf-8" -u ' & clip('peresvet-180801') & ':' & clip('b6WHf9r3') & clip(' https://api2.vetrf.ru:8002/platform/services/2.0/IkarService') & ' -o ' & clip(Loc:NameOutTmp)).

  if ~exists(Loc:NameOutTmp)
     FsMessagePr('Ошибка отправки запроса!')
     exit
  .

  lor:err=0
  Loc:NameTmp=Loc:NameOutTmp
  Loc:NameVbsTmp=GetNameTmp(FsAccess:ActiveUserDir,'vbs',0)
  Loc:NameOutTmp=GetNameTmp(FsAccess:ActiveUserDir,'txt',0)

  !читаем ответ
  fsXmlPar.init(Loc:NameTmp,Loc:NameVbsTmp,Loc:NameOutTmp)
  fsXmlPar.LoadQueue('dt:country','lor:queue',lor:queue)
  fsXmlPar.MakeScript(1)
  if fsXmlPar.ErrorCode<>0
     FsMessagePr('Ошибка! ' & clip(fsXmlPar.ErrorMessage))
     lor:err=1
  .
  fsXmlPar.kill

  if lor:err=0 and records(lor:queue)<>0
     remove(Loc:NameTmp)
     remove(Loc:NameOutTmp)
     fsViewQueue('',lor:queue)
  elsif lor:err=0
     run('notepad.exe ' & Loc:NameTmp)
     run('notepad.exe ' & Loc:NameOutTmp)
  .

  free(lor:queue)
  
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Посмотрел подробнее эту тему. В общем, принципы взаимодействия похожи на Егаис и несколько проще (нет локальной инфраструктуры со всеми вытекающими). Создаем xml нужного вида (копируем образец из вики), применяем в нем идентификаторы и логины, полученные в Россельхознадзоре. Шлем на один из сервисов. Их несколько, в зависимости от типа запроса. В ответ получаем в виде xml либо сразу нужную информацию (например, всякие справочники), либо идентификатор запроса (для более сложных операций). Во втором случае через некоторое время шлем запрос на получение результата, указав в нем идентификатор, присвоенный основному запросу. Получаем результат. Для розницы несложно, там только гасить всд требуется. Для опта и, тем более, производства надо вникать в разные тонкости бизнес-процессов глазами меркурианцев...
Технически в словаре несколько структур (для розницы 4 таблицы насчитал) и dll.
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Попробовал вчера получение всд в рабочем контуре. В общем, система пока явно не справляется с нагрузкой. Запрос проходит с десятой попытки, иначе вываливается отказ по неизвестной причине. Поглядел на форумах, народ стонет, начиная с июля. Большинство используют веб интерфейс, который работает более стабильно. А в шлюз все ставят на автомат и долбят его запросами через определенные промежутки времени, пока запрос наконец не пройдет...
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Дошли руки до гашения ВСД. Обмен с сервером Ветис через curl.exe. Долбим несколько попыток на получение списка непогашенных ВСД, если сервер перегружен и возвращает ошибку.
Основная проблема в том, что информация в запросе на гашение сверяется сервером с содержимым исходного ВСД. Это сопоставление не "тэг в тэг" и не документировано. Приходится уточнять по мере тестирования. Для этого сохраняем последний полученный xml со списком непогашенных ВСД и xml последнего отправленного запроса на гашения. В случае ошибки смотрим их содержание и пытаемся понять... Один из примеров. В запросе на гашение присутствует информация о номере транспорта. Берем ее из аналогичного тэга в ВСД. Но если в ВСД есть информация о маршруте и в нем указан второй транспорт после перегрузки, то передавать в запросе на гашение надо номер этого второго транспорта, хотя он в других тэгах...
Вложения
vetis.jpg
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 4849
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-ДоМу

Работа с Меркурием

Сообщение Игорь Столяров »

На основе кода Юрия, сделал простой парсер XML ответов под Меркурий.
Вроде бы тащит всё - буду благодарен, если есть желающие присоединится к проверке.

Код: Выделить всё

LoadQueueFromXML     PROCEDURE  (*IDynStr xBuffer_,*Queue xMyQueue_, String xTagRow_)

Loc:XMLCount         LONG(1)
Loc:XMLDoc           &Document,AUTO
Loc:RetValue         LONG(0)  ! Возвращает кол-во добавленных строк в xMyQueue_
Loc:Value            CSTRING(256)
Loc:FlagRecord       BYTE(False)
Loc:TagParent        CSTRING(81)
Loc:TagName          CSTRING(81)
Loc:Column           LONG
Loc:Field            ANY
Loc:AttrIndex        LONG
Loc:FlagData         BYTE(False)

Loc:XMLList  Queue(DOMQueue)
             end
MyParentNode &node,auto
nnm          &NamedNodeMap,auto
ANode        &Node,Auto

  CODE
  Loc:XMLDoc &= XMLStringToDOM(xBuffer_.Str())

  If ~(Loc:XMLDoc &= NULL)
     FillDOMQueue(Loc:XMLDoc,Loc:XMLList)

     !ViewXML(Loc:XMLDoc)

     Loop While(Loc:XMLCount <= Records(Loc:XMLList))
       Get(Loc:XMLList,Loc:XMLCount)

       Loc:TagName = Lower(Loc:XMLList.Node.GetNodeName())  ! Сразу получаем имя тега - он нужен для поиска начала строки

       If Loc:FlagRecord  ! Если ведётся запись строки

          MyParentNode &= Loc:XMLList.node.GetParentNode()  ! Родительский тег
          If (MyParentNode &= NULL) then Message('Ошибка ParentNode !').

          Loc:TagParent = Lower(MyParentNode.GetNodeName())

          ! --- Получаем данные тега из следующей строки

          Get(Loc:XMLList,Loc:XMLCount + 1)
          If ~ErrorCode() and (Loc:XMLList.Node.GetNodeName() = '#text')

             Loc:XMLCount += 1

             ! --- Поиск поля в очереди

             Loc:Column = 1
             Loop While(Who(xMyQueue_,Loc:Column) <> '')

               If Lower(Who(xMyQueue_,Loc:Column)) = (Loc:TagParent & '!' & Loc:TagName)

                  Loc:Field &= What(xMyQueue_,Loc:Column)
                  If ~(Loc:Field &= NULL)

                                    ! Что бы не конвертировать из UTF-8 в ANSI цифры и GUID
                     If (IsString(Loc:Field) = False) Or (Size(What(xMyQueue_,Loc:Column)) = 36)
                        Loc:Value = Loc:XMLList.Node.GetNodeValue() 
                     else           ! Перекодировать строку UTF-8 в ANSI
                        Loc:Value = UTF8toANSI(Loc:XMLList.Node.GetNodeValue())
                     end

                     If    Lower(Loc:Value) = 'true'
                        Loc:Field = True
                     elsIf Lower(Loc:Value) = 'false'
                        Loc:Field = False
                     else
                        Loc:Field = Loc:Value
                     end

                     Loc:FlagData = True  ! В записи есть данные
                  end
               end

               Loc:Column += 1
             end
          end
       end

       ! --- Поиск тега начала строки с данными
       If Loc:TagName = Lower(xTagRow_)

          If Loc:FlagRecord   ! Если велась запись
             If Loc:FlagData  ! Если в буфере есть данные
                Add(xMyQueue_)         ! Добавить запись
                If ~ErrorCode() then Loc:RetValue += 1.
             end
          else
             Loc:FlagRecord = True  ! Начать запись
          end
          Clear(xMyQueue_)      ! Очистить буфер записи
          Loc:FlagData = False  ! В буфере нет данных
       end

       Loc:XMLCount += 1
     end

     If Loc:FlagData  ! Если в буфере есть данные - добавить последнюю запись
        Add(xMyQueue_)
        If ~ErrorCode() then Loc:RetValue += 1.
     end

     Free(Loc:XMLList)
     Loc:XMLDoc.Release()
  end

  Return(Loc:RetValue)
Ну и на примере, опубликованного здесь ранее, получения справочника стран:

Код: Выделить всё

Loc:MyCountry  Queue  ! Список стран (УКАЗЫВЕТСЯ ИМЯ ПОЛЯ С РОДИТЕЛЬСКИМ ТЕГОМ, Т.К. В XML ИМЕНА НЕ УНИКАЛЬНЫ !!!)
UUID             String(36),   Name('dt:country!bs:uuid')         ! Идентификатор версии
GUID             String(36),   Name('dt:country!bs:guid')         ! Глобальный идентификатор страны в реестре системы Икар
Status           Short,        Name('dt:country!bs:status')       ! Статус записи
Name             CString(129), Name('dt:country!dt:name')         ! Название страны (например, Белоруссия)
FullName         CString(256), Name('dt:country!dt:fullName')     ! Полное название страны (например, Республика Беларусь)
EnglishName      CString(129), Name('dt:country!dt:englishName')  ! Название страны на английском языке
Code             String(2),    Name('dt:country!dt:code')         ! Двухбуквенный код страны в соответствии со стандартом ISO 3166-1 alpha-2
Code3            String(3),    Name('dt:country!dt:code3')        ! Трёхбуквенный код страны в соответствии со стандартом ISO 3166-1 alpha-3
               end
               
Loc:Buffer  &IDynStr
RLoad  Long
               
  Code
  
  ! Выполнили запрос и получили текст XML ответа в Loc:Buffer (см. LibCURL)
  
  RLoad = LoadQueueFromXML(Loc:Buffer,Loc:MyCountry,'dt:country')  ! Указываем тег строки с данными
  Message('Загружено стран: ' & RLoad)  ! Ну а список стран - в Loc:MyCountry :)
«V» значит Вендетта !

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Игорь, получилось список стран прочитать?
C6/C11, ШВС, tps/btrieve.

Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 4849
Зарегистрирован: 07 Июль 2005, 9:19
Откуда: г. Ростов-на-ДоМу

Работа с Меркурием

Сообщение Игорь Столяров »

finsoftrz писал(а):
14 Июнь 2019, 21:08
Игорь, получилось список стран прочитать?
Спасибо, да, конечно. Страны, ед. измерения и т.д. - всё грузится.
Конкретно со странами - был затык из-за неправильного тега в шапке запроса из примера на сайте Ветис.API.
Взял шапку с Вашего примера в этой ветке форума - всё загрузилось с полутыка … :)
«V» значит Вендетта !

Аватара пользователя
finsoftrz
✯ Ветеран ✯
Сообщения: 2156
Зарегистрирован: 06 Ноябрь 2014, 12:48

Работа с Меркурием

Сообщение finsoftrz »

Да, я тоже разобрался. Тот вариант, который я посылал Вам, был для тестового контура. Надо правильно указать адрес сервиса и пространство имен.

Для рабочего контура доступ к адресам (икар):
https://api.vetrf.ru/platform/services/2.0/IkarService

Запрос стран для рабочего контура (важно правильно указать адреса в 2-3 строках):

Код: Выделить всё

  fsFileMakerL.AddOutLine('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"')
  fsFileMakerL.AddOutLine('                  xmlns:ws="http://api.vetrf.ru/schema/cdm/registry/ws-definitions/v2"')
  fsFileMakerL.AddOutLine('                  xmlns:base="http://api.vetrf.ru/schema/cdm/base">')
  fsFileMakerL.AddOutLine('  <soapenv:Header/>')
  fsFileMakerL.AddOutLine('  <soapenv:Body>')
  fsFileMakerL.AddOutLine('    <ws:getAllCountryListRequest>')
  fsFileMakerL.AddOutLine('      <base:listOptions>')
  fsFileMakerL.AddOutLine('        <base:count>100</base:count>')
  fsFileMakerL.AddOutLine('        <base:offset>' & Loc:Sm & '</base:offset>')
  fsFileMakerL.AddOutLine('      </base:listOptions>')
  fsFileMakerL.AddOutLine('    </ws:getAllCountryListRequest>')
  fsFileMakerL.AddOutLine('  </soapenv:Body>')
  fsFileMakerL.AddOutLine('</soapenv:Envelope>')
C6/C11, ШВС, tps/btrieve.

Ответить