Ensure transaction id unicity, add logging to spplus

This commit is contained in:
Benjamin Dauvergne 2011-04-26 12:41:19 +02:00
parent 7b899eea74
commit 5af4679368
3 changed files with 42 additions and 13 deletions

View File

@ -5,6 +5,7 @@ from decimal import Decimal
import logging
import os
import os.path
import uuid
from common import PaymentCommon, HTML
@ -35,10 +36,21 @@ REQUEST_VALID_PARAMS = ['merchant_id', 'merchant_country', 'amount',
'capture_day', 'capture_mode', 'bgcolor', 'block_align', 'block_order',
'textcolor', 'receipt_complement', 'caddie', 'customer_id', 'customer_email',
'customer_ip_address', 'data', 'return_context', 'target', 'order_id']
RESPONSE_PARAMS = [ 'code', 'error', 'merchant_id', 'merchant_country',
'amount', 'transaction_id', 'payment_means', 'transmission_date',
'payment_time', 'payment_date', 'response_code', 'payment_certificate',
'authorisation_id', 'currency_code', 'card_number', 'cvv_flag',
'cvv_response_code', 'bank_response_code', 'complementary_code',
'complementary_info', 'return_context', 'caddie', 'receipt_complement',
'merchant_language', 'language', 'customer_id', 'order_id', 'customer_email',
'customer_ip_address', 'capture_day', 'capture_mode', 'data', ]
DATA = 'DATA'
PARAMS = 'params'
TRANSACTION_ID = 'transaction_id'
ORDER_ID = 'order_id'
MERCHANT_ID = 'merchant_id'
RESPONSE_CODE = 'response_code'
@ -75,6 +87,7 @@ class Payment(PaymentCommon):
transaction_id = self.transaction_id(6, string.digits, 'sips',
params[MERCHANT_ID])
params[TRANSACTION_ID] = transaction_id
params[ORDER_ID] = str(uuid.uuid4()).replace('-','')
params['amount'] = str(Decimal(amount)*100)
if email:
params['customer_email'] = email
@ -82,7 +95,7 @@ class Payment(PaymentCommon):
params['normal_return_url'] = next_url
code, error, form = self.execute('request', params)
if int(code) == 0:
return transaction_id, HTML, form
return params[ORDER_ID], HTML, form
else:
raise RuntimeError('sips/request returned -1: %s' % error)
@ -90,6 +103,6 @@ class Payment(PaymentCommon):
form = urlparse.parse_qs(query_string)
params = {'message': form[DATA]}
result = self.execute('response', params)
d = dict([p.split('=',1) for p in result])
d = dict(zip(RESPONSE_PARAMS, result))
LOGGER.debug('response contains fields %s' % d)
return result.get(RESPONSE_CODE) == '00', form.get(TRANSACTION_ID), d
return result.get(RESPONSE_CODE) == '00', form.get(ORDER_ID), d, None

View File

@ -11,12 +11,15 @@ import logging
import Crypto.Cipher.DES
from common import PaymentCommon, URL
__all__ = ['Payment']
KEY_DES_KEY = '\x45\x1f\xba\x4f\x4c\x3f\xd4\x97'
IV = '\x30\x78\x30\x62\x2c\x30\x78\x30'
REFERENCE = 'reference'
ETAT = 'etat'
ETAT_PAIEMENT_ACCEPTE = '1'
SPCHECKOK = 'spcheckok'
LOGGER = logging.getLogger(__name__)
def decrypt_ntkey(ntkey):
key = binascii.unhexlify(ntkey.replace(' ',''))
@ -49,6 +52,7 @@ LOGGER = logging.getLogger(__name__)
class Payment(PaymentCommon):
def __init__(self, options):
LOGGER.debug('initializing spplus payment with %s' % options)
self.cle = options['cle']
self.siret = options['siret']
self.devise = '978'
@ -56,6 +60,8 @@ class Payment(PaymentCommon):
self.taxe = options.get('taxe', '0.00')
def request(self, montant, email=None, next_url=None):
LOGGER.debug('requesting spplus payment with montant %s email=%s and \
next_url=%s' % (montant, email, next_url))
reference = self.transaction_id(20, ALPHANUM, 'spplus', self.siret)
validite = dt.date.today()+dt.timedelta(days=1)
validite = validite.strftime('%d/%m/%Y')
@ -75,9 +81,12 @@ class Payment(PaymentCommon):
or '?' in next_url:
raise ValueError('next_url must be an absolute URL without parameters')
fields['urlretour'] = next_url
LOGGER.debug('sending fields %s' % fields)
query = urllib.urlencode(fields)
return reference, URL, '%s?%s&hmac=%s' % (SERVICE_URL, query,
sign_ntkey_query(self.cle, query))
url = '%s?%s&hmac=%s' % (SERVICE_URL, query, sign_ntkey_query(self.cle,
query))
LOGGER.debug('full url %s' % url)
return reference, URL, url
def response(self, query_string):
form = urlparse.parse_qs(query_string)

