summaryrefslogtreecommitdiff
path: root/addons/payment_authorize
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-11-30 18:43:08 +0100
committerChristophe Simonis <chs@odoo.com>2017-11-30 18:43:08 +0100
commit42264d8dcb7f8d0795c84718d1fc9a5fd1aefd32 (patch)
tree216ded7eac5ba06623892aaaece74c586afd4b5e /addons/payment_authorize
parente4a281b5a5f7ea44e4f25259b1a84cb0dc437ebc (diff)
parent5d7ad2b16cc3ef579a6657822b7c57b07fef4f52 (diff)
[MERGE] forward port branch saas-16 up to 5d7ad2b16cc
Diffstat (limited to 'addons/payment_authorize')
-rw-r--r--addons/payment_authorize/models/authorize_request.py54
-rw-r--r--addons/payment_authorize/tests/test_authorize.py19
2 files changed, 69 insertions, 4 deletions
diff --git a/addons/payment_authorize/models/authorize_request.py b/addons/payment_authorize/models/authorize_request.py
index 7388a1a4329..eea5b6ae276 100644
--- a/addons/payment_authorize/models/authorize_request.py
+++ b/addons/payment_authorize/models/authorize_request.py
@@ -29,6 +29,34 @@ def strip_ns(xml, ns):
return it.root
+def error_check(elem):
+ """Check if the response sent by Authorize.net contains an error.
+
+ Errors can be a failure to try the transaction (in that case, the transasctionResponse
+ is empty, and the meaningful error message will be in message/code) or a failure to process
+ the transaction (in that case, the message/code content will be generic and the actual error
+ message is in transactionResponse/errors/error/errorText).
+
+ :param etree._Element elem: the root element of the response that will be parsed
+
+ :rtype: tuple (bool, str)
+ :return: tuple containnig a boolean indicating if the response should be considered
+ as an error and the most meaningful error message found in it.
+ """
+ result_code = elem.find('messages/resultCode')
+ msg = 'No meaningful error message found, please check logs or the Authorize.net backend'
+ has_error = result_code is not None and result_code.text == 'Error'
+ if has_error:
+ # accumulate the most meangingful error
+ error = elem.find('transactionResponse/errors/error')
+ error = error if error is not None else elem.find('messages/message')
+ if error is not None:
+ code = error[0].text
+ text = error[1].text
+ msg = '%s: %s' % (code, text)
+ return (has_error, msg)
+
+
class AuthorizeAPI():
"""Authorize.net Gateway API integration.
@@ -38,6 +66,9 @@ class AuthorizeAPI():
- Customer Profile/Payment Profile creation
- Transaction authorization/capture/voiding
"""
+
+ AUTH_ERROR_STATUS = 3
+
def __init__(self, acquirer):
"""Initiate the environment with the acquirer data.
@@ -62,9 +93,6 @@ class AuthorizeAPI():
r = requests.post(self.url, data=data, headers={'Content-Type': 'text/xml'})
r.raise_for_status()
response = strip_ns(r.content, XMLNS)
- if response.find('messages/resultCode').text == 'Error':
- messages = [m.text for m in response.findall('messages/message/text')]
- raise ValidationError(_('Authorize.net Error Message(s):\n %s') % '\n'.join(messages))
return response
def _base_tree(self, requestType):
@@ -216,6 +244,11 @@ class AuthorizeAPI():
etree.SubElement(order, "invoiceNumber").text = reference
response = self._authorize_request(root)
res = dict()
+ (has_error, error_msg) = error_check(response)
+ if has_error:
+ res['x_response_code'] = self.AUTH_ERROR_STATUS
+ res['x_response_reason_text'] = error_msg
+ return res
res['x_response_code'] = response.find('transactionResponse/responseCode').text
res['x_trans_id'] = response.find('transactionResponse/transId').text
res['x_type'] = 'auth_capture'
@@ -246,6 +279,11 @@ class AuthorizeAPI():
etree.SubElement(order, "invoiceNumber").text = reference
response = self._authorize_request(root)
res = dict()
+ (has_error, error_msg) = error_check(response)
+ if has_error:
+ res['x_response_code'] = self.AUTH_ERROR_STATUS
+ res['x_response_reason_text'] = error_msg
+ return res
res['x_response_code'] = response.find('transactionResponse/responseCode').text
res['x_trans_id'] = response.find('transactionResponse/transId').text
res['x_type'] = 'auth_only'
@@ -271,6 +309,11 @@ class AuthorizeAPI():
etree.SubElement(tx, "refTransId").text = transaction_id
response = self._authorize_request(root)
res = dict()
+ (has_error, error_msg) = error_check(response)
+ if has_error:
+ res['x_response_code'] = self.AUTH_ERROR_STATUS
+ res['x_response_reason_text'] = error_msg
+ return res
res['x_response_code'] = response.find('transactionResponse/responseCode').text
res['x_trans_id'] = response.find('transactionResponse/transId').text
res['x_type'] = 'prior_auth_capture'
@@ -291,6 +334,11 @@ class AuthorizeAPI():
etree.SubElement(tx, "refTransId").text = transaction_id
response = self._authorize_request(root)
res = dict()
+ (has_error, error_msg) = error_check(response)
+ if has_error:
+ res['x_response_code'] = self.AUTH_ERROR_STATUS
+ res['x_response_reason_text'] = error_msg
+ return res
res['x_response_code'] = response.find('transactionResponse/responseCode').text
res['x_trans_id'] = response.find('transactionResponse/transId').text
res['x_type'] = 'void'
diff --git a/addons/payment_authorize/tests/test_authorize.py b/addons/payment_authorize/tests/test_authorize.py
index 98d87b04116..9e438deb76c 100644
--- a/addons/payment_authorize/tests/test_authorize.py
+++ b/addons/payment_authorize/tests/test_authorize.py
@@ -212,7 +212,7 @@ class AuthorizeForm(AuthorizeCommon):
'acquirer_id': authorize.id,
'type': 'server2server',
'currency_id': self.currency_usd.id,
- 'reference': 'test_ref_%s' % odoo.fields.Date.today(),
+ 'reference': 'test_ref_%s' % int(time.time()),
'payment_token_id': payment_token.id,
'partner_id': self.buyer_id,
@@ -254,3 +254,20 @@ class AuthorizeForm(AuthorizeCommon):
self.assertEqual(transaction.state, 'authorized')
transaction.action_void()
self.assertEqual(transaction.state, 'cancel')
+
+ # try charging an unexisting profile
+ ghost_payment_token = payment_token.copy()
+ ghost_payment_token.authorize_profile = '99999999999'
+ # create normal s2s transaction
+ transaction = self.env['payment.transaction'].create({
+ 'amount': 500,
+ 'acquirer_id': authorize.id,
+ 'type': 'server2server',
+ 'currency_id': self.currency_usd.id,
+ 'reference': 'test_ref_%s' % int(time.time()),
+ 'payment_token_id': ghost_payment_token.id,
+ 'partner_id': self.buyer_id,
+
+ })
+ transaction.authorize_s2s_do_transaction()
+ self.assertEqual(transaction.state, 'error')