Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Изменения в README.rst #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 168 additions & 44 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,138 @@ ROBOKASSA (http://robokassa.ru/Doc/Ru/Interface.aspx). Приложение ре
Форма для приема платежей
-------------------------

Для того, чтобы упростить конструирование html-форм для отправки пользователей в
Для того, чтобы упростить отправку и валидацию данных в
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RobokassaForm не выполняет валидацию данных.

Robokassa, в django-robokassa есть форма RobokassaForm. Она нужна
для упрощения вывода информации в шаблонах, вычисления контрольной суммы и
формирования параметров GET-запросов.
для вычисления контрольной суммы (в том числе, для проверки того,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Контрольную сумму только для этой проверки и вычисляют, а "в том числе" подразумевает, что еще для чего-то.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Показалось, что кроме этого, она может использоваться просто для проверки того, не потерялось ли что по дороге при передаче "пакета" полей.

что взаимодействие происходит именно с robokassa.ru, а не его подделкой)
и формирования параметров GET-запросов. Для вывода информации в шаблон и
обработки запроса пользователя необходимо реализовать свою собственную форму
для ввода информации о платеже пользователем и view для обработки этой формы.
При POST запросе из этой формы необходимо во view извлекать ее параметры,
создавать form=RobokassaForm() с нужными значениями в initial и делать redirect
на form.get_redirect_url().

Пример::
Пример view::

# views.py

from django.shortcuts import get_object_or_404, render
from django.contrib.auth.decorators import login_required

from robokassa.forms import RobokassaForm

@login_required
def pay_with_robokassa(request, order_id)
order = get_object_or_404(Order, pk = order_id)

form = RobokassaForm(initial={
'OutSum': order.total,
'InvId': order.id,
'Desc': order.name,
'Email': request.user.email,
# 'IncCurrLabel': '',
# 'Culture': 'ru'
})

return render(request, 'pay_with_robokassa.html', {'form': form})
def balance_top_up(request):
"""
Отправка запроса на пополнение баланса на robokassa.ru
"""

if request.method == 'POST':

# Создание экземпляра своей формы после POST запроса
top_up_balance_form = TopUpBalanceForm(request.POST)

# Проверка на валидность полей в своей форме
if top_up_balance_form.is_valid():

# Здесь необходимо сгенерировать уникальный номер операции op_id

op_id = ...

# Генерация контрольной суммы с использованием
# ROBOKASSA_PASSWORD1 и остальными параметрами.
# _get_check_sum() см. ниже

check_sum = _get_check_sum(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А это зачем? Форма же сама должна подпись считать. Если не считает, то нужно django-robokassa исправлять.
Кроме того, мне кажется, что простой пример тоже можно оставить (с ним что-то не так было?).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это велосипед мой. У меня обработка делалась в своей вьюхе, поэтому так получилось - поздно заглянул в исходники django-robokassa. Думаю, что, если это делать правильно, то надо передавать свою форму в Вашу внутреннюю вьюху, чтобы она ее выводила для взаимодействия с пользователем. Еще не уверен, что в этом случае необходима вторая форма для конструирования и редиректа, но тут, видимо, Вам виднее - т.е. не знаю, корректно ли будет использовать для этого именно форму, а не что-то другое - две формы как то очень необычно, хотя т.к. не так давно начал работать с формами и вообще с джангой, поэтому, могу чего-то не знать.

# Логин пользователя
login=settings.ROBOKASSA_LOGIN,
# Сумма, на которую происходит повышение баланса
rebalancing_sum=\
top_up_balance_form.cleaned_data['OutSum'],
# Уникальный счетчик операции
operation_id=op_id,
# Пароль №1
password=settings.ROBOKASSA_PASSWORD1
)

# Отправка запроса на robokassa.ru для инициации процедуры
# начисления средств на счет