View File

@ -15,6 +15,7 @@ __all__ = ['Payment']
PAYMENT_URL = "https://systempay.cyberpluspaiement.com/vads-payment/"
LOGGER = logging.getLogger(__name__)
SERVICE_URL = '???'
VADS_TRANS_DATE = 'vads_trans_date'
def isonow():
return dt.datetime.now() \
@ -97,7 +98,7 @@ PARAMETERS = [
Parameter('signature', 'an', None, length=40),
Parameter('vads_site_id', 'n', 02, length=8, needed=True),
Parameter('vads_theme_config', 'ans', 32, max_length=255),
Parameter('vads_trans_date', 'n', 04, length=14, needed=True,
Parameter(VADS_TRANS_DATE, 'n', 04, length=14, needed=True,
default=isonow),
Parameter('vads_trans_id', 'n', 03, length=6, needed=True),
Parameter('vads_validation_mode', 'n', 5, max_length=1, choices=('', 0, 1),
@ -205,8 +206,8 @@ class Payment(PaymentCommon):
if next_url:
kwargs['vads_url_return'] = next_url
transaction_id = self.transaction_id(6, string.digits,
'systempay', self.options['vads_site_id'])
transaction_id = self.transaction_id(6,
string.digits, 'systempay', self.options['vads_site_id'])
kwargs['vads_trans_id'] = transaction_id
fields = kwargs
for parameter in PARAMETERS:
@ -232,6 +233,7 @@ parameters received: %s' % (name, kwargs))
parameter.ptype))
fields['signature'] = self.signature(fields)
url = '%s?%s' % (SERVICE_URL, urllib.urlencode(fields))
transaction_id = '%s_%s' % (fields[VADS_TRANS_DATE], transaction_id)
return transaction_id, URL, fields
def response(self, query_string):
@ -239,27 +241,32 @@ parameters received: %s' % (name, kwargs))
copy = fields.copy()
if 'vads_auth_result' in fields:
v = copy['vads_auth_result']
copy['vads_auth_result'] = '%s: %s' % (v, AUTH_RESULT_MAP.get(v, 'Code inconnu'))
ctx = (v, AUTH_RESULT_MAP.get(v, 'Code inconnu'))
copy['vads_auth_result'] = '%s: %s' % ctx
if 'vads_result' in copy:
v = copy['vads_result']
copy['vads_result'] = '%s: %s' % (v, RESULT_MAP.get(v, 'Code inconnu'))
ctx = (v, RESULT_MAP.get(v, 'Code inconnu'))
copy['vads_result'] = '%s: %s' % ctx
if v == '30':
if 'vads_extra_result' in fields:
v = fields['vads_extra_result']
if v.isdigit():
for parameter in PARAMETERS:
if int(v) == parameter.code:
fields['vads_extra_result'] = 'erreur dans le champ %s' % parameter.name
s ='erreur dans le champ %s' % parameter.name
fields['vads_extra_result'] = s
elif v in ('05', '00'):
v = fields['vads_extra_result']
fields['vads_extra_result'] = '%s: %s' % (v, EXTRA_RESULT_MAP.get(v, 'Code inconnu'))
fields['vads_extra_result'] = '%s: %s' % (v,
EXTRA_RESULT_MAP.get(v, 'Code inconnu'))
LOGGER.debug('checking systempay response on:')
for key in sorted(fields.keys):
LOGGER.debug(' %s: %s' % (key, copy[key]))
signature = self.signature(fields)
result = signature == fields['signature']
LOGGER.debug('signature check result: %s' % result)
return result
transaction_id = '%s_%s' % (copy[VADS_TRANS_DATE], copy[VADS_TRANS_ID])
return result, transaction_id, copy, None
def signature(self, fields):
LOGGER.debug('got fields %s to sign' % fields )