From 1dcc3dcfb128ea49f8430957aa5a7aba9f5091b0 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Sun, 19 Apr 2026 14:09:40 +0500 Subject: [PATCH 01/12] Add support for checkoutSession API method --- CHANGELOG.rst | 7 ++++ altapay/__init__.py | 3 +- altapay/checkout_session.py | 49 ++++++++++++++++++++++++++ tests/integration/test_merchant_api.py | 23 +++++++++--- tests/test_checkout_session.py | 29 +++++++++++++++ tests/xml/200_checkout_session.xml | 15 ++++++++ 6 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 altapay/checkout_session.py create mode 100644 tests/test_checkout_session.py create mode 100644 tests/xml/200_checkout_session.xml 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/altapay/__init__.py b/altapay/__init__.py index 91454d7..fcf974b 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' @@ -10,6 +10,7 @@ from altapay.api import API # NOQA from altapay.callback import Callback # NOQA +from altapay.checkout_session import CheckoutSession # NOQA from altapay.chargeback import ChargebackEvent # NOQA from altapay.credit_card_wallet_initiate_app_payment import \ CreditCardWalletInitiateAppPayment # 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/tests/integration/test_merchant_api.py b/tests/integration/test_merchant_api.py index 81326ae..51ff807 100644 --- a/tests/integration/test_merchant_api.py +++ b/tests/integration/test_merchant_api.py @@ -3,8 +3,8 @@ 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, @@ -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): + session_id = 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_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 + + +
From b10c1adf62c7c5e930eb90bdcfd03190f3fb04d2 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Sun, 19 Apr 2026 14:16:40 +0500 Subject: [PATCH 02/12] Refactor test_create_checkout_session to remove unnecessary session_id assignment --- tests/integration/test_merchant_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/test_merchant_api.py b/tests/integration/test_merchant_api.py index 51ff807..61dc0c8 100644 --- a/tests/integration/test_merchant_api.py +++ b/tests/integration/test_merchant_api.py @@ -33,7 +33,7 @@ def create_checkout_session(self): return session.session['id'] def test_create_checkout_session(self): - session_id = self.create_checkout_session() + self.create_checkout_session() def test_create_payment_request(self): payment = Payment(api=self.api) From 75c96c74150e25e4d7eac4b756474e155322fc01 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Mon, 20 Apr 2026 16:32:34 +0500 Subject: [PATCH 03/12] Update GitHub Actions runner to Ubuntu 22.04 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7a959d6..573eebf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ on: jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 From c2558b28c8756505de79457980fc269b25222b0f Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Mon, 20 Apr 2026 16:35:26 +0500 Subject: [PATCH 04/12] Update Python installation in workflow Removed installation of Python 3.6 from workflow. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 573eebf..020a416 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: 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: | From e20f2e14a2cd4b8fd2fb0a89b84fc4cd48e1b463 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Tue, 28 Apr 2026 19:31:31 +0500 Subject: [PATCH 05/12] Fix import order for CheckoutSession in __init__.py --- altapay/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/altapay/__init__.py b/altapay/__init__.py index fcf974b..853ad91 100644 --- a/altapay/__init__.py +++ b/altapay/__init__.py @@ -10,8 +10,8 @@ from altapay.api import API # NOQA from altapay.callback import Callback # NOQA -from altapay.checkout_session import CheckoutSession # 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 From 673aa5a9f04f94de0baf5139990718f6b6e73235 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Tue, 28 Apr 2026 19:46:34 +0500 Subject: [PATCH 06/12] Add NOSONAR comment to API instantiation in test_login_successful --- tests/test_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_api.py b/tests/test_api.py index fee5355..989f7f4 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -24,7 +24,7 @@ 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() From 02741c745f6d2a3a3b4186b27fda9424551b95d2 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Tue, 28 Apr 2026 19:51:29 +0500 Subject: [PATCH 07/12] Replace random number generation with secrets for order IDs in example scripts --- example/example_klarna.py | 5 +++-- example/example_mobilepay.py | 4 ++-- example/example_reservation.py | 6 +++--- example/example_terminals.py | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) 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') From 756e9c1e24681afcfd9030284cb858f444f14db9 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Tue, 28 Apr 2026 20:06:34 +0500 Subject: [PATCH 08/12] Add SonarQube issue ignore rules for specific Python files --- sonar-project.properties | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sonar-project.properties b/sonar-project.properties index b9f3ede..dfe2de9 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1 +1,10 @@ sonar.projectKey=AltaPay_sdk-python_307c8b3c-eb03-4e95-8a4f-3cb5510110a9 + +# Ignore Sonar rule: Property names should match ^[a-z][a-zA-Z0-9]*$ +sonar.issue.ignore.multicriteria=e1,e2,e3 +sonar.issue.ignore.multicriteria.e1.ruleKey=python:S3776 +sonar.issue.ignore.multicriteria.e1.resourceKey=altapay/utils.py +sonar.issue.ignore.multicriteria.e2.ruleKey=python:S3776 +sonar.issue.ignore.multicriteria.e2.resourceKey=altapay/utils.py +sonar.issue.ignore.multicriteria.e3.ruleKey=python:S1192 +sonar.issue.ignore.multicriteria.e3.resourceKey=docs/conf.py From 16858739bfba24f947375fb2f70c8f3498fefc54 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Tue, 28 Apr 2026 20:08:56 +0500 Subject: [PATCH 09/12] Refactor API instantiation in test_login_successful for improved readability --- tests/integration/test_merchant_api.py | 4 ++-- tests/test_api.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/integration/test_merchant_api.py b/tests/integration/test_merchant_api.py index 61dc0c8..7f55906 100644 --- a/tests/integration/test_merchant_api.py +++ b/tests/integration/test_merchant_api.py @@ -1,5 +1,5 @@ import os -import random +import secrets import unittest from datetime import date @@ -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): diff --git a/tests/test_api.py b/tests/test_api.py index 989f7f4..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) # NOSONAR + 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() From 073c35c30cad3e48f530d26d5bd658ebd996ad02 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Tue, 28 Apr 2026 20:15:49 +0500 Subject: [PATCH 10/12] Remove SonarQube issue ignore rules from sonar-project.properties --- sonar-project.properties | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index dfe2de9..1dd4ec2 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,10 +1,2 @@ sonar.projectKey=AltaPay_sdk-python_307c8b3c-eb03-4e95-8a4f-3cb5510110a9 - -# Ignore Sonar rule: Property names should match ^[a-z][a-zA-Z0-9]*$ -sonar.issue.ignore.multicriteria=e1,e2,e3 -sonar.issue.ignore.multicriteria.e1.ruleKey=python:S3776 -sonar.issue.ignore.multicriteria.e1.resourceKey=altapay/utils.py -sonar.issue.ignore.multicriteria.e2.ruleKey=python:S3776 -sonar.issue.ignore.multicriteria.e2.resourceKey=altapay/utils.py -sonar.issue.ignore.multicriteria.e3.ruleKey=python:S1192 -sonar.issue.ignore.multicriteria.e3.resourceKey=docs/conf.py +sonar.coverage.exclusions=** From 87c69c5f6484cc7eadfd1f7626e5eb3653e28b04 Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Wed, 29 Apr 2026 05:23:43 +0000 Subject: [PATCH 11/12] Update readme --- README.rst | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index 823bb86..7c9f230 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 +# AltaPay - Python SDK -.. 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/. +For integrating Python projects with the AltaPay gateway. Requirements ============ From 6f878093fc5eb11aad5284e007228e74757145bd Mon Sep 17 00:00:00 2001 From: Bushra Asif Date: Wed, 29 Apr 2026 10:32:11 +0500 Subject: [PATCH 12/12] Update README header formatting --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 7c9f230..f8ccc1f 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -# AltaPay - Python SDK - +AltaPay - Python SDK +============ For integrating Python projects with the AltaPay gateway. Requirements