Это старая версия документа.
Модуль для работы с сервисом Onpay.ru для сайта, построенного на фреймворке Django.
Пользователи других фреймворков могут написать своё приложение, специально для этого основная функциональность собрана в файле `common.py`.
Фреймворко-зависимую часть (запросы, систему хранения, обработку форм, оповещение менеджеров) нужно будет переписать, взяв за основу текущий код.
1. Сгенерировать тег `iframe` из множества параметров. В этом поможет класс `IframeGenerator`.
2. Принять запрос от сервиса, который предоставит данные (кому какую сумму в какой валюте перечислили).
3. Внести эти данные в базу данных.
В личном кабинете Onpay.ru (Настройки магазина) необходимо настроить параметры API IN:
Уведомлять по API - Да Проверять MD5 на ссылках - Да (не обязательно) URL API: http://вашдомен/onpay/api/ (можно переопределить через URLconf) Пароль для API IN: ksjgJskLJds - ваш секретный код, который будет нужен при настройках платежного модуля Onpay.ru в Django
Приложение требует модуль lxml. Начиная с версии 2.6 python содержит его в стандартной библиотеке. Если вы пользуетесь более ранней версией (например, той, что идёт в пакетах с debian lenny), необходимо установить пакет python-lxml.
Для собственно установки пакета подойдет один из вариантов:
$ hg clone http://bitbucket.org/denger/django-onpay $ ln -s /path/to/django-onpay/onpay /usr/lib/python2.6/site-packages или $ hg clone http://bitbucket.org/denger/django-onpay $ cd django-onpay $ sudo python setup.py install или $ sudo pip install -e hg+http://bitbucket.org/denger/django-onpay
Далее:
1. прописываем `onpay` в `INSTALLED_APPS`, 2. `./manage.py syncdb` 3. в `settings.py` добавляем переменную `ONPAY` с минимумом настроек (см. ниже), 4. добавляем в `urls.py`: `('^onpay/', include('onpay.urls')),`, 5. тестируем работу.
Настройка Все параметры хранятся в словаре `ONPAY` в файле `settings.py`.
Обязательные параметры:
ONPAY = { "onpay_login": "example", # Ваш логин на onpay "private_code": "ksjgJskLJds", # Пароль, который вы ввели на сайте onpay }
Необязательные параметры:
"url_success": "http://example.org/onpay/api/", # default: то что задано в настройках на сайте onpay
"use_balance_table": True, # записывать в таблицу баланса.
"pay_mode": "fix", # "free" - обновление баланса, юзер может изменить цифру # "fix" - фиксированный платеж, цифра в фрейме только для чтения
"f": None, # скин, возможные значения - None, 1, 2, 3 # в зависимости от скина # подробнее: http://onpay.ru/form/
"enable_email_notify": None, # если включить опцию, при платежах будет отправлен email # через функцию email_managers
"debug": None, # на данный момент отправляет через mail_admins запрос от Onpay.ru
Чтобы встроить платежную систему в свой дизайн надо переопределить шаблоны из папки onpay.
Можно вместо include в urls.py прописать свои роуты к своим views, если требуется какие-то изменения.
Можно поменять параметры после инициализации IframeGenerator:
iframe_generator = IframeGenerator() iframe_generator.set_f(3) iframe_generator.width = 100500 iframe_generator.pay_mode = "free"
После оплаты отправляется сигнал `onpay.signals.refilled_balance`, если на него подписать свою функцию, можно добиться любой функциональности. Примеры смотрите в файле `signals.py`.
Ну и, наконец, можно изменить исходные тексты и прислать hg патчи нам - по возможности добавим в репозиторий.
common.py для работы с dom.minidom
# coding: UTF-8 import urllib from hashlib import md5 #from lxml import etree from xml.dom.minidom import getDOMImplementation
from onpay.conf import get_constant
class IframeGenerator(object): def __init__(self): self.pay_mode = get_constant("pay_mode", "fix") self.currency = get_constant("currency", "RUR") self.convert = get_constant("convert", "yes") self.url_success = get_constant("url_success") self.private_code = get_constant("private_code") self.onpay_login = get_constant("onpay_login") self.set_f(get_constant("f"))
def iframe_url_params(self, operation_id, summ, email=None): "Функция определения параметров платежной формы." query = { "pay_mode": self.pay_mode, "currency": self.currency, "convert": self.convert,
"pay_for": operation_id, 'price_final' : 'true', "price": summ, "md5": self.md5check(summ, operation_id), } if self.url_success: query["url_success"] = self.url_success if email: query['user_email'] = email if self.f: query['f'] = self.f return urllib.urlencode(query)
def md5check (self, summ, operation_id): return md5(";".join( (self.pay_mode, str(summ), self.currency, str(operation_id), self.convert, self.private_code,))).hexdigest().upper()
def set_f(self, f): "Определение ширины и высоты в зависимости от текущего скина" self.f = f self.width, self.height = { None: ( 300, 500), 1: (1020, 660), 2: ( 250, 540), 3: ( 960, 800), }[f]
def iframe_tag (self, operation_id, summ, email=None): url = "http://secure.onpay.ru/pay/%s?%s" % (self.onpay_login, self.iframe_url_params(operation_id, summ, email=email)) options = { "src": url, "width": self.width, "height": self.height, "frameborder": "no", "scrolling": "no", "name": "onpay", "id": "onpay", } options_gen = ((u'%s="%s"' % o_0) for o_0 in options.iteritems()) return u'<iframe %s></iframe>' % (u" ".join(options_gen))
def answer(type, code, pay_for, order_amount, order_currency, text): "функция выдает ответ для сервиса onpay в формате XML на чек запрос" array_for_md5 = (type, pay_for, order_amount, order_currency, str(code), get_constant('private_code')) result_md5 = md5(";".join(array_for_md5)).hexdigest().upper()
dom = getDOMImplementation() doc = dom.createDocument(None, 'result', None) def xml_add(name, value): node = doc.createElement(name) node.appendChild(doc.createTextNode(value)) doc.documentElement.appendChild(node)
xml_add('code', str(code)) xml_add('pay_for', pay_for) xml_add('comment', text) xml_add('md5', result_md5) return doc.toxml('UTF-8') #root = etree.Element("result") #etree.SubElement(root, "code").text = str(code) #etree.SubElement(root, "pay_for").text = pay_for #etree.SubElement(root, "comment").text = text #etree.SubElement(root, "md5").text = result_md5 #return ''etree.tostring(root, pretty_print=True, # xml_declaration=True, encoding='UTF-8')
def answer_dict(POST, code, text): "Shortcut for call answer with POST or form dict as parameter" return answer( POST.get("type"), code, POST.get("pay_for"), POST.get("order_amount"), POST.get("order_currency"), text, )
def answerpay(type, code, pay_for, order_amount, order_currency, text, onpay_id): "функция выдает ответ для сервиса onpay в формате XML на pay запрос"
array_for_md5 = (type, pay_for, onpay_id, pay_for, order_amount, order_currency, str(code), get_constant('private_code')) result_md5 = md5(";".join(array_for_md5)).hexdigest().upper()
dom = getDOMImplementation() doc = dom.createDocument(None, 'result', None) def xml_add(name, value): node = doc.createElement(name) node.appendChild(doc.createTextNode(value)) doc.documentElement.appendChild(node) xml_add('code', str(code)) xml_add('comment', text) xml_add('onpay_id', onpay_id) xml_add('pay_for', pay_for) xml_add('order_id', pay_for) xml_add('md5', result_md5) return doc.toxml('UTF-8') #root = etree.Element("result") #etree.SubElement(root, "code").text = str(code) #etree.SubElement(root, "comment").text = text #etree.SubElement(root, "onpay_id").text = onpay_id #etree.SubElement(root, "pay_for").text = pay_for #etree.SubElement(root, "order_id").text = pay_for #etree.SubElement(root, "md5").text = result_md5 #return etree.tostring(root, pretty_print=True, # xml_declaration=True, encoding='UTF-8')
def answerpay_dict(request_dict, code, text): "Shortcut for call answerpay with POST or form dict as parameter" return answerpay( request_dict.get('type'), code, request_dict.get('pay_for'), request_dict.get('order_amount'), request_dict.get('order_currency'), unicode(text), request_dict.get('onpay_id'), )
Автор: Денис Бурый
Лицензия: MIT