[WebMoney]XML-интерфейсы. X20

Discussion in 'Платежные системы' started by cockey, 7 Jul 2011.

  1. cockey

    cockey Banned

    Joined:
    16 Aug 2010
    Messages:
    40
    Likes Received:
    41
    Reputations:
    0
    Х20 - это новый XML-интерфейс WebMoney, который работает на той же платформе, что и WebMoney Merchant и интерфейс Х18. Он обращается к тому же серверу merchant.webmoney.ru и использует те же принципы аутентификации на базе SecretKey и торговых кошельков.

    Х20 позволяет принимать оплату БЕЗ отправки юзера на сайт merchant.webmoney.ru в браузере. Поэтому Х20 - это идеальный способ принимать WM-платежи там, где открытие и использование браузера нежелательно или невозможно. Например, в мобильных приложениях, Windows-программах.

    Тем не менее, для простоты и наглядности, мы будем демонстировать работу Х20 именно в браузере здесь. Программный код мы реализуем на PHP и включим соответствующую функцию _WMXML20() в библитеку XOWM, которую оВебМани.Ру давно поддерживает и дополняет.

    Использовать Х20 может любой торговец - владелец кошелька, настроенного на работу с WM Merchant. Статью о том, как работает этот сервис и как его использовать, можно прочесть здесь на owebmoney.ru.

    Как работает Х20

    Этот интерфейс - единственный из существующих, который работает 2-тактно. Иными словами, он совмещает в себе 2 запроса, которые нужно отправлять последовательно, при этом второй без первого существовать не может.

    Как работает Х20 детально описано на wiki. Читать обязательно! Однако, оВебМани.Ру для того и нужен, чтобы расжевать всё и разложить по полочкам :) Поэтому вернитесь сюда, когда дочитаете статью на wiki.

    Х20 работает так:

    1-й запрос, инициирование оплаты

    В 1-м запросе вы передаете:

    идентификатор плательщика - email, либо телефон, либо WMID;
    желаемый способ подтверждения платежа - SMS или USSD.
    другие параметры будущего платежа, например, сумму (это очень похоже на "форму запроса платежа" в классическом протоколе WM Merchant).

    Исходя из идентификатора юзера и желаемого способа подтверждения, сервер WebMoney определяет недостающую информацию. Например, если вы сообщили: "email юзера такой-то, а подтвердить оплату он хочет по SMS", то сервер WebMoney по email отыщет его WMID и телефон, после чего отправит на телефон SMS с кодом подтверждения.

    Независимо от того, какой способ подтверждения выбран - SMS или USSD - сервер WebMoney всегда дополнительно выписывает WM-счет. Юзер на выбор может либо подтвердить оплату по SMS\USSD, либо оплатить WM-счет в своем Кипере (а оплачивать счета - напомним - позволяет абсолютно любая версия Кипера: Классик, Лайт, Мини и Мобайл).

    При подтверждении по SMS\USSD сервер WebMoney списывает оплату с первого попавшегося кошелька юзера (если внутри его WMID есть несколько кошельков), на котором достаточно денег.

    Таблица ниже демонстрирует, что происходит на сервере WebMoney в зависимости от тех или иных входных данных:
    [​IMG]

    При нахождении WMID по email, WMID по телефону, телефона по WMID и т.п. - используются email и телефон, которые указаны в аттестате.

    Кроме того, X20 учитывает телефоны, зарегистрированные в WebMoney Чек. Если в запросе будет передан телефон, который зарегистрирован в WebMoney Чек и не зарегистрирован ни в одном аттестате, то оплата спишется именно с Чека. При этом, конечно, WM-счет выписан не будет, т.к. Чек не поддерживает оплату счетов.

    Если вы обратите внимание на последнюю строчку таблицы, то увидите, что Х20 позволяет просто выписать юзеру WM-счет, не отправляя SMS или USSD. А значит, Х20 - это простая и удобная замена совместному использованию интерфейсов X1 + X4. Мы говорим "простая", потому что в Х1 и Х4 обязательно нужно применять WMSigner для подписи запросов, а в X20 - не обязательно.

    В ответ на 1-й запрос WebMoney отдает вам уникальный номер счета.

    2-й запрос, подтверждение оплаты

    Вызов 2-го запроса разумно возложить на самого юзера, например, показать ему кнопку типа "я подтверждаю оплату".

    Во 2-м запросе вы передаете:

    номер счета, который получен в 1-м запросе;
    если подтверждение по SMS, то юзер должен ввести у вас на сайте (в программе, в приложении) SMS-код, который он получил от WebMoney, а вы должны передать этот SMS-код.

    Получив от вас 2-й запрос, сервер WebMoney:
    Проверяет, а не оплачен ли уже данный счет. Это логично, потому что после отработки 1-го запроса до вызова 2-го могло пройти время, в течение которого юзер мог подтвердить оплату, например, через USSD (если, конечно, было заказано подтверждение по USSD), либо путем оплаты WM-счета в Кипере.
    Если подтверждение по SMS, то проверяется корректность SMS-кода, который вы передали в запросе, и если он корректен, то тут же происходит списание денег с кошелька юзера и сервер WebMoney рапортует вам о том, что оплата успешно произведена.

    1-й запрос

    Как мы уже знаем, 1-й запрос инициирует оплату.

    Отправляется на URL https://merchant.webmoney.ru/conf/xml/XMLTransRequest.asp методом POST.

    Состав запроса:
    Code:
    <merchant.request>
        <wmid></wmid>
        <lmi_payee_purse></lmi_payee_purse>
        <lmi_payment_no></lmi_payment_no>
        <lmi_payment_amount></lmi_payment_amount> 
        <lmi_payment_desc></lmi_payment_desc> 
        <lmi_clientnumber></lmi_clientnumber>     
        <lmi_clientnumber_type></lmi_clientnumber_type>     
        <lmi_sms_type></lmi_sms_type>
        <secret_key></secret_key>
        <sign></sign>
        <md5></md5>
    </merchant.request>
    wmid - ваш WMID, подключенный к WM Merchant.
    lmi_payee_purse - ваш торговый кошелек (в рамках wmid), подключенный к WM Merchant.
    lmi_payment_no - номер платежа в вашей учетной системе (аналог LMI_PAYMENT_NO в "форме запроса платежа" WM Merchant). Можно оставлять пустым, но лучше все-таки назначать и, более того, лучше делать его уникальным.
    lmi_payment_amount - сумма в валюте кошелька (аналог LMI_PAYMENT_AMOUNT в "форме запроса платежа" WM Merchant), разделитель дробной части - точка.
    lmi_payment_desc - описание покупки (аналог LMI_PAYMENT_DESC в "форме запроса платежа" WM Merchant). Внимание! В отличие от WM Merchant, где этот параметр передается в Win1251, здесь его нужно передавать в UTF8.
    lmi_clientnumber - идентификатор юзера: номер телефона (без знака "+"), либо email, либо WMID.
    lmi_clientnumber_type - указатель, что именно было передано в lmi_clientnumber (0 - телефон; 1 - WMID; 2 - email).
    lmi_sms_type - желаемый способ подтверждения (1 - SMS; 2 - USSD; 4 - только оплата WM-счета; 3 - WebMoney по какому-то ей одной известному алгоритму определит способ подтверждения, предпочтительный для данного юзера).
    sign, md5, secret_key - это поля для подтверждения аутентичности вашего запроса. Можно использовать ЛЮБОЙ из этих способов, тогда 2 других поля нужно оставить незаполненными. Мы в наших примерах будем использовать md5.

    Начнем писать нашу PHP-функцию, которая будет реализовывать работу с Х20:

    Code:
    if($step==1) {
        $md5=strtoupper(md5($wmid.$lmi_payee_purse.$lmi_payment_no.$lmi_clientnumber.$lmi_clientnumber_type.$secret_key));
        $lmi_payment_desc=iconv("CP1251", "UTF-8", $lmi_payment_desc);
        $xml="
        <merchant.request>
            <wmid>$wmid</wmid>
            <lmi_payee_purse>$lmi_payee_purse</lmi_payee_purse>
            <lmi_payment_no>$lmi_payment_no</lmi_payment_no>
            <lmi_payment_amount>$lmi_payment_amount</lmi_payment_amount>
            <lmi_payment_desc>$lmi_payment_desc</lmi_payment_desc>
            <lmi_clientnumber>$lmi_clientnumber</lmi_clientnumber>
            <lmi_clientnumber_type>$lmi_clientnumber_type</lmi_clientnumber_type>
            <lmi_sms_type>$lmi_sms_type</lmi_sms_type>
            <secret_key></secret_key>
            <sign></sign>
            <md5>$md5</md5>
        </merchant.request>";
        $resxml=_GetAnswer($XML_addr[201], $xml);
    }
    
    
    
    В поле <md5> передается МД5-хеш строки параметров. Эта строка получается путем склейки параметров, среди которых $secret_key. В эту переменную мы будем передавать SecretKey из настроек нашего торгового кошелька в WM Merchant.

    Ответ сервера WebMoney:
    Code:
    <?xml version="1.0"?>
    <merchant.response>
        <operation  wminvoiceid="">
            <realsmstype></realsmstype>
        </operation> 
        <retval>0</retval> 
        <retdesc></retdesc>
        <userdesc></userdesc>  
    </merchant.response> 
    атрибут wminvoiceid - номер счета, выписанного юзеру, в системе WebMoney. Если возникла ошибка, то здесь будет пусто.
    realsmstype - какой способ подтверждения применен (1 - SMS; 2 - USSD; 4 - SMS и USSD не отправлялись, а только был выписан WM-счет).
    Возникает вопрос, а зачем нам это поле в ответе, ведь способ подтверждения мы сами назначили и передали в поле <lmi_sms_type> запроса. Дело в том, что если в <lmi_sms_type> было передано "3", то WebMoney самостоятельно приняла решение, какой способ подтверждения для юзера предпочтительный. Предположим, WebMoney решила, что предпочтительно отправить SMS, тогда в <realsmstype> мы увидим "1".
    retval - результат отработки запроса. "0" свидетельствует о том, что запрос успешно отработан, и WM-счет выписан (+ SMS\USSD отправлено). Другое значение retval свидетельствует об ошибке.
    retdesc - описание ошибки.
    userdesc - текст на русском языке, который можно транслировать юзеру. В нем WebMoney передает "юзеропонятный" текст ошибки, либо указания к дальнейшим действиям.

    Внимание! wminvoiceid нужно обязательно сохранить хотя бы в сессии, а лучше - в базе данных.

    Если юзер заказал подтверждение по SMS (realsmstype = 1), то на этом этапе у него нужно запросить код, который он получил в телефон.

    2-й запрос

    Зачем нужен 2-й запрос?
    1) Если юзер оплачивал WM-счет (realsmstype = 4) или подтверждал оплату по USSD (realsmstype = 2), иными словами, если оплата произошла без вашего участия, то 2-й запрос позволяет проверить состояние оплаты. Кстати, то же самое можно делать с помощью X18.
    2) Если юзер подтверждал оплату по SMS (realsmstype = 1), после чего ввел полученный SMS-код на вашей стороне (на сайте или в программе), то 2-м запросом вы передаете этот SMS-код на сервер WebMoney и тем самым завершаете операцию оплаты.
    3) Если юзер еще не успел оплатить (не подтвердил USSD и не оплатил WM-счет), то 2-й запрос позволяет отменить операцию.

    Отправляется на URL https://merchant.webmoney.ru/conf/xml/XMLTransConfirm.asp методом POST.

    Состав запроса:
    Code:
    <merchant.request>
        <wmid></wmid>
        <lmi_payee_purse></lmi_payee_purse>
        <lmi_clientnumber_code></lmi_clientnumber_code>     
        <lmi_wminvoiceid></lmi_wminvoiceid>     
        <secret_key></secret_key>
        <sign></sign>
        <md5></md5>
    </merchant.request>
    wmid и lmi_payee_purse - то же, что и в 1-м запросе.
    lmi_clientnumber_code - здесь нужно передать SMS-код, полученный от юзера, если оплата подтверждалась по SMS (realsmstype = 1). Если же оплата подтверждалась по USSD (realsmstype = 2) или был только выписан WM-счет (realsmstype = 4), то в этом поле нужно передать "0".
    lmi_wminvoiceid - номер счета, полученный в 1-м запросе (вы же его сохранили хотя бы в сессии?!).
    sign, md5, secret_key - это поля для подтверждения аутентичности вашего запроса. Можно использовать ЛЮБОЙ из этих способов, тогда 2 других поля нужно оставить незаполненными. Мы в наших примерах будем использовать md5.

    Наша функция дополнилась таким кодом:
    Code:
    if($step==1) {
    ...
    } elseif($step==2) {
        $md5=strtoupper(md5($wmid.$lmi_payee_purse.$lmi_wminvoiceid.$lmi_clientnumber_code.$secret_key));
        $xml="
        <merchant.request>
            <wmid>$wmid</wmid>
            <lmi_payee_purse>$lmi_payee_purse</lmi_payee_purse>
            <lmi_clientnumber_code>$lmi_clientnumber_code</lmi_clientnumber_code>
            <lmi_wminvoiceid>$lmi_wminvoiceid</lmi_wminvoiceid> 
            <secret_key></secret_key>
            <sign></sign>
            <md5>$md5</md5>
        </merchant.request>";
        $resxml=_GetAnswer($XML_addr[202], $xml);
    }
    
    
    
    Поле <md5> здесь формируется точно по такому же принципу, как и в 1-м запросе, только строка подписи формируется из других переменных.

    Ответ сервера WebMoney:
    Code:
    <merchant.response>
        <operation  wmtransid="" wminvoiceid="">
            <amount></amount>
            <operdate></operdate>
            <purpose></purpose>
            <pursefrom></pursefrom>
            <wmidfrom></wmidfrom>
        </operation> 
        <retval>0</retval> 
        <retdesc></retdesc> 
        <userdesc></userdesc> 
    </merchant.response> 
    
    атрибут wmtransid - уникальный номер транзакции в системе WebMoney (если операция оплаты прошла успешно).
    operdate - дата и время проведения этой транзакции на сервере WebMoney (если операция оплаты прошла успешно).
    pursefrom и wmidfrom - кошелек и WMID плательщика (если операция оплаты прошла успешно).
    retval - результат отработки запроса. "0" свидетельствует о том, что запрос успешно отработан, и оплата успешно произведена.
    retdesc и userdesc - смысл у этих полей такой же, как и в 1-м запросе.

    Это, в принципе, уже финал. Осталось лишь обратить ваше внимание на несколько принципиальных моментов по поводу 2-го запроса:

    1) Во-первых, получение retval = 0 и wmtransid > 0 - говорит о том, что оплата успешно состоялась!

    2) Во-вторых, получение retval = 556 означает, что оплата еще не подтверждена (если был USSD или чистый WM-счет), либо SMS-код передан неверный (если было SMS-потверждение).

    3) В-третьих, если вы хотите отменить операцию, то в lmi_clientnumber_code передавайте "-1". Если юзер еще не успел оплатить, то операция будет отменена и в ответе вы увидите retval = 557 или retval = 551. Рекоммендуем дать юзеру кнопку "отметить", чтобы он сам на вашей стороне мог инициировать отмену ранее заказанного платежа.

    4) В-четвертых, если юзер оплачивал WM-счет или подтверждал оплату по USSD, то вы отправляете lmi_clientnumber_code = 0 и этим 2-м запросом просто проверяете текущее состояние оплаты. Можно его вообще не посылать, а вместо этого воспользоваться интерфейсом Х18. Однако, в любом случае помните, что при использовании Х20 сервер WebMoney не дергает ваш Result URL из настроек WM Merchant! Result URL задействуется только в случае "классической" оплаты через WM Merchant.

    Функция _WMXML20()

    Функция _WMXML20() для работы с Х20 включена в библиотеку XOWM. Ничего сверхъестественного она не делает. В зависимости от принятого параметра $step (1 или 2) отправляет соответственно 1-й или 2-й запрос. Набор входных параметров у этой функции одинаковый для обеих step (запросов). Он огромен:
    Code:
    function _WMXML20 ($step, $wmid, $lmi_payee_purse, $lmi_payment_no, $lmi_payment_amount, $lmi_payment_desc, $lmi_clientnumber, $lmi_clientnumber_type, $lmi_sms_type, $lmi_clientnumber_code, $lmi_wminvoiceid, $secret_key) {
          ...
          return $result;
    }
    Однако, поскольку у 1-го и 2-го запроса есть как общие параметры, так и отличающиеся, то некоторые параметры будут отсутствовать в вызове функции при 1-м запросе, а некоторые параметры будут отсутствовать в вызове функции при 2-м запросе. Вот пример вызова функции для 1-го запроса. Пустуют $lmi_clientnumber_code и $lmi_wminvoiceid:

    $res=_WMXML20($step, $wmid, $lmi_payee_purse, $lmi_payment_no, $lmi_payment_amount, $lmi_payment_desc, $lmi_clientnumber, $lmi_clientnumber_type, $lmi_sms_type, "", "", $secretkey);

    А вот пример вызова для 2-го запроса. Пустуют $lmi_payment_no, $lmi_payment_amount, $lmi_payment_desc, $lmi_clientnumber, $lmi_clientnumber_type, $lmi_sms_type:

    $res=_WMXML20($step, $wmid, $lmi_payee_purse, "", "", "", "", "", "", $lmi_clientnumber_code, $lmi_wminvoiceid, $secretkey);

    Понятное дело, функция и возвращает в 1-м и 2-м запросе несколько разный набор параметров в массиве $result.

    Если вы будете использовать библиотеку XOWM и не хотите читать предыдущие статьи нашего цикла о XML-интерфейсах, то сразу даём подсказку: для Х20 нужно в блоке настроек прописать $Global_WMID и $Path_Certs.

    Для работы библиотеки нужны расширения PHP: simplexml, iconv, curl.

    Логика со стороны клиента

    Здесь мы продемонстрировали работу Х20 в реализации на PHP. Не очень оригинально, тем не менее, понять логику вполне можно.

    А логика такая.

    1) Демонстрируем юзеру, сколько и за что он сейчас будет платить.

    V

    2) Юзер выбирает, как он хочет идентифицироваться в системе WebMoney (email, телефон, WMID) и как он хочет подтвердить оплату (SMS, USSD, либо только оплата WM-счета).

    V

    3) По нажатию на кнопку посылаем 1-й запрос.

    V

    4) Если есть ошибки (retval не 0) - отображаем на экране userdesc и просим повторить.
    Если же ошибок нет (retval = 0), то предлагаем юзеру ввести SMS-код (но только если было заказано подтверждение по SMS: realsmstype = 1) и подтвердить оплату.

    V

    5) По нажатию на кнопку посылаем 2-й запрос.

    V

    6) Если есть ошибки (любой retval кроме 0, 557, 551) - отображаем на экране userdesc и просим повторить.
    Если retval = 557 или retval = 551, то понимаем, что оплата была отменена (например, юзер в Кипере отказался от оплаты WM-счета).
    Если же retval = 0 и wmtransid > 0, то оплата подтверждена. Отображаем сообщение об УСПЕХЕ и отрабатываем бизнес-поведение при успешном платеже.

    Вот и всё. Еще на шаге 4 даем юзеру возможность отменить операцию. Тогда посылаем 2-й запрос с lmi_clientnumber_code = -1 , а в ответе получим retval = 557 или retval = 551.


    © Никита Сенченко, 06.07.2011
    http://owebmoney.ru/articles/x20/