add python3 compatibility (#23720)
This commit is contained in:
parent
31b85ae9fd
commit
887832bc5f
|
@ -1,9 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import importlib
|
||||
import logging
|
||||
|
||||
from common import (URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED,
|
||||
CANCELED, CANCELLED, ERROR, WAITING, ResponseError, force_text)
|
||||
from .common import (URL, HTML, FORM, RECEIVED, ACCEPTED, PAID, DENIED,
|
||||
CANCELED, CANCELLED, ERROR, WAITING, ResponseError, force_text)
|
||||
|
||||
__all__ = ['Payment', 'URL', 'HTML', 'FORM', 'SIPS',
|
||||
'SYSTEMPAY', 'SPPLUS', 'TIPI', 'DUMMY', 'get_backend', 'RECEIVED', 'ACCEPTED',
|
||||
|
@ -23,7 +24,7 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
def get_backend(kind):
|
||||
'''Resolve a backend name into a module object'''
|
||||
module = __import__(kind, globals(), locals(), [])
|
||||
module = importlib.import_module('.' + kind, package='eopayment')
|
||||
return module.Payment
|
||||
|
||||
__BACKENDS = [ DUMMY, SIPS, SIPS2, SYSTEMPAY, SPPLUS, OGONE, PAYBOX, PAYZEN, TIPI ]
|
||||
|
|
|
@ -2,9 +2,15 @@ import os.path
|
|||
import os
|
||||
import random
|
||||
import logging
|
||||
import cgi
|
||||
from datetime import date
|
||||
|
||||
import six
|
||||
|
||||
if six.PY3:
|
||||
import html
|
||||
else:
|
||||
import cgi
|
||||
|
||||
__all__ = ['PaymentCommon', 'URL', 'HTML', 'RANDOM', 'RECEIVED', 'ACCEPTED',
|
||||
'PAID', 'ERROR', 'WAITING']
|
||||
|
||||
|
@ -29,15 +35,27 @@ ORDERID_TRANSACTION_SEPARATOR = '!'
|
|||
|
||||
|
||||
def force_text(s, encoding='utf-8'):
|
||||
if isinstance(s, unicode):
|
||||
if issubclass(type(s), six.text_type):
|
||||
return s
|
||||
try:
|
||||
return unicode(s, encoding)
|
||||
if not issubclass(type(s), six.string_types):
|
||||
if six.PY3:
|
||||
if isinstance(s, bytes):
|
||||
s = six.text_type(s, encoding)
|
||||
else:
|
||||
s = six.text_type(s)
|
||||
elif hasattr(s, '__unicode__'):
|
||||
s = six.text_type(s)
|
||||
else:
|
||||
s = six.text_type(bytes(s), encoding)
|
||||
else:
|
||||
s = s.decode(encoding)
|
||||
except UnicodeDecodeError:
|
||||
return unicode(s)
|
||||
return six.text_type(s, encoding, 'ignore')
|
||||
return s
|
||||
|
||||
def force_byte(s, encoding='utf-8'):
|
||||
if isinstance(s, str):
|
||||
if isinstance(s, bytes):
|
||||
return s
|
||||
try:
|
||||
return s.encode(encoding)
|
||||
|
@ -148,7 +166,10 @@ class Form(object):
|
|||
return s
|
||||
|
||||
def escape(self, s):
|
||||
return cgi.escape(force_text(s, self.encoding).encode(self.encoding))
|
||||
if six.PY3:
|
||||
return html.escape(force_text(s, self.encoding))
|
||||
else:
|
||||
return cgi.escape(force_text(s, self.encoding)).encode(self.encoding)
|
||||
|
||||
def __str__(self):
|
||||
s = '<form method="%s" action="%s">' % (self.method, self.url)
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import urllib
|
||||
import string
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
def N_(message): return message
|
||||
|
||||
try:
|
||||
from cgi import parse_qs
|
||||
except ImportError:
|
||||
from urlparse import parse_qs
|
||||
from six.moves.urllib.parse import parse_qs, urlencode
|
||||
|
||||
from common import PaymentCommon, URL, PaymentResponse, PAID, ERROR, WAITING, ResponseError
|
||||
from .common import (PaymentCommon, URL, PaymentResponse, PAID, ERROR, WAITING,
|
||||
ResponseError, force_text)
|
||||
|
||||
__all__ = [ 'Payment' ]
|
||||
|
||||
SERVICE_URL = 'http://dummy-payment.demo.entrouvert.com/'
|
||||
ALPHANUM = string.letters + string.digits
|
||||
ALPHANUM = string.ascii_letters + string.digits
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class Payment(PaymentCommon):
|
||||
|
@ -114,14 +111,14 @@ class Payment(PaymentCommon):
|
|||
}
|
||||
query.update(dict(name=name, address=address, email=email, phone=phone,
|
||||
orderid=orderid, info1=info1, info2=info2, info3=info3))
|
||||
for key in query.keys():
|
||||
for key in list(query.keys()):
|
||||
if query[key] is None:
|
||||
del query[key]
|
||||
url = '%s?%s' % (SERVICE_URL, urllib.urlencode(query))
|
||||
url = '%s?%s' % (SERVICE_URL, urlencode(query))
|
||||
return transaction_id, URL, url
|
||||
|
||||
def response(self, query_string, logger=LOGGER, **kwargs):
|
||||
form = parse_qs(query_string)
|
||||
form = parse_qs(force_text(query_string))
|
||||
if not 'transaction_id' in form:
|
||||
raise ResponseError()
|
||||
transaction_id = form.get('transaction_id',[''])[0]
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import hashlib
|
||||
import string
|
||||
import urlparse
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
|
||||
from common import (PaymentCommon, PaymentResponse, FORM, CANCELLED, PAID,
|
||||
from .common import (PaymentCommon, PaymentResponse, FORM, CANCELLED, PAID,
|
||||
ERROR, Form, DENIED, ACCEPTED, ORDERID_TRANSACTION_SEPARATOR,
|
||||
WAITING, ResponseError, force_byte, force_text)
|
||||
def N_(message): return message
|
||||
|
@ -499,7 +500,7 @@ class Payment(PaymentCommon):
|
|||
# arrondi comptable francais
|
||||
amount = amount.quantize(Decimal('1.'), rounding=ROUND_HALF_UP)
|
||||
params = {
|
||||
'AMOUNT': unicode(amount),
|
||||
'AMOUNT': force_text(amount),
|
||||
'ORDERID': reference,
|
||||
'PSPID': self.pspid,
|
||||
'LANGUAGE': language,
|
||||
|
@ -517,7 +518,7 @@ class Payment(PaymentCommon):
|
|||
params['EMAIL'] = email
|
||||
if description:
|
||||
params['COM'] = description
|
||||
for key, value in kwargs.iteritems():
|
||||
for key, value in kwargs.items():
|
||||
params[key.upper()] = value
|
||||
params['SHASIGN'] = self.sha_sign_in(params)
|
||||
# uniformize all values to UTF-8 string
|
||||
|
@ -533,7 +534,10 @@ class Payment(PaymentCommon):
|
|||
return reference, FORM, form
|
||||
|
||||
def response(self, query_string, **kwargs):
|
||||
params = urlparse.parse_qs(query_string, True)
|
||||
if six.PY3:
|
||||
params = urlparse.parse_qs(query_string, True, encoding='iso-8859-1')
|
||||
else:
|
||||
params = urlparse.parse_qs(query_string, True)
|
||||
params = dict((key.upper(), params[key][0]) for key in params)
|
||||
if not set(params) >= set(['ORDERID', 'PAYID', 'STATUS', 'NCERROR']):
|
||||
raise ResponseError()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: utf-8
|
||||
|
||||
import codecs
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
import logging
|
||||
|
@ -9,15 +10,18 @@ from decimal import Decimal, ROUND_DOWN
|
|||
from Crypto.Signature import PKCS1_v1_5
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Hash import SHA
|
||||
import urlparse
|
||||
import urllib
|
||||
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from six.moves.urllib import parse as urllib
|
||||
|
||||
import base64
|
||||
from gettext import gettext as _
|
||||
import string
|
||||
import warnings
|
||||
|
||||
from common import (PaymentCommon, PaymentResponse, FORM, PAID, ERROR, Form,
|
||||
ORDERID_TRANSACTION_SEPARATOR, ResponseError)
|
||||
from .common import (PaymentCommon, PaymentResponse, FORM, PAID, ERROR, Form,
|
||||
ORDERID_TRANSACTION_SEPARATOR, ResponseError, force_text)
|
||||
|
||||
__all__ = ['sign', 'Payment']
|
||||
|
||||
|
@ -109,9 +113,10 @@ def sign(data, key):
|
|||
algo = ALGOS[v]
|
||||
break
|
||||
assert algo, 'Missing or invalid PBX_HASH'
|
||||
tosign = ['%s=%s' % (k, unicode(v).encode('utf-8')) for k, v in data]
|
||||
tosign = ['%s=%s' % (k, force_text(v)) for k, v in data]
|
||||
tosign = '&'.join(tosign)
|
||||
logger.debug('signed string %r', tosign)
|
||||
tosign = tosign.encode('utf-8')
|
||||
signature = hmac.new(key, tosign, algo)
|
||||
return tuple(data) + (('PBX_HMAC', signature.hexdigest().upper()),)
|
||||
|
||||
|
@ -208,22 +213,22 @@ class Payment(PaymentCommon):
|
|||
|
||||
def request(self, amount, email, name=None, orderid=None, **kwargs):
|
||||
d = OrderedDict()
|
||||
d['PBX_SITE'] = unicode(self.site)
|
||||
d['PBX_RANG'] = unicode(self.rang).strip()[-2:]
|
||||
d['PBX_IDENTIFIANT'] = unicode(self.identifiant)
|
||||
d['PBX_SITE'] = force_text(self.site)
|
||||
d['PBX_RANG'] = force_text(self.rang).strip()[-2:]
|
||||
d['PBX_IDENTIFIANT'] = force_text(self.identifiant)
|
||||
d['PBX_TOTAL'] = (amount * Decimal(100)).to_integral_value(ROUND_DOWN)
|
||||
d['PBX_DEVISE'] = unicode(self.devise)
|
||||
d['PBX_DEVISE'] = force_text(self.devise)
|
||||
transaction_id = kwargs.get('transaction_id') or \
|
||||
self.transaction_id(12, string.digits, 'paybox', self.site,
|
||||
self.rang, self.identifiant)
|
||||
d['PBX_CMD'] = unicode(transaction_id)
|
||||
d['PBX_CMD'] = force_text(transaction_id)
|
||||
# prepend order id command reference
|
||||
if orderid:
|
||||
d['PBX_CMD'] = orderid + ORDERID_TRANSACTION_SEPARATOR + d['PBX_CMD']
|
||||
d['PBX_PORTEUR'] = unicode(email)
|
||||
d['PBX_PORTEUR'] = force_text(email)
|
||||
d['PBX_RETOUR'] = 'montant:M;reference:R;code_autorisation:A;erreur:E;signature:K'
|
||||
d['PBX_HASH'] = 'SHA512'
|
||||
d['PBX_TIME'] = kwargs.get('time') or (unicode(datetime.datetime.utcnow().isoformat('T')).split('.')[0]+'+00:00')
|
||||
d['PBX_TIME'] = kwargs.get('time') or (force_text(datetime.datetime.utcnow().isoformat('T')).split('.')[0]+'+00:00')
|
||||
d['PBX_ARCHIVAGE'] = transaction_id
|
||||
if self.normal_return_url:
|
||||
d['PBX_EFFECTUE'] = self.normal_return_url
|
||||
|
@ -236,16 +241,21 @@ class Payment(PaymentCommon):
|
|||
"use automatic_return_url", DeprecationWarning)
|
||||
automatic_return_url = self.callback
|
||||
if automatic_return_url:
|
||||
d['PBX_REPONDRE_A'] = unicode(automatic_return_url)
|
||||
d['PBX_REPONDRE_A'] = force_text(automatic_return_url)
|
||||
d = d.items()
|
||||
d = sign(d, self.shared_secret.decode('hex'))
|
||||
|
||||
if six.PY3:
|
||||
shared_secret = codecs.decode(bytes(self.shared_secret, 'ascii'), 'hex')
|
||||
else:
|
||||
shared_secret = codecs.decode(bytes(self.shared_secret), 'hex')
|
||||
d = sign(d, shared_secret)
|
||||
url = URLS[self.platform]
|
||||
fields = []
|
||||
for k, v in d:
|
||||
fields.append({
|
||||
'type': u'hidden',
|
||||
'name': unicode(k),
|
||||
'value': unicode(v),
|
||||
'name': force_text(k),
|
||||
'value': force_text(v),
|
||||
})
|
||||
form = Form(url, 'POST', fields, submit_name=None,
|
||||
submit_value=u'Envoyer', encoding='utf-8')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import urlparse
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import string
|
||||
import subprocess
|
||||
from decimal import Decimal
|
||||
|
@ -9,8 +9,8 @@ import os.path
|
|||
import uuid
|
||||
import warnings
|
||||
|
||||
from common import PaymentCommon, HTML, PaymentResponse, ResponseError
|
||||
from cb import CB_RESPONSE_CODES
|
||||
from .common import PaymentCommon, HTML, PaymentResponse, ResponseError
|
||||
from .cb import CB_RESPONSE_CODES
|
||||
|
||||
'''
|
||||
Payment backend module for the ATOS/SIPS system used by many Frenck banks.
|
||||
|
@ -112,7 +112,7 @@ class Payment(PaymentCommon):
|
|||
if PATHFILE in self.options:
|
||||
params[PATHFILE] = self.options[PATHFILE]
|
||||
executable = os.path.join(self.binpath, executable)
|
||||
args = [executable] + ["%s=%s" % p for p in params.iteritems()]
|
||||
args = [executable] + ["%s=%s" % p for p in params.items()]
|
||||
self.logger.debug('executing %s' % args)
|
||||
result,_ = subprocess.Popen(' '.join(args),
|
||||
stdout=subprocess.PIPE, shell=True).communicate()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import collections
|
||||
import json
|
||||
import urlparse
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import string
|
||||
from decimal import Decimal
|
||||
import uuid
|
||||
|
@ -11,8 +11,8 @@ from gettext import gettext as _
|
|||
import requests
|
||||
import warnings
|
||||
|
||||
from common import (PaymentCommon, FORM, Form, PaymentResponse, PAID, ERROR,
|
||||
CANCELED, ResponseError)
|
||||
from .common import (PaymentCommon, FORM, Form, PaymentResponse, PAID, ERROR,
|
||||
CANCELED, ResponseError, force_text)
|
||||
|
||||
__all__ = ['Payment']
|
||||
|
||||
|
@ -139,12 +139,12 @@ class Payment(PaymentCommon):
|
|||
}
|
||||
|
||||
def encode_data(self, data):
|
||||
return u'|'.join(u'%s=%s' % (unicode(key), unicode(value))
|
||||
for key, value in data.iteritems())
|
||||
return u'|'.join(u'%s=%s' % (force_text(key), force_text(value))
|
||||
for key, value in data.items())
|
||||
|
||||
def seal_data(self, data):
|
||||
s = self.encode_data(data)
|
||||
s += unicode(self.secret_key)
|
||||
s += force_text(self.secret_key)
|
||||
s = s.encode('utf-8')
|
||||
s = hashlib.sha256(s).hexdigest()
|
||||
return s
|
||||
|
@ -172,13 +172,13 @@ class Payment(PaymentCommon):
|
|||
info1=None, info2=None, info3=None, next_url=None, **kwargs):
|
||||
data = self.get_data()
|
||||
transaction_id = self.transaction_id(10, string.digits, 'sips2', data['merchantId'])
|
||||
data['transactionReference'] = unicode(transaction_id)
|
||||
data['orderId'] = orderid or unicode(uuid.uuid4()).replace('-', '')
|
||||
data['transactionReference'] = force_text(transaction_id)
|
||||
data['orderId'] = orderid or force_text(uuid.uuid4()).replace('-', '')
|
||||
if info1:
|
||||
data['statementReference'] = unicode(info1)
|
||||
data['statementReference'] = force_text(info1)
|
||||
else:
|
||||
data['statementReference'] = data['transactionReference']
|
||||
data['amount'] = unicode(int(Decimal(amount) * 100))
|
||||
data['amount'] = force_text(int(Decimal(amount) * 100))
|
||||
if email:
|
||||
data['billingContact.email'] = email
|
||||
if 'captureDay' in kwargs:
|
||||
|
@ -215,7 +215,7 @@ class Payment(PaymentCommon):
|
|||
|
||||
def decode_data(self, data):
|
||||
data = data.split('|')
|
||||
data = [map(unicode, p.split('=', 1)) for p in data]
|
||||
data = [map(force_text, p.split('=', 1)) for p in data]
|
||||
return collections.OrderedDict(data)
|
||||
|
||||
def check_seal(self, data, seal):
|
||||
|
@ -254,9 +254,9 @@ class Payment(PaymentCommon):
|
|||
for key in sorted(data.keys()):
|
||||
if key in ('keyVersion', 'sealAlgorithm', 'seal'):
|
||||
continue
|
||||
data_to_send.append(unicode(data[key]))
|
||||
data_to_send.append(force_text(data[key]))
|
||||
data_to_send_str = u''.join(data_to_send).encode('utf-8')
|
||||
return hmac.new(unicode(self.secret_key).encode('utf-8'), data_to_send_str, hashlib.sha256).hexdigest()
|
||||
return hmac.new(force_text(self.secret_key).encode('utf-8'), data_to_send_str, hashlib.sha256).hexdigest()
|
||||
|
||||
def perform_cash_management_operation(self, endpoint, data):
|
||||
data['merchantId'] = self.merchant_id
|
||||
|
@ -282,13 +282,13 @@ class Payment(PaymentCommon):
|
|||
|
||||
def cancel(self, amount, bank_data, **kwargs):
|
||||
data = {}
|
||||
data['operationAmount'] = unicode(int(Decimal(amount) * 100))
|
||||
data['operationAmount'] = force_text(int(Decimal(amount) * 100))
|
||||
data['transactionReference'] = bank_data.get('transactionReference')
|
||||
return self.perform_cash_management_operation('cancel', data)
|
||||
|
||||
def validate(self, amount, bank_data, **kwargs):
|
||||
data = {}
|
||||
data['operationAmount'] = unicode(int(Decimal(amount) * 100))
|
||||
data['operationAmount'] = force_text(int(Decimal(amount) * 100))
|
||||
data['transactionReference'] = bank_data.get('transactionReference')
|
||||
return self.perform_cash_management_operation('validate', data)
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ import binascii
|
|||
from gettext import gettext as _
|
||||
import hmac
|
||||
import hashlib
|
||||
import urlparse
|
||||
import urllib
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from six.moves.urllib import parse as urllib
|
||||
import string
|
||||
import datetime as dt
|
||||
import logging
|
||||
|
@ -13,15 +13,15 @@ import re
|
|||
import warnings
|
||||
|
||||
import Crypto.Cipher.DES
|
||||
from common import (PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED,
|
||||
PAID, ERROR, ResponseError)
|
||||
from .common import (PaymentCommon, URL, PaymentResponse, RECEIVED, ACCEPTED,
|
||||
PAID, ERROR, ResponseError, force_byte)
|
||||
|
||||
def N_(message): return message
|
||||
|
||||
__all__ = ['Payment']
|
||||
|
||||
KEY_DES_KEY = '\x45\x1f\xba\x4f\x4c\x3f\xd4\x97'
|
||||
IV = '\x30\x78\x30\x62\x2c\x30\x78\x30'
|
||||
KEY_DES_KEY = b'\x45\x1f\xba\x4f\x4c\x3f\xd4\x97'
|
||||
IV = b'\x30\x78\x30\x62\x2c\x30\x78\x30'
|
||||
REFERENCE = 'reference'
|
||||
ETAT = 'etat'
|
||||
SPCHECKOK = 'spcheckok'
|
||||
|
@ -56,7 +56,7 @@ TEST_STATE = ('99',)
|
|||
|
||||
|
||||
def decrypt_ntkey(ntkey):
|
||||
key = binascii.unhexlify(ntkey.replace(' ',''))
|
||||
key = binascii.unhexlify(ntkey.replace(b' ', b''))
|
||||
return decrypt_key(key)
|
||||
|
||||
def decrypt_key(key):
|
||||
|
@ -70,7 +70,7 @@ def extract_values(query_string):
|
|||
k, v = kv.split('=', 1)
|
||||
if k != 'hmac':
|
||||
result.append(v)
|
||||
return ''.join(result)
|
||||
return force_byte(''.join(result))
|
||||
|
||||
def sign_ntkey_query(ntkey, query):
|
||||
key = decrypt_ntkey(ntkey)
|
||||
|
@ -89,7 +89,7 @@ def sign_url_paiement(ntkey, query):
|
|||
data_to_sign = ''.join(fields)
|
||||
return hmac.new(key[:20], data_to_sign, hashlib.sha1).hexdigest().upper()
|
||||
|
||||
ALPHANUM = string.letters + string.digits
|
||||
ALPHANUM = string.ascii_letters + string.digits
|
||||
SERVICE_URL = "https://www.spplus.net/paiement/init.do"
|
||||
|
||||
class Payment(PaymentCommon):
|
||||
|
@ -178,7 +178,7 @@ class Payment(PaymentCommon):
|
|||
form = urlparse.parse_qs(query_string)
|
||||
if not set(form) >= set([REFERENCE, ETAT, REFSFP]):
|
||||
raise ResponseError()
|
||||
for key, value in form.iteritems():
|
||||
for key, value in form.items():
|
||||
form[key] = value[0]
|
||||
logger.debug('received query_string %s' % query_string)
|
||||
logger.debug('parsed as %s' % form)
|
||||
|
@ -233,8 +233,8 @@ if __name__ == '__main__':
|
|||
|
||||
ntkey = '58 6d fc 9c 34 91 9b 86 3f fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
|
||||
if len(sys.argv) == 2:
|
||||
print sign_url_paiement(ntkey, sys.argv[1])
|
||||
print sign_ntkey_query(ntkey, sys.argv[1])
|
||||
print(sign_url_paiement(ntkey, sys.argv[1]))
|
||||
print(sign_ntkey_query(ntkey, sys.argv[1]))
|
||||
elif len(sys.argv) > 2:
|
||||
print sign_url_paiement(sys.argv[1], sys.argv[2])
|
||||
print sign_ntkey_query(sys.argv[1], sys.argv[2])
|
||||
print(sign_url_paiement(sys.argv[1], sys.argv[2]))
|
||||
print(sign_ntkey_query(sys.argv[1], sys.argv[2]))
|
||||
|
|
|
@ -4,13 +4,13 @@ import datetime as dt
|
|||
import hashlib
|
||||
import logging
|
||||
import string
|
||||
import urlparse
|
||||
from six.moves.urllib import parse as urlparse
|
||||
import warnings
|
||||
from gettext import gettext as _
|
||||
|
||||
from common import (PaymentCommon, PaymentResponse, PAID, ERROR, FORM, Form,
|
||||
ResponseError, force_text, force_byte)
|
||||
from cb import CB_RESPONSE_CODES
|
||||
from .common import (PaymentCommon, PaymentResponse, PAID, ERROR, FORM, Form,
|
||||
ResponseError, force_text, force_byte)
|
||||
from .cb import CB_RESPONSE_CODES
|
||||
|
||||
__all__ = ['Payment']
|
||||
|
||||
|
@ -117,20 +117,20 @@ PARAMETERS = [
|
|||
'ONEY_SANDBOX, PAYPAL, PAYPAL_SB, PAYSAFECARD, '
|
||||
'VISA')),
|
||||
# must be SINGLE or MULTI with parameters
|
||||
Parameter('vads_payment_config', '', 07, default='SINGLE',
|
||||
Parameter('vads_payment_config', '', 7, default='SINGLE',
|
||||
choices=('SINGLE', 'MULTI'), needed=True),
|
||||
Parameter('vads_return_mode', None, 48, default='GET',
|
||||
choices=('', 'NONE', 'POST', 'GET')),
|
||||
Parameter('signature', 'an', None, length=40),
|
||||
Parameter('vads_site_id', 'n', 02, length=8, needed=True,
|
||||
Parameter('vads_site_id', 'n', 2, length=8, needed=True,
|
||||
description=_(u'Identifiant de la boutique')),
|
||||
Parameter('vads_theme_config', 'ans', 32, max_length=255),
|
||||
Parameter(VADS_TRANS_DATE, 'n', 04, length=14, needed=True,
|
||||
Parameter(VADS_TRANS_DATE, 'n', 4, length=14, needed=True,
|
||||
default=isonow),
|
||||
Parameter('vads_trans_id', 'n', 03, length=6, needed=True),
|
||||
Parameter('vads_trans_id', 'n', 3, length=6, needed=True),
|
||||
Parameter('vads_validation_mode', 'n', 5, max_length=1, choices=('', 0, 1),
|
||||
default=''),
|
||||
Parameter('vads_version', 'an', 01, default='V2', needed=True,
|
||||
Parameter('vads_version', 'an', 1, default='V2', needed=True,
|
||||
choices=('V2',)),
|
||||
Parameter('vads_url_success', 'ans', 24, max_length=127),
|
||||
Parameter('vads_url_referral', 'ans', 26, max_length=127),
|
||||
|
@ -173,7 +173,7 @@ EXTRA_RESULT_MAP = {
|
|||
|
||||
def add_vads(kwargs):
|
||||
new_vargs = {}
|
||||
for k, v in kwargs.iteritems():
|
||||
for k, v in kwargs.items():
|
||||
if k.startswith('vads_'):
|
||||
new_vargs[k] = v
|
||||
else:
|
||||
|
@ -276,8 +276,8 @@ class Payment(PaymentCommon):
|
|||
info2, info3, next_url, kwargs)
|
||||
# amount unit is cents
|
||||
amount = '%.0f' % (100 * amount)
|
||||
kwargs.update(add_vads({'amount': unicode(amount)}))
|
||||
if amount < 0:
|
||||
kwargs.update(add_vads({'amount': force_text(amount)}))
|
||||
if int(amount) < 0:
|
||||
raise ValueError('amount must be an integer >= 0')
|
||||
normal_return_url = self.normal_return_url
|
||||
if next_url:
|
||||
|
@ -285,30 +285,30 @@ class Payment(PaymentCommon):
|
|||
"set normal_return_url in options", DeprecationWarning)
|
||||
normal_return_url = next_url
|
||||
if normal_return_url:
|
||||
kwargs[VADS_URL_RETURN] = unicode(normal_return_url)
|
||||
kwargs[VADS_URL_RETURN] = force_text(normal_return_url)
|
||||
if name is not None:
|
||||
kwargs['vads_cust_name'] = unicode(name)
|
||||
kwargs['vads_cust_name'] = force_text(name)
|
||||
if first_name is not None:
|
||||
kwargs[VADS_CUST_FIRST_NAME] = unicode(first_name)
|
||||
kwargs[VADS_CUST_FIRST_NAME] = force_text(first_name)
|
||||
if last_name is not None:
|
||||
kwargs[VADS_CUST_LAST_NAME] = unicode(last_name)
|
||||
kwargs[VADS_CUST_LAST_NAME] = force_text(last_name)
|
||||
|
||||
if address is not None:
|
||||
kwargs['vads_cust_address'] = unicode(address)
|
||||
kwargs['vads_cust_address'] = force_text(address)
|
||||
if email is not None:
|
||||
kwargs['vads_cust_email'] = unicode(email)
|
||||
kwargs['vads_cust_email'] = force_text(email)
|
||||
if phone is not None:
|
||||
kwargs['vads_cust_phone'] = unicode(phone)
|
||||
kwargs['vads_cust_phone'] = force_text(phone)
|
||||
if info1 is not None:
|
||||
kwargs['vads_order_info'] = unicode(info1)
|
||||
kwargs['vads_order_info'] = force_text(info1)
|
||||
if info2 is not None:
|
||||
kwargs['vads_order_info2'] = unicode(info2)
|
||||
kwargs['vads_order_info2'] = force_text(info2)
|
||||
if info3 is not None:
|
||||
kwargs['vads_order_info3'] = unicode(info3)
|
||||
kwargs['vads_order_info3'] = force_text(info3)
|
||||
if orderid is not None:
|
||||
# check orderid format first
|
||||
name = 'vads_order_id'
|
||||
orderid = unicode(orderid)
|
||||
orderid = force_text(orderid)
|
||||
ptype = 'an-'
|
||||
p = Parameter(name, ptype, 13, max_length=32)
|
||||
if not p.check_value(orderid):
|
||||
|
@ -318,14 +318,14 @@ class Payment(PaymentCommon):
|
|||
|
||||
transaction_id = self.transaction_id(6, string.digits, 'systempay',
|
||||
self.options[VADS_SITE_ID])
|
||||
kwargs[VADS_TRANS_ID] = unicode(transaction_id)
|
||||
kwargs[VADS_TRANS_ID] = force_text(transaction_id)
|
||||
fields = kwargs
|
||||
for parameter in PARAMETERS:
|
||||
name = parameter.name
|
||||
# import default parameters from configuration
|
||||
if name not in fields \
|
||||
and name in self.options:
|
||||
fields[name] = unicode(self.options[name])
|
||||
fields[name] = force_text(self.options[name])
|
||||
# import default parameters from module
|
||||
if name not in fields and parameter.default is not None:
|
||||
if callable(parameter.default):
|
||||
|
@ -333,7 +333,7 @@ class Payment(PaymentCommon):
|
|||
else:
|
||||
fields[name] = parameter.default
|
||||
check_vads(fields)
|
||||
fields[SIGNATURE] = unicode(self.signature(fields))
|
||||
fields[SIGNATURE] = force_text(self.signature(fields))
|
||||
self.logger.debug('%s request contains fields: %s', __name__, fields)
|
||||
transaction_id = '%s_%s' % (fields[VADS_TRANS_DATE], transaction_id)
|
||||
self.logger.debug('%s transaction id: %s', __name__, transaction_id)
|
||||
|
@ -346,14 +346,14 @@ class Payment(PaymentCommon):
|
|||
'name': force_text(field_name),
|
||||
'value': force_text(field_value),
|
||||
}
|
||||
for field_name, field_value in fields.iteritems()])
|
||||
for field_name, field_value in fields.items()])
|
||||
return transaction_id, FORM, form
|
||||
|
||||
def response(self, query_string, **kwargs):
|
||||
fields = urlparse.parse_qs(query_string, True)
|
||||
if not set(fields) >= set([SIGNATURE, VADS_CTX_MODE, VADS_AUTH_RESULT]):
|
||||
raise ResponseError()
|
||||
for key, value in fields.iteritems():
|
||||
for key, value in fields.items():
|
||||
fields[key] = value[0]
|
||||
copy = fields.copy()
|
||||
bank_status = []
|
||||
|
@ -417,8 +417,8 @@ class Payment(PaymentCommon):
|
|||
self.logger.debug('ordered keys %s' % ordered_keys)
|
||||
ordered_fields = [force_byte(fields[key]) for key in ordered_keys]
|
||||
secret = getattr(self, 'secret_%s' % fields['vads_ctx_mode'].lower())
|
||||
signed_data = '+'.join(ordered_fields)
|
||||
signed_data = '%s+%s' % (signed_data, force_byte(secret))
|
||||
signed_data = b'+'.join(ordered_fields)
|
||||
signed_data = b'%s+%s' % (signed_data, force_byte(secret))
|
||||
self.logger.debug(u'generating signature on «%s»', signed_data)
|
||||
sign = hashlib.sha1(signed_data).hexdigest()
|
||||
self.logger.debug(u'signature «%s»', sign)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from decimal import Decimal, ROUND_DOWN
|
||||
from common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED,
|
||||
from .common import (PaymentCommon, PaymentResponse, URL, PAID, DENIED,
|
||||
CANCELLED, ERROR, ResponseError)
|
||||
from urllib import urlencode
|
||||
from urlparse import parse_qs
|
||||
from six.moves.urllib.parse import urlencode, parse_qs
|
||||
|
||||
from gettext import gettext as _
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
from systempayv2 import isonow
|
||||
from .systempayv2 import isonow
|
||||
|
||||
__all__ = ['Payment']
|
||||
|
||||
|
@ -95,12 +95,12 @@ class Payment(PaymentCommon):
|
|||
refdet = str(refdet)
|
||||
if 6 > len(refdet) > 30:
|
||||
raise ValueError('len(REFDET) < 6 or > 30')
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
raise ValueError('REFDET format invalide, %r' % refdet, e)
|
||||
if objet is not None:
|
||||
try:
|
||||
objet = str(objet)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
raise ValueError('OBJET must be a string', e)
|
||||
if not objet.replace(' ','').isalnum():
|
||||
raise ValueError('OBJECT must only contains '
|
||||
|
@ -113,7 +113,7 @@ class Payment(PaymentCommon):
|
|||
raise ValueError('no @ in MEL')
|
||||
if not (6 <= len(mel) <= 80):
|
||||
raise ValueError('len(MEL) is invalid, must be between 6 and 80')
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
raise ValueError('MEL is not a valid email, %r' % mel, e)
|
||||
|
||||
saisie = saisie or self.saisie
|
||||
|
@ -146,7 +146,7 @@ class Payment(PaymentCommon):
|
|||
fields = parse_qs(query_string, True)
|
||||
if not set(fields) >= set(['refdet', 'resultrans']):
|
||||
raise ResponseError()
|
||||
for key, value in fields.iteritems():
|
||||
for key, value in fields.items():
|
||||
fields[key] = value[0]
|
||||
refdet = fields.get('refdet')
|
||||
if refdet is None:
|
||||
|
@ -183,11 +183,11 @@ class Payment(PaymentCommon):
|
|||
|
||||
if __name__ == '__main__':
|
||||
p = Payment({'numcli': '12345'})
|
||||
print p.request(amount=Decimal('123.12'),
|
||||
print(p.request(amount=Decimal('123.12'),
|
||||
exer=9999,
|
||||
refdet=999900000000999999,
|
||||
objet='tout a fait',
|
||||
email='info@entrouvert.com',
|
||||
urlcl='http://example.com/tipi/test',
|
||||
saisie='T')
|
||||
print p.response('objet=tout+a+fait&montant=12312&saisie=T&mel=info%40entrouvert.com&numcli=12345&exer=9999&refdet=999900000000999999&resultrans=P')
|
||||
saisie='T'))
|
||||
print(p.response('objet=tout+a+fait&montant=12312&saisie=T&mel=info%40entrouvert.com&numcli=12345&exer=9999&refdet=999900000000999999&resultrans=P'))
|
||||
|
|
9
setup.py
9
setup.py
|
@ -46,7 +46,7 @@ class TestCommand(distutils.core.Command):
|
|||
class eo_sdist(sdist):
|
||||
|
||||
def run(self):
|
||||
print "creating VERSION file"
|
||||
print("creating VERSION file")
|
||||
if os.path.exists('VERSION'):
|
||||
os.remove('VERSION')
|
||||
version = get_version()
|
||||
|
@ -54,7 +54,7 @@ class eo_sdist(sdist):
|
|||
version_file.write(version)
|
||||
version_file.close()
|
||||
sdist.run(self)
|
||||
print "removing VERSION file"
|
||||
print("removing VERSION file")
|
||||
if os.path.exists('VERSION'):
|
||||
os.remove('VERSION')
|
||||
|
||||
|
@ -72,7 +72,7 @@ def get_version():
|
|||
stderr=subprocess.PIPE)
|
||||
result = p.communicate()[0]
|
||||
if p.returncode == 0:
|
||||
version = result.split()[0][1:]
|
||||
version = str(result.split()[0][1:])
|
||||
version = version.replace('-', '.')
|
||||
return version
|
||||
return '0.0.0'
|
||||
|
@ -83,7 +83,7 @@ setuptools.setup(
|
|||
license='GPLv3 or later',
|
||||
description='Common API to use all French online payment credit card '
|
||||
'processing services',
|
||||
long_description=file(
|
||||
long_description=open(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'README.txt')).read(),
|
||||
|
@ -96,6 +96,7 @@ setuptools.setup(
|
|||
install_requires=[
|
||||
'pycrypto >= 2.5',
|
||||
'requests',
|
||||
'six',
|
||||
],
|
||||
cmdclass={
|
||||
'sdist': eo_sdist,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from unittest import TestCase
|
||||
import urllib
|
||||
from six.moves.urllib import parse as urllib
|
||||
|
||||
import eopayment
|
||||
import eopayment.ogone as ogone
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import codecs
|
||||
from unittest import TestCase
|
||||
from decimal import Decimal
|
||||
import base64
|
||||
import urllib
|
||||
from six.moves.urllib import parse as urllib
|
||||
|
||||
import eopayment.paybox as paybox
|
||||
import eopayment
|
||||
|
@ -19,7 +20,8 @@ BACKEND_PARAMS = {
|
|||
|
||||
class PayboxTests(TestCase):
|
||||
def test_sign(self):
|
||||
key = '0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'.decode('hex')
|
||||
key = b'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF'
|
||||
key = codecs.decode(key, 'hex')
|
||||
d = dict(paybox.sign([
|
||||
['PBX_SITE', u'12345678'],
|
||||
['PBX_RANG', u'32'],
|
||||
|
@ -97,7 +99,7 @@ UX4D2A/QcMvkEcRVXFx5tQqcE9/JnMqE41TF/ebn7jC/MBxxtPFkUN7+EZoeMN7x
|
|||
OWzAMDm/xsCWRvvel4GGixgm3aQRUPyTrlm4Ksy32Ya0rNnEDMAvB3dxOn7cp8GR
|
||||
ZdzrudBlevZXpr6iYwIDAQAB
|
||||
-----END PUBLIC KEY-----'''
|
||||
data = 'coin\n'
|
||||
data = b'coin\n'
|
||||
sig64 = '''VCt3sgT0ecacmDEWWNVXJ+jGmIPBMApK42tBJV0FlDjpllOGPy8MsAmLW4/QjTtx
|
||||
z0Dkz0NjxvU+5WzQZh9Uuxr/egRCwV4NMRWqu0zaVVioeBvl4/5CWm4f4/1L9+0m
|
||||
FBFKOZhgBJnkC+l6+XhT4aYWKaQ4ocmOMV92yjeXTE4='''
|
||||
|
|
|
@ -2,8 +2,8 @@ from unittest import TestCase
|
|||
import eopayment.spplus as spplus
|
||||
|
||||
class SPPlustTest(TestCase):
|
||||
ntkey = '58 6d fc 9c 34 91 9b 86 3f ' \
|
||||
'fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
|
||||
ntkey = b'58 6d fc 9c 34 91 9b 86 3f ' \
|
||||
b'fd 64 63 c9 13 4a 26 ba 29 74 1e c7 e9 80 79'
|
||||
|
||||
tests = [('x=coin', 'c04f8266d6ae3ce37551cce996c751be4a95d10a'),
|
||||
('x=coin&y=toto', 'ef008e02f8dbf5e70e83da416b0b3a345db203de'),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import urlparse
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from eopayment.systempayv2 import Payment, VADS_CUST_FIRST_NAME, \
|
||||
VADS_CUST_LAST_NAME, PAID
|
||||
|
|
4
tox.ini
4
tox.ini
|
@ -3,6 +3,10 @@
|
|||
# test suite on all supported python versions. To use it, "pip install tox"
|
||||
# and then run "tox" from this directory.
|
||||
|
||||
[tox]
|
||||
envlist = py2,py3
|
||||
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/eopayment/
|
||||
|
||||
[testenv]
|
||||
# django.contrib.auth is not tested it does not work with our templates
|
||||
commands =
|
||||
|
|
Loading…
Reference in New Issue