From f489c23d1bdf0abd8b9569b446447eb1a24c7223 Mon Sep 17 00:00:00 2001 From: aibaq Date: Thu, 11 Jun 2020 23:40:41 +0600 Subject: [PATCH] ADD: initial commit --- README.md | 0 paybox_api/__init__.py | 124 ++++++++++++++++++ requirements.txt | 5 + setup.py | 17 +++ test_app/__init__.py | 0 test_app/__init__.pyc | Bin 0 -> 162 bytes test_app/settings.py | 29 ++++ test_app/settings.pyc | Bin 0 -> 1173 bytes test_app/tests/__init__.py | 0 .../tests/__pycache__/__init__.cpython-37.pyc | Bin 0 -> 168 bytes .../__pycache__/test_utils.cpython-37.pyc | Bin 0 -> 905 bytes test_app/tests/test_utils.py | 18 +++ test_app/urls.py | 6 + test_app/utils.py | 3 + 14 files changed, 202 insertions(+) create mode 100644 README.md create mode 100644 paybox_api/__init__.py create mode 100644 requirements.txt create mode 100644 setup.py create mode 100644 test_app/__init__.py create mode 100644 test_app/__init__.pyc create mode 100644 test_app/settings.py create mode 100644 test_app/settings.pyc create mode 100644 test_app/tests/__init__.py create mode 100644 test_app/tests/__pycache__/__init__.cpython-37.pyc create mode 100644 test_app/tests/__pycache__/test_utils.cpython-37.pyc create mode 100644 test_app/tests/test_utils.py create mode 100644 test_app/urls.py create mode 100644 test_app/utils.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/paybox_api/__init__.py b/paybox_api/__init__.py new file mode 100644 index 0000000..dba8bc6 --- /dev/null +++ b/paybox_api/__init__.py @@ -0,0 +1,124 @@ +import hashlib +import random +import string + +from functools import wraps +from urllib.parse import parse_qs + +from django.conf import settings + +from requests import Request + + +class PayboxAPI: + """ + 100 'Некорректная подпись запроса *' + 101 'Неверный номер магазина'' + 110 'Отсутствует или не действует контракт с магазином' + 120 'Запрошенное действие отключено в настройках магазина'' + 200 'Не хватает или некорректный параметр запроса' + 340 'Транзакция не найдена' + 350 'Транзакция заблокирована' + 360 'Транзакция просрочена' + 365 'Срок жизни рекуррентного профиля истек' + 400 'Платеж отменен покупателем или платежной системой' + 420 'Платеж отменен по причине превышения лимита' + 465 'Ошибка связи с платежной системой' + 466 'Истек SSL сертификат' + 470 'Ошибка на стороне платежной системы' + 475 'Общий сбой платежной системы' + 490 'Отмена платежа невозможна' + 600 'Общая ошибка' + 700 'Ошибка в данных введенных покупателем' + 701 'Некорректный номер телефона' + 711 'Номер телефона неприемлем для выбранной ПС' + 850 'Ни одна из платежных систем не готова принять запрос' + 1000 'Внутренняя ошибка сервиса (может не повториться при повторном обращении)' + """ + def __init__(self, *args, **kwargs): + self.PG_URL = kwargs.pop('pg_url', None) or getattr(settings, 'PG_URL', '') + self.PG_SECRET = kwargs.pop('pg_secret', None) or getattr(settings, 'PG_SECRET', '') + self.PG_MERCHANT_ID = kwargs.pop('pg_merchant_id', None) or getattr(settings, 'PG_MERCHANT_ID', '') + self.PG_TESTING_MODE = kwargs.pop('pg_testing', None) or getattr(settings, 'PG_TESTING_MODE', '') + self.PG_RESULT_URL = kwargs.pop('pg_result_url', None) or getattr(settings, 'PG_RESULT_URL', '') + self.PG_SUCCESS_URL = kwargs.pop('pg_success_url', None) or getattr(settings, 'PG_SUCCESS_URL', '') + self.PG_CHECK_URL = kwargs.pop('pg_check_url', None) or getattr(settings, 'PG_CHECK_URL', '') + self.PG_REFUND_URL = kwargs.pop('pg_refund_url', None) or getattr(settings, 'PG_REFUND_URL', '') + self.PG_CAPTURE_URL = kwargs.pop('pg_capture_url', None) or getattr(settings, 'PG_CAPTURE_URL', '') + self.PG_FAILURE_URL = kwargs.pop('pg_failure_url', None) or getattr(settings, 'PG_FAILURE_URL', '') + + @staticmethod + def parse_body(body): + body = body.decode('utf-8') + body = parse_qs(body) + for k, v in body.items(): + body[k] = v[0] + return body + + def get_sig(self, mydict, url='payment.php'): + new_list = list() + for key in sorted(mydict.keys()): + new_list.append(str(mydict[key])) + res = url + ';' + ';'.join(new_list) + ';' + self.PG_SECRET + hashed = hashlib.md5(res.encode('utf-8')).hexdigest() + return hashed + + @staticmethod + def verify_sig(request, url=''): + if request.method == 'GET': + sig = request.GET.get('pg_sig') + my_dict = request.GET.dict() + else: + my_dict = PayboxAPI.parse_body(request.body) + sig = my_dict.pop('pg_sig', None) + if sig != PayboxAPI().get_sig(my_dict, url=url): + return False + return True + + @staticmethod + def verify_paybox(): + def decorator(func): + @wraps(func) + def inner(request, *args, **kwargs): + if not PayboxAPI.verify_sig(request): + raise Exception(detail='Неправильная подпись') + response = func(request, *args, **kwargs) + return response + return inner + return decorator + + @staticmethod + def generate_salt(length=8): + chars = string.ascii_letters + string.digits + rnd = random.SystemRandom() + return ''.join(rnd.choice(chars) for _ in range(length)) + + def get_url(self, order_id, amount, description, salt, email=None, phone=None): + params = { + 'pg_order_id': order_id, + 'pg_merchant_id': self.PG_MERCHANT_ID, + 'pg_amount': amount, + 'pg_currency': 'KZT', + 'pg_description': description, + 'pg_salt': salt, + 'pg_testing_mode': self.PG_TESTING_MODE, + 'pg_request_method': 'POST', + 'pg_success_url_method': 'POST', + 'pg_failure_url_method': 'POST', + 'pg_result_url': self.PG_RESULT_URL, + 'pg_success_url': self.PG_SUCCESS_URL, + 'pg_check_url': self.PG_CHECK_URL, + 'pg_refund_url': self.PG_REFUND_URL, + 'pg_capture_url': self.PG_CAPTURE_URL, + 'pg_failure_url': self.PG_FAILURE_URL, + } + + if email: + params['pg_user_contact_email'] = email + + if phone: + params['pg_user_phone'] = phone + + params['pg_sig'] = self.get_sig(params) + + return Request('GET', self.PG_URL, params=params).prepare().url diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8f50dab --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +django>=1.11 +requests>=2.14 +coverage +codecov +flake8 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d548fee --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +from setuptools import ( + find_packages, + setup, +) + +setup( + name='django-paybox-api', + version='0.0.1', + author='Aiba', + description='Django paybox api', + url='https://github.com/aibaq/django-paybox-api', + packages=find_packages(exclude=('*tests*',)), + install_requires=[ + 'django>=1.11', + 'requests>=2.14', + ], +) diff --git a/test_app/__init__.py b/test_app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_app/__init__.pyc b/test_app/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a285447016ba8a578b22e0fe93bbfd48795d5de GIT binary patch literal 162 zcmZSn%*(Y&>1#|f0~9a{Y2 zU;m-%FZ2W2Sp!NX@MU&q&Y9V>vs?T#HU9h8QmX@3Pld)U`sGhDoIVXg02e?2^fl-g zZcK_GN^qfFeeMYG0=Q)m6>vv$I|jT6?l|xgxD&vMPzGKBJ_?*5icdg~$deFg5EOt< z0-u8QtM#TpP(l?h2$+U-J_GA+75FT;)4=Dzow?4M2fje~9pHCqSR~pk@O#kHz@1aO zu$S-Cj)K4RnDP}(SE4jN+t~2pwboYjWNXk~UEO>dbi>oq&fe{;u=>#pYUn zO}tItbe2}+6s4h%==n)f%hFKFQHtmieGEFfTp)+{{iqk$I&p+)(60G>5JYnR79hh@ z`S503C5i~~JP}eZ-ozz^gE+bs8xZFA$UL|uFW1-&LXtmDaL32g?|cuU-v4aguC*yD zA}(w4M;M@Zjb&mpb9dilQY8}Q8Yz)$8ebWzOT$Ii&qB=iH0%)up{(@;dI<^3H}zO? z^Co#wEJe*EiPO&{lDe0w7LB>+FUO9z$BZ3j<*hkIOymb$&!k96 zmSR%l2Uw)^rgfMrzr;|Z(8{tp2P}|@B`WcWkEfU7gEaC7BA@$hna9=9dY`8 z4V!s8`&KT+W_61>-T^zwD>-QP7~*^R?*%)$wZI?Q%F zt7)3#E2WNQ)DM_tqq?wExN%IS_ZqfiFH-=9Mjnu>H>rP8_k*^tCu!Ul9h5r83HqT< z*HLBzk^0@P9}sDHZS?Cy)}=soLb8^e=c|7l#5@bdC)IPgN@lXSqLtNKpubquhVNMJ PRkTMX!U`&0(W<3?f`%tK literal 0 HcmV?d00001 diff --git a/test_app/tests/__init__.py b/test_app/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test_app/tests/__pycache__/__init__.cpython-37.pyc b/test_app/tests/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f168d90fee407f1740b245308d2bcf6ae3bb2a8 GIT binary patch literal 168 zcmZ?b<>g`kf=x>K!yVl7qb9~6oz01O-8?!3`HPe1o10SKeRZts8~NS zGbvHOpeR2pHMyi%za+n)Br!)nIX|zsG&i*N5~C000lUEcO5Z literal 0 HcmV?d00001 diff --git a/test_app/tests/__pycache__/test_utils.cpython-37.pyc b/test_app/tests/__pycache__/test_utils.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e83505b3f7f637095c9a51ac78190fbe77da9914 GIT binary patch literal 905 zcmbtS!EV$r5Vakrgl=}*D~JQ)79=)&074ZNEvFTtaEXvCH})=Dl1*wmhh4R&?T55S zZivtEl@lMpr6*<_3JX#tBu4UR#`c?eZ|oPt;Wh#L^62~f&y0~E=aAHC71own{kmaZ{NpS*=+ zUs|0}pU$)stpvYpb%}r*V-W1YvJb#%Qcy(-rl?{Uq=@=<1@9aAokQ(j|15&VOHdLF zi=c{qSoR?}N7m$$DtblF=^43XE;^%YD0&qX0qbaTO>@s*HMP#TLA;NEogYYRwQ(;` zJ6Rbl3BtJ5)zsfHy}VDvq_BT|l)rtF@8Sshq>5 zQaU5ckMqSWcR*aowhaLQFzwvDvg3B??}c=8SmFav6pIFXS|mhhN>|xmlNjHM`>z?T z;#?k=`6`(-?#afiOaeU2U3C474E`=NK!-$oH-yOFzlGUS+g&*SE$Q(;N&?^{i+v)* zLc(N(-xi{7R99h~3V|=zpO_I++4;riPi7{D1Ed`&BrM@!XOeCCfjW_kSrdjD{)UO* jUNH(%;OWNUy@K?B+0Yz%1mVfEp4D^wT%pHqoJKzYM