Commit 40fa9ff0 authored by Rafael Monnerat's avatar Rafael Monnerat

Payzen rest

See merge request !274
parents eb35deda 79de2138
"""
This script was introduced for backward compatibility on migration and for
introduce custom delays on what configures the expiration dates.
"""
from DateTime import DateTime
return int(DateTime()) - int(transaction_date) > 86400
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>state_change</string> </value> <value> <string>transaction_date</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>PayzenEvent_registerPayzen</string> </value> <value> <string>PayzenEvent_isPaymentExpired</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -13,104 +13,95 @@ transaction = payzen_event.getDestinationValue() ...@@ -13,104 +13,95 @@ transaction = payzen_event.getDestinationValue()
if transaction is None: if transaction is None:
raise ValueError("Unable to find related transaction") raise ValueError("Unable to find related transaction")
assert signature in (True, False) isTransitionPossible = context.getPortalObject().portal_workflow.isTransitionPossible
if signature is False:
# signature is wrong, bye bye status = data_kw['status']
payzen_event.confirm(comment='Signature does not match') answer = data_kw['answer']
if status != "SUCCESS":
error_code = answer["error_code"]
if error_code == "PSP_010":
# Transaction Not Found
# Mark on payment transaction history log that transaction was not processed yet
transaction_date, _ = transaction.PaymentTransaction_getPayzenId()
payzen_event.confirm()
payzen_event.acknowledge(comment='Transaction not found on payzen side.')
if context.PayzenEvent_isPaymentExpired(transaction_date):
if isTransitionPossible(transaction, 'cancel'):
transaction.cancel(comment='Aborting unknown payzen payment.')
else:
storeWorkflowComment(transaction,
'Error code PSP_010 (Not found) did not changed the document state.')
return
else:
# Unknown errorCode
payzen_event.confirm(comment='Unknown errorCode %r' % error_code)
return
transaction_list = answer["transactions"]
if len(transaction_list) != 1:
# Unexpected Number of Transactions
payzen_event.confirm(comment='Unexpected Number of Transaction for this order')
return return
isTransitionPossible = context.getPortalObject().portal_workflow.isTransitionPossible transaction_kw = transaction_list[0]
# See Full Status list at https://payzen.io/en-EN/rest/V4.0/api/kb/status_reference.html
mark_transaction_id_list = [
'AUTHORISED_TO_VALIDATE',
'WAITING_AUTHORISATION',
'WAITING_AUTHORISATION_TO_VALIDATE',
]
continue_transaction_id_list = ['AUTHORISED', 'CAPTURED', 'PARTIALLY_AUTHORISED']
cancel_transaction_id_list = ['REFUSED']
transaction_status = transaction_kw['detailedStatus']
error_code = data_kw['errorCode'] if transaction_status in mark_transaction_id_list:
if error_code == '2':
transaction_date, _ = transaction.PaymentTransaction_getPayzenId()
# Mark on payment transaction history log that transaction was not processed yet # Mark on payment transaction history log that transaction was not processed yet
storeWorkflowComment(transaction, 'Transaction status %s did not changed the document state' % (transaction_status))
payzen_event.confirm() payzen_event.confirm()
payzen_event.acknowledge(comment='Transaction not found on payzen side.') payzen_event.acknowledge(comment='Automatic acknowledge as result of correct communication')
if int(DateTime()) - int(transaction_date) > 86400: if isTransitionPossible(transaction, 'confirm'):
if isTransitionPossible(transaction, 'cancel'): transaction.confirm(comment='Confirmed as really saw in PayZen.')
transaction.cancel(comment='Aborting unknown payzen payment.')
else: elif transaction_status in continue_transaction_id_list:
storeWorkflowComment(transaction, # Check authAmount and authDevise and if match, stop transaction
'Error code 2 (Not found) did not changed the document state.') auth_amount = int(transaction_kw['transactionDetails']['cardDetails']['authorizationResponse']['amount'])
return auth_devise = transaction_kw['transactionDetails']['cardDetails']['authorizationResponse']['currency']
transaction_amount = int((round(transaction.PaymentTransaction_getTotalPayablePrice(), 2) * -100))
if transaction_amount != auth_amount:
payzen_event.confirm(comment='Received amount (%r) does not match stored on transaction (%r)'% (auth_amount, transaction_amount))
return
elif error_code == '0': transaction_devise = transaction.getResourceReference()
transaction_code_mapping = { if transaction_devise != auth_devise:
'0': 'Initial (being treated)', payzen_event.confirm(comment='Received devise (%r) does not match stored on transaction (%r)'% (auth_devise, transaction_devise))
'1': 'To be validated ',
'2': 'To be forced - Contact issuer',
'3': 'To be validated and authorized',
'4': 'Waiting for submission',
'5': 'Waiting for authorization',
'6': 'Submitted',
'7': 'Expired',
'8': 'Refused',
'9': 'Cancelled',
'10': 'Waiting',
'11': 'Being submitted',
'12': 'Being authorized',
'13': 'Failed',
}
mark_transaction_id_list = ['0', '1', '3', '5', '10', '11', '12']
continue_transaction_id_list = ['4', '6']
cancel_transaction_id_list = ['8']
transaction_status = data_kw['transactionStatus']
transaction_status_description = transaction_code_mapping.get(transaction_status, None)
if transaction_status_description is None:
payzen_event.confirm(comment='Unknown transactionStatus %r' % transaction_status)
return return
if transaction_status in mark_transaction_id_list: comment = 'PayZen considered as paid.'
# Mark on payment transaction history log that transaction was not processed yet if isTransitionPossible(transaction, 'confirm'):
storeWorkflowComment(transaction, 'Transaction status %s (%s) did not changed the document state' % (transaction_status, transaction_status_description)) transaction.confirm(comment=comment)
payzen_event.confirm() if isTransitionPossible(transaction, 'start'):
payzen_event.acknowledge(comment='Automatic acknowledge as result of correct communication') transaction.start(comment=comment)
if isTransitionPossible(transaction, 'confirm'): if isTransitionPossible(transaction, 'stop'):
transaction.confirm(comment='Confirmed as really saw in PayZen.') transaction.stop(comment=comment)
elif transaction_status in continue_transaction_id_list:
# Check authAmount and authDevise and if match, stop transaction
auth_amount = int(data_kw['authAmount'])
auth_devise = data_kw['authDevise']
transaction_amount = int((round(transaction.PaymentTransaction_getTotalPayablePrice(), 2) * -100))
if transaction_amount != auth_amount:
payzen_event.confirm(comment='Received amount (%r) does not match stored on transaction (%r)'% (auth_amount, transaction_amount))
return
transaction_devise = transaction.getResourceValue().Currency_getIntegrationMapping()
if transaction_devise != auth_devise:
payzen_event.confirm(comment='Received devise (%r) does not match stored on transaction (%r)'% (auth_devise, transaction_devise))
return
comment = 'PayZen considered as paid.'
if isTransitionPossible(transaction, 'confirm'):
transaction.confirm(comment=comment)
if isTransitionPossible(transaction, 'start'):
transaction.start(comment=comment)
if isTransitionPossible(transaction, 'stop'):
transaction.stop(comment=comment)
if transaction.getSimulationState() == 'stopped':
payzen_event.confirm()
payzen_event.acknowledge(comment='Automatic acknowledge as result of correct communication')
else:
payzen_event.confirm(comment='Expected to put transaction in stopped state, but achieved only %s state' % transaction.getSimulationState())
elif transaction_status in cancel_transaction_id_list: if transaction.getSimulationState() == 'stopped':
payzen_event.confirm() payzen_event.confirm()
payzen_event.acknowledge(comment='Refused payzen payment.') payzen_event.acknowledge(comment='Automatic acknowledge as result of correct communication')
if isTransitionPossible(transaction, 'cancel'):
transaction.cancel(comment='Aborting refused payzen payment.')
return
else: else:
payzen_event.confirm(comment='Transaction status %r (%r) is not supported' \ payzen_event.confirm(comment='Expected to put transaction in stopped state, but achieved only %s state' % transaction.getSimulationState())
% (transaction_status, transaction_status_description))
return
elif transaction_status in cancel_transaction_id_list:
payzen_event.confirm()
payzen_event.acknowledge(comment='Refused payzen payment.')
if isTransitionPossible(transaction, 'cancel'):
transaction.cancel(comment='Aborting refused payzen payment.')
return
else: else:
# Unknown errorCode payzen_event.confirm(comment='Transaction status %r is not supported' \
payzen_event.confirm(comment='Unknown errorCode %r' % error_code) % (transaction_status))
return
...@@ -50,7 +50,15 @@ ...@@ -50,7 +50,15 @@
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
<value> <string>data_kw, signature, REQUEST=None</string> </value> <value> <string>data_kw, REQUEST=None</string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
...@@ -183,7 +183,7 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -183,7 +183,7 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
event.PayzenEvent_processUpdate, event.PayzenEvent_processUpdate,
'a', 'b', 'a',
REQUEST={}) REQUEST={})
def test_processUpdate_noTransaction(self): def test_processUpdate_noTransaction(self):
...@@ -191,66 +191,76 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -191,66 +191,76 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
self.assertRaises( self.assertRaises(
ValueError, ValueError,
event.PayzenEvent_processUpdate, event.PayzenEvent_processUpdate,
'a', 'b') 'a')
def test_processUpdate_signatureBoolean(self): def test_processUpdate_wrongDataDictionnary(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
payment = self.createPaymentTransaction() payment = self.createPaymentTransaction()
event.edit(destination_value=payment) event.edit(destination_value=payment)
self.assertRaises( self.assertRaises(
AssertionError, TypeError,
event.PayzenEvent_processUpdate, event.PayzenEvent_processUpdate,
'a', 'b') 'a')
def test_processUpdate_falseSignature(self): def test_processUpdate_unknownErrorCode(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
payment = self.createPaymentTransaction() payment = self.createPaymentTransaction()
event.edit(destination_value=payment) event.edit(destination_value=payment)
event.PayzenEvent_processUpdate('a', False) data_kw = {
'status': 'ERROR',
'answer':{
'error_code': "foo",
},
}
event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
'Signature does not match', "Unknown errorCode 'foo'",
event.workflow_history['system_event_workflow'][-1]['comment']) event.workflow_history['system_event_workflow'][-1]['comment'])
def test_processUpdate_wrongDataDictionnary(self): def test_processUpdate_noTransactionsForOrder(self):
event = self.createPayzenEvent()
payment = self.createPaymentTransaction()
event.edit(destination_value=payment)
self.assertRaises(
TypeError,
event.PayzenEvent_processUpdate,
'a', True)
def test_processUpdate_unknownErrorCode(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
payment = self.createPaymentTransaction() payment = self.createPaymentTransaction()
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': 'foo', "status": "SUCCESS",
"answer": {
"transactions": [],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
"Unknown errorCode 'foo'", "Unexpected Number of Transaction for this order",
event.workflow_history['system_event_workflow'][-1]['comment']) event.workflow_history['system_event_workflow'][-1]['comment'])
def test_processUpdate_unknownTransactionStatus(self): def test_processUpdate_tooManyTransactionsForOrder(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
payment = self.createPaymentTransaction() payment = self.createPaymentTransaction()
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': 'foo', "answer": {
"transactions": [
{
"detailedStatus": "ACCEPTED",
},
{
"detailedStatus": "ACCEPTED",
},
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
"Unknown transactionStatus 'foo'", "Unexpected Number of Transaction for this order",
event.workflow_history['system_event_workflow'][-1]['comment']) event.workflow_history['system_event_workflow'][-1]['comment'])
def test_processUpdate_notSupportedTransactionStatus(self): def test_processUpdate_notSupportedTransactionStatus(self):
...@@ -259,14 +269,20 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -259,14 +269,20 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '2', "answer": {
"transactions": [
{
"detailedStatus": "ACCEPTED",
}
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
"Transaction status '2' ('To be forced - Contact issuer') " \ "Transaction status 'ACCEPTED' " \
"is not supported", "is not supported",
event.workflow_history['system_event_workflow'][-1]['comment']) event.workflow_history['system_event_workflow'][-1]['comment'])
...@@ -277,11 +293,17 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -277,11 +293,17 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '0', "answer": {
"transactions": [
{
"detailedStatus": "WAITING_AUTHORISATION_TO_VALIDATE",
}
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw, None)
self.assertEqual(event.getValidationState(), "acknowledged") self.assertEqual(event.getValidationState(), "acknowledged")
self.assertEqual( self.assertEqual(
...@@ -290,7 +312,7 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -290,7 +312,7 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
self.assertEqual(payment.getSimulationState(), "confirmed") self.assertEqual(payment.getSimulationState(), "confirmed")
self.assertEqual( self.assertEqual(
'Transaction status 0 (Initial (being treated)) did not changed ' \ 'Transaction status WAITING_AUTHORISATION_TO_VALIDATE did not changed ' \
'the document state', 'the document state',
payment.workflow_history['edit_workflow'][-1]['comment']) payment.workflow_history['edit_workflow'][-1]['comment'])
self.assertEqual( self.assertEqual(
...@@ -305,10 +327,17 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -305,10 +327,17 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '0', "answer": {
"transactions": [
{
"detailedStatus": "WAITING_AUTHORISATION_TO_VALIDATE",
}
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True)
event.PayzenEvent_processUpdate(data_kw)
def test_processUpdate_noAuthAmount(self): def test_processUpdate_noAuthAmount(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
...@@ -317,14 +346,26 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -317,14 +346,26 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '6', "answer": {
"transactions": [
{
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
},
},
},
}
],
},
} }
self.assertRaises( self.assertRaises(
KeyError, KeyError,
event.PayzenEvent_processUpdate, event.PayzenEvent_processUpdate,
data_kw, True) data_kw)
def test_processUpdate_noAuthDevise(self): def test_processUpdate_noAuthDevise(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
...@@ -333,15 +374,27 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -333,15 +374,27 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '6', "answer": {
'authAmount': 1, "transactions": [
{
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": 1,
},
},
},
}
],
},
} }
self.assertRaises( self.assertRaises(
KeyError, KeyError,
event.PayzenEvent_processUpdate, event.PayzenEvent_processUpdate,
data_kw, True) data_kw)
def test_processUpdate_differentAmount(self): def test_processUpdate_differentAmount(self):
event = self.createPayzenEvent() event = self.createPayzenEvent()
...@@ -350,14 +403,26 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -350,14 +403,26 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '6', "answer": {
'authAmount': 1, "transactions": [
'authDevise': 1, {
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": 1,
"currency": 1,
},
},
},
}
],
},
} }
self.assertEqual(payment.PaymentTransaction_getTotalPayablePrice(), 0) self.assertEqual(payment.PaymentTransaction_getTotalPayablePrice(), 0)
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
...@@ -373,18 +438,30 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -373,18 +438,30 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '6', "answer": {
'authAmount': 0, "transactions": [
'authDevise': "dollars", {
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": 0,
"currency": "dollars",
},
},
},
}
],
},
} }
self.assertEqual(payment.PaymentTransaction_getTotalPayablePrice(), 0) self.assertEqual(payment.PaymentTransaction_getTotalPayablePrice(), 0)
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
"Received devise ('dollars') does not match stored on transaction ('978')", "Received devise ('dollars') does not match stored on transaction ('EUR')",
event.workflow_history['system_event_workflow'][-1]['comment']) event.workflow_history['system_event_workflow'][-1]['comment'])
def test_processUpdate_cancelledTransaction(self): def test_processUpdate_cancelledTransaction(self):
...@@ -397,13 +474,25 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -397,13 +474,25 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '6', "answer": {
'authAmount': 0, "transactions": [
'authDevise': '978', {
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": 0,
"currency": "EUR",
},
},
},
}
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "confirmed") self.assertEqual(event.getValidationState(), "confirmed")
self.assertEqual( self.assertEqual(
...@@ -420,13 +509,25 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort): ...@@ -420,13 +509,25 @@ class TestSlapOSPayzenEvent_processUpdate(SlapOSTestCaseMixinWithAbort):
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '6', "answer": {
'authAmount': 0, "transactions": [
'authDevise': '978', {
"detailedStatus": "AUTHORISED",
"transactionDetails": {
"cardDetails": {
"authorizationResponse": {
"amount": 0,
"currency": "EUR",
},
},
},
}
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(payment.getSimulationState(), "stopped") self.assertEqual(payment.getSimulationState(), "stopped")
self.assertEqual(event.getValidationState(), "acknowledged") self.assertEqual(event.getValidationState(), "acknowledged")
...@@ -466,12 +567,15 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f ...@@ -466,12 +567,15 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '2', "status": "ERROR",
"answer": {
"error_code": "PSP_010",
},
} }
self._simulatePaymentTransaction_getRecentPayzenId() self._simulatePaymentTransaction_getRecentPayzenId()
try: try:
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
finally: finally:
self._dropPaymentTransaction_getPayzenId() self._dropPaymentTransaction_getPayzenId()
...@@ -481,21 +585,27 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f ...@@ -481,21 +585,27 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
event.workflow_history['system_event_workflow'][-1]['comment']) event.workflow_history['system_event_workflow'][-1]['comment'])
self.assertNotEqual(payment.getSimulationState(), "cancelled") self.assertNotEqual(payment.getSimulationState(), "cancelled")
self.assertEqual( self.assertEqual(
'Error code 2 (Not found) did not changed the document state.', 'Error code PSP_010 (Not found) did not changed the document state.',
payment.workflow_history['edit_workflow'][-1]['comment']) payment.workflow_history['edit_workflow'][-1]['comment'])
def test_processUpdate_oldNotFoundOnPayzenSide(self): def test_processUpdate_oldNotFoundOnPayzenSide(self):
"""
This Test is supposed to Fail as for now we do not want to cancel automatically
"""
event = self.createPayzenEvent() event = self.createPayzenEvent()
payment = self.createPaymentTransaction() payment = self.createPaymentTransaction()
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '2', "status": "ERROR",
"answer": {
"error_code": "PSP_010",
},
} }
self._simulatePaymentTransaction_getOldPayzenId() self._simulatePaymentTransaction_getOldPayzenId()
try: try:
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
finally: finally:
self._dropPaymentTransaction_getPayzenId() self._dropPaymentTransaction_getPayzenId()
...@@ -514,11 +624,17 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f ...@@ -514,11 +624,17 @@ return addToDate(DateTime(), to_add={'day': -1, 'second': -1}).toZone('UTC'), 'f
event.edit(destination_value=payment) event.edit(destination_value=payment)
data_kw = { data_kw = {
'errorCode': '0', "status": "SUCCESS",
'transactionStatus': '8', "answer": {
"transactions": [
{
"detailedStatus": "REFUSED",
}
],
},
} }
event.PayzenEvent_processUpdate(data_kw, True) event.PayzenEvent_processUpdate(data_kw)
self.assertEqual(event.getValidationState(), "acknowledged") self.assertEqual(event.getValidationState(), "acknowledged")
self.assertEqual( self.assertEqual(
......
...@@ -5,7 +5,7 @@ from DateTime import DateTime ...@@ -5,7 +5,7 @@ from DateTime import DateTime
from Products.ERP5Type.tests.utils import createZODBPythonScript from Products.ERP5Type.tests.utils import createZODBPythonScript
import difflib import difflib
HARDCODED_PRICE = 99.6 HARDCODED_PRICE = -99.6
vads_url_cancel = 'http://example.org/cancel' vads_url_cancel = 'http://example.org/cancel'
vads_url_error = 'http://example.org/error' vads_url_error = 'http://example.org/error'
...@@ -187,6 +187,7 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort): ...@@ -187,6 +187,7 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
'vads_amount': str(int(HARDCODED_PRICE * -100)), 'vads_amount': str(int(HARDCODED_PRICE * -100)),
'vads_currency': 978, 'vads_currency': 978,
'vads_trans_id': transaction_id, 'vads_trans_id': transaction_id,
'vads_order_id': transaction_id,
'vads_site_id': 'foo', 'vads_site_id': 'foo',
} }
# Calculate the signature... # Calculate the signature...
...@@ -201,10 +202,10 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort): ...@@ -201,10 +202,10 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
'%(vads_url_return)s">\n\n\n <input type="hidden" name="vads_site_id" '\ '%(vads_url_return)s">\n\n\n <input type="hidden" name="vads_site_id" '\
'value="%(vads_site_id)s">\n\n\n <input type="hidden" name="vads_url_e'\ 'value="%(vads_site_id)s">\n\n\n <input type="hidden" name="vads_url_e'\
'rror"\n value="%(vads_url_error)s">\n\n\n <input type="hidden'\ 'rror"\n value="%(vads_url_error)s">\n\n\n <input type="hidden'\
'" name="vads_trans_id" value="%(vads_trans_id)s">\n\n\n <input type="'\ '" name="vads_trans_id" value="%(vads_trans_id)s">\n\n\n '\
'hidden" name="vads_action_mode"\n value="INTERACTIVE">\n\n\n '\
'<input type="hidden" name="vads_url_success"\n value="'\ '<input type="hidden" name="vads_url_success"\n value="'\
'%(vads_url_success)s">\n\n\n <input type="hidden" name="vads_url_refe'\ '%(vads_url_success)s">\n\n\n <input type="hidden" name="vads_order_id'\
'" value="%(vads_trans_id)s">\n\n\n <input type="hidden" name="vads_url_refe'\
'rral"\n value="%(vads_url_referral)s">\n\n\n <input type="hid'\ 'rral"\n value="%(vads_url_referral)s">\n\n\n <input type="hid'\
'den" name="vads_page_action"\n value="PAYMENT">\n\n\n <input '\ 'den" name="vads_page_action"\n value="PAYMENT">\n\n\n <input '\
'type="hidden" name="vads_trans_date"\n value="'\ 'type="hidden" name="vads_trans_date"\n value="'\
...@@ -218,7 +219,8 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort): ...@@ -218,7 +219,8 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
'\n <input type="hidden" name="vads_language" value="%(vads_language)s">\n\n\n <inpu'\ '\n <input type="hidden" name="vads_language" value="%(vads_language)s">\n\n\n <inpu'\
't type="hidden" name="vads_currency" value="%(vads_currency)s">\n\n\n '\ 't type="hidden" name="vads_currency" value="%(vads_currency)s">\n\n\n '\
' <input type="hidden" name="vads_amount" value="%(vads_amount)s">\n\n\n'\ ' <input type="hidden" name="vads_amount" value="%(vads_amount)s">\n\n\n'\
' <input type="hidden" name="vads_version" value="V2">\n\n<center>\n '\ ' <input type="hidden" name="vads_version" value="V2">\n\n\n <input type="'\
'hidden" name="vads_action_mode"\n value="INTERACTIVE">\n\n<center>\n '\
' <input type="submit" value="Click to pay">\n</center>\n</form>' % data_dict ' <input type="submit" value="Click to pay">\n</center>\n</form>' % data_dict
# Event message state # Event message state
...@@ -252,17 +254,17 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort): ...@@ -252,17 +254,17 @@ class TestSlapOSPayzenInterfaceWorkflow(SlapOSTestCaseMixinWithAbort):
_ , _ = payment.PaymentTransaction_generatePayzenId() _ , _ = payment.PaymentTransaction_generatePayzenId()
self.assertRaises(AttributeError, event.updateStatus) self.assertRaises(AttributeError, event.updateStatus)
def mockSoapGetInfo(self, method_to_call, expected_args, result_tuple): def mockRestGetInfo(self, method_to_call, expected_args, result_tuple):
payment_service = self.portal.portal_secure_payments.slapos_payzen_test payment_service = self.portal.portal_secure_payments.slapos_payzen_test
def mocksoad_getInfo(arg1, arg2): def mockrest_getInfo(arg1, arg2):
self.assertEqual(arg1, expected_args[0]) self.assertEqual(arg1, expected_args[0])
self.assertEqual(arg2, expected_args[1]) self.assertEqual(arg2, expected_args[1])
return result_tuple return result_tuple
setattr(payment_service, 'soap_getInfo', mocksoad_getInfo) setattr(payment_service, 'rest_getInfo', mockrest_getInfo)
try: try:
return method_to_call() return method_to_call()
finally: finally:
del payment_service.soap_getInfo del payment_service.rest_getInfo
def _simulatePayzenEvent_processUpdate(self): def _simulatePayzenEvent_processUpdate(self):
script_name = 'PayzenEvent_processUpdate' script_name = 'PayzenEvent_processUpdate'
...@@ -293,16 +295,15 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by P ...@@ -293,16 +295,15 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by P
payment.PaymentTransaction_generatePayzenId() payment.PaymentTransaction_generatePayzenId()
mocked_data_kw = 'mocked_data_kw' mocked_data_kw = 'mocked_data_kw'
mocked_signature = 'mocked_signature'
mocked_sent_text = 'mocked_sent_text' mocked_sent_text = 'mocked_sent_text'
mocked_received_text = 'mocked_received_text' mocked_received_text = 'mocked_received_text'
self._simulatePayzenEvent_processUpdate() self._simulatePayzenEvent_processUpdate()
try: try:
self.mockSoapGetInfo( self.mockRestGetInfo(
event.updateStatus, event.updateStatus,
(transaction_date.toZone('UTC').asdatetime(), transaction_id), (transaction_date.toZone('UTC').asdatetime(), transaction_id),
(mocked_data_kw, mocked_signature, mocked_sent_text, mocked_received_text), (mocked_data_kw, mocked_sent_text, mocked_received_text),
) )
finally: finally:
self._dropPayzenEvent_processUpdate() self._dropPayzenEvent_processUpdate()
...@@ -311,11 +312,11 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by P ...@@ -311,11 +312,11 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by P
self.assertEqual(len(event_message_list), 2) self.assertEqual(len(event_message_list), 2)
sent_message = [x for x in event_message_list \ sent_message = [x for x in event_message_list \
if x.getTitle() == 'Sent SOAP'][0] if x.getTitle() == 'Sent Data'][0]
self.assertEqual(sent_message.getTextContent(), mocked_sent_text) self.assertEqual(sent_message.getTextContent(), mocked_sent_text)
received_message = [x for x in event_message_list \ received_message = [x for x in event_message_list \
if x.getTitle() == 'Received SOAP'][0] if x.getTitle() == 'Received Data'][0]
self.assertEqual(received_message.getPredecessor(), self.assertEqual(received_message.getPredecessor(),
sent_message.getRelativeUrl()) sent_message.getRelativeUrl())
self.assertEqual(received_message.getTextContent(), mocked_received_text) self.assertEqual(received_message.getTextContent(), mocked_received_text)
......
...@@ -29,6 +29,7 @@ payzen_dict = { ...@@ -29,6 +29,7 @@ payzen_dict = {
'vads_amount': str(int(round((payment_transaction.PaymentTransaction_getTotalPayablePrice() * -100), 0))), 'vads_amount': str(int(round((payment_transaction.PaymentTransaction_getTotalPayablePrice() * -100), 0))),
'vads_trans_date': now.toZone('UTC').asdatetime().strftime('%Y%m%d%H%M%S'), 'vads_trans_date': now.toZone('UTC').asdatetime().strftime('%Y%m%d%H%M%S'),
'vads_trans_id': transaction_id, 'vads_trans_id': transaction_id,
'vads_order_id': transaction_id,
'vads_language': 'en', 'vads_language': 'en',
'vads_url_cancel': vads_url_cancel, 'vads_url_cancel': vads_url_cancel,
'vads_url_error': vads_url_error, 'vads_url_error': vads_url_error,
......
"""Registers current transaction in payment
In order to not transmit sensitive information the registration is done by looking the newest
payzen related transaction for destination_section and doing its duplicate"""
from DateTime import DateTime
payzen_event = state_change['object']
transaction = payzen_event.getDestinationValue()
payment_service = payzen_event.getSourceValue(portal_type="Payzen Service")
previous_id = transaction.PaymentTransaction_getPreviousPayzenId()
if previous_id is None:
payzen_event.confirm(comment='No previous id found')
return
transaction_date, transaction_id = transaction.PaymentTransaction_generatePayzenId()
if transaction_id is None:
raise ValueError('Transaction already mapped in integration tool.')
# do causality mapping in integration_site between transaction.getRelativeUrl and today + transaction_id
payzen_dict = {}
payzen_dict.update(
devise=transaction.getResourceValue().Currency_getIntegrationMapping(),
amount=str(int(round((transaction.PaymentTransaction_getTotalPayablePrice() * -100), 0))),
presentationDate=transaction.getStartDate().toZone('UTC').asdatetime(),
newTransactionId=transaction_id,
transmissionDate=transaction_date.asdatetime(),
transactionId=previous_id
)
data_kw, signature, sent_text, received_text = payment_service.soap_duplicate(**payzen_dict)
# SENT
sent = payzen_event.newContent(title='Sent SOAP',
portal_type='Payzen Event Message',
text_content=sent_text)
# RECEIVED
payzen_event.newContent(title='Received SOAP',
text_content=received_text,
predecessor_value=sent,
portal_type='Payzen Event Message')
context.PayzenEvent_processUpdate(state_change, data_kw, signature)
...@@ -6,20 +6,20 @@ if transaction_id is None: ...@@ -6,20 +6,20 @@ if transaction_id is None:
raise ValueError('Transaction not registered in payzen integration tool') raise ValueError('Transaction not registered in payzen integration tool')
payment_service = payzen_event.getSourceValue(portal_type="Payzen Service") payment_service = payzen_event.getSourceValue(portal_type="Payzen Service")
data_kw, signature, sent_text, received_text = payment_service.soap_getInfo( data_kw, sent_text, received_text = payment_service.rest_getInfo(
transaction_date.toZone('UTC').asdatetime(), transaction_date.toZone('UTC').asdatetime(),
transaction_id) transaction_id)
# SENT # SENT
sent = payzen_event.newContent( sent = payzen_event.newContent(
title='Sent SOAP', title='Sent Data',
portal_type='Payzen Event Message', portal_type='Payzen Event Message',
text_content=sent_text) text_content=sent_text)
# RECEIVED # RECEIVED
payzen_event.newContent( payzen_event.newContent(
title='Received SOAP', title='Received Data',
portal_type='Payzen Event Message', portal_type='Payzen Event Message',
text_content=received_text, text_content=received_text,
predecessor_value=sent) predecessor_value=sent)
payzen_event.PayzenEvent_processUpdate(data_kw, signature) payzen_event.PayzenEvent_processUpdate(data_kw)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="TransitionDefinition" module="Products.DCWorkflow.Transitions"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>actbox_category</string> </key>
<value> <string>workflow</string> </value>
</item>
<item>
<key> <string>actbox_icon</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>actbox_url</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>after_script_name</string> </key>
<value> <string>PayzenEvent_registerPayzen</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>guard</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>register_payzen</string> </value>
</item>
<item>
<key> <string>new_state_id</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>script_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>trigger_type</string> </key>
<value> <int>2</int> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
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