feat: vv-de vv-fr vv-it API support
This commit is contained in:
parent
100362b6a5
commit
fb24ec24e4
|
|
@ -564,7 +564,7 @@ ALLOWED_HOSTS = env.list(
|
||||||
"localhost",
|
"localhost",
|
||||||
"0.0.0.0",
|
"0.0.0.0",
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
"e124-2a02-21b4-9679-d800-9c5-c205-e72c-82f2.ngrok-free.app",
|
"2375-2a02-21b4-9679-d800-8151-6008-2b6c-7a32.ngrok-free.app",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,35 @@
|
||||||
# Setup
|
# Setup steps for Production
|
||||||
|
|
||||||
## Shop Product
|
## Shop Product
|
||||||
|
|
||||||
- In Django Shop App, create a new product (Products model).
|
In Django Shop App, create new products (Products model) that should be available in the shop.
|
||||||
- `SKU` must be `VV`, Price 30000 (300_00 -> 300.00 CHF), name & description can be anything.
|
Products:
|
||||||
- Done for staging but not yet for production!
|
|
||||||
|
- `vv-de` Price 30000 (300_00 -> 300.00 CHF), name & description can be anything.
|
||||||
|
- ONLY if `COURSE_VERSICHERUNGSVERMITTLERIN_ID` exists!
|
||||||
|
- `vv-fr` Price 30000 (300_00 -> 300.00 CHF), name & description can be anything.
|
||||||
|
- ONLY if `COURSE_VERSICHERUNGSVERMITTLERIN_ID_FR` exists!
|
||||||
|
- `vv-it` Price 30000 (300_00 -> 300.00 CHF), name & description can be anything.
|
||||||
|
- ONLY if `COURSE_VERSICHERUNGSVERMITTLERIN_ID_IT` exists!
|
||||||
|
|
||||||
## Datatrans
|
## Datatrans
|
||||||
|
|
||||||
- Set `DATATRANS_BASIC_AUTH_KEY`:
|
- Set `DATATRANS_BASIC_AUTH_KEY`:
|
||||||
- https://admin.sandbox.datatrans.com/MenuDispatch.jsp?main=1&sub=4
|
- https://admin.sandbox.datatrans.com/MenuDispatch.jsp?main=1&sub=4
|
||||||
- `echo -n "{merchantid}:{password}" | base64`
|
- `echo -n "{merchantid}:{password}" | base64`
|
||||||
|
|
||||||
- Set `DATATRANS_HMAC_KEY`:
|
- Set `DATATRANS_HMAC_KEY`:
|
||||||
- https://admin.sandbox.datatrans.com/MerchSecurAdmin.jsp
|
- https://admin.sandbox.datatrans.com/MerchSecurAdmin.jsp
|
||||||
|
|
||||||
- Ensure that the webhook is set up correctly by Datatrans:
|
- Ensure that the webhook is set up correctly by Datatrans:
|
||||||
- Be default transitions from `initialized` to `failed` do not trigger the webhook.
|
- Be default transitions from `initialized` to `failed` do not trigger the webhook.
|
||||||
- Edgecase: When user starts a datatrans payment and then closes the browser, the payment will be in `initialized`
|
- Edgecase: When user starts a datatrans payment and then closes the browser, the payment will be
|
||||||
state forever. -> That's why we need the webhook for `initialized` -> `failed` transitions.
|
in `initialized`
|
||||||
- This can and needs to be enabled by datatrans (according to Mario from datatrans).
|
state forever. -> That's why we need the webhook for `initialized` -> `failed` transitions.
|
||||||
- Livio 21.11.23: Mario promised to enable it,
|
- This can and needs to be enabled by datatrans (according to Mario from datatrans).
|
||||||
- Livio 27.11.23. Not yet enabled for the sandbox. -> Followed up!
|
- Livio 21.11.23: Mario promised to enable it,
|
||||||
- Livio: TODO still not enabled. Follow up again!
|
- Livio 27.11.23. Not yet enabled for the sandbox. -> Followed up!
|
||||||
|
- Livio: TODO still not enabled. Follow up again!
|
||||||
|
|
||||||
### Production / "going live"
|
### Production / "going live"
|
||||||
|
|
||||||
|
|
@ -57,7 +64,7 @@ Make sure that the following env vars are set:
|
||||||
### Frontend:
|
### Frontend:
|
||||||
|
|
||||||
- Update `VITE_OAUTH_API_BASE_URL` in `caprover_deploy.sh` for production.
|
- Update `VITE_OAUTH_API_BASE_URL` in `caprover_deploy.sh` for production.
|
||||||
- NEEDS to be updated! Should be the SSO Prod one from Lernnetz -> Lookup from Metadata URL
|
- Should be the SSO Prod one from Lernnetz.
|
||||||
|
|
||||||
### Cleanup
|
### Cleanup
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
# available products for VV
|
||||||
|
VV_DE_PRODUCT_SKU = "vv-de"
|
||||||
|
VV_FR_PRODUCT_SKU = "vv-fr"
|
||||||
|
VV_IT_PRODUCT_SKU = "vv-it"
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
VV_PRODUCT_SKU = "VV"
|
|
||||||
|
|
||||||
|
|
||||||
class Country(models.Model):
|
class Country(models.Model):
|
||||||
country_id = models.IntegerField(primary_key=True)
|
country_id = models.IntegerField(primary_key=True)
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,7 @@ def is_signature_valid(
|
||||||
hmac_key: str = settings.DATATRANS_HMAC_KEY,
|
hmac_key: str = settings.DATATRANS_HMAC_KEY,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
See the docs:
|
See the docs: https://docs.datatrans.ch/docs/additional-security
|
||||||
https://docs.datatrans.ch/docs/additional-security
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -126,13 +125,13 @@ def get_payment_url(transaction_id: str):
|
||||||
|
|
||||||
|
|
||||||
def datatrans_state_to_checkout_state(
|
def datatrans_state_to_checkout_state(
|
||||||
transaction_state: str,
|
datatrans_transaction_state: str,
|
||||||
) -> CheckoutState:
|
) -> CheckoutState:
|
||||||
if transaction_state in ["settled", "transmitted"]:
|
if datatrans_transaction_state in ["settled", "transmitted"]:
|
||||||
return CheckoutState.PAID
|
return CheckoutState.PAID
|
||||||
elif transaction_state == "failed":
|
elif datatrans_transaction_state == "failed":
|
||||||
return CheckoutState.FAILED
|
return CheckoutState.FAILED
|
||||||
elif transaction_state == "canceled":
|
elif datatrans_transaction_state == "canceled":
|
||||||
return CheckoutState.CANCELED
|
return CheckoutState.CANCELED
|
||||||
else:
|
else:
|
||||||
# An intermediate state such as "initialized", "challenge_ongoing", etc.
|
# An intermediate state such as "initialized", "challenge_ongoing", etc.
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ 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.shop.const import VV_DE_PRODUCT_SKU
|
||||||
from vbv_lernwelt.shop.models import (
|
from vbv_lernwelt.shop.models import (
|
||||||
CheckoutInformation,
|
CheckoutInformation,
|
||||||
CheckoutState,
|
CheckoutState,
|
||||||
Product,
|
Product,
|
||||||
VV_PRODUCT_SKU,
|
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.shop.services import InitTransactionException
|
from vbv_lernwelt.shop.services import InitTransactionException
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ REDIRECT_URL = "http://testserver/redirect-url"
|
||||||
class CheckoutAPITestCase(APITestCase):
|
class CheckoutAPITestCase(APITestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
Product.objects.create(
|
Product.objects.create(
|
||||||
sku=VV_PRODUCT_SKU,
|
sku=VV_DE_PRODUCT_SKU,
|
||||||
price=300_00,
|
price=300_00,
|
||||||
description="VV",
|
description="VV",
|
||||||
name="VV",
|
name="VV",
|
||||||
|
|
@ -65,6 +65,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -79,7 +80,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
CheckoutInformation.objects.filter(
|
CheckoutInformation.objects.filter(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
product_sku=VV_PRODUCT_SKU,
|
product_sku=VV_DE_PRODUCT_SKU,
|
||||||
state=CheckoutState.INITIALIZED.value,
|
state=CheckoutState.INITIALIZED.value,
|
||||||
).exists()
|
).exists()
|
||||||
)
|
)
|
||||||
|
|
@ -105,6 +106,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -114,7 +116,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
|
|
||||||
expected = (
|
expected = (
|
||||||
f"{REDIRECT_URL}/onboarding/vv/checkout/address?error&"
|
f"{REDIRECT_URL}/onboarding/vv/checkout/address?error&"
|
||||||
f"message=vv_product_does_not_exist_needs_to_be_created"
|
f"message=vv-de_product_sku_does_not_exist_needs_to_be_created_first"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(expected, response.json()["next_step_url"])
|
self.assertEqual(expected, response.json()["next_step_url"])
|
||||||
|
|
@ -132,6 +134,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -152,7 +155,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
CheckoutInformation.objects.create(
|
CheckoutInformation.objects.create(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
product_sku=VV_PRODUCT_SKU,
|
product_sku=VV_DE_PRODUCT_SKU,
|
||||||
product_price=0,
|
product_price=0,
|
||||||
state=CheckoutState.PAID.value,
|
state=CheckoutState.PAID.value,
|
||||||
)
|
)
|
||||||
|
|
@ -163,6 +166,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -180,7 +184,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
|
|
||||||
CheckoutInformation.objects.create(
|
CheckoutInformation.objects.create(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
product_sku=VV_PRODUCT_SKU,
|
product_sku=VV_DE_PRODUCT_SKU,
|
||||||
product_price=0,
|
product_price=0,
|
||||||
state=CheckoutState.INITIALIZED.value,
|
state=CheckoutState.INITIALIZED.value,
|
||||||
transaction_id=transaction_id,
|
transaction_id=transaction_id,
|
||||||
|
|
@ -192,6 +196,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -212,7 +217,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
|
|
||||||
CheckoutInformation.objects.create(
|
CheckoutInformation.objects.create(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
product_sku=VV_PRODUCT_SKU,
|
product_sku=VV_DE_PRODUCT_SKU,
|
||||||
product_price=0,
|
product_price=0,
|
||||||
state=state,
|
state=state,
|
||||||
transaction_id="0000000000",
|
transaction_id="0000000000",
|
||||||
|
|
@ -224,6 +229,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -244,7 +250,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
|
|
||||||
CheckoutInformation.objects.create(
|
CheckoutInformation.objects.create(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
product_sku=VV_PRODUCT_SKU,
|
product_sku=VV_DE_PRODUCT_SKU,
|
||||||
product_price=0,
|
product_price=0,
|
||||||
state=state,
|
state=state,
|
||||||
transaction_id="1111111111",
|
transaction_id="1111111111",
|
||||||
|
|
@ -256,6 +262,7 @@ class CheckoutAPITestCase(APITestCase):
|
||||||
format="json",
|
format="json",
|
||||||
data={
|
data={
|
||||||
"redirect_url": REDIRECT_URL,
|
"redirect_url": REDIRECT_URL,
|
||||||
|
"product": VV_DE_PRODUCT_SKU,
|
||||||
"address": TEST_ADDRESS_DATA,
|
"address": TEST_ADDRESS_DATA,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,14 @@ 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.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
|
||||||
|
from vbv_lernwelt.shop.const import VV_DE_PRODUCT_SKU
|
||||||
from vbv_lernwelt.shop.models import (
|
from vbv_lernwelt.shop.models import (
|
||||||
CheckoutInformation,
|
CheckoutInformation,
|
||||||
CheckoutState,
|
CheckoutState,
|
||||||
Product,
|
Product,
|
||||||
VV_PRODUCT_SKU,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@ def create_checkout_information(
|
||||||
return CheckoutInformation.objects.create(
|
return CheckoutInformation.objects.create(
|
||||||
user=user,
|
user=user,
|
||||||
transaction_id=transaction_id,
|
transaction_id=transaction_id,
|
||||||
product_sku=VV_PRODUCT_SKU,
|
product_sku=VV_DE_PRODUCT_SKU,
|
||||||
product_price=300_00,
|
product_price=300_00,
|
||||||
state=state.value,
|
state=state.value,
|
||||||
)
|
)
|
||||||
|
|
@ -31,8 +32,13 @@ def create_checkout_information(
|
||||||
|
|
||||||
class DatatransWebhookTestCase(APITestCase):
|
class DatatransWebhookTestCase(APITestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
course, _ = create_course(title="VV")
|
course, _ = create_course(
|
||||||
create_course_session(course=course, title="Versicherungsvermittler/-in")
|
title="VV_in_DE",
|
||||||
|
# needed for VV_DE_PRODUCT_SKU
|
||||||
|
_id=COURSE_VERSICHERUNGSVERMITTLERIN_ID,
|
||||||
|
)
|
||||||
|
|
||||||
|
create_course_session(course=course, title="Versicherungsvermittler/-in DE")
|
||||||
|
|
||||||
self.user = User.objects.create_user(
|
self.user = User.objects.create_user(
|
||||||
username="testuser",
|
username="testuser",
|
||||||
|
|
@ -42,7 +48,7 @@ class DatatransWebhookTestCase(APITestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.product = Product.objects.create(
|
self.product = Product.objects.create(
|
||||||
sku=VV_PRODUCT_SKU,
|
sku=VV_DE_PRODUCT_SKU,
|
||||||
price=300_00,
|
price=300_00,
|
||||||
description="VV",
|
description="VV",
|
||||||
name="VV",
|
name="VV",
|
||||||
|
|
@ -110,12 +116,12 @@ class DatatransWebhookTestCase(APITestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# THEN
|
# THEN
|
||||||
self.assertEqual(response_settled.status_code, status.HTTP_200_OK)
|
self.assertEqual(status.HTTP_200_OK, response_settled.status_code)
|
||||||
self.assertEqual(response_transmitted.status_code, status.HTTP_200_OK)
|
self.assertEqual(status.HTTP_200_OK, response_transmitted.status_code)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
CheckoutInformation.objects.get(transaction_id=transaction_id).state,
|
|
||||||
CheckoutState.PAID.value,
|
CheckoutState.PAID.value,
|
||||||
|
CheckoutInformation.objects.get(transaction_id=transaction_id).state,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
|
@ -124,8 +130,13 @@ class DatatransWebhookTestCase(APITestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
CourseSessionUser.objects.first().user,
|
|
||||||
self.user,
|
self.user,
|
||||||
|
CourseSessionUser.objects.first().user,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
COURSE_VERSICHERUNGSVERMITTLERIN_ID,
|
||||||
|
CourseSessionUser.objects.first().course_session.course.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.is_signature_valid")
|
@patch("vbv_lernwelt.shop.views.is_signature_valid")
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,22 @@ 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 rest_framework.response import Response
|
||||||
|
|
||||||
|
from vbv_lernwelt.course.consts import (
|
||||||
|
COURSE_VERSICHERUNGSVERMITTLERIN_ID,
|
||||||
|
COURSE_VERSICHERUNGSVERMITTLERIN_FR_ID,
|
||||||
|
COURSE_VERSICHERUNGSVERMITTLERIN_IT_ID,
|
||||||
|
)
|
||||||
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
|
||||||
|
from vbv_lernwelt.shop.const import (
|
||||||
|
VV_DE_PRODUCT_SKU,
|
||||||
|
VV_FR_PRODUCT_SKU,
|
||||||
|
VV_IT_PRODUCT_SKU,
|
||||||
|
)
|
||||||
from vbv_lernwelt.shop.models import (
|
from vbv_lernwelt.shop.models import (
|
||||||
BillingAddress,
|
BillingAddress,
|
||||||
CheckoutInformation,
|
CheckoutInformation,
|
||||||
CheckoutState,
|
CheckoutState,
|
||||||
Product,
|
Product,
|
||||||
VV_PRODUCT_SKU,
|
|
||||||
)
|
)
|
||||||
from vbv_lernwelt.shop.serializers import BillingAddressSerializer
|
from vbv_lernwelt.shop.serializers import BillingAddressSerializer
|
||||||
from vbv_lernwelt.shop.services import (
|
from vbv_lernwelt.shop.services import (
|
||||||
|
|
@ -24,7 +33,11 @@ from vbv_lernwelt.shop.services import (
|
||||||
|
|
||||||
logger = structlog.get_logger(__name__)
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
COURSE_SESSION_TITLE_VV = "Versicherungsvermittler/-in"
|
PRODUCT_SKU_TO_COURSE = {
|
||||||
|
VV_DE_PRODUCT_SKU: COURSE_VERSICHERUNGSVERMITTLERIN_ID,
|
||||||
|
VV_FR_PRODUCT_SKU: COURSE_VERSICHERUNGSVERMITTLERIN_FR_ID,
|
||||||
|
VV_IT_PRODUCT_SKU: COURSE_VERSICHERUNGSVERMITTLERIN_IT_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@api_view(["GET"])
|
@api_view(["GET"])
|
||||||
|
|
@ -62,11 +75,6 @@ def update_billing_address(request):
|
||||||
|
|
||||||
@api_view(["POST"])
|
@api_view(["POST"])
|
||||||
def transaction_webhook(request):
|
def transaction_webhook(request):
|
||||||
"""
|
|
||||||
VERY IMPORTANT: Datatrans had/has to set up stuff manually on their side:
|
|
||||||
Otherwise, this webhook was/will not be called for "initialized" -> "failed" state changes
|
|
||||||
For timed out transactions (cleaned up in 15 minute intervals, after 30 minutes by them),
|
|
||||||
"""
|
|
||||||
logger.info("Webhook: Datatrans called transaction webhook", body=request.body)
|
logger.info("Webhook: Datatrans called transaction webhook", body=request.body)
|
||||||
|
|
||||||
if not is_signature_valid(
|
if not is_signature_valid(
|
||||||
|
|
@ -99,22 +107,20 @@ def transaction_webhook(request):
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
def checkout_vv(request):
|
def checkout_vv(request):
|
||||||
"""
|
"""
|
||||||
Checkout for the Versicherungsvermittler product (VV).
|
Checkout for the Versicherungsvermittler products (vv-de, vv-fr, vv-it)
|
||||||
|
|
||||||
VV_PRODUCT_SKU: The one and only product, thus hardcoded
|
|
||||||
Expected to be created in the admin interface first.
|
|
||||||
"""
|
"""
|
||||||
sku = VV_PRODUCT_SKU
|
sku = request.data["product"]
|
||||||
logger.info(f"Checkout requested: sku={sku}", user_id=request.user.id)
|
|
||||||
base_redirect_url = request.data["redirect_url"]
|
base_redirect_url = request.data["redirect_url"]
|
||||||
|
|
||||||
|
logger.info(f"Checkout requested: sku={sku}", user_id=request.user.id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
product = Product.objects.get(sku=sku)
|
product = Product.objects.get(sku=sku)
|
||||||
except Product.DoesNotExist:
|
except Product.DoesNotExist:
|
||||||
return next_step_response(
|
return next_step_response(
|
||||||
url=checkout_error_url(
|
url=checkout_error_url(
|
||||||
base_url=base_redirect_url,
|
base_url=base_redirect_url,
|
||||||
message="vv_product_does_not_exist_needs_to_be_created",
|
message=f"{sku}_product_sku_does_not_exist_needs_to_be_created_first",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -172,11 +178,12 @@ def update_checkout_state(checkout_info: CheckoutInformation, state: CheckoutSta
|
||||||
|
|
||||||
def create_vv_course_session_user(checkout_info: CheckoutInformation):
|
def create_vv_course_session_user(checkout_info: CheckoutInformation):
|
||||||
logger.info("Creating VV course session user", user_id=checkout_info.user_id)
|
logger.info("Creating VV course session user", user_id=checkout_info.user_id)
|
||||||
|
|
||||||
CourseSessionUser.objects.get_or_create(
|
CourseSessionUser.objects.get_or_create(
|
||||||
user=checkout_info.user,
|
user=checkout_info.user,
|
||||||
role=CourseSessionUser.Role.MEMBER,
|
role=CourseSessionUser.Role.MEMBER,
|
||||||
course_session=CourseSession.objects.filter(
|
course_session=CourseSession.objects.filter(
|
||||||
title=COURSE_SESSION_TITLE_VV
|
course_id=PRODUCT_SKU_TO_COURSE[checkout_info.product_sku]
|
||||||
).first(),
|
).first(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue