From c01e9f7e80081ada1b9f9b55a04b20e22999a45d Mon Sep 17 00:00:00 2001 From: Nicholas Wolff Date: Mon, 14 Oct 2019 09:29:17 +0200 Subject: [PATCH] query --- .../templates/netaxept/query_result.html | 13 ++ example_project/templates/operation_list.html | 3 + example_project/views/netaxept.py | 40 ++-- payment/gateways/netaxept/actions.py | 57 ++++-- .../gateways/netaxept/netaxept_protocol.py | 64 ++++-- tests/gateways/test_netaxept.py | 185 ++++++++++++++---- tests/settings.py | 4 +- 7 files changed, 284 insertions(+), 82 deletions(-) create mode 100644 example_project/templates/netaxept/query_result.html diff --git a/example_project/templates/netaxept/query_result.html b/example_project/templates/netaxept/query_result.html new file mode 100644 index 0000000..7155071 --- /dev/null +++ b/example_project/templates/netaxept/query_result.html @@ -0,0 +1,13 @@ + + + +

Annuled: {{ query_response.annuled }}

+ +

Authorized: {{ query_response.authorized }}

+ +

Status code: {{ query_response.raw_response.status_code }}

+ +

Raw response:

 {{ query_response.raw_response.text }} 

+ + + diff --git a/example_project/templates/operation_list.html b/example_project/templates/operation_list.html index 4206c31..b713084 100644 --- a/example_project/templates/operation_list.html +++ b/example_project/templates/operation_list.html @@ -21,6 +21,9 @@

Operations

  • Authorize - Payment intents manual flow {% elif payment.gateway == 'netaxept' %}
  • Register and Authorize
  • + {% if payment.token %} +
  • Query
  • + {% endif %} {% endif %}
  • See payment in admin
  • diff --git a/example_project/views/netaxept.py b/example_project/views/netaxept.py index a48e715..89ae6d8 100644 --- a/example_project/views/netaxept.py +++ b/example_project/views/netaxept.py @@ -1,9 +1,11 @@ """ Example views for interactive testing of payment with netaxept. """ + from django.http import HttpRequest from django.http import HttpResponse from django.shortcuts import redirect, get_object_or_404 +from django.template.response import TemplateResponse from django.urls import path from django.views.decorators.http import require_GET from structlog import get_logger @@ -11,7 +13,7 @@ from payment import get_payment_gateway from payment.gateways.netaxept import actions from payment.gateways.netaxept import gateway_to_netaxept_config -from payment.gateways.netaxept.netaxept_protocol import get_payment_terminal_url +from payment.gateways.netaxept import netaxept_protocol from payment.models import Payment logger = get_logger() @@ -20,7 +22,7 @@ @require_GET def register_and_authorize(request: HttpRequest, payment_id: int) -> HttpResponse: """ - Register the payment with netaxept, and take the user to the terminal page for payment authorization. + Register the payment with netaxept, and take the user to the terminal page for payment authorization """ logger.info('netaxept-register-and-authorize', payment_id=payment_id) @@ -29,7 +31,7 @@ def register_and_authorize(request: HttpRequest, payment_id: int) -> HttpRespons payment = get_object_or_404(Payment, id=payment_id) payment_gateway, gateway_config = get_payment_gateway(payment.gateway) netaxept_config = gateway_to_netaxept_config(gateway_config) - return redirect(get_payment_terminal_url(config=netaxept_config, transaction_id=transaction_id)) + return redirect(netaxept_protocol.get_payment_terminal_url(config=netaxept_config, transaction_id=transaction_id)) @require_GET @@ -39,28 +41,34 @@ def after_terminal(request): We expect query-string parameters: transactionId and responseCode. See: https://shop.nets.eu/web/partners/response-codes - We know we opened the terminal with AutoAuth set to True, so we interpret this callback to mean that an - AUTH operation was performed. Netaxept does not provide any way to authenticate that the callback really comes - from netaxept (other than them sending us a valid hard to guess 32 character long transaction_id), so we cannot - be 100% sure of the information received. - We decide to store the authorization operation nonetheless. If by any chance the information was faked we will - detect it in the next step, when we try to capture the money. + We opened the terminal with AutoAuth set to True, so this callback should mean an AUTH operation was performed + (and the response_code should indicate the outcome of the operation). + But we cannot rely on the information received (because netaxept does not include any digital signature), + so we go on and verify if the authorization was succesful. """ transaction_id = request.GET['transactionId'] response_code = request.GET['responseCode'] - logger.info('netaxept-webhook', transaction_id=transaction_id, response_code=response_code) + logger.info('netaxept-after-terminal', transaction_id=transaction_id, response_code=response_code) + + payment_authorized = actions.verify_auth_transaction(transaction_id=transaction_id, response_code=response_code) - success = (response_code == 'OK') + return HttpResponse('transaction id {}, response code {}, payment authorized {}' + .format(transaction_id, response_code, payment_authorized)) - actions.create_auth_transaction(transaction_id=transaction_id, success=success) - if success: - return HttpResponse('ok') - elif response_code: - return HttpResponse('response code {}'.format(response_code)) +def query(request: HttpRequest, transaction_id: str) -> HttpResponse: + """ + Retries the status of the given transaction from netaxept. + """ + logger.info('netaxept-query', transaction_id=transaction_id) + payment_gateway, gateway_config = get_payment_gateway('netaxept') + netaxept_config = gateway_to_netaxept_config(gateway_config) + query_response = netaxept_protocol.query(config=netaxept_config, transaction_id=transaction_id) + return TemplateResponse(request, 'netaxept/query_result.html', {'query_response': query_response}) urls = [ path('register_and_authorize/', register_and_authorize, name='netaxept_register_and_authorize'), path('after_terminal', after_terminal, name='netaxept_after_terminal'), + path('query/', query, name='netaxept_query'), ] diff --git a/payment/gateways/netaxept/actions.py b/payment/gateways/netaxept/actions.py index eb7c31f..a3dfc42 100644 --- a/payment/gateways/netaxept/actions.py +++ b/payment/gateways/netaxept/actions.py @@ -1,11 +1,15 @@ from django.db import transaction from django.shortcuts import get_object_or_404 +from structlog import get_logger +from payment.gateways.netaxept.netaxept_protocol import query from payment import get_payment_gateway, TransactionKind from payment.gateways.netaxept import NetaxeptProtocolError from payment.gateways.netaxept import netaxept_protocol, gateway_to_netaxept_config from payment.models import Payment, Transaction +logger = get_logger() + class NetaxeptException(Exception): def __str__(self): @@ -19,13 +23,15 @@ class PaymentAlreadyRegistered(NetaxeptException): def register_payment(payment_id: int) -> str: """ - Registers the payment with netaxept. - - Records a Transaction representing the registration. - Stores the newly created netaxept transaction_id in the Payment. + - Records a Transaction representing the registration. :param payment_id: The id of a Payment object. :return: The newly created netaxept transaction_id - :raises NetaxeptException: If the registration fails + :raises NetaxeptException: If the payment was already registered or the registration fails """ + logger.info('netaxept-actions-register', payment_id=payment_id) + payment = get_object_or_404(Payment, id=payment_id) if payment.token != '': @@ -39,7 +45,8 @@ def register_payment(payment_id: int) -> str: config=netaxept_config, order_number=payment_id, amount=payment.total, - language='en') + language='en', + customer_email=payment.customer_email) except NetaxeptProtocolError as exception: Transaction.objects.create( payment=payment, @@ -52,6 +59,9 @@ def register_payment(payment_id: int) -> str: raise NetaxeptException(exception.error) with transaction.atomic(): + payment.token = register_response.transaction_id + payment.save() + Transaction.objects.create( payment=payment, kind=TransactionKind.REGISTER, @@ -61,21 +71,44 @@ def register_payment(payment_id: int) -> str: error=None, gateway_response=register_response.raw_response) - payment.token = register_response.transaction_id - payment.save() - return register_response.transaction_id -def create_auth_transaction(transaction_id: str, success: bool) -> Transaction: - """ Record the outcome of a netaxept auth transaction. """ +def verify_auth_transaction(transaction_id: str, response_code: str) -> bool: + """ + Verify and record the outcome of a netaxept auth transaction. + + :param transaction_id: The id of the transaction + :param response_code: The response code received in the callback + :return: whether the transaction was effectively authorized + """ + logger.info('netaxept-actions-verify-auth-transaction', transaction_id=transaction_id, response_code=response_code) + payment = Payment.objects.get(token=transaction_id) - return Transaction.objects.create( + _payment_gateway, gateway_config = get_payment_gateway('netaxept') + netaxept_config = gateway_to_netaxept_config(gateway_config) + + try: + query_response = query(config=netaxept_config, transaction_id=transaction_id) + transaction_authorized = query_response.authorized + error = None + except NetaxeptProtocolError as exception: + transaction_authorized = False + error = exception + + if response_code == 'OK' and not transaction_authorized: + logger.error('Inconsistent auth status detected!', transaction_id=transaction_id, response_code=response_code, + transaction_authorized=transaction_authorized) + + # Record the outcome whether the authorization succeeded or not + Transaction.objects.create( payment=payment, kind=TransactionKind.AUTH, token=transaction_id, - is_success=success, + is_success=transaction_authorized, amount=payment.total, - error=None, - gateway_response={}) + error=error, + gateway_response={'response_code': response_code}) + + return transaction_authorized diff --git a/payment/gateways/netaxept/netaxept_protocol.py b/payment/gateways/netaxept/netaxept_protocol.py index 7686f68..63f7c8b 100644 --- a/payment/gateways/netaxept/netaxept_protocol.py +++ b/payment/gateways/netaxept/netaxept_protocol.py @@ -14,16 +14,16 @@ API details: https://shop.nets.eu/web/partners/appi Test card numbers: https://shop.nets.eu/web/partners/test-cards """ +from dataclasses import dataclass from decimal import Decimal from enum import Enum +from typing import Optional, Union, Dict, Any from urllib.parse import urlencode, urljoin import requests import xmltodict -from dataclasses import dataclass from moneyed import Money from structlog import get_logger -from typing import Optional, Union, Dict logger = get_logger() @@ -54,11 +54,12 @@ def __init__(self, error: str, raw_response: Dict[str, str]): @dataclass class RegisterResponse: transaction_id: str - raw_response: Dict[str, str] + raw_response: Dict[str, Any] def register(config: NetaxeptConfig, amount: Money, order_number: Union[str, int], - language: Optional[str] = None, description: Optional[str] = None) -> RegisterResponse: + language: Optional[str] = None, description: Optional[str] = None, + customer_email: Optional[str] = None) -> RegisterResponse: """ Registering a payment is the first step for netaxept, before taking the user to the netaxept terminal hosted page. @@ -70,12 +71,13 @@ def register(config: NetaxeptConfig, amount: Money, order_number: Union[str, int :param order_number: An alphanumerical string identifying the payment. 32 chars max (letters and numbers) :param language: The iso639-1 code of the language in which the terminal should be displayed. :param description: A text that will be displayed in the netaxept admin (but not to the user). + :param customer_email: The email of the customer, can then be seen in the netaxept admin portal. :return: a RegisterResponse :raises: NetaxeptProtocolError """ logger.info('netaxept-register', amount=amount, order_number=order_number, language=language, - description=description) + description=description, customer_email=customer_email) params = { 'merchantId': config.merchant_id, @@ -94,10 +96,11 @@ def register(config: NetaxeptConfig, amount: Money, order_number: Union[str, int 'redirectUrl': config.after_terminal_url } - response = requests.post(url=urljoin(config.base_url, 'Netaxept/Register.aspx'), - data=params) - raw_response = _build_raw_response(response) + if customer_email is not None: + params['customerEmail'] = customer_email + response = requests.post(url=urljoin(config.base_url, 'Netaxept/Register.aspx'), data=params) + raw_response = _build_raw_response(response) logger.info('netaxept-register', amount=amount, order_number=order_number, language=language, description=description, raw_response=raw_response) @@ -115,7 +118,7 @@ def register(config: NetaxeptConfig, amount: Money, order_number: Union[str, int @dataclass class ProcessResponse: response_code: str - raw_response: Dict[str, str] + raw_response: Dict[str, Any] def process(config: NetaxeptConfig, transaction_id: str, operation: NetaxeptOperation, @@ -138,11 +141,8 @@ def process(config: NetaxeptConfig, transaction_id: str, operation: NetaxeptOper 'transactionAmount': _decimal_to_netaxept_amount(amount), } - response = requests.post(url=urljoin(config.base_url, 'Netaxept/Process.aspx'), - data=params) - + response = requests.post(url=urljoin(config.base_url, 'Netaxept/Process.aspx'), data=params) raw_response = _build_raw_response(response) - logger.info('netaxept-process-response', transaction_id=transaction_id, operation=operation.value, amount=amount, raw_response=raw_response) @@ -162,6 +162,44 @@ def get_payment_terminal_url(config: NetaxeptConfig, transaction_id: str) -> str return '{}?{}'.format(urljoin(config.base_url, 'Terminal/default.aspx'), qs) +@dataclass +class QueryResponse: + """ The query response is a very complete object, but we just model what's interesting for our use-case. + (The complete response is captured in the raw_response) + """ + annuled: bool + authorized: bool + raw_response: Dict[str, Any] + + +def query(config: NetaxeptConfig, transaction_id: str) -> QueryResponse: + logger.info('netaxept-query', transaction_id=transaction_id) + + params = { + 'merchantId': config.merchant_id, + 'token': config.secret, + 'transactionId': transaction_id, + } + + response = requests.post(url=urljoin(config.base_url, 'Netaxept/Query.aspx'), data=params) + raw_response = _build_raw_response(response) + logger.info('netaxept-query-response', transaction_id=transaction_id, raw_response=raw_response) + if response.status_code == requests.codes.ok: + d = xmltodict.parse(response.text) + if 'PaymentInfo' in d: + summary = d['PaymentInfo']['Summary'] + annuled = summary['Annuled'] == 'true' + authorized = summary['Authorized'] == 'true' + return QueryResponse( + annuled=annuled, + authorized=authorized, + raw_response=raw_response + ) + elif 'Exception' in d: + raise NetaxeptProtocolError(d['Exception']['Error']['Message'], raw_response) + raise NetaxeptProtocolError(response.reason, raw_response) + + def _decimal_to_netaxept_amount(decimal_amount: Decimal) -> int: """ Return the netaxept representation of the decimal representation of the amount. """ return int((decimal_amount * 100).to_integral_value()) diff --git a/tests/gateways/test_netaxept.py b/tests/gateways/test_netaxept.py index fde536e..9876cf1 100644 --- a/tests/gateways/test_netaxept.py +++ b/tests/gateways/test_netaxept.py @@ -5,13 +5,14 @@ import pytest from moneyed import Money -from pytest import raises +from pytest import raises, mark from payment import GatewayConfig, ChargeStatus from payment.gateways.netaxept import gateway_to_netaxept_config, capture, refund +from payment.gateways.netaxept.actions import verify_auth_transaction from payment.gateways.netaxept.netaxept_protocol import NetaxeptConfig, get_payment_terminal_url, \ _iso6391_to_netaxept_language, _money_to_netaxept_amount, _money_to_netaxept_currency, register, RegisterResponse, \ - NetaxeptProtocolError, process, ProcessResponse, NetaxeptOperation + NetaxeptProtocolError, process, ProcessResponse, NetaxeptOperation, query, QueryResponse from payment.interface import GatewayResponse from payment.utils import create_payment_information @@ -50,11 +51,6 @@ def it_should_transform_money_to_netaxept_representation(): assert _money_to_netaxept_currency(money) == 'NOK' -def it_should_build_terminal_url(): - assert get_payment_terminal_url(_netaxept_config, transaction_id='11111') == \ - 'https://test.epayment.nets.eu/Terminal/default.aspx?merchantId=123456&transactionId=11111' - - ############################################################################## # Protocol tests @@ -79,15 +75,16 @@ def it_should_register(requests_post): 7624b99699f344e3b6da9884d20f0b27 """) requests_post.return_value = mock_response - register_response = register(_netaxept_config, amount=Money(10, 'CHF'), order_number='123') + register_response = register(config=_netaxept_config, amount=Money(10, 'CHF'), order_number='123', + customer_email='nwolff@gmail.com') assert register_response == RegisterResponse( transaction_id='7624b99699f344e3b6da9884d20f0b27', raw_response=asdict(mock_response)) - requests_post.assert_called_with( + requests_post.assert_called_once_with( url='https://test.epayment.nets.eu/Netaxept/Register.aspx', data={'merchantId': '123456', 'token': 'supersekret', 'description': None, 'orderNumber': '123', 'amount': 1000, 'currencyCode': 'CHF', 'autoAuth': True, 'terminalSinglePage': True, - 'language': None, 'redirectUrl': 'http://localhost'}) + 'language': None, 'customerEmail': 'nwolff@gmail.com', 'redirectUrl': 'http://localhost'}) @patch('requests.post') @@ -109,7 +106,7 @@ def it_should_handle_registration_failure(requests_post): assert excinfo.value == NetaxeptProtocolError( error='Unable to translate supermerchant to submerchant, please check currency code and merchant ID', raw_response=asdict(mock_response)) - requests_post.assert_called_with( + requests_post.assert_called_once_with( url='https://test.epayment.nets.eu/Netaxept/Register.aspx', data={'merchantId': '123456', 'token': 'supersekret', 'description': None, 'orderNumber': '123', 'amount': 1000, 'currencyCode': 'CAD', 'autoAuth': True, 'terminalSinglePage': True, @@ -141,7 +138,7 @@ def it_should_process(requests_post): assert process_response == ProcessResponse( response_code='OK', raw_response=asdict(mock_response)) - requests_post.assert_called_with( + requests_post.assert_called_once_with( url='https://test.epayment.nets.eu/Netaxept/Process.aspx', data={'merchantId': '123456', 'token': 'supersekret', 'operation': 'CAPTURE', 'transactionId': '1111111111114cf693a1cf86123e0d8f', 'transactionAmount': 1000}) @@ -170,17 +167,104 @@ def it_should_handle_process_failure(requests_post): assert excinfo.value == NetaxeptProtocolError( error='Unable to translate supermerchant to submerchant, please check currency code and merchant ID', raw_response=asdict(mock_response)) - requests_post.assert_called_with( + requests_post.assert_called_once_with( url='https://test.epayment.nets.eu/Netaxept/Process.aspx', data={'merchantId': '123456', 'token': 'supersekret', 'operation': 'CAPTURE', 'transactionId': '1111111111114cf693a1cf86123e0d8f', 'transactionAmount': 1000}) +@patch('requests.post') +def it_should_query(requests_post): + mock_response = MockResponse( + status_code=200, + url='https://test.epayment.nets.eu/Netaxept/Query.aspx', + encoding='ISO-8859-1', + reason='OK', + text=""" + + 11111111 + 2019-10-14T10:15:07.2677951+02:00 + 1111111111114cf693a1cf86123e0d8f + + 700 + NOK + 7 + + 0 + 0 + 700 + 2019-09-11T16:30:06.967 + + + 2019-09-11T16:30:08.513 + 2019-09-11T16:30:24.903 + Chrome-Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36 + + + + 85.218.56.162 + + + + + + + + + + + + + + + 700 + 0 + false + false + true + 169337 + + + Visa + NO + 492500******0004 + Visa + 2301 + 3 + + + + 2019-09-11T16:30:06.967 + Register + + + 2019-09-11T16:30:24.81 + 127.0.0.1: Auto AUTH + Auth + 672 + + + + + + + CH + false + + """) + requests_post.return_value = mock_response + query_response = query(config=_netaxept_config, transaction_id='233abb21f18b47dc98469fb9000b1f21') + assert query_response == QueryResponse( + annuled=False, + authorized=True, + raw_response=asdict(mock_response)) + + ############################################################################## # SPI tests @pytest.fixture() -def netaxept_authorized_payment(payment_dummy): +def netaxept_payment(payment_dummy): payment_dummy.charge_status = ChargeStatus.NOT_CHARGED payment_dummy.save() return payment_dummy @@ -191,7 +275,7 @@ def it_builds_netaxept_config(): @patch('payment.gateways.netaxept.process') -def it_should_capture(process, netaxept_authorized_payment): +def it_should_capture(process, netaxept_payment): mock_process_response = ProcessResponse( response_code='OK', raw_response={'status_code': 200, 'url': 'https://test.epayment.nets.eu/Netaxept/Register.aspx', @@ -199,9 +283,9 @@ def it_should_capture(process, netaxept_authorized_payment): 'text': '\n \n 675\n 2019-09-16T17:31:00.7593672+02:00\n 123456\n CAPTURE\n OK\n 1111111111114cf693a1cf86123e0d8f\n '}) process.return_value = mock_process_response payment_info = create_payment_information( - payment=netaxept_authorized_payment, - payment_token='1111111111114cf693a1cf86123e0d8f', - amount=Money(10, 'CHF')) + payment=netaxept_payment, + payment_token='1111111111114cf693a1cf86123e0d8f', + amount=Money(10, 'CHF')) capture_result = capture(config=_gateway_config, payment_information=payment_info) assert capture_result == GatewayResponse( is_success=True, @@ -211,7 +295,7 @@ def it_should_capture(process, netaxept_authorized_payment): transaction_id='1111111111114cf693a1cf86123e0d8f', error=None, raw_response=mock_process_response.raw_response) - process.assert_called_with( + process.assert_called_once_with( config=NetaxeptConfig( merchant_id='123456', secret='supersekret', @@ -223,12 +307,12 @@ def it_should_capture(process, netaxept_authorized_payment): @patch('payment.gateways.netaxept.process') -def it_should_not_capture_when_protocol_error(process, netaxept_authorized_payment): +def it_should_not_capture_when_protocol_error(process, netaxept_payment): process.side_effect = NetaxeptProtocolError(error='some error', raw_response={}) payment_info = create_payment_information( - payment=netaxept_authorized_payment, - payment_token='1111111111114cf693a1cf86123e0d8f', - amount=Money(10, 'CHF')) + payment=netaxept_payment, + payment_token='1111111111114cf693a1cf86123e0d8f', + amount=Money(10, 'CHF')) capture_result = capture(config=_gateway_config, payment_information=payment_info) assert capture_result == GatewayResponse( is_success=False, @@ -238,19 +322,15 @@ def it_should_not_capture_when_protocol_error(process, netaxept_authorized_payme transaction_id='1111111111114cf693a1cf86123e0d8f', error='some error', raw_response={}) - process.assert_called_with( - config=NetaxeptConfig( - merchant_id='123456', - secret='supersekret', - base_url='https://test.epayment.nets.eu', - after_terminal_url='http://localhost'), + process.assert_called_once_with( + config=_netaxept_config, amount=Decimal('10'), transaction_id='1111111111114cf693a1cf86123e0d8f', operation=NetaxeptOperation.CAPTURE) @patch('payment.gateways.netaxept.process') -def it_should_refund(process, netaxept_authorized_payment): +def it_should_refund(process, netaxept_payment): mock_process_response = ProcessResponse( response_code='OK', raw_response={ @@ -260,9 +340,9 @@ def it_should_refund(process, netaxept_authorized_payment): 'text': '\n \n 675\n 2019-09-16T17:31:00.7593672+02:00\n 123456\n REFUND\n OK\n 1111111111114cf693a1cf86123e0d8f\n '}) process.return_value = mock_process_response payment_info = create_payment_information( - payment=netaxept_authorized_payment, - payment_token='1111111111114cf693a1cf86123e0d8f', - amount=Money(10, 'CHF')) + payment=netaxept_payment, + payment_token='1111111111114cf693a1cf86123e0d8f', + amount=Money(10, 'CHF')) capture_result = refund(config=_gateway_config, payment_information=payment_info) assert capture_result == GatewayResponse( is_success=True, @@ -272,12 +352,39 @@ def it_should_refund(process, netaxept_authorized_payment): transaction_id='1111111111114cf693a1cf86123e0d8f', error=None, raw_response=mock_process_response.raw_response) - process.assert_called_with( - config=NetaxeptConfig( - merchant_id='123456', - secret='supersekret', - base_url='https://test.epayment.nets.eu', - after_terminal_url='http://localhost'), + process.assert_called_once_with( + config=_netaxept_config, amount=Decimal('10'), transaction_id='1111111111114cf693a1cf86123e0d8f', operation=NetaxeptOperation.CREDIT) + + +############################################################################## +# Actions tests + +@pytest.fixture() +def netaxept_payment_with_token(netaxept_payment): + netaxept_payment.token = '1111111111114cf693a1cf86123e0d8f' + netaxept_payment.save() + return netaxept_payment + + +@mark.django_db +@patch('payment.gateways.netaxept.actions.query') +def it_should_verify(query, netaxept_payment_with_token): + mock_query_response = QueryResponse( + annuled=False, + authorized=False, + raw_response={} + ) + query.return_value = mock_query_response + + verify_result = verify_auth_transaction(transaction_id='1111111111114cf693a1cf86123e0d8f', response_code='OK') + assert not verify_result + + +def it_should_build_terminal_url(): + assert get_payment_terminal_url(_netaxept_config, transaction_id='11111') == \ + 'https://test.epayment.nets.eu/Terminal/default.aspx?merchantId=123456&transactionId=11111' + + diff --git a/tests/settings.py b/tests/settings.py index dfc2b73..034f72d 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -100,10 +100,10 @@ 'auto_capture': True, 'template_path': 'payment/netaxept.html', 'connection_params': { - 'merchant_id': os.environ.get('NETAXEPT_MERCHANT_ID'), - 'token': os.environ.get('NETAXEPT_TOKEN'), 'base_url': os.environ.get('NETAXEPT_BASE_URL') or 'https://test.epayment.nets.eu', 'after_terminal_url': os.environ.get('NETAXEPT_AFTER_TERMINAL_URL'), + 'merchant_id': os.environ.get('NETAXEPT_MERCHANT_ID'), + 'secret': os.environ.get('NETAXEPT_TOKEN'), } } },