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

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

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

Сообщение finsoftrz » 07 Август 2018, 9:52

Глянул сегодня с утра, что за зверь. В общем, обмен 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), который парсим. Его вид тоже описан в документации и зависит от запроса. При наличии опыта работы с Егаис все выглядит очень похоже, объектная обвязка идентичная.
Рязань решает.

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

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

Сообщение Игорь Столяров » 07 Август 2018, 13:42

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

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

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

Сообщение finsoftrz » 07 Август 2018, 14:02

Запрос 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>')
Рязань решает.

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

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

Сообщение Игорь Столяров » 07 Август 2018, 14:04

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

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

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

Сообщение finsoftrz » 07 Август 2018, 15:10

У меня работа с Егаис через curl.exe, поскольку там все примеры в доке на нем. Ну и подумал, зачем зоопарк плодить со всеми этими делами, пусть будет curl.exe. Другие тоже, видимо, после Егаиса его задействуют. Хотя сами меркурианцы рекомендуют soapUI.
Рязань решает.

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

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

Сообщение Игорь Столяров » 07 Август 2018, 16:21

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

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

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

Сообщение Yufil » 08 Август 2018, 18:53

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

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

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

Сообщение finsoftrz » 26 Август 2018, 16:42

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

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

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)
  
Рязань решает.

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

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

Сообщение finsoftrz » 08 Сентябрь 2018, 13:49

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

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

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

Сообщение finsoftrz » 25 Сентябрь 2018, 9:16

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

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

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

Сообщение finsoftrz » 27 Декабрь 2018, 18:18

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

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

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

Сообщение Игорь Столяров » 14 Июнь 2019, 18:11

На основе кода Юрия, сделал простой парсер 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
✯ Ветеран ✯
Сообщения: 1272
Зарегистрирован: 06 Ноябрь 2014, 12:48

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

Сообщение finsoftrz » 14 Июнь 2019, 21:08

Игорь, получилось список стран прочитать?
Рязань решает.

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

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

Сообщение Игорь Столяров » 14 Июнь 2019, 21:36

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

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

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

Сообщение finsoftrz » 14 Июнь 2019, 22:11

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

Для рабочего контура доступ к адресам (икар):
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>')
Рязань решает.

Ответить