Add fake datatrans endpoints for e2e tests
This commit is contained in:
parent
ec21238ece
commit
f8c6e135e1
|
|
@ -211,7 +211,6 @@ const executePayment = async () => {
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 class="mb-4 mt-10">{{ $t("a.Adresse") }}</h3>
|
<h3 class="mb-4 mt-10">{{ $t("a.Adresse") }}</h3>
|
||||||
<pre>{{ address }}</pre>
|
|
||||||
<p class="mb-2">
|
<p class="mb-2">
|
||||||
{{
|
{{
|
||||||
$t(
|
$t(
|
||||||
|
|
|
||||||
|
|
@ -675,8 +675,12 @@ if APP_ENVIRONMENT.startswith("prod"):
|
||||||
DATATRANS_API_ENDPOINT = "https://api.datatrans.com"
|
DATATRANS_API_ENDPOINT = "https://api.datatrans.com"
|
||||||
DATATRANS_PAY_URL = "https://pay.datatrans.com"
|
DATATRANS_PAY_URL = "https://pay.datatrans.com"
|
||||||
else:
|
else:
|
||||||
DATATRANS_API_ENDPOINT = "https://api.sandbox.datatrans.com"
|
DATATRANS_API_ENDPOINT = env(
|
||||||
DATATRANS_PAY_URL = "https://pay.sandbox.datatrans.com"
|
"DATATRANS_API_ENDPOINT", default="https://api.sandbox.datatrans.com"
|
||||||
|
)
|
||||||
|
DATATRANS_PAY_URL = env(
|
||||||
|
"DATATRANS_PAY_URL", default="https://pay.sandbox.datatrans.com"
|
||||||
|
)
|
||||||
|
|
||||||
# Only for debugging the webhook (locally)
|
# Only for debugging the webhook (locally)
|
||||||
DATATRANS_DEBUG_WEBHOOK_OVERWRITE = env(
|
DATATRANS_DEBUG_WEBHOOK_OVERWRITE = env(
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ from .base import * # noqa
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
# https://docs.djangoproject.com/en/dev/ref/settings/#secret-key
|
||||||
DATABASES["default"]["NAME"] = "vbv_lernwelt_cypress"
|
DATABASES["default"]["NAME"] = "vbv_lernwelt_cypress"
|
||||||
|
|
||||||
|
DATATRANS_API_ENDPOINT = 'http://localhost:8001/server/fakeapi/datatrans/api'
|
||||||
|
DATATRANS_PAY_URL = 'http://localhost:8001/server/fakeapi/datatrans/pay'
|
||||||
|
|
||||||
# EMAIL
|
# EMAIL
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
# https://docs.djangoproject.com/en/dev/ref/settings/#email-backend
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,11 @@ from wagtail import urls as wagtail_urls
|
||||||
from wagtail.admin import urls as wagtailadmin_urls
|
from wagtail.admin import urls as wagtailadmin_urls
|
||||||
from wagtail.documents import urls as media_library_urls
|
from wagtail.documents import urls as media_library_urls
|
||||||
|
|
||||||
|
from vbv_lernwelt.shop.datatrans_fake_server import (
|
||||||
|
fake_datatrans_api_view,
|
||||||
|
fake_datatrans_pay_view,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SignedIntConverter(IntConverter):
|
class SignedIntConverter(IntConverter):
|
||||||
regex = r"-?\d+"
|
regex = r"-?\d+"
|
||||||
|
|
@ -242,6 +247,16 @@ if settings.DEBUG:
|
||||||
# Static file serving when using Gunicorn + Uvicorn for local web socket development
|
# Static file serving when using Gunicorn + Uvicorn for local web socket development
|
||||||
urlpatterns += staticfiles_urlpatterns()
|
urlpatterns += staticfiles_urlpatterns()
|
||||||
|
|
||||||
|
if "fakeapi" in settings.DATATRANS_API_ENDPOINT:
|
||||||
|
urlpatterns += [
|
||||||
|
re_path(
|
||||||
|
r"^server/fakeapi/datatrans/api(?P<api_url>.*)$", fake_datatrans_api_view
|
||||||
|
),
|
||||||
|
re_path(
|
||||||
|
r"^server/fakeapi/datatrans/pay(?P<api_url>.*)$", fake_datatrans_pay_view
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ class MeUserViewTest(APITestCase):
|
||||||
)
|
)
|
||||||
self.client.login(username="testuser", password="testpassword")
|
self.client.login(username="testuser", password="testpassword")
|
||||||
add_organisations()
|
add_organisations()
|
||||||
add_countries()
|
add_countries(small_set=True)
|
||||||
|
|
||||||
def test_user_can_update_language(self) -> None:
|
def test_user_can_update_language(self) -> None:
|
||||||
# GIVEN
|
# GIVEN
|
||||||
|
|
|
||||||
|
|
@ -1011,7 +1011,7 @@ countries = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def add_countries(apps=None, schema_editor=None):
|
def add_countries(apps=None, schema_editor=None, small_set=False):
|
||||||
if apps is None:
|
if apps is None:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from vbv_lernwelt.core.models import Country
|
from vbv_lernwelt.core.models import Country
|
||||||
|
|
@ -1025,6 +1025,9 @@ def add_countries(apps=None, schema_editor=None):
|
||||||
for country_id, country_name in countries.items():
|
for country_id, country_name in countries.items():
|
||||||
country_code = country_name["country_code"]
|
country_code = country_name["country_code"]
|
||||||
|
|
||||||
|
if small_set and country_code not in ["CH", "LI", "DE", "AT", "FR", "IT"]:
|
||||||
|
continue
|
||||||
|
|
||||||
if has_country_code:
|
if has_country_code:
|
||||||
Country.objects.get_or_create(
|
Country.objects.get_or_create(
|
||||||
country_code=country_code,
|
country_code=country_code,
|
||||||
|
|
|
||||||
|
|
@ -76,4 +76,6 @@ After everything runs fine, we should be able to remove the following deprecated
|
||||||
|
|
||||||
### Datatrans Test Credit Card
|
### Datatrans Test Credit Card
|
||||||
|
|
||||||
5100 0010 0000 0014 06/25 123
|
5100 0010 0000 0014
|
||||||
|
06/25
|
||||||
|
123
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,161 @@
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.http import HttpResponse, JsonResponse
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
|
from vbv_lernwelt.core.middleware.auth import django_view_authentication_exempt
|
||||||
|
from vbv_lernwelt.core.models import User
|
||||||
|
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
@django_view_authentication_exempt
|
||||||
|
def fake_datatrans_api_view(request, api_url=""):
|
||||||
|
# if api_url == "/redirect":
|
||||||
|
# fake_tamedia_token = request.GET.get("token")
|
||||||
|
# pai = fake_tamedia_token.split(":")[1]
|
||||||
|
# sub = SubhubCustomerSubscription.objects.filter(id=pai).first()
|
||||||
|
#
|
||||||
|
# header = f"<h1>fake tamedia activation for {pai}"
|
||||||
|
#
|
||||||
|
# if not sub:
|
||||||
|
# return HttpResponse(
|
||||||
|
# content=f"""
|
||||||
|
# {header}
|
||||||
|
# <p>no subscription found</p>
|
||||||
|
# """,
|
||||||
|
# status=404,
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# if request.method == "GET":
|
||||||
|
# if (
|
||||||
|
# sub
|
||||||
|
# and sub.partner_status
|
||||||
|
# == SubhubCustomerSubscription.PARTNER_STATUS_ENROLLED
|
||||||
|
# ):
|
||||||
|
# return HttpResponse(
|
||||||
|
# content=f"""
|
||||||
|
# {header}
|
||||||
|
# <div>
|
||||||
|
# <input type="text" name="partnerSubscriptionId" value="{pai}">
|
||||||
|
# <form action="{create_register_url(fake_tamedia_token)}" method="post">
|
||||||
|
# <button type="submit" data-cy="register-button">Register</button>
|
||||||
|
# </form>
|
||||||
|
# </div>
|
||||||
|
# """,
|
||||||
|
# status=200,
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# return HttpResponse(
|
||||||
|
# content=f"""
|
||||||
|
# {header}
|
||||||
|
# <p>already activated</p>
|
||||||
|
# """,
|
||||||
|
# status=200,
|
||||||
|
# )
|
||||||
|
# if request.method == "POST":
|
||||||
|
# if sub:
|
||||||
|
# response = requests.post(
|
||||||
|
# f"{settings.APPLICATION_ABSOLUTE_URL}/subhub/ottwebhook",
|
||||||
|
# json={
|
||||||
|
# "PartnerIntegration": {
|
||||||
|
# "effectiveDate": datetime.now().isoformat(),
|
||||||
|
# "eventType": "activation",
|
||||||
|
# "offerId": sub.subscription_choice.partner_product_id,
|
||||||
|
# "optionalAttributes": None,
|
||||||
|
# "pai": pai,
|
||||||
|
# "partnerType": "Tamedia",
|
||||||
|
# "transactionId": str(uuid.uuid4()),
|
||||||
|
# },
|
||||||
|
# "eventId": str(uuid.uuid4()),
|
||||||
|
# "eventType": "OTT Partner Events",
|
||||||
|
# "publisherId": "Partner Events",
|
||||||
|
# "status": "new",
|
||||||
|
# "timestamp": datetime.now().isoformat(),
|
||||||
|
# },
|
||||||
|
# auth=HTTPBasicAuth(
|
||||||
|
# "swisscom_ott_webhook",
|
||||||
|
# "swisscom-ott-webhook-rLaYG0btVJMPtfnzfLilZtm50",
|
||||||
|
# ),
|
||||||
|
# )
|
||||||
|
# print(response)
|
||||||
|
# return redirect(f"{create_register_url(fake_tamedia_token)}")
|
||||||
|
#
|
||||||
|
# if api_url.startswith("/enroll") and request.method == "POST":
|
||||||
|
# return HttpResponse(status=204)
|
||||||
|
#
|
||||||
|
|
||||||
|
if api_url == "/v1/transactions" and request.method == "POST":
|
||||||
|
data = json.loads(request.body.decode("utf-8"))
|
||||||
|
user = User.objects.get(id=data["user_id"])
|
||||||
|
user.additional_json_data["datatrans_transaction_payload"] = data
|
||||||
|
user.save()
|
||||||
|
return JsonResponse({"transactionId": data["refno"]}, status=201)
|
||||||
|
|
||||||
|
return HttpResponse(
|
||||||
|
content="unknown api url", content_type="application/json", status=400
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
@django_view_authentication_exempt
|
||||||
|
def fake_datatrans_pay_view(request, api_url=""):
|
||||||
|
def call_transaction_complete_webhook(
|
||||||
|
webhook_url, transaction_id, datatrans_status="settled"
|
||||||
|
):
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"transactionId": transaction_id,
|
||||||
|
"status": datatrans_status,
|
||||||
|
}
|
||||||
|
key_hex_bytes = bytes.fromhex(settings.DATATRANS_HMAC_KEY)
|
||||||
|
|
||||||
|
# Create sign with timestamp and payload
|
||||||
|
sign = hmac.new(key_hex_bytes, bytes(str(1) + json.dumps(payload), "utf-8"), hashlib.sha256)
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
url=webhook_url,
|
||||||
|
json=payload,
|
||||||
|
headers={
|
||||||
|
"Datatrans-Signature": f"t=1,s0={sign.hexdigest()}"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
print(response)
|
||||||
|
|
||||||
|
if api_url.startswith("/v1/start/") and request.method == "GET":
|
||||||
|
transaction_id = api_url.split("/")[-1]
|
||||||
|
transaction_user = User.objects.filter(
|
||||||
|
additional_json_data__datatrans_transaction_payload__refno=transaction_id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
redirect_url = transaction_user.additional_json_data[
|
||||||
|
"datatrans_transaction_payload"
|
||||||
|
]["redirect"]["successUrl"]
|
||||||
|
|
||||||
|
# start new thread which will call webhook after 2 seconds
|
||||||
|
webhook_url = transaction_user.additional_json_data[
|
||||||
|
"datatrans_transaction_payload"
|
||||||
|
]["webhook"]["url"]
|
||||||
|
thread = threading.Thread(
|
||||||
|
target=call_transaction_complete_webhook,
|
||||||
|
args=(
|
||||||
|
webhook_url,
|
||||||
|
transaction_id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
# redirect to url
|
||||||
|
return redirect(redirect_url + f"?datatransTrxId={transaction_id}")
|
||||||
|
|
||||||
|
return HttpResponse(
|
||||||
|
content="unknown api url", content_type="application/json", status=400
|
||||||
|
)
|
||||||
|
|
@ -72,17 +72,34 @@ def create_customer_xml(checkout_information: CheckoutInformation):
|
||||||
abacus_debitor_number=customer.abacus_debitor_number,
|
abacus_debitor_number=customer.abacus_debitor_number,
|
||||||
last_name=checkout_information.last_name,
|
last_name=checkout_information.last_name,
|
||||||
first_name=checkout_information.first_name,
|
first_name=checkout_information.first_name,
|
||||||
company_name=checkout_information.company_name,
|
company_name=checkout_information.organisation_detail_name
|
||||||
street=(checkout_information.company_street or checkout_information.street),
|
if checkout_information.invoice_address == "org"
|
||||||
|
else "",
|
||||||
|
street=(
|
||||||
|
checkout_information.organisation_street
|
||||||
|
if checkout_information.invoice_address == "org"
|
||||||
|
else checkout_information.street
|
||||||
|
),
|
||||||
house_number=(
|
house_number=(
|
||||||
checkout_information.company_street_number
|
checkout_information.organisation_street_number
|
||||||
or checkout_information.street_number
|
if checkout_information.invoice_address == "org"
|
||||||
|
else checkout_information.street_number
|
||||||
),
|
),
|
||||||
zip_code=(
|
zip_code=(
|
||||||
checkout_information.company_postal_code or checkout_information.postal_code
|
checkout_information.organisation_postal_code
|
||||||
|
if checkout_information.invoice_address == "org"
|
||||||
|
else checkout_information.postal_code
|
||||||
|
),
|
||||||
|
city=(
|
||||||
|
checkout_information.organisation_city
|
||||||
|
if checkout_information.invoice_address == "org"
|
||||||
|
else checkout_information.city
|
||||||
|
),
|
||||||
|
country=(
|
||||||
|
checkout_information.organisation_country_id
|
||||||
|
if checkout_information.invoice_address == "org"
|
||||||
|
else checkout_information.country_id
|
||||||
),
|
),
|
||||||
city=(checkout_information.company_city or checkout_information.city),
|
|
||||||
country=(checkout_information.company_country or checkout_information.country),
|
|
||||||
language=customer.language,
|
language=customer.language,
|
||||||
email=customer.email,
|
email=customer.email,
|
||||||
)
|
)
|
||||||
|
|
@ -187,7 +204,8 @@ def render_customer_xml(
|
||||||
SubElement(address_data, "AddressNumber").text = str(abacus_debitor_number)
|
SubElement(address_data, "AddressNumber").text = str(abacus_debitor_number)
|
||||||
SubElement(address_data, "Name").text = last_name
|
SubElement(address_data, "Name").text = last_name
|
||||||
SubElement(address_data, "FirstName").text = first_name
|
SubElement(address_data, "FirstName").text = first_name
|
||||||
SubElement(address_data, "Text").text = company_name
|
if company_name:
|
||||||
|
SubElement(address_data, "Text").text = company_name
|
||||||
SubElement(address_data, "Street").text = street
|
SubElement(address_data, "Street").text = street
|
||||||
SubElement(address_data, "HouseNumber").text = house_number
|
SubElement(address_data, "HouseNumber").text = house_number
|
||||||
SubElement(address_data, "ZIP").text = zip_code
|
SubElement(address_data, "ZIP").text = zip_code
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ def migrate_checkout_information_country(apps, schema_editor):
|
||||||
if info.old_company_country:
|
if info.old_company_country:
|
||||||
country = Country.objects.get(vbv_country_id=info.old_company_country)
|
country = Country.objects.get(vbv_country_id=info.old_company_country)
|
||||||
info.organisation_country = country
|
info.organisation_country = country
|
||||||
info.save(update_fields=["country", "organisation_country"])
|
info.invoice_address = "org"
|
||||||
|
info.save(update_fields=["country", "organisation_country", "invoice_address"])
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
@ -103,4 +104,7 @@ class Migration(migrations.Migration):
|
||||||
model_name="checkoutinformation",
|
model_name="checkoutinformation",
|
||||||
name="old_company_country",
|
name="old_company_country",
|
||||||
),
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='BillingAddress',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ def is_signature_valid(
|
||||||
return s0_actual == s0_expected
|
return s0_actual == s0_expected
|
||||||
|
|
||||||
|
|
||||||
def init_transaction(
|
def init_datatrans_transaction(
|
||||||
user: User,
|
user: User,
|
||||||
amount_chf_centimes: int,
|
amount_chf_centimes: int,
|
||||||
redirect_url_success: str,
|
redirect_url_success: str,
|
||||||
|
|
@ -76,6 +76,10 @@ def init_transaction(
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# add testing configuration data
|
||||||
|
if 'fakeapi' in settings.DATATRANS_API_ENDPOINT:
|
||||||
|
payload['user_id'] = str(user.id)
|
||||||
|
|
||||||
logger.info("Initiating transaction", payload=payload)
|
logger.info("Initiating transaction", payload=payload)
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,14 @@ TEST_ADDRESS_DATA = {
|
||||||
"street_number": "1",
|
"street_number": "1",
|
||||||
"postal_code": "1234",
|
"postal_code": "1234",
|
||||||
"city": "Test City",
|
"city": "Test City",
|
||||||
"country": "209",
|
"country_code": "CH",
|
||||||
"company_name": "Test Company",
|
"invoice_address": "org",
|
||||||
"company_street": "Test Company Street",
|
"organisation_detail_name": "Test Company",
|
||||||
"company_street_number": "1",
|
"organisation_street": "Test Company Street",
|
||||||
"company_postal_code": "1234",
|
"organisation_street_number": "1",
|
||||||
"company_city": "Test Company City",
|
"organisation_postal_code": "1234",
|
||||||
"company_country": "209",
|
"organisation_city": "Test Company City",
|
||||||
|
"organisation_country_code": "CH",
|
||||||
}
|
}
|
||||||
|
|
||||||
REDIRECT_URL = "http://testserver/redirect-url"
|
REDIRECT_URL = "http://testserver/redirect-url"
|
||||||
|
|
@ -50,40 +51,9 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.client.login(username=USER_USERNAME, password=USER_PASSWORD)
|
self.client.login(username=USER_USERNAME, password=USER_PASSWORD)
|
||||||
add_countries()
|
add_countries(small_set=True)
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
@patch("vbv_lernwelt.shop.views.init_datatrans_transaction")
|
||||||
def test_checkout_no_company_address_updates_user(self, mock_init_transaction):
|
|
||||||
# GIVEN
|
|
||||||
mock_init_transaction.return_value = "1234567890"
|
|
||||||
|
|
||||||
# WHEN
|
|
||||||
response = self.client.post(
|
|
||||||
path=reverse("checkout-vv"),
|
|
||||||
format="json",
|
|
||||||
data={
|
|
||||||
"redirect_url": REDIRECT_URL,
|
|
||||||
"product": VV_DE_PRODUCT_SKU,
|
|
||||||
"address": {
|
|
||||||
"first_name": "Test",
|
|
||||||
"last_name": "User",
|
|
||||||
"street": "Test Street",
|
|
||||||
"street_number": "1",
|
|
||||||
"postal_code": "1234",
|
|
||||||
"city": "Test City",
|
|
||||||
"country": "209",
|
|
||||||
# NO company data
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
# THEN
|
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
|
||||||
|
|
||||||
user = User.objects.get(username=USER_USERNAME)
|
|
||||||
self.assertEqual(user.invoice_address, User.INVOICE_ADDRESS_PRIVATE)
|
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
|
||||||
def test_checkout_happy_case(self, mock_init_transaction):
|
def test_checkout_happy_case(self, mock_init_transaction):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
mock_init_transaction.return_value = "1234567890"
|
mock_init_transaction.return_value = "1234567890"
|
||||||
|
|
@ -106,13 +76,12 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
response.json()["next_step_url"],
|
response.json()["next_step_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertTrue(
|
ci = CheckoutInformation.objects.first()
|
||||||
CheckoutInformation.objects.filter(
|
self.assertEqual(ci.first_name, "Test")
|
||||||
user=self.user,
|
self.assertEqual(ci.last_name, "User")
|
||||||
product_sku=VV_DE_PRODUCT_SKU,
|
self.assertEqual(ci.country_id, "CH")
|
||||||
state=CheckoutState.ONGOING,
|
self.assertEqual(ci.state, "ongoing")
|
||||||
).exists()
|
self.assertEqual(ci.transaction_id, "1234567890")
|
||||||
)
|
|
||||||
|
|
||||||
mock_init_transaction.assert_called_once_with(
|
mock_init_transaction.assert_called_once_with(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
|
|
@ -123,13 +92,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
webhook_url=f"{REDIRECT_URL}/api/shop/transaction/webhook/",
|
webhook_url=f"{REDIRECT_URL}/api/shop/transaction/webhook/",
|
||||||
)
|
)
|
||||||
|
|
||||||
user = User.objects.get(username=USER_USERNAME)
|
@patch("vbv_lernwelt.shop.views.init_datatrans_transaction")
|
||||||
|
|
||||||
self.assertEqual(user.street, TEST_ADDRESS_DATA["street"])
|
|
||||||
self.assertEqual(str(user.country.country_id), TEST_ADDRESS_DATA["country"])
|
|
||||||
self.assertEqual(user.invoice_address, User.INVOICE_ADDRESS_ORGANISATION)
|
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
|
||||||
def test_incomplete_setup(self, mock_init_transaction):
|
def test_incomplete_setup(self, mock_init_transaction):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
Product.objects.all().delete()
|
Product.objects.all().delete()
|
||||||
|
|
@ -156,7 +119,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
|
|
||||||
self.assertEqual(expected, response.json()["next_step_url"])
|
self.assertEqual(expected, response.json()["next_step_url"])
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
@patch("vbv_lernwelt.shop.views.init_datatrans_transaction")
|
||||||
def test_checkout_init_transaction_exception(self, mock_init_transaction):
|
def test_checkout_init_transaction_exception(self, mock_init_transaction):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
mock_init_transaction.side_effect = InitTransactionException(
|
mock_init_transaction.side_effect = InitTransactionException(
|
||||||
|
|
@ -213,7 +176,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
response.json()["next_step_url"],
|
response.json()["next_step_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
@patch("vbv_lernwelt.shop.views.init_datatrans_transaction")
|
||||||
def test_checkout_double_checkout(self, mock_init_transaction):
|
def test_checkout_double_checkout(self, mock_init_transaction):
|
||||||
"""Advise by Datatrans: Just create a new transaction."""
|
"""Advise by Datatrans: Just create a new transaction."""
|
||||||
# GIVEN
|
# GIVEN
|
||||||
|
|
@ -277,7 +240,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
).exists()
|
).exists()
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
@patch("vbv_lernwelt.shop.views.init_datatrans_transaction")
|
||||||
def test_checkout_failed_creates_new(self, mock_init_transaction):
|
def test_checkout_failed_creates_new(self, mock_init_transaction):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
state = CheckoutState.FAILED
|
state = CheckoutState.FAILED
|
||||||
|
|
@ -310,7 +273,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
response.json()["next_step_url"],
|
response.json()["next_step_url"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.init_transaction")
|
@patch("vbv_lernwelt.shop.views.init_datatrans_transaction")
|
||||||
def test_checkout_cancelled_creates_new(self, mock_init_transaction):
|
def test_checkout_cancelled_creates_new(self, mock_init_transaction):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
state = CheckoutState.CANCELED
|
state = CheckoutState.CANCELED
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from django.test import override_settings, TestCase
|
||||||
from vbv_lernwelt.core.models import User
|
from vbv_lernwelt.core.models import User
|
||||||
from vbv_lernwelt.shop.services import (
|
from vbv_lernwelt.shop.services import (
|
||||||
get_payment_url,
|
get_payment_url,
|
||||||
init_transaction,
|
init_datatrans_transaction,
|
||||||
InitTransactionException,
|
InitTransactionException,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ class DatatransServiceTest(TestCase):
|
||||||
self.user.language = "it"
|
self.user.language = "it"
|
||||||
|
|
||||||
# WHEN
|
# WHEN
|
||||||
transaction_id = init_transaction(
|
transaction_id = init_datatrans_transaction(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
amount_chf_centimes=324_30,
|
amount_chf_centimes=324_30,
|
||||||
redirect_url_success=f"{REDIRECT_URL}/success",
|
redirect_url_success=f"{REDIRECT_URL}/success",
|
||||||
|
|
@ -76,7 +76,7 @@ class DatatransServiceTest(TestCase):
|
||||||
|
|
||||||
# WHEN / THEN
|
# WHEN / THEN
|
||||||
with self.assertRaises(InitTransactionException):
|
with self.assertRaises(InitTransactionException):
|
||||||
init_transaction(
|
init_datatrans_transaction(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
amount_chf_centimes=324_30,
|
amount_chf_centimes=324_30,
|
||||||
redirect_url_success=f"/success",
|
redirect_url_success=f"/success",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from rest_framework import status
|
||||||
from rest_framework.test import APITestCase
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
from vbv_lernwelt.core.admin import User
|
from vbv_lernwelt.core.admin import User
|
||||||
|
from vbv_lernwelt.core.model_utils import add_countries
|
||||||
from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN_ID
|
from vbv_lernwelt.course.consts import COURSE_VERSICHERUNGSVERMITTLERIN_ID
|
||||||
from vbv_lernwelt.course.creators.test_utils import create_course, create_course_session
|
from vbv_lernwelt.course.creators.test_utils import create_course, create_course_session
|
||||||
from vbv_lernwelt.course.models import CourseSessionUser
|
from vbv_lernwelt.course.models import CourseSessionUser
|
||||||
|
|
@ -29,6 +30,8 @@ def create_checkout_information(
|
||||||
|
|
||||||
class DatatransWebhookTestCase(APITestCase):
|
class DatatransWebhookTestCase(APITestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
|
add_countries(small_set=True)
|
||||||
|
|
||||||
course, _ = create_course(
|
course, _ = create_course(
|
||||||
title="VV_in_DE",
|
title="VV_in_DE",
|
||||||
# needed for VV_DE_PRODUCT_SKU
|
# needed for VV_DE_PRODUCT_SKU
|
||||||
|
|
@ -102,13 +105,13 @@ class DatatransWebhookTestCase(APITestCase):
|
||||||
checkout_info.street_number = "1"
|
checkout_info.street_number = "1"
|
||||||
checkout_info.postal_code = "1234"
|
checkout_info.postal_code = "1234"
|
||||||
checkout_info.city = "Musterstadt"
|
checkout_info.city = "Musterstadt"
|
||||||
checkout_info.country = "Schweiz"
|
checkout_info.country_id = "CH"
|
||||||
checkout_info.company_name = "Musterfirma"
|
checkout_info.organisation_detail_name = "Musterfirma"
|
||||||
checkout_info.company_street = "Firmastrasse"
|
checkout_info.organisation_street = "Firmastrasse"
|
||||||
checkout_info.company_street_number = "2"
|
checkout_info.organisation_street_number = "2"
|
||||||
checkout_info.company_postal_code = "5678"
|
checkout_info.organisation_postal_code = "5678"
|
||||||
checkout_info.company_city = "Firmastadt"
|
checkout_info.organisation_city = "Firmastadt"
|
||||||
checkout_info.company_country = "Schweiz"
|
checkout_info.organisation_country_id = "CH"
|
||||||
checkout_info.save()
|
checkout_info.save()
|
||||||
|
|
||||||
mock_is_signature_valid.return_value = True
|
mock_is_signature_valid.return_value = True
|
||||||
|
|
@ -181,10 +184,10 @@ class DatatransWebhookTestCase(APITestCase):
|
||||||
"target_url": "https://my.vbv-afa.ch/",
|
"target_url": "https://my.vbv-afa.ch/",
|
||||||
"name": "Max Mustermann",
|
"name": "Max Mustermann",
|
||||||
"private_street": "Musterstrasse 1",
|
"private_street": "Musterstrasse 1",
|
||||||
"private_city": "1234 Musterstadt Schweiz",
|
"private_city": "CH-1234 Musterstadt",
|
||||||
"company_name": "Musterfirma",
|
"company_name": "Musterfirma",
|
||||||
"company_street": "Firmastrasse 2",
|
"company_street": "Firmastrasse 2",
|
||||||
"company_city": "5678 Firmastadt Schweiz",
|
"company_city": "CH-5678 Firmastadt",
|
||||||
},
|
},
|
||||||
template_language=self.user.language,
|
template_language=self.user.language,
|
||||||
fail_silently=ANY,
|
fail_silently=ANY,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ from django.test import TestCase
|
||||||
|
|
||||||
from vbv_lernwelt.core.admin import User
|
from vbv_lernwelt.core.admin import User
|
||||||
from vbv_lernwelt.core.create_default_users import create_default_users
|
from vbv_lernwelt.core.create_default_users import create_default_users
|
||||||
|
from vbv_lernwelt.core.model_utils import add_countries
|
||||||
from vbv_lernwelt.shop.invoice.abacus import (
|
from vbv_lernwelt.shop.invoice.abacus import (
|
||||||
AbacusInvoiceCreator,
|
AbacusInvoiceCreator,
|
||||||
create_customer_xml,
|
create_customer_xml,
|
||||||
|
|
@ -23,6 +24,7 @@ USER_PASSWORD = "testpassword"
|
||||||
|
|
||||||
class AbacusInvoiceTestCase(TestCase):
|
class AbacusInvoiceTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
add_countries(small_set=True)
|
||||||
create_default_users()
|
create_default_users()
|
||||||
|
|
||||||
def test_create_invoice_xml(self):
|
def test_create_invoice_xml(self):
|
||||||
|
|
@ -136,13 +138,14 @@ class AbacusInvoiceTestCase(TestCase):
|
||||||
street_number="32",
|
street_number="32",
|
||||||
postal_code="1719",
|
postal_code="1719",
|
||||||
city="Zumholz",
|
city="Zumholz",
|
||||||
country="209",
|
country_id="CH",
|
||||||
company_name="VBV",
|
invoice_address="org",
|
||||||
company_street="Laupenstrasse",
|
organisation_detail_name="VBV",
|
||||||
company_street_number="10",
|
organisation_street="Laupenstrasse",
|
||||||
company_postal_code="3000",
|
organisation_street_number="10",
|
||||||
company_city="Bern",
|
organisation_postal_code="3000",
|
||||||
company_country="209",
|
organisation_city="Bern",
|
||||||
|
organisation_country_id="CH",
|
||||||
)
|
)
|
||||||
feuz_checkout_info.created_at = datetime(2024, 2, 15, 8, 33, 12, 0)
|
feuz_checkout_info.created_at = datetime(2024, 2, 15, 8, 33, 12, 0)
|
||||||
|
|
||||||
|
|
@ -158,10 +161,11 @@ class AbacusInvoiceTestCase(TestCase):
|
||||||
"<Email>andreas.feuz@eiger-versicherungen.ch</Email>"
|
"<Email>andreas.feuz@eiger-versicherungen.ch</Email>"
|
||||||
in customer_xml_content
|
in customer_xml_content
|
||||||
)
|
)
|
||||||
|
assert "<AddressNumber>60000012</AddressNumber>" in customer_xml_content
|
||||||
|
assert "<Name>Feuz</Name>" in customer_xml_content
|
||||||
assert "<Text>VBV</Text>" in customer_xml_content
|
assert "<Text>VBV</Text>" in customer_xml_content
|
||||||
|
assert "<Street>Laupenstrasse</Street>" in customer_xml_content
|
||||||
# FIXME refactor country
|
assert "<Country>CH</Country>" in customer_xml_content
|
||||||
assert "<Country>209</Country>" in customer_xml_content
|
|
||||||
|
|
||||||
def test_render_customer_xml(self):
|
def test_render_customer_xml(self):
|
||||||
customer_xml = render_customer_xml(
|
customer_xml = render_customer_xml(
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import structlog
|
import structlog
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
from rest_framework import status
|
|
||||||
from rest_framework.decorators import api_view, permission_classes
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
|
||||||
from sentry_sdk import capture_exception
|
from sentry_sdk import capture_exception
|
||||||
|
|
||||||
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
||||||
|
|
@ -18,7 +16,7 @@ from vbv_lernwelt.shop.models import CheckoutInformation, CheckoutState, Product
|
||||||
from vbv_lernwelt.shop.services import (
|
from vbv_lernwelt.shop.services import (
|
||||||
datatrans_state_to_checkout_state,
|
datatrans_state_to_checkout_state,
|
||||||
get_payment_url,
|
get_payment_url,
|
||||||
init_transaction,
|
init_datatrans_transaction,
|
||||||
InitTransactionException,
|
InitTransactionException,
|
||||||
is_signature_valid,
|
is_signature_valid,
|
||||||
)
|
)
|
||||||
|
|
@ -109,7 +107,7 @@ def checkout_vv(request):
|
||||||
return next_step_response(url="/")
|
return next_step_response(url="/")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
transaction_id = init_transaction(
|
transaction_id = init_datatrans_transaction(
|
||||||
user=request.user,
|
user=request.user,
|
||||||
amount_chf_centimes=product.price,
|
amount_chf_centimes=product.price,
|
||||||
redirect_url_success=checkout_success_url(
|
redirect_url_success=checkout_success_url(
|
||||||
|
|
@ -176,10 +174,10 @@ def send_vv_welcome_email(checkout_info: CheckoutInformation):
|
||||||
"target_url": "https://my.vbv-afa.ch/",
|
"target_url": "https://my.vbv-afa.ch/",
|
||||||
"name": f"{checkout_info.first_name} {checkout_info.last_name}",
|
"name": f"{checkout_info.first_name} {checkout_info.last_name}",
|
||||||
"private_street": f"{checkout_info.street} {checkout_info.street_number}",
|
"private_street": f"{checkout_info.street} {checkout_info.street_number}",
|
||||||
"private_city": f"{checkout_info.postal_code} {checkout_info.city} {checkout_info.country}",
|
"private_city": f"{checkout_info.country_id}-{checkout_info.postal_code} {checkout_info.city}",
|
||||||
"company_name": checkout_info.company_name,
|
"company_name": checkout_info.organisation_detail_name,
|
||||||
"company_street": f"{checkout_info.company_street} {checkout_info.company_street_number}",
|
"company_street": f"{checkout_info.organisation_street} {checkout_info.organisation_street_number}",
|
||||||
"company_city": f"{checkout_info.company_postal_code} {checkout_info.company_city} {checkout_info.company_country}",
|
"company_city": f"{checkout_info.organisation_country_id}-{checkout_info.organisation_postal_code} {checkout_info.organisation_city}",
|
||||||
},
|
},
|
||||||
template_language=checkout_info.user.language,
|
template_language=checkout_info.user.language,
|
||||||
fail_silently=True,
|
fail_silently=True,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue