diff --git a/README.md b/README.md index 7b590e2..e28d781 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,9 @@ Supports: This implementation: -- Handles the exchanges with datatrans, including the signing of requests and the verification of the signature of notifications. -- Introduces persistent models for AliasRegistration, Payment, and Refund. These models record all exchanges with datatrans. +- Handles the exchanges with datatrans, including the signing of requests and the verification of the signature of notifications. All exchanges are logged as structured events, to make auditing easy. +- Introduces persistent models for AliasRegistration, Payment, and Refund. Both successes and failures are stored. +- Offers a rich admin interface, allowing ad-hoc payments using registered credit cards, as well as refunds. - Sends signals whenever an AliasRegistration, Payment, or Refund is done. The signal is sent even if the operation failed, the receiver should check the `success` flag received with the signal. @@ -46,7 +47,7 @@ Include `datatrans-urls` to the urlpatterns in your urls.py, for instance: url(r'^datatrans/', include('datatrans.urls')), ] -Configure the callback url in your upp +Configure the callback url in the datatrans UPP Administration page. In your settings.py, enter the configuration for your web and mpo merchants. For instance: diff --git a/datatrans/__init__.py b/datatrans/__init__.py index e3a585c..2935eea 100644 --- a/datatrans/__init__.py +++ b/datatrans/__init__.py @@ -1,4 +1,4 @@ -__version__ = '1.0.5' +__version__ = '1.0.6' __copyright__ = 'Copyright (c) 2017, skioo SA' __licence__ = 'MIT' __URL__ = 'https://github.com/skioo/django-datatrans-gateway' diff --git a/datatrans/gateway/xml_helpers.py b/datatrans/gateway/money_xml_converters.py similarity index 100% rename from datatrans/gateway/xml_helpers.py rename to datatrans/gateway/money_xml_converters.py diff --git a/datatrans/gateway/notification.py b/datatrans/gateway/notification.py index ec3df26..c67a8ba 100644 --- a/datatrans/gateway/notification.py +++ b/datatrans/gateway/notification.py @@ -2,7 +2,7 @@ from structlog import get_logger from typing import Union -from .xml_helpers import parse_money +from .money_xml_converters import parse_money from ..config import sign_web from ..models import AliasRegistration, Payment @@ -19,7 +19,7 @@ def handle_notification(xml: str) -> None: def parse_notification_xml(xml: str) -> Union[AliasRegistration, Payment]: """" Both alias registration and payments are received here. - We can differentiate them by looking at the use-alias user-parameter (and verifying the amount is o). + We can differentiate them by looking at the use-alias user-parameter (and verifying the amount is 0). """ body = fromstring(xml).find('body') diff --git a/datatrans/gateway/payment_parameters.py b/datatrans/gateway/payment_parameters.py index dfb0070..f81a8d5 100644 --- a/datatrans/gateway/payment_parameters.py +++ b/datatrans/gateway/payment_parameters.py @@ -1,8 +1,9 @@ from collections import namedtuple + from moneyed import Money from structlog import get_logger -from .xml_helpers import money_to_amount_and_currency +from .money_xml_converters import money_to_amount_and_currency from ..config import sign_web, web_merchant_id logger = get_logger() diff --git a/datatrans/gateway/payment_with_alias.py b/datatrans/gateway/payment_with_alias.py index f875482..a401536 100644 --- a/datatrans/gateway/payment_with_alias.py +++ b/datatrans/gateway/payment_with_alias.py @@ -5,7 +5,7 @@ import requests from structlog import get_logger -from .xml_helpers import money_to_amount_and_currency, parse_money +from .money_xml_converters import money_to_amount_and_currency, parse_money from ..config import datatrans_authorize_url, mpo_merchant_id, sign_mpo from ..models import AliasRegistration, Payment diff --git a/datatrans/gateway/refunding.py b/datatrans/gateway/refunding.py index 1e87571..b438ff8 100644 --- a/datatrans/gateway/refunding.py +++ b/datatrans/gateway/refunding.py @@ -5,7 +5,7 @@ from moneyed import Money from structlog import get_logger -from .xml_helpers import money_to_amount_and_currency, parse_money +from .money_xml_converters import money_to_amount_and_currency, parse_money from ..config import datatrans_processor_url, sign_web from ..models import Payment, Refund diff --git a/tests/gateway/__init__.py b/tests/gateway/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/utils.py b/tests/gateway/assertions.py similarity index 100% rename from tests/utils.py rename to tests/gateway/assertions.py diff --git a/tests/test_notification_xml.py b/tests/gateway/test_notification.py similarity index 98% rename from tests/test_notification_xml.py rename to tests/gateway/test_notification.py index a2f10d8..94bfc0d 100644 --- a/tests/test_notification_xml.py +++ b/tests/gateway/test_notification.py @@ -3,7 +3,7 @@ from datatrans.gateway.notification import parse_notification_xml from datatrans.models import AliasRegistration, Payment -from .utils import assertModelEqual +from .assertions import assertModelEqual class ParseRegisterAliasTest(TestCase): @@ -41,8 +41,7 @@ def test_success(self): - - """ +""" expected = AliasRegistration( success=True, transaction_id='170707111922838874', @@ -99,9 +98,7 @@ def test_empty_response_code(self): - - """ - +""" expected = AliasRegistration( success=True, transaction_id='170707111922838874', @@ -156,8 +153,7 @@ def test_wrong_sign2(self): - - """ +""" with self.assertRaises(ValueError): parse_notification_xml(xml) @@ -192,8 +188,7 @@ def test_wrong_expiry_date(self): - - """ +""" expected = AliasRegistration( success=False, transaction_id='170710155947695609', @@ -242,8 +237,7 @@ def test_card_number_and_alias_are_not_always_present(self): - - """ +""" expected = AliasRegistration( success=False, transaction_id='170710155947695609', @@ -293,8 +287,7 @@ def test_success(self): - - """ +""" expected = Payment( success=True, transaction_id='170719094930353253', @@ -396,8 +389,7 @@ def test_wrong_expiry(self): - -""" +""" expected = Payment( success=False, transaction_id='170720154219033737', diff --git a/tests/test_payment_parameters.py b/tests/gateway/test_payment_parameters.py similarity index 94% rename from tests/test_payment_parameters.py rename to tests/gateway/test_payment_parameters.py index a4c9926..da1fb2c 100644 --- a/tests/test_payment_parameters.py +++ b/tests/gateway/test_payment_parameters.py @@ -4,7 +4,7 @@ from datatrans.gateway import PaymentParameters, build_payment_parameters, build_register_credit_card_parameters -class PaymentTest(TestCase): +class PaymentParametersTest(TestCase): def test_it_should_generate_payment_parameters(self): parameters = build_payment_parameters(amount=Money(8.50, 'CHF'), client_ref='91827364') expected = PaymentParameters( @@ -17,8 +17,6 @@ def test_it_should_generate_payment_parameters(self): ) assert parameters == expected - -class RegisterCreditCardTest(TestCase): def test_it_should_generate_register_credit_card_parameters(self): parameters = build_register_credit_card_parameters(client_ref='someref') expected = PaymentParameters( diff --git a/tests/test_charge_xml.py b/tests/gateway/test_payment_with_aliasl.py similarity index 98% rename from tests/test_charge_xml.py rename to tests/gateway/test_payment_with_aliasl.py index d94d802..d5ef00d 100644 --- a/tests/test_charge_xml.py +++ b/tests/gateway/test_payment_with_aliasl.py @@ -3,10 +3,10 @@ from datatrans.gateway.payment_with_alias import build_pay_with_alias_request_xml, parse_pay_with_alias_response_xml from datatrans.models import AliasRegistration, Payment -from .utils import assertModelEqual +from .assertions import assertModelEqual -class BuildChargeRequestTest(TestCase): +class BuildPayWithAliasRequestTest(TestCase): def test_build_request(self): xml = build_pay_with_alias_request_xml( amount=Money(123, "CHF"), @@ -34,7 +34,7 @@ def test_build_request(self): assert xml.decode() == expected -class ParseChargeResponseTest(TestCase): +class ParsePayWithAliasResponseTest(TestCase): def test_success(self): response = """ diff --git a/tests/test_refund_xml.py b/tests/gateway/test_refunding.py similarity index 98% rename from tests/test_refund_xml.py rename to tests/gateway/test_refunding.py index 4c0bff9..59a369c 100644 --- a/tests/test_refund_xml.py +++ b/tests/gateway/test_refunding.py @@ -3,7 +3,7 @@ from datatrans.gateway.refunding import build_refund_request_xml, parse_refund_response_xml from datatrans.models import Refund -from .utils import assertModelEqual +from .assertions import assertModelEqual class BuildRefundRequestTest(TestCase): @@ -111,8 +111,7 @@ def test_invalid_payment_transaction_id(self): - - """ +""" expected = Refund( success=False, merchant_id='2222222222', diff --git a/tests/settings.py b/tests/settings.py index 6d825a2..91daaf6 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -17,7 +17,7 @@ 'django.contrib.sessions', 'django.contrib.admin', 'tests', - 'datatrans', + 'datatrans.apps.DatatransConfig', ] MIDDLEWARE = [ diff --git a/tests/test_gateway.py b/tests/test_gateway.py deleted file mode 100644 index 08db70c..0000000 --- a/tests/test_gateway.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.test import TestCase - - -class GatewayChargeTest(TestCase): - def test_it_can_charge(self): - pass - - -class GatewayRefundTest(TestCase): - def test_it_can_refund(self): - pass diff --git a/tests/test_models.py b/tests/test_models.py index 757edc1..02b859e 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -142,6 +142,7 @@ def test_save_many_errored_refund(self): error_message='access denied', error_detail='incorrect merchantId', ) + refund1.full_clean() refund1.save() refund2 = Refund( @@ -155,4 +156,5 @@ def test_save_many_errored_refund(self): error_message='access denied', error_detail='incorrect merchantId', ) + refund2.full_clean() refund2.save() diff --git a/tests/test_event_processing.py b/tests/test_signals.py similarity index 100% rename from tests/test_event_processing.py rename to tests/test_signals.py diff --git a/tests/test_views.py b/tests/test_views.py index b238c7a..ea154f1 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -50,6 +50,16 @@ def test_it_should_show_a_form_for_the_example_register_credit_card_page(self): response = Client().get(reverse('example_register_credit_card')) assert response.status_code == 200 + def test_it_should_process_form_for_the_example_register_credit_card_page(self): + response = Client().post(reverse('example_register_credit_card'), + {'client_ref': 'a ref'}) + assert response.status_code == 200 + def test_it_should_show_a_form_for_the_example_pay_page(self): response = Client().get(reverse('example_pay')) assert response.status_code == 200 + + def test_it_should_process_form_for_the_example_pay_page(self): + response = Client().post(reverse('example_pay'), + {'amount_0': 1, 'amount_1': 'CHF', 'client_ref': 'a ref'}) + assert response.status_code == 200