From 6998900193b234b53a9da89b43435e5f8aba22e6 Mon Sep 17 00:00:00 2001 From: Serghei Mihai Date: Tue, 9 Oct 2018 16:43:41 +0200 Subject: [PATCH 2/3] paybox: add support for payment cancelling (#26960) --- eopayment/paybox.py | 33 +++++++++++++++++++++++++++++++++ tests/test_paybox.py | 38 ++++++++++++++++++++++++++++++++++++++ tox.ini | 1 + 3 files changed, 72 insertions(+) diff --git a/eopayment/paybox.py b/eopayment/paybox.py index 705f1fe..a6e7938 100644 --- a/eopayment/paybox.py +++ b/eopayment/paybox.py @@ -6,6 +6,7 @@ import datetime import logging import hashlib import hmac +import requests from decimal import Decimal, ROUND_DOWN from Crypto.Signature import PKCS1_v1_5 from Crypto.PublicKey import RSA @@ -99,6 +100,12 @@ URLS = { 'https://tpeweb1.paybox.com/cgi/MYchoix_pagepaiement.cgi', } +DIRECT_URLS = { + 'test': 'https://preprod-ppps.paybox.com/PPPS.php', + 'prod': 'https://ppps.paybox.com/PPPS.php', + 'backup': 'https://ppps1.paybox.com/PPPS.php' +} + def sign(data, key): '''Take a list of tuple key, value and sign it by building a string to @@ -174,6 +181,12 @@ class Payment(PaymentCommon): 'validation': lambda x: isinstance(x, basestring) and x.isdigit() and len(x) == 7, }, + { + 'name': 'cle', + 'caption': _('Clé du site'), + 'required': False, + 'validation': lambda x: isinstance(x, basestring), + }, { 'name': 'rang', 'caption': _('Numéro de rang'), @@ -311,3 +324,23 @@ class Payment(PaymentCommon): bank_data=d, result=result, bank_status=bank_status) + + def cancel(self, amount, bank_data, **kwargs): + logger = logging.getLogger(__name__) + url = DIRECT_URLS[self.platform] + params = {'VERSION': '00104', # protocol version + 'TYPE': '00005', # cancelling operation code + 'SITE': force_text(self.site), + 'RANG': self.rang.strip(), + 'CLE': force_text(self.cle), + 'NUMQUESTION': bank_data['numero_transaction'][0].zfill(10), + 'MONTANT': (amount * Decimal(100)).to_integral_value(ROUND_DOWN), + 'DEVISE': force_text(self.devise), + 'NUMTRANS': bank_data['numero_transaction'][0], # paybox transaction number + 'NUMAPPEL': bank_data['numero_appel'][0], + 'REFERENCE': bank_data['reference'][0], + 'DATEQ': datetime.datetime.now().strftime('%d%m%Y%H%M%S'), + } + response = requests.post(url, params) + logger.debug('received %r', response.content) + return response diff --git a/tests/test_paybox.py b/tests/test_paybox.py index 93d3c32..50a8a8d 100644 --- a/tests/test_paybox.py +++ b/tests/test_paybox.py @@ -4,6 +4,7 @@ import codecs from unittest import TestCase from decimal import Decimal import base64 +import mock from six.moves.urllib import parse as urllib from xml.etree import ElementTree as ET @@ -116,6 +117,43 @@ class PayboxTests(TestCase): with self.assertRaisesRegexp(eopayment.ResponseError, 'missing erreur or reference'): backend.response('foo=bar') + def test_cancel_payment(self): + params = BACKEND_PARAMS.copy() + params['cle'] = 'cancelling_key' + backend = eopayment.Payment('paybox', params) + bank_data = {'numero_transaction': ['13957441'], + 'numero_appel': ['30310733'], + 'reference': ['830657461681'] + } + + with mock.patch('eopayment.paybox.requests.post') as requests_post: + backend.cancel(Decimal('10'), bank_data) + assert requests_post.call_args[0][0] == 'https://preprod-ppps.paybox.com/PPPS.php' + params_sent = requests_post.call_args[0][1] + # make sure the date parameter is present + assert 'DATEQ' in params_sent + # don't care about its value + params_sent.pop('DATEQ') + expected_params = {'CLE': 'cancelling_key', + 'VERSION': '00104', + 'TYPE': '00005', + 'MONTANT': Decimal('1000'), + 'NUMAPPEL': '30310733', + 'NUMTRANS': '13957441', + 'NUMQUESTION': '0013957441', + 'REFERENCE': '830657461681', + 'RANG': backend.backend.rang, + 'SITE': backend.backend.site, + 'DEVISE': backend.backend.devise + } + assert params_sent == expected_params + params['platform'] = 'prod' + backend = eopayment.Payment('paybox', params) + with mock.patch('eopayment.paybox.requests.post') as requests_post: + backend.cancel(Decimal('10'), bank_data) + assert requests_post.call_args[0][0] == 'https://ppps.paybox.com/PPPS.php' + + def test_rsa_signature_validation(self): pkey = '''-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUgYufHuheMztK1LhQSG6xsOzb diff --git a/tox.ini b/tox.ini index 61acc97..31e0d0a 100644 --- a/tox.ini +++ b/tox.ini @@ -15,3 +15,4 @@ usedevelop = True deps = coverage pytest pytest-cov + mock -- 2.19.1