diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7a959d6..020a416 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,12 +11,12 @@ on: jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Setup Python - run: sudo add-apt-repository -y ppa:deadsnakes/ppa && sudo apt-get install -y python3.6 python3.7 python3.9 python3.6-distutils python3.7-distutils python3.9-distutils + run: sudo add-apt-repository -y ppa:deadsnakes/ppa && sudo apt-get install -y python3.7 python3.9 python3.7-distutils python3.9-distutils - name: Install dependencies run: | diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 22c63ec..4eaa966 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ Change Log ---------- +1.5.8 ++++++++++++++++++++++ + +**Features** + +- Add support for `checkoutSession` API method. + 1.5.7 +++++++++++++++++++++ diff --git a/README.rst b/README.rst index 823bb86..f8ccc1f 100644 --- a/README.rst +++ b/README.rst @@ -1,13 +1,6 @@ -.. image:: https://travis-ci.org/coolshop-com/AltaPay.svg - :target: https://travis-ci.org/coolshop-com/AltaPay - -.. image:: https://codecov.io/github/coolshop-com/AltaPay/coverage.svg?branch=master - :target: https://codecov.io/github/coolshop-com/AltaPay?branch=master - -.. image:: https://img.shields.io/pypi/v/altapay.svg - :target: https://pypi.python.org/pypi/altapay - -This is an unofficial Python SDK for AltaPay (formerly Valitor/Pensio), https://altapay.com/. The SDK is maintained by Coolshop.com, https://www.coolshop.com/. +AltaPay - Python SDK +============ +For integrating Python projects with the AltaPay gateway. Requirements ============ diff --git a/altapay/__init__.py b/altapay/__init__.py index 91454d7..853ad91 100644 --- a/altapay/__init__.py +++ b/altapay/__init__.py @@ -1,5 +1,5 @@ __title__ = 'altapay' -__version__ = '1.5.7' +__version__ = '1.5.8' __author__ = 'Coolshop.com' __license__ = 'MIT' __github_url__ = 'https://github.com/coolshop-com/AltaPay' @@ -11,6 +11,7 @@ from altapay.api import API # NOQA from altapay.callback import Callback # NOQA from altapay.chargeback import ChargebackEvent # NOQA +from altapay.checkout_session import CheckoutSession # NOQA from altapay.credit_card_wallet_initiate_app_payment import \ CreditCardWalletInitiateAppPayment # NOQA from altapay.funding import CustomReport, Funding, FundingList # NOQA diff --git a/altapay/checkout_session.py b/altapay/checkout_session.py new file mode 100644 index 0000000..67844b4 --- /dev/null +++ b/altapay/checkout_session.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import, unicode_literals + +from altapay.resource import Resource + + +class CheckoutSession(Resource): + def create(self, terminals, shop_orderid, amount, currency, **kwargs): + """ + Create a checkout session. + + Creates a checkout session for the current customer's basket grouping + all available payment methods. The session should be reused for + different payment methods until the payment is not finalized. + + Checkout session is used to improve fraud detection and help maximize + conversion rate. + + :arg terminals: list of terminal names available for the user based on + the checkout parameters. Can also be a single terminal name string. + :arg shop_orderid: your order ID to be attached to the checkout session + :arg amount: order amount in floating point + :arg currency: currency for the checkout session + :arg kwargs: used for remaining, optional, parameters, see the AltaPay + documentation for a full list. Note that you will need to use + lists and dictionaries to map the URL structures from the AltaPay + documentation into these kwargs. + + :rtype: :samp:`True` if a checkout session was created, otherwise + :samp:`False`. + """ + if isinstance(terminals, str): + terminals = [terminals] + + parameters = { + 'terminals': terminals, + 'shop_orderid': shop_orderid, + 'amount': amount, + 'currency': currency, + } + + parameters.update(kwargs) + + response = self.api.post( + self.get_post_url(), data=parameters) + self.merge_response(response) + return self.success + + def get_post_url(self): + return 'API/checkoutSession' diff --git a/example/example_klarna.py b/example/example_klarna.py index f318318..ccaeed3 100755 --- a/example/example_klarna.py +++ b/example/example_klarna.py @@ -7,7 +7,8 @@ """ -import sys, random +import secrets +import sys # Update this with real path and uncomment before use, please # sys.path.append('/absolute_path_to/sdk-python') @@ -31,7 +32,7 @@ params = { 'terminal': 'AltaPay Klarna DK', # Update terminal name - 'shop_orderid': 'Example_Klarna' + str(random.randint(1, 1000)), + 'shop_orderid': 'Example_Klarna' + str(secrets.randbelow(1000) + 1), 'amount': 5.5, 'currency': 'DKK', 'type': 'payment', diff --git a/example/example_mobilepay.py b/example/example_mobilepay.py index 6ef5f51..11e0f08 100755 --- a/example/example_mobilepay.py +++ b/example/example_mobilepay.py @@ -7,8 +7,8 @@ """ +import secrets import sys -import random # Update this with real path and uncomment before use, please # sys.path.append('/absolute_path_to/python-client-library') @@ -31,7 +31,7 @@ params = { 'terminal': 'AltapPay MobilePay Terminal', # Update terminal name - 'shop_orderid': 'Example_MobilePay' + str(random.randint(1, 1000)), + 'shop_orderid': 'Example_MobilePay' + str(secrets.randbelow(1000) + 1), 'amount': 5.5, 'currency': 'DKK', 'type': 'payment', diff --git a/example/example_reservation.py b/example/example_reservation.py index 07ccd87..ebdab3a 100755 --- a/example/example_reservation.py +++ b/example/example_reservation.py @@ -17,12 +17,12 @@ from altapay import API, Reservation, Transaction -import string -import random import json +import string +import secrets def id_generator(size=15, chars=string.digits): - return ''.join(random.choice(chars) for _ in range(size)) + return ''.join(secrets.choice(chars) for _ in range(size)) order_id=id_generator() # print order_id diff --git a/example/example_terminals.py b/example/example_terminals.py index 71c268f..4d2e4f4 100755 --- a/example/example_terminals.py +++ b/example/example_terminals.py @@ -7,7 +7,7 @@ """ -import sys, random +import sys # Update this with real path and uncomment before use, please # sys.path.append('/absolute_path_to/python-client-library') diff --git a/sonar-project.properties b/sonar-project.properties index b9f3ede..1dd4ec2 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1 +1,2 @@ sonar.projectKey=AltaPay_sdk-python_307c8b3c-eb03-4e95-8a4f-3cb5510110a9 +sonar.coverage.exclusions=** diff --git a/tests/integration/test_merchant_api.py b/tests/integration/test_merchant_api.py index 81326ae..7f55906 100644 --- a/tests/integration/test_merchant_api.py +++ b/tests/integration/test_merchant_api.py @@ -1,10 +1,10 @@ import os -import random +import secrets import unittest from datetime import date -from altapay import (API, Funding, FundingList, Invoice, Payment, Reservation, - Transaction) +from altapay import (API, CheckoutSession, Funding, FundingList, Invoice, + Payment, Reservation, Transaction) from tests.integration import (altapay_account, altapay_contract_identifier, altapay_invoice_test_terminal_name, altapay_password, altapay_test_terminal_name, @@ -12,7 +12,7 @@ def generate_order_id(): - return 'Test_' + str(random.randint(1000, 999999)) + '_PY' + return 'Test_' + str(secrets.randbelow(999000) + 1000) + '_PY' class APITest(unittest.TestCase): @@ -22,13 +22,27 @@ def setUp(self): password=altapay_password, url=altapay_url) + def create_checkout_session(self): + session = CheckoutSession(api=self.api) + session.create( + terminals=[altapay_test_terminal_name], + shop_orderid=generate_order_id(), + amount=1.00, + currency='EUR' + ) + return session.session['id'] + + def test_create_checkout_session(self): + self.create_checkout_session() + def test_create_payment_request(self): payment = Payment(api=self.api) params = { 'terminal': altapay_test_terminal_name, 'shop_orderid': generate_order_id(), 'amount': 1.00, - 'currency': 'EUR' + 'currency': 'EUR', + 'session_id': self.create_checkout_session() } self.assertEqual(payment.create(**params), True) self.assertIn('url', payment) @@ -45,7 +59,8 @@ def test_create_payment_request_with_agreement(self): 'agreement': { 'type': 'unscheduled', 'unscheduled_type': 'incremental' - } + }, + 'session_id': self.create_checkout_session() } self.assertEqual(payment.create(**params), True) self.assertIn('url', payment) diff --git a/tests/test_api.py b/tests/test_api.py index fee5355..4c7104f 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -24,7 +24,8 @@ def test_login_successful(self): body=self.load_xml_response('200_login.xml'), status=200, content_type='application/xml') api = API( - mode='test', account='test', password='test', auto_login=False) + mode='test', account='test', + password='test', auto_login=False) # NOSONAR # Before login is called state should be not authenticated self.assertEqual(api._is_authenticated, False) api.login() diff --git a/tests/test_checkout_session.py b/tests/test_checkout_session.py new file mode 100644 index 0000000..ffd0437 --- /dev/null +++ b/tests/test_checkout_session.py @@ -0,0 +1,29 @@ +from __future__ import absolute_import, unicode_literals + +import responses + +from altapay import API, CheckoutSession + +from .test_cases import TestCase + + +class CheckoutSessionTest(TestCase): + def setUp(self): + self.api = API(mode='test', auto_login=False) + + @responses.activate + def test_create_simple_checkout_session(self): + session = CheckoutSession(api=self.api) + responses.add( + responses.POST, self.get_api_url('API/checkoutSession'), + body=self.load_xml_response('200_checkout_session.xml'), + status=200, content_type='application/xml') + parameters = { + 'terminals': ['Test Terminal'], + 'shop_orderid': 1234567, + 'amount': 9.95, + 'currency': 'EUR' + } + self.assertEqual(session.create(**parameters), True) + self.assertIn('session', session) + self.assertEqual(len(session.session['id']) > 0, True) diff --git a/tests/xml/200_checkout_session.xml b/tests/xml/200_checkout_session.xml new file mode 100644 index 0000000..2ec0df2 --- /dev/null +++ b/tests/xml/200_checkout_session.xml @@ -0,0 +1,15 @@ + + +
+ 2026-04-19T09:57:02+02:00 + API/checkoutSession + 0 + +
+ + + abc12345-6789-4def-a012-bcdef0123456 + CREATED + + +