Commit 1634c4a5 authored by Łukasz Nowak's avatar Łukasz Nowak

Rewrite and simplify.

Have only one method for signature calculation and a bit of data modification:
_getSignature

Use method introspection to manipulate fields, fallback to strings later.

Accept DateTime objects for dates.

Implement soap_duplicate.
parent db24a3e6
...@@ -4,7 +4,6 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces ...@@ -4,7 +4,6 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Document import newTempDocument from Products.ERP5Type.Document import newTempDocument
import hashlib import hashlib
import datetime
from zLOG import LOG, WARNING from zLOG import LOG, WARNING
try: try:
...@@ -25,7 +24,7 @@ else: ...@@ -25,7 +24,7 @@ else:
SOAP protocol is assumed as untrusted and dangerous, users of those methods SOAP protocol is assumed as untrusted and dangerous, users of those methods
are encouraged to log such messages for future debugging.""" are encouraged to log such messages for future debugging."""
def _check_transcationInfoSignature(self, data): def _check_transactionInfoSignature(self, data):
"""Checks transactionInfo signature """Checks transactionInfo signature
Can raise. Can raise.
""" """
...@@ -45,27 +44,8 @@ else: ...@@ -45,27 +44,8 @@ else:
'authDate', 'authNb', 'authResult', 'authCVV2_CVC2', 'warrantlyResult', 'authDate', 'authNb', 'authResult', 'authCVV2_CVC2', 'warrantlyResult',
'captureDate', 'captureNumber', 'rapprochementStatut', 'refoundAmount', 'captureDate', 'captureNumber', 'rapprochementStatut', 'refoundAmount',
'refundDevise', 'litige', 'timestamp'] 'refundDevise', 'litige', 'timestamp']
signature = ''
for k in received_sorted_keys: signature = self._getSignature(data, received_sorted_keys)
v = getattr(data, k, None)
if v is None:
# empty or not transmitted: add as empty string
v = ''
elif k in ['transmissionDate', 'presentationDate', 'cardExpirationDate',
'markDate', 'authDate', 'captureDate'] \
or isinstance(v, datetime.datetime):
# dates (or field like dates) shall be converted to YYYYMMDD
if isinstance(v, datetime.datetime):
v = v.strftime('%Y%m%d')
else:
# defensive: maybe date-like field is represented not as datetime?
v = time.strftime('%Y%m%d', time.strptime(str(v),
'%Y-%m-%d %H:%M:%S'))
# convert to string (there could be ints, longs, etc)
v = str(v)
signature += v + '+'
signature += self.getServicePassword()
signature = hashlib.sha1(signature).hexdigest()
return signature == data.signature return signature == data.signature
def soap_getInfo(self, transmissionDate, transactionId): def soap_getInfo(self, transmissionDate, transactionId):
...@@ -77,30 +57,20 @@ else: ...@@ -77,30 +57,20 @@ else:
As soon as communication happeneded does not raise. As soon as communication happeneded does not raise.
""" """
client = suds.client.Client(self.wsdl_link.getUrlString()) client = suds.client.Client(self.wsdl_link.getUrlString())
sorted_keys = ('shopId', 'transmissionDate', 'transactionId', sorted_keys = ['shopId', 'transmissionDate', 'transactionId',
'sequenceNb', 'ctxMode') 'sequenceNb', 'ctxMode']
kw = dict( kw = dict(
transactionId=transactionId, transactionId=transactionId,
ctxMode=self.getPayzenVadsCtxMode(), ctxMode=self.getPayzenVadsCtxMode(),
shopId=self.getServiceUsername(), shopId=self.getServiceUsername(),
sequenceNb=1, sequenceNb=1,
transmissionDate=transmissionDate,
) )
date = time.strptime(transmissionDate, '%Y%m%d') kw['wsSignature'] = self._getSignature(kw, sorted_keys)
signature = ''
for k in sorted_keys:
if k == 'transmissionDate':
# craziness: date format in signature is different then in sent message
v = time.strftime('%Y%m%d', date)
kw['transmissionDate'] = time.strftime('%Y-%m-%dT%H:%M:%S', date)
else:
v = kw[k]
signature += str(v) + '+'
signature += self.getServicePassword()
kw['wsSignature'] = hashlib.sha1(signature).hexdigest()
data = client.service.getInfo(**kw)
# Note: Code shall not raise since now, as communication begin and caller # Note: Code shall not raise since now, as communication begin and caller
# will have to log sent/received messages. # will have to log sent/received messages.
data = client.service.getInfo(**kw)
try: try:
data_kw = dict(data) data_kw = dict(data)
for k in data_kw.keys(): for k in data_kw.keys():
...@@ -114,7 +84,68 @@ else: ...@@ -114,7 +84,68 @@ else:
'Issue during processing data_kw:', error=True) 'Issue during processing data_kw:', error=True)
else: else:
try: try:
signature = self._check_transcationInfoSignature(data) signature = self._check_transactionInfoSignature(data)
except Exception:
LOG('PayzenService', WARNING, 'Issue during signature calculation:',
error=True)
signature = False
try:
last_sent = str(client.last_sent())
except Exception:
LOG('PayzenService', WARNING,
'Issue during converting last_sent to string:', error=True)
signature = False
try:
last_received = str(client.last_received())
except Exception:
LOG('PayzenService', WARNING,
'Issue during converting last_received to string:', error=True)
signature = False
return [data_kw, signature, last_sent, last_received]
def soap_duplicate(self, transmissionDate, transactionId, presentationDate,
newTransactionId, amount, devise, orderId='', orderInfo='', orderInfo2='',
orderInfo3='', validationMode=0, comment=''):
# prepare with passed parameters
kw = dict(transmissionDate=transmissionDate, transactionId=transactionId,
presentationDate=presentationDate, newTransactionId=newTransactionId,
amount=amount, devise=devise, orderId=orderId, orderInfo=orderInfo,
orderInfo2=orderInfo2, orderInfo3=orderInfo3,
validationMode=validationMode, comment=comment)
signature_sorted_key_list= ['shopId', 'transmissionDate', 'transactionId',
'sequenceNb', 'ctxMode', 'orderId', 'orderInfo', 'orderInfo2',
'orderInfo3', 'amount', 'devise', 'newTransactionId',
'presentationDate', 'validationMode', 'comment']
kw.update(
ctxMode=self.getPayzenVadsCtxMode(),
shopId=self.getServiceUsername(),
sequenceNb=1,
)
kw['wsSignature'] = self._getSignature(kw, signature_sorted_key_list)
# Note: Code shall not raise since now, as communication begin and caller
# will have to log sent/received messages.
client = suds.client.Client(self.wsdl_link.getUrlString())
data = client.service.duplicate(**kw)
# Note: Code shall not raise since now, as communication begin and caller
# will have to log sent/received messages.
try:
data_kw = dict(data)
for k in data_kw.keys():
v = data_kw[k]
if not isinstance(v, str):
data_kw[k] = str(v)
except Exception:
data_kw = {}
signature = False
LOG('PayzenService', WARNING,
'Issue during processing data_kw:', error=True)
else:
try:
signature = self._check_transactionInfoSignature(data)
except Exception: except Exception:
LOG('PayzenService', WARNING, 'Issue during signature calculation:', LOG('PayzenService', WARNING, 'Issue during signature calculation:',
error=True) error=True)
...@@ -155,29 +186,67 @@ class PayzenService(XMLObject, PayzenSOAP): ...@@ -155,29 +186,67 @@ class PayzenService(XMLObject, PayzenSOAP):
"""See Payment Service Interface Documentation""" """See Payment Service Interface Documentation"""
pass pass
def _getSignature(self, field_list): def _getSignature(self, ob, sorted_key_list,
field_list.sort() output_date_format='%Y-%m-%dT%H:%M:%S', signature_date_format='%Y%m%d'):
"""Calculates signature from ob
ob can be dict or getattr capable object
in case if ob is a dict all .strftime callable values
are converted to datetime soapish format
"""
if isinstance(ob, dict):
isdict = True
else:
isdict = False
signature = '' signature = ''
for k, v in field_list: for k in sorted_key_list:
if isdict:
v = ob[k]
else:
v = getattr(ob, k, None)
if v is None:
# empty or not transmitted -- add as empty
v = ''
elif getattr(v, 'strftime', None) is not None:
# for sure date
# Manipulate a dict
if isdict:
ob[k] = v.strftime(output_date_format)
# set acceptable date in signature
v = v.strftime(signature_date_format)
elif k.lower().endswith('date'):
# maybe date?
try:
v = time.strftime('%Y%m%d', time.strptime(str(v),
'%Y-%m-%d %H:%M:%S'))
except Exception:
v = str(v)
else:
# anything else cast to string
v = str(v)
signature += v + '+' signature += v + '+'
signature += self.getServicePassword() signature += self.getServicePassword()
return hashlib.sha1(signature).hexdigest() return hashlib.sha1(signature).hexdigest()
def _getFieldList(self, payzen_dict): def _getFieldList(self, payzen_dict):
field_list = [ payzen_dict.update(
('vads_action_mode', self.getPayzenVadsActionMode()), vads_action_mode=self.getPayzenVadsActionMode(),
('vads_ctx_mode', self.getPayzenVadsCtxMode()), vads_ctx_mode=self.getPayzenVadsCtxMode(),
('vads_contrib', 'ERP5'), vads_contrib='ERP5',
('vads_page_action', self.getPayzenVadsPageAction()), vads_page_action=self.getPayzenVadsPageAction(),
('vads_payment_config', 'SINGLE'), vads_payment_config='SINGLE',
('vads_site_id', self.getServiceUsername()), vads_site_id=self.getServiceUsername(),
('vads_version', self.getPayzenVadsVersion()) vads_version=self.getPayzenVadsVersion()
] )
# fetch all prepared vads_ values and remove them from dict # fetch all prepared vads_ values and remove them from dict
signature = self._getSignature(payzen_dict,
sorted(payzen_dict.keys()), '%Y%m%d%H%M%S', '%Y%m%d%H%M%S')
payzen_dict['signature'] = signature
field_list = []
for k,v in payzen_dict.iteritems(): for k,v in payzen_dict.iteritems():
field_list.append((k, v)) field_list.append((k, v))
signature = self._getSignature(field_list)
field_list.append(('signature', signature))
return field_list return field_list
def navigate(self, page_template, payzen_dict, REQUEST=None, **kw): def navigate(self, page_template, payzen_dict, REQUEST=None, **kw):
......
35 36
\ No newline at end of file \ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment