2018-01-16 06:58:15 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
import hmac
|
|
|
|
import time
|
|
|
|
import unittest
|
|
|
|
from lxml import objectify
|
|
|
|
from werkzeug import urls
|
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
import flectra
|
|
|
|
from flectra.addons.payment.models.payment_acquirer import ValidationError
|
|
|
|
from flectra.addons.payment.tests.common import PaymentAcquirerCommon
|
|
|
|
from flectra.addons.payment_authorize.controllers.main import AuthorizeController
|
|
|
|
from flectra.tools import mute_logger
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
@flectra.tests.common.at_install(True)
|
|
|
|
@flectra.tests.common.post_install(True)
|
2018-01-16 06:58:15 +01:00
|
|
|
class AuthorizeCommon(PaymentAcquirerCommon):
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
super(AuthorizeCommon, self).setUp()
|
|
|
|
# authorize only support USD in test environment
|
|
|
|
self.currency_usd = self.env['res.currency'].search([('name', '=', 'USD')], limit=1)[0]
|
|
|
|
# get the authorize account
|
|
|
|
self.authorize = self.env.ref('payment.payment_acquirer_authorize')
|
|
|
|
# Be sure to be in 'capture' mode
|
|
|
|
# self.authorize.auto_confirm = 'confirm_so'
|
|
|
|
|
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
@flectra.tests.common.at_install(True)
|
|
|
|
@flectra.tests.common.post_install(True)
|
2018-01-16 06:58:15 +01:00
|
|
|
class AuthorizeForm(AuthorizeCommon):
|
|
|
|
|
|
|
|
def _authorize_generate_hashing(self, values):
|
|
|
|
data = '^'.join([
|
|
|
|
values['x_login'],
|
|
|
|
values['x_fp_sequence'],
|
|
|
|
values['x_fp_timestamp'],
|
|
|
|
values['x_amount'],
|
|
|
|
]) + '^'
|
|
|
|
return hmac.new(values['x_trans_key'].encode('utf-8'), data.encode('utf-8'), hashlib.md5).hexdigest()
|
|
|
|
|
|
|
|
def test_10_Authorize_form_render(self):
|
|
|
|
self.assertEqual(self.authorize.environment, 'test', 'test without test environment')
|
|
|
|
|
|
|
|
# ----------------------------------------
|
|
|
|
# Test: button direct rendering
|
|
|
|
# ----------------------------------------
|
|
|
|
base_url = self.env['ir.config_parameter'].get_param('web.base.url')
|
|
|
|
form_values = {
|
|
|
|
'x_login': self.authorize.authorize_login,
|
|
|
|
'x_trans_key': self.authorize.authorize_transaction_key,
|
2018-07-09 15:14:39 +02:00
|
|
|
'x_amount': '56.16',
|
2018-01-16 06:58:15 +01:00
|
|
|
'x_show_form': 'PAYMENT_FORM',
|
|
|
|
'x_type': 'AUTH_CAPTURE',
|
|
|
|
'x_method': 'CC',
|
|
|
|
'x_fp_sequence': '%s%s' % (self.authorize.id, int(time.time())),
|
|
|
|
'x_version': '3.1',
|
|
|
|
'x_relay_response': 'TRUE',
|
|
|
|
'x_fp_timestamp': str(int(time.time())),
|
|
|
|
'x_relay_url': urls.url_join(base_url, AuthorizeController._return_url),
|
|
|
|
'x_cancel_url': urls.url_join(base_url, AuthorizeController._cancel_url),
|
|
|
|
'return_url': None,
|
|
|
|
'x_currency_code': 'USD',
|
|
|
|
'x_invoice_num': 'SO004',
|
|
|
|
'x_first_name': 'Norbert',
|
|
|
|
'x_last_name': 'Buyer',
|
2018-04-05 10:25:40 +02:00
|
|
|
'x_company': 'Big Company',
|
2018-01-16 06:58:15 +01:00
|
|
|
'x_address': 'Huge Street 2/543',
|
|
|
|
'x_city': 'Sin City',
|
|
|
|
'x_zip': '1000',
|
|
|
|
'x_country': 'Belgium',
|
|
|
|
'x_phone': '0032 12 34 56 78',
|
|
|
|
'x_email': 'norbert.buyer@example.com',
|
|
|
|
'x_state': None,
|
|
|
|
'x_ship_to_first_name': 'Norbert',
|
|
|
|
'x_ship_to_last_name': 'Buyer',
|
|
|
|
'x_ship_to_address': 'Huge Street 2/543',
|
|
|
|
'x_ship_to_city': 'Sin City',
|
|
|
|
'x_ship_to_zip': '1000',
|
|
|
|
'x_ship_to_country': 'Belgium',
|
|
|
|
'x_ship_to_phone': '0032 12 34 56 78',
|
|
|
|
'x_ship_to_email': 'norbert.buyer@example.com',
|
|
|
|
'x_ship_to_state': None,
|
|
|
|
}
|
|
|
|
|
|
|
|
form_values['x_fp_hash'] = self._authorize_generate_hashing(form_values)
|
|
|
|
# render the button
|
2018-07-09 15:14:39 +02:00
|
|
|
res = self.authorize.render('SO004', 56.16, self.currency_usd.id, values=self.buyer_values)
|
2018-01-16 06:58:15 +01:00
|
|
|
# check form result
|
|
|
|
tree = objectify.fromstring(res)
|
|
|
|
|
|
|
|
data_set = tree.xpath("//input[@name='data_set']")
|
|
|
|
self.assertEqual(len(data_set), 1, 'Authorize: Found %d "data_set" input instead of 1' % len(data_set))
|
|
|
|
self.assertEqual(data_set[0].get('data-action-url'), 'https://test.authorize.net/gateway/transact.dll', 'Authorize: wrong data-action-url POST url')
|
|
|
|
for el in tree.iterfind('input'):
|
|
|
|
values = list(el.attrib.values())
|
|
|
|
if values[1] in ['submit', 'x_fp_hash', 'return_url', 'x_state', 'x_ship_to_state', 'data_set']:
|
|
|
|
continue
|
|
|
|
self.assertEqual(
|
|
|
|
values[2],
|
|
|
|
form_values[values[1]],
|
|
|
|
'Authorize: wrong value for input %s: received %s instead of %s' % (values[1], values[2], form_values[values[1]])
|
|
|
|
)
|
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
@mute_logger('flectra.addons.payment_authorize.models.payment', 'ValidationError')
|
2018-01-16 06:58:15 +01:00
|
|
|
def test_20_authorize_form_management(self):
|
|
|
|
# be sure not to do stupid thing
|
|
|
|
self.assertEqual(self.authorize.environment, 'test', 'test without test environment')
|
|
|
|
|
|
|
|
# typical data posted by authorize after client has successfully paid
|
|
|
|
authorize_post_data = {
|
|
|
|
'return_url': u'/shop/payment/validate',
|
|
|
|
'x_MD5_Hash': u'7934485E1C105940BE854208D10FAB4F',
|
|
|
|
'x_account_number': u'XXXX0027',
|
|
|
|
'x_address': u'Huge Street 2/543',
|
|
|
|
'x_amount': u'320.00',
|
|
|
|
'x_auth_code': u'E4W7IU',
|
|
|
|
'x_avs_code': u'Y',
|
|
|
|
'x_card_type': u'Visa',
|
|
|
|
'x_cavv_response': u'2',
|
|
|
|
'x_city': u'Sun City',
|
|
|
|
'x_company': u'',
|
|
|
|
'x_country': u'Belgium',
|
|
|
|
'x_cust_id': u'',
|
|
|
|
'x_cvv2_resp_code': u'',
|
|
|
|
'x_description': u'',
|
|
|
|
'x_duty': u'0.00',
|
|
|
|
'x_email': u'norbert.buyer@example.com',
|
|
|
|
'x_fax': u'',
|
|
|
|
'x_first_name': u'Norbert',
|
|
|
|
'x_freight': u'0.00',
|
|
|
|
'x_invoice_num': u'SO004',
|
|
|
|
'x_last_name': u'Buyer',
|
|
|
|
'x_method': u'CC',
|
|
|
|
'x_phone': u'0032 12 34 56 78',
|
|
|
|
'x_po_num': u'',
|
|
|
|
'x_response_code': u'1',
|
|
|
|
'x_response_reason_code': u'1',
|
|
|
|
'x_response_reason_text': u'This transaction has been approved.',
|
|
|
|
'x_ship_to_address': u'Huge Street 2/543',
|
|
|
|
'x_ship_to_city': u'Sun City',
|
|
|
|
'x_ship_to_company': u'',
|
|
|
|
'x_ship_to_country': u'Belgium',
|
|
|
|
'x_ship_to_first_name': u'Norbert',
|
|
|
|
'x_ship_to_last_name': u'Buyer',
|
|
|
|
'x_ship_to_state': u'',
|
|
|
|
'x_ship_to_zip': u'1000',
|
|
|
|
'x_state': u'',
|
|
|
|
'x_tax': u'0.00',
|
|
|
|
'x_tax_exempt': u'FALSE',
|
|
|
|
'x_test_request': u'false',
|
|
|
|
'x_trans_id': u'2217460311',
|
|
|
|
'x_type': u'auth_capture',
|
|
|
|
'x_zip': u'1000'
|
|
|
|
}
|
|
|
|
|
|
|
|
# should raise error about unknown tx
|
|
|
|
with self.assertRaises(ValidationError):
|
|
|
|
self.env['payment.transaction'].form_feedback(authorize_post_data, 'authorize')
|
|
|
|
|
|
|
|
tx = self.env['payment.transaction'].create({
|
|
|
|
'amount': 320.0,
|
|
|
|
'acquirer_id': self.authorize.id,
|
|
|
|
'currency_id': self.currency_usd.id,
|
|
|
|
'reference': 'SO004',
|
|
|
|
'partner_name': 'Norbert Buyer',
|
|
|
|
'partner_country_id': self.country_france.id})
|
|
|
|
# validate it
|
|
|
|
self.env['payment.transaction'].form_feedback(authorize_post_data, 'authorize')
|
|
|
|
# check state
|
|
|
|
self.assertEqual(tx.state, 'done', 'Authorize: validation did not put tx into done state')
|
|
|
|
self.assertEqual(tx.acquirer_reference, authorize_post_data.get('x_trans_id'), 'Authorize: validation did not update tx payid')
|
|
|
|
|
|
|
|
# reset tx
|
|
|
|
tx.write({'state': 'draft', 'date_validate': False, 'acquirer_reference': False})
|
|
|
|
|
|
|
|
# simulate an error
|
|
|
|
authorize_post_data['x_response_code'] = u'3'
|
|
|
|
self.env['payment.transaction'].form_feedback(authorize_post_data, 'authorize')
|
|
|
|
# check state
|
|
|
|
self.assertEqual(tx.state, 'error', 'Authorize: erroneous validation did not put tx into error state')
|
|
|
|
|
|
|
|
@unittest.skip("Authorize s2s test disabled: We do not want to overload Authorize.net with runbot's requests")
|
|
|
|
def test_30_authorize_s2s(self):
|
|
|
|
# be sure not to do stupid thing
|
|
|
|
authorize = self.authorize
|
|
|
|
self.assertEqual(authorize.environment, 'test', 'test without test environment')
|
|
|
|
|
|
|
|
# add credential
|
2018-01-16 11:34:37 +01:00
|
|
|
# FIXME: put this test in master-nightly on flectra/flectra + create sandbox account
|
2018-01-16 06:58:15 +01:00
|
|
|
authorize.write({
|
|
|
|
'authorize_transaction_key': '',
|
|
|
|
'authorize_login': '',
|
|
|
|
})
|
|
|
|
self.assertTrue(authorize.authorize_test_credentials, 'Authorize.net: s2s authentication failed')
|
|
|
|
|
|
|
|
# create payment meethod
|
|
|
|
payment_token = self.env['payment.token'].create({
|
|
|
|
'acquirer_id': authorize.id,
|
|
|
|
'partner_id': self.buyer_id,
|
|
|
|
'cc_number': '4111 1111 1111 1111',
|
|
|
|
'cc_expiry': '02 / 26',
|
|
|
|
'cc_brand': 'visa',
|
|
|
|
'cc_cvc': '111',
|
|
|
|
'cc_holder_name': 'test',
|
|
|
|
})
|
|
|
|
|
|
|
|
# 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': payment_token.id,
|
|
|
|
'partner_id': self.buyer_id,
|
|
|
|
|
|
|
|
})
|
|
|
|
transaction.authorize_s2s_do_transaction()
|
|
|
|
self.assertEqual(transaction.state, 'done',)
|
|
|
|
|
|
|
|
# switch to 'authorize only'
|
|
|
|
# create authorize only s2s transaction & capture it
|
|
|
|
self.authorize.capture_manually = True
|
|
|
|
transaction = self.env['payment.transaction'].create({
|
|
|
|
'amount': 500,
|
|
|
|
'acquirer_id': authorize.id,
|
|
|
|
'type': 'server2server',
|
|
|
|
'currency_id': self.currency_usd.id,
|
|
|
|
'reference': 'test_%s' % int(time.time()),
|
|
|
|
'payment_token_id': payment_token.id,
|
|
|
|
'partner_id': self.buyer_id,
|
|
|
|
|
|
|
|
})
|
|
|
|
transaction.authorize_s2s_do_transaction()
|
|
|
|
self.assertEqual(transaction.state, 'authorized')
|
|
|
|
transaction.action_capture()
|
|
|
|
self.assertEqual(transaction.state, 'done')
|
|
|
|
|
|
|
|
# create authorize only s2s transaction & void it
|
|
|
|
self.authorize.capture_manually = True
|
|
|
|
transaction = self.env['payment.transaction'].create({
|
|
|
|
'amount': 500,
|
|
|
|
'acquirer_id': authorize.id,
|
|
|
|
'type': 'server2server',
|
|
|
|
'currency_id': self.currency_usd.id,
|
|
|
|
'reference': 'test_%s' % int(time.time()),
|
|
|
|
'payment_token_id': payment_token.id,
|
|
|
|
'partner_id': self.buyer_id,
|
|
|
|
|
|
|
|
})
|
|
|
|
transaction.authorize_s2s_do_transaction()
|
|
|
|
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')
|