form = RobokassaForm(initial={
'MrchLogin': settings.ROBOKASSA_LOGIN,
'OutSum':
top_up_balance_form.cleaned_data['OutSum'],
'InvId': op_id,
'Desc': 'description',
'SignatureValue': check_sum,
'Email': request.user.email,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне кажется, это важное замечание, и его нужно оставить.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Имхо, надо чуть поменять его контекст, подразумевая, что это вспомогательная форма.

'Culture': 'ru'
})

# Перенаправление
return redirect(form.get_redirect_url())
else:
# Обработка ошибкок валидации.(Чтобы исключить их наличие
# после отправки формы, для каждого из ее полей стоит
# использовать HTML5 атрибут "pattern", содержащий регулярное
# выражение. Подробнее см. ниже)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Атрибут pattern ошибки валидации не исключит; чтоб обрабатывать ошибки валидации, лучше же форму с ошибками показать пользователю.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да, но приведенные html5 атрибуты просто не дадут отправить форму - поэтому я их использую для быстрой валидации, Т.е. пишу регэксп для каждого поля формы и она не отправится и поле будет подсвечиваться красным, пока юзер нормально не заполнит это поле. Тут это действительно не к месту. Все же, приложение, никак с htm5 не связано.

else:
# Создание экземпляра своей формы для взаимодействия с пользователем.
# В данном случае форма содержит одно поле - OutSum - сумма перевода.

form = TopUpBalanceForm()

# Шаблон см. ниже
return render(
request,
'example.html',
{ 'form': form }
)

Пример функции подсчета контрольной суммы::

def _get_check_sum(login, rebalancing_sum, operation_id, password):
"""
md5 checksum
"""

data = u':'.join([
u"%s" % str(login),
u"%s" % str(rebalancing_sum),
u"%s" % str(operation_id),
u"%s" % password
])

return hashlib.md5(data).hexdigest()

Пример формы::

# forms.py

# Неотрицательное целое число
_regexp_template = r'^\d+$'
_regexp = u'\d+'

class TopUpBalanceForm(forms.Form):
"""
Пополнение баланса
"""

OutSum = forms.CharField(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а почему не DecimalField?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Полностью согласен, DecimalField лучше.

max_length=15,
label=_(u"Введите сумму в рублях для изменения баланса"),
widget=forms.TextInput(
attrs={
'pattern': _regexp,
'maxlength': '7',
'placeholder': u'Сумма перевода',
'required': 'required',
'value': 100500
}
)
)

def clean(self):
cleaned_data = super(TopUpBalanceForm, self).clean()
OutSum = cleaned_data['OutSum']
if not re.match(_regexp_template, OutSum, re.UNICODE):
raise forms.ValidationError(_(u'Неверная сумма перевода'))
return cleaned_data

В initial все параметры необязательны. Детальную справку по параметрам
лучше посмотреть в `документации <http://robokassa.ru/ru/Doc/Ru/Interface.aspx#222>`_
Expand All @@ -101,29 +205,18 @@ Robokassa, в django-robokassa есть форма RobokassaForm. Она нуж

{% extends 'base.html' %}

{% load i18n %}

{% block title %}{% trans "Пополнение баланса" %}{% endblock %}

{% block content %}
<form action="{{ form.target }}" method="POST">
<p>{{ form.as_p }}</p>
<p><input type="submit" value="Купить"></p>
<form action="{% url app_name.views.balance_top_up %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">{% trans "Пополнение баланса" %}</button>
</form>
{% endblock %}

Форма выведется в виде набора скрытых input-тегов.

У формы есть атрибут target, содержащий URL, по которому форму следует
отправлять. В тестовом режиме это будет тестовый URL, в боевом - боевой.

Обратите внимание, {% csrf_token %} в форме не нужен (и более того, добавлять
его к форме небезопасно), т.к. форма ведет на внешний сайт - сайт робокассы.

Вместо отправки формы можно сформировать GET-запрос. У формы есть
метод get_redirect_url, который возвращает нужный адрес со всеми параметрами.
Редирект на этот адрес равносилен отправке формы методом GET.

django-robokassa не включает в себя модели "Покупка" (``Order`` в примере),
т.к. эта модель будет отличаться от сайта к сайту. Обработку смены статусов
покупок следует осуществлять в обработчиках сигналов.


Получение результатов платежей
------------------------------
Expand All @@ -138,10 +231,42 @@ django-robokassa не включает в себя модели "Покупка"
3. Можно запрашивать статус платежа через XML-сервис.

В django-robokassa на данный момент поддерживаются методы 1 и 2 и их совмещение
(дополнительная проверка, что при переходе на Success URL уже было уведомление
на Result URL при использовании опции ROBOKASSA_STRICT_CHECK = True).
(дополнительное подтверждение сначала через ResultURL, а затем переход на
SuccessURL при использовании опции ROBOKASSA_STRICT_CHECK = True,
рекомендуется для безопасного обмена данными).

Механизм строгой проверки (подтверждения через ResultURL):

1. robokassa.ru, вызывает ResultURL.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

запятая лишняя


2. Внутри view, связанного с ResultURL, происходит проверка содержащейся в
запросе md5 подписи через ROBOKASSA_PASSWORD2 - второй пароль, который не
передается по сети и известен только отправителю и получателю. Он нужен
для подтверждения того, что запрос был послан именно с robokassa.ru.

3. Через callback, который принимает сигнал из этого view,
производятся манипуляции внутри сайта (например, начисление средств согласно
пришедшему запросу). Этот пункт необходим, если не реализуется свой view,
а используется view, содержащийся в django-robokassa.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А когда может понадобиться не использовать вьюху из django-robokassa?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Свои views испольовал только потому, что:

  1. Использовал свою форму, а ее надо же как то обрабатывать. Я это сделал в своем view.
  2. Из-за этого https://bitbucket.org/kmike/django-robokassa/issue/7/fail-url-signature бага сразу не получилось использовать подключение views через urls (как в доке описано). Думаю, что исправить его довольно просто - надо добавить html шаблон туда, куда скажет трейсбек. Но так как у нас релиз через неделю, и мне нужен был работающий биллинг, я решил не рисковать с правкой багов и просто написать свою вьюху.


4. Затем этот view отправляет на robokassa.ru ответ вида
HttpResponse("".join(["OK", str(operation_id)]),
где operation_id - уникальный id текущей операции. Этот ответ необходим в
том числе для того, чтобы robokassa.ru получила подтверждение того, что все
необходимые действия произведены.

5. Если robokassa.ru получает этот ответ, она посылает второй запрос уже на
SuccessURL, для вывода информативного сообщения пользователю об успешном
прохождении всей операции. То есть, здесь должен быть только вывод оповещения.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

robokassa.ru не посылает запрос на SuccessURL, запрос посылает браузер клиента. robokassa.ru перенаправляет клиента на SuccessURL. Разница принципиальна тем, что ResultURL - секретная штука для внутреннего общения сайта и робокассы, а по SuccessURL висит публичная вьюха.


6. Либо, в случае, если HttpResponse не соответвтует ожидаемому,
посылается запрос на FailURL, тогда пользователь видит сообщение о
произошедшей ошибке.

Обработчики подключаются через urls.py, рендерят соответствующие
шаблоны и шлют сигналы в зависимости от успешности платежа.
Также можно сделать свои views, и подключить их самостоятельно через urls.py,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Про обработчики SuccessURL и FailURL - согласен, а обработчик ResultURL зачем переопределять?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно не переопределять - почему сделано так, написал тремя комментами выше.

а формы робокассы использовать для валидации данных.


Сигналы
Expand Down Expand Up @@ -182,7 +307,6 @@ ROBOKASSA_EXTRA_PARAMS).
result_received.connect(payment_received)



urls.py
-------

Expand Down