Подключение интернет-магазина к WebMoney на Python

Матеріал з Wiki Welard
Версія від 19:03, 7 березня 2010, створена 94.248.41.234 (обговорення) (Created page with 'http://habrahabr.ru/blogs/django/86123/ Организационная часть Существует несколько вариантов подключения к сист...')
(різн.) ← Попередня версія | Поточна версія (різн.) | Новіша версія → (різн.)
Перейти до навігації Перейти до пошуку

http://habrahabr.ru/blogs/django/86123/

Организационная часть

Существует несколько вариантов подключения к системе WebMoney. В данной статье я опишу два варианта: WebMoney XML-interface (по сути WebMoney API для продавцов) и Web Merchant Interface (переход на страницу оплаты WebMoney по специально сформированной ссылке).

Чтобы иметь возможность работать с любым из этих вариантов, вам нужно получить аттестат продавца. То есть зарегистрироваться и подтвердить, что вы являетесь юридическим лицом. Правда на практике все нужные нам функции обоих вариантов подключения работают и при обычном персональном аттестате (хотя в документации и написано обратное). Поэтому смело можете начать с него и потом получить аттестат продавца. Процесс получения персонального аттестата или аттестата продавца выходит за пределы данной статьи.


Вариант подключения через WebMoney XML-interface

Для работы с ним нам потребуются библиотеки openssl и curl (скомпилированный с поддержкой ssl). Плюс потребуется питоновская библиотека для работы с curl: pycurl. Команды для инсталляции библиотек из мак-портов (в убунту ставим из пакетов):

sudo port install openssl sudo port install curl +ssl sudo port install py26-curl

Предупреждение: не используйте версию openssl 0.9.8l. В ней баг работы с ssl-ключами! К сожалению на данный момент эта библиотека идет по умолчанию в мак-портах. Я потратил несколько часов, прежде чем понял, что дело было в ней. Точно рабочими являются версии openssl 0.9.8k или 0.9.8g.

Для оплаты товара через WebMoney из всех функций API нам нужны только следующие:

— Выставление счета — Проверка, что счет оплачен

Все запросы и ответы производятся в формате XML. Не буду долго расписывать и просто приведу примеры кода.

Выставить счет на оплату:

   Copy Source | Copy HTML
   xml_request = """\
           <w3s.request>
           <reqn>%s</reqn>
               <invoice>
                   <orderid>%s</orderid>
                   <customerwmid>%s</customerwmid>
                   <storepurse>%s</storepurse>
                   <amount>%s</amount>
                   <desc>%s</desc>
                   <period>0</period>
                   <expiration>0</expiration>
               </invoice>
           </w3s.request>
           """ % (_get_reqn(), payment_id, customer_wmid, your_web_money_purse, payment_amount,
                  payment_description)
    
           result = request('https://w3s.wmtransfer.com/asp/XMLInvoiceCert.asp',
                                     xml_request.encode('utf-8'))


Пояснение параметров запроса:

   * _get_reqn() — функция формирования уникального номера запроса (приведена ниже)
   * payment_id — id платежа в вашем интернет-магазине
   * customer_wmid — WMID покупателя (предполагается, что у покупателя есть кошелек в той же валюте, что и у вас)
   * your_web_money_purse — ваш номер кошелька, например: R12345678900
   * payment_amount — цена вашего заказа
   * payment_description — описание заказа


В XML-ответе будет содержаться номер выставленного счета (invoice_id) и дата его создания (created). Мы используем их в следующем запросе.

Проверка, что счет оплачен:

   Copy Source | Copy HTML
   from datetime import timedelta
    
       xml_request = """\
           <w3s.request>
           <reqn>%s</reqn>
               <getoutinvoices>
                   <purse>%s</purse>
                   <wminvid>%s</wminvid>
                   <orderid>%s</orderid>
                   <datestart>%s 00:00:00</datestart>
                   <datefinish>%s 00:00:00</datefinish>
               </getoutinvoices> 
           </w3s.request>
           """ % (_get_reqn(), customer_web_money_purse, invoice_id, payment_id,
                  created.strftime('%Y%m%d'), (created + timedelta(1)).strftime('%Y%m%d'))
    
           result = request('https://w3s.webmoney.ru/asp/XMLOutInvoicesCert.asp', xml_request.encode('utf-8'))


Пояснение параметров запроса:

   * your_web_money_purse — ваш номер кошелька, например: R12345678900
   * invoice_id — номер выставленного счета в WebMoney
   * payment_id — номер счета в вашем интернет-магазине
   * created — дата создания счета в WebMoney


В XML-ответе, будет указано состояние счета. Возможные варианты состояния: 1 — не оплачен 2 — оплачен 3 — отменен пользователем

Самое интересное — код функций формирования уникального номера и самого запроса:

   Copy Source | Copy HTML
   import pycurl
   import random
   import StringIO
   from time import time, sleep
    
   def _get_reqn():
       return int(time()*100)
    
   def request(url, xml_body, retries=5, delay=5):
       import os.path
       current_dir = os.path.dirname(__file__)
    
       for i in range( 0, retries):
           def is_last_attempt():
               return i >= retries - 1
    
           try:
               r = pycurl.Curl()
               r.setopt(pycurl.URL, url)
               r.setopt(pycurl.TIMEOUT, 30)
               r.setopt(pycurl.HEADER,  0)
               r.setopt(pycurl.POST, 1)
               b = StringIO.StringIO()
               r.setopt(pycurl.WRITEFUNCTION, b.write)
               r.setopt(pycurl.POSTFIELDS, xml_body)
               r.setopt(pycurl.CAINFO, current_dir + 'WebMoneyCA.crt')
               r.setopt(pycurl.SSLKEY, current_dir + 'your_key.key')
               r.setopt(pycurl.SSLKEYPASSWD, '12345')
               r.setopt(pycurl.SSLCERT, current_dir + 'your_certificate.cer')
               r.perform()
               return b.getvalue()
           except BaseException as e:
               logging.warning(u'Http request to web-money, Curl error: %s' % e) # e.args[0] - error code
               if is_last_attempt():
                   raise
           finally:
               r.close()
    
           sleep(delay)


Пояснение: В параметрах запроса указываются следующие файлы: сертификат WebMoney (WebMoneyCA.crt), ваш ssl-сертификат (your_certificate.cer), ваш ssl-ключ (your_key.key). Так же указывается пароль к ключу: «12345». Как сформировать сертификат и ключ вы можете посмотреть в статье Программное обращение к XML-интерфейсам системы... (внизу). Сертификат WebMoney вы можете взять с сайта WebMoney

Вариант подключения через web merchant interface

Тут все проще, никаких дополнительных библиотек нам ставить не нужно. Все что нужно — это сформировать POST запрос на страницу https://merchant.webmoney.ru/lmi/payment.asp. Пример html-формы:

   Copy Source | Copy HTML
   <form action="https://merchant.webmoney.ru/lmi/payment.asp" method="post" id="web_money_redirect_form">
       <input type="hidden" name="LMI_PAYMENT_AMOUNT" value="10.0">
       <input type="hidden" name="LMI_PAYMENT_DESC" value="Описание товара">
       <input type="hidden" name="LMI_PAYMENT_NO" value="11">
       <input type="hidden" name="LMI_PAYEE_PURSE" value="Номер вашего кошелька в Web-money">
       <input type="hidden" name="LMI_SUCCESS_URL" value="URL-страницы в случае успешной операции">
       <input type="hidden" name="LMI_SUCCESS_METHOD" value="1">
       <input type="hidden" name="LMI_FAIL_URL" value="URL-страницы в случае ошибки проведения платежа">
       <input type="hidden" name="LMI_FAIL_METHOD" value="1">
       <input type="submit" value="Перейти на сайт Web Money для оплаты" id="return_button">
   </form>


Описание переменных формы:

   * LMI_PAYMENT_AMOUNT — стоимость вашего заказа
   * LMI_PAYMENT_DESC — текстовое описание заказа
   * LMI_PAYMENT_NO — номер платежа в вашей системе (в вашем интернет-магазине)
   * LMI_PAYEE_PURSE — Номер вашего кошелька в WebMoney, например R12345678900
   * LMI_SUCCESS_URL — URL вашей страницы, на которую покупатель попадет после оплаты в системе WebMoney в случае успешной операции
   * LMI_SUCCESS_METHOD — метод вызова вашей успешной страницы, указанной в LMI_SUCCESS_URL. Варианты: 0 — GET, 1 — POST, 2 — LINK
   * LMI_FAIL_URL — URL вашей страницы, на которую покупатель попадет в случае ошибки оплаты в системе WebMoney или если покупатель просто отказался от оплаты
   * LMI_FAIL_METHOD — метод вызова вашей страницы в случае ошибки. Варианты такие же: 0 — GET, 1 — POST, 2 — LINK


Примечание: вы можете указать LMI_SUCCESS_URL, LMI_SUCCESS_METHOD, LMI_FAILED_URL и LMI_FAILED_METHOD в настройках вашего кошелька в WebMoney, если они у вас всегда одинаковые и не указывать их в параметрах формы. В нашем случае они у нас всегда меняются.

В процессе оплаты WebMoney дополнительно вызовет указанный в настройках вашего кошелька Result URL, причем два раза: сначала до снятия денег (предварительный запрос) и второй раз в случае успешного снятия денег. Если произошла ошибка в процессе оплаты, то второго вызова не будет. Метод вызова: POST.

Параметры предварительного запросы мы пропустим, тем более что они по умолчанию пустые (указывается в настройках вашего кошелька в WebMoney). Если вы не собираетесь обрабатывать предварительный запрос, то в коде django view можно написать такую заглушку:

   Copy Source | Copy HTML
   if not request.POST or request.POST.get('LMI_PREREQUEST', None):
           return HttpResponse('OK')


Важные для нас параметры второго POST-запроса от WebMoney:

   * LMI_PAYEE_PURSE — номер нашего кошелька в WebMoney
   * LMI_PAYMENT_AMOUNT — стоимость вашего заказа
   * LMI_PAYMENT_NO — номер заказа в нашем интернет-магазине
   * LMI_MODE — 1 — тестовый режим (реально деньги в WebMoney не снимаются), 0 — нормальный режим работы
   * LMI_SYS_INVS_NO — номер счета в системе WebMoney
   * LMI_SYS_TRANS_NO — номер транзакции в системе WebMoney
   * LMI_SYS_TRANS_DATE — дата транзакции
   * LMI_PAYER_PURSE — номер кошелька покупателя
   * LMI_PAYER_WM — WMID покупателя
   * LMI_HASH — подпись, чтобы проверить параметры запроса и убедиться, что это действительно запрос от WebMoney


В WebMoney есть два алгоритма формирования подписи: MD5 и собственный алгоритм (SIGN).В случае использования MD5 код проверки подписи в вашем view может быть такой:

   Copy Source | Copy HTML
       import hashlib
    
       string_to_sign = .join([request.POST['LMI_PAYEE_PURSE'], request.POST['LMI_PAYMENT_AMOUNT'],
                                request.POST['LMI_PAYMENT_NO'], request.POST['LMI_MODE'],
                                request.POST['LMI_SYS_INVS_NO'], request.POST['LMI_SYS_TRANS_NO'],
                                request.POST['LMI_SYS_TRANS_DATE'], secret_key,
                                request.POST['LMI_PAYER_PURSE'], request.POST['LMI_PAYER_WM']])
       sign = hashlib.md5(string_to_sign).hexdigest().upper()
       if sign != request.POST['LMI_HASH']:
           return HttpResponseBadRequest('Some error')


Как видно из кода, вам нужно указать в переменной secret_key ваш секретный ключ, который вы указали в настройках вашего кошелька.

Так же хорошей идеей является проверить номер вашего кошелька и стоимость товара, что они действительно совпадают с тем, что вы ожидаете:

   Copy Source | Copy HTML
   if request.POST['LMI_PAYEE_PURSE'] != your_web_money_purse:
       return HttpResponseBadRequest('Some error')
    
   if request.POST['LMI_PAYMENT_AMOUNT'] != your_payment_amount:
       return HttpResponseBadRequest('Some error')


Дальше вы можете делать, все что нужно для вашего интернет-магазина, чтобы отметить, что товар был оплачен и в самом конце view написать ответ на запрос: return HttpResponse('OK')

Заключение

Надеюсь описание было понятным и полезным. Замечания по теме статьи всегда приветствуются :)