Created
June 4, 2015 12:15
-
-
Save Znack/6edc51d79b67d3c8bea7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
from hashlib import md5 | |
from urllib import urlencode | |
from django.conf import settings | |
_ADDRESS = 'https://auth.robokassa.ru/Merchant/Index.aspx?' | |
_EXTRA_PARAMS_PREFIX = 'shp_' | |
_COST = settings.CARDBOARD_COST | |
_LOGIN = settings.ROBOKASSA['LOGIN'] | |
_PASSWORD1 = settings.ROBOKASSA['PASSWORD1'] | |
_PASSWORD2 = settings.ROBOKASSA['PASSWORD2'] | |
class RobokassaBaseException(Exception): | |
def __init__(self, message): | |
self.message = message | |
def __str__(self): | |
return '%s: %s.' % (self.__class__.__name__, self.message) | |
class InvalidRequestError(RobokassaBaseException): | |
pass | |
class InvalidSignError(RobokassaBaseException): | |
pass | |
class IncorrectAmountError(RobokassaBaseException): | |
pass | |
class InitializationHandler(): | |
def __init__(self, amount, **kwargs): | |
self._amount = amount | |
self._extra_params = kwargs | |
def get_url(self): | |
params = self._get_params() | |
return _ADDRESS + params | |
def _get_params(self): | |
params = { | |
'OutSum': unicode(self._amount), | |
} | |
sign_extra_parts = self._set_extra_params(params) | |
self._set_auth_params(params, sign_extra_parts) | |
for k, v in params.iteritems(): | |
params[k] = v.encode('utf-8') | |
return urlencode(params) | |
def _set_extra_params(self, params): | |
for key in sorted(self._extra_params.keys()): | |
formatted_key = _EXTRA_PARAMS_PREFIX + key | |
value = self._extra_params[key] | |
params[formatted_key] = value | |
yield '='.join([formatted_key, value]) | |
def _set_auth_params(self, params, sign_extra_parts): | |
params.update({ | |
'MrchLogin': _LOGIN, | |
'SignatureValue': self._get_sign(sign_extra_parts) | |
}) | |
def _get_sign(self, extra_parts): | |
sign_src = ':'.join([_LOGIN, str(self._amount), ':' + _PASSWORD1] + [ | |
part for part in extra_parts]) | |
return md5(sign_src.encode('utf-8')).hexdigest() | |
class ResultHandler(): | |
def __init__(self, data): | |
try: | |
self._sign = data['SignatureValue'] | |
self._amount = data['OutSum'] | |
self.transaction_id = data['InvId'] | |
self.form_data = {} | |
sign_extra_parts = self._get_extra_params(data) | |
except KeyError as e: | |
raise InvalidRequestError('key %s not found' % e.args[0]) | |
self._check_sign(sign_extra_parts) | |
self._check_amount() | |
def _get_extra_params(self, data): | |
for key in sorted(data.keys()): | |
value = data[key] | |
formatted_key = key.replace(_EXTRA_PARAMS_PREFIX, '') | |
if formatted_key == key: | |
continue | |
form_value = value.encode('cp1251').decode('utf-8') | |
self.form_data[formatted_key] = form_value | |
yield '='.join([key, value]) | |
def _check_sign(self, sign_extra_parts): | |
if self._sign.lower() != self._get_sign(sign_extra_parts).lower(): | |
raise InvalidSignError('sign %s is not valid' % self._sign) | |
def _get_sign(self, extra_parts): | |
sign_src = ':'.join( | |
[str(self._amount), str(self.transaction_id), _PASSWORD2] + [ | |
part for part in extra_parts]) | |
return md5(sign_src.encode('utf-8')).hexdigest() | |
def _check_amount(self): | |
expected_amount = _COST * int(self.form_data['quantity']) | |
if long(float(self._amount)) != long(expected_amount): | |
raise IncorrectAmountError( | |
'received %s, expected %s' % (self._amount, _COST)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.http.response import HttpResponseNotAllowed, HttpResponse, \ | |
HttpResponseBadRequest, HttpResponseForbidden | |
from django.shortcuts import render, redirect | |
from django.conf import settings | |
from django.views.decorators.csrf import csrf_exempt | |
from project.core.forms import BuyRequestForm | |
from project.core.payments.robokassa import InitializationHandler, \ | |
ResultHandler, InvalidRequestError, InvalidSignError, IncorrectAmountError | |
from project.core.models import BuyRequest | |
# Create your views here. | |
def get_main_page(request): | |
form = BuyRequestForm() | |
return render(request, 'index.html', {'form': form}, ) | |
def sent_buy_request(request): | |
if request.method == 'POST': | |
form = BuyRequestForm(request.POST) | |
if form.is_valid(): | |
if form.cleaned_data['delivery'] == '1': | |
quantity = form.cleaned_data['quantity'] | |
extra_fields = { | |
'name': request.POST['name'], | |
'phone': request.POST['phone'], | |
'email': request.POST['email'], | |
'city': request.POST['city'], | |
'address': request.POST['address'], | |
'quantity': str(quantity), | |
'delivery': request.POST['delivery'], | |
} | |
final_amount = settings.CARDBOARD_COST * quantity | |
handler = InitializationHandler( | |
final_amount, **extra_fields) | |
return redirect(handler.get_url()) | |
else: | |
form.save() | |
return render(request, 'index.html', {'form': BuyRequestForm(), 'success': True}) | |
else: | |
form = BuyRequestForm() | |
return render(request, 'index.html', {'form': form, 'success': False}) | |
@csrf_exempt | |
def robokassa_result_handler(request): | |
if request.method != 'POST': | |
return HttpResponseNotAllowed(['POST']) | |
try: | |
handler = ResultHandler(request.POST.dict()) | |
except (InvalidRequestError, InvalidSignError, IncorrectAmountError) as e: | |
if isinstance(e, InvalidRequestError): | |
return HttpResponseBadRequest() | |
elif isinstance(e, InvalidSignError): | |
return HttpResponseForbidden() | |
else: | |
return HttpResponse('Invalid amount.') | |
form = BuyRequestForm(handler.form_data) | |
form.save() | |
return HttpResponse('OK' + handler.transaction_id) | |
@csrf_exempt | |
def successful_order_handler(request): | |
if request.method != 'POST': | |
return HttpResponseNotAllowed(['POST']) | |
return render( | |
request, 'index.html', {'form': BuyRequestForm(), 'success': True}) | |
@csrf_exempt | |
def failed_order_handler(request): | |
if request.method != 'POST': | |
return HttpResponseNotAllowed(['POST']) | |
return render( | |
request, 'index.html', {'form': BuyRequestForm(), 'success': False}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment