From 809c45235f3062b992c06e511e8bb46d833e3939 Mon Sep 17 00:00:00 2001 From: Livio Bieri Date: Mon, 20 Nov 2023 15:57:53 +0100 Subject: [PATCH] chore: test for checkout flow --- server/vbv_lernwelt/shop/services.py | 5 +- .../shop/tests/test_checkout_api.py | 84 +++++++++++++++++++ server/vbv_lernwelt/shop/views.py | 8 +- 3 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 server/vbv_lernwelt/shop/tests/test_checkout_api.py diff --git a/server/vbv_lernwelt/shop/services.py b/server/vbv_lernwelt/shop/services.py index 5f9bc1f9..da6992ba 100644 --- a/server/vbv_lernwelt/shop/services.py +++ b/server/vbv_lernwelt/shop/services.py @@ -62,10 +62,6 @@ def init_transaction( webhook_url = overwrite payload = { - # See https://api-reference.datatrans.ch/#tag/v1transactions: - # -> It _should_ be unique for each transaction (according to docs) - # -> We use transaction id for checking transaction state - "refno": str(uuid.uuid4()), # We use autoSettle=True, so that we don't have to settle the transaction: # -> Be aware that autoSettle has implications of the possible transaction states # -> see CheckoutState docstring. @@ -73,6 +69,7 @@ def init_transaction( "amount": amount_chf_centimes, "currency": "CHF", "language": user.language, + "refno": str(uuid.uuid4()), "webhook": {"url": webhook_url}, "redirect": { "successUrl": redirect_url_success, diff --git a/server/vbv_lernwelt/shop/tests/test_checkout_api.py b/server/vbv_lernwelt/shop/tests/test_checkout_api.py new file mode 100644 index 00000000..a243ae36 --- /dev/null +++ b/server/vbv_lernwelt/shop/tests/test_checkout_api.py @@ -0,0 +1,84 @@ +from unittest.mock import patch + +from django.urls import reverse +from rest_framework import status +from rest_framework.test import APITestCase + +from vbv_lernwelt.core.admin import User +from vbv_lernwelt.shop.models import ( + CheckoutInformation, + CheckoutState, + Product, + VV_PRODUCT_SKU, +) +from vbv_lernwelt.shop.services import get_payment_url + +USER_USERNAME = "testuser" +USER_EMAIL = "test@example.com" +USER_PASSWORD = "testpassword" + +TEST_ADDRESS_DATA = { + "first_name": "Test", + "last_name": "User", + "street": "Test Street", + "street_number": "1", + "postal_code": "1234", + "city": "Test City", + "country": "Test Country", + "company_name": "Test Company", + "company_street": "Test Company Street", + "company_street_number": "1", + "company_postal_code": "1234", + "company_city": "Test Company City", + "company_country": "Test Company Country", +} + + +class CheckoutAPIView(APITestCase): + def setUp(self) -> None: + Product.objects.create( + sku=VV_PRODUCT_SKU, + price=300_00, + description="VV", + name="VV", + ) + + self.user = User.objects.create_user( + username=USER_USERNAME, + email=USER_EMAIL, + password=USER_PASSWORD, + is_active=True, + ) + + self.client.login(username=USER_USERNAME, password=USER_PASSWORD) + + @patch("vbv_lernwelt.shop.views.init_transaction") + def test_checkout(self, mock_init_transaction): + # GIVEN + mock_init_transaction.return_value = "1234567890" + redirect_url = "http://testserver/redirect-url" + + # WHEN + response = self.client.post( + path=reverse("checkout-vv"), + format="json", + data={ + "redirect_url": redirect_url, + "address": TEST_ADDRESS_DATA, + }, + ) + + # THEN + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + response.json()["next_step_url"], + get_payment_url("1234567890"), + ) + + self.assertTrue( + CheckoutInformation.objects.filter( + user=self.user, + product_sku=VV_PRODUCT_SKU, + state=CheckoutState.INITIALIZED.value, + ).exists() + ) diff --git a/server/vbv_lernwelt/shop/views.py b/server/vbv_lernwelt/shop/views.py index 57fdf1f3..ee6df6eb 100644 --- a/server/vbv_lernwelt/shop/views.py +++ b/server/vbv_lernwelt/shop/views.py @@ -32,8 +32,8 @@ def get_billing_address(request): data = BillingAddressSerializer(billing_address).data except BillingAddress.DoesNotExist: data = BillingAddressSerializer().data - data["first_name"] = request.user.first_name - data["last_name"] = request.user.last_name + data["first_name"] = request.user.first_name # noqa + data["last_name"] = request.user.last_name # noqa return Response(data) @@ -128,10 +128,6 @@ def checkout_vv(request): # already initialized -> redirect to payment page again if checkout := checkouts.filter(state=CheckoutState.INITIALIZED).first(): - # FIXME: Ask datatrans how they advice to handle this case: - # - 1. Why is the payment url not reusable? Calling the payment url again - # with the same transaction id results in a blank page. - # - 2. After 30 minutes, the transaction is fails but our webhook is not called? return JsonResponse({"next_step_url": get_payment_url(checkout.transaction_id)}) # not yet initialized at all, or canceled/failed