chore: get datatrans admin helper cleanup
This commit is contained in:
parent
18385b6870
commit
6f90d381f3
|
|
@ -13,7 +13,6 @@ def generate_invoice(modeladmin, request, queryset):
|
||||||
def sync_transaction_state(modeladmin, request, queryset):
|
def sync_transaction_state(modeladmin, request, queryset):
|
||||||
for checkout in queryset:
|
for checkout in queryset:
|
||||||
state = get_transaction_state(transaction_id=checkout.transaction_id)
|
state = get_transaction_state(transaction_id=checkout.transaction_id)
|
||||||
print(state)
|
|
||||||
checkout.state = state.value
|
checkout.state = state.value
|
||||||
checkout.save(
|
checkout.save(
|
||||||
update_fields=[
|
update_fields=[
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ def init_transaction(
|
||||||
|
|
||||||
def get_transaction_state(
|
def get_transaction_state(
|
||||||
transaction_id: str,
|
transaction_id: str,
|
||||||
) -> CheckoutState | None:
|
) -> CheckoutState:
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
f"{settings.DATATRANS_API_ENDPOINT}/v1/transactions/{transaction_id}",
|
f"{settings.DATATRANS_API_ENDPOINT}/v1/transactions/{transaction_id}",
|
||||||
headers={
|
headers={
|
||||||
|
|
@ -110,9 +110,6 @@ def get_transaction_state(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code != 200:
|
|
||||||
return None
|
|
||||||
|
|
||||||
transaction_state = response.json()["status"]
|
transaction_state = response.json()["status"]
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
@ -121,8 +118,23 @@ def get_transaction_state(
|
||||||
response=transaction_state,
|
response=transaction_state,
|
||||||
)
|
)
|
||||||
|
|
||||||
return CheckoutState(transaction_state)
|
return datatrans_state_to_checkout_state(transaction_state)
|
||||||
|
|
||||||
|
|
||||||
def get_payment_url(transaction_id: str):
|
def get_payment_url(transaction_id: str):
|
||||||
return f"{settings.DATATRANS_PAY_URL}/v1/start/{transaction_id}"
|
return f"{settings.DATATRANS_PAY_URL}/v1/start/{transaction_id}"
|
||||||
|
|
||||||
|
|
||||||
|
def datatrans_state_to_checkout_state(
|
||||||
|
transaction_state: str,
|
||||||
|
) -> CheckoutState:
|
||||||
|
if transaction_state in ["settled", "transmitted"]:
|
||||||
|
return CheckoutState.PAID
|
||||||
|
elif transaction_state == "failed":
|
||||||
|
return CheckoutState.FAILED
|
||||||
|
elif transaction_state == "canceled":
|
||||||
|
return CheckoutState.CANCELED
|
||||||
|
else:
|
||||||
|
# An intermediate state such as "initialized", "challenge_ongoing", etc.
|
||||||
|
# -> we don't care about those states, we only care about final states here.
|
||||||
|
return CheckoutState.INITIALIZED
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class DatatransWebhookTestCase(APITestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("vbv_lernwelt.shop.views.is_signature_valid")
|
@patch("vbv_lernwelt.shop.views.is_signature_valid")
|
||||||
def test_webhook_creates_course_session_user(self, mock_is_signature_valid):
|
def test_webhook_settled_transmitted_paid(self, mock_is_signature_valid):
|
||||||
# GIVEN
|
# GIVEN
|
||||||
transaction_id = "1234567890"
|
transaction_id = "1234567890"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ from vbv_lernwelt.shop.models import (
|
||||||
)
|
)
|
||||||
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 (
|
||||||
|
datatrans_state_to_checkout_state,
|
||||||
get_payment_url,
|
get_payment_url,
|
||||||
init_transaction,
|
init_transaction,
|
||||||
InitTransactionException,
|
InitTransactionException,
|
||||||
|
|
@ -66,7 +67,6 @@ def transaction_webhook(request):
|
||||||
Otherwise, this webhook was/will not be called for "initialized" -> "failed" state changes
|
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),
|
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(
|
||||||
|
|
@ -78,26 +78,19 @@ def transaction_webhook(request):
|
||||||
|
|
||||||
transaction = request.data
|
transaction = request.data
|
||||||
transaction_id = transaction["transactionId"]
|
transaction_id = transaction["transactionId"]
|
||||||
transaction_status = transaction["status"]
|
|
||||||
|
|
||||||
# keep webhook history for debugging
|
# keep webhook history (for debugging)
|
||||||
checkout_info = CheckoutInformation.objects.get(transaction_id=transaction_id)
|
checkout_info = CheckoutInformation.objects.get(transaction_id=transaction_id)
|
||||||
checkout_info.webhook_history.append(transaction)
|
checkout_info.webhook_history.append(transaction)
|
||||||
checkout_info.save(update_fields=["webhook_history"])
|
checkout_info.save(update_fields=["webhook_history"])
|
||||||
|
|
||||||
# be aware autoSettle has implications on possible transaction states we get!
|
# update checkout state
|
||||||
# See https://api-reference.datatrans.ch/#tag/v1transactions/operation/status
|
checkout_state = datatrans_state_to_checkout_state(transaction["status"])
|
||||||
if transaction_status in ["settled", "transmitted"]:
|
update_checkout_state(checkout_info=checkout_info, state=checkout_state)
|
||||||
update_checkout_state(checkout_info=checkout_info, state=CheckoutState.PAID)
|
|
||||||
|
# handle paid
|
||||||
|
if checkout_state == CheckoutState.PAID:
|
||||||
create_vv_course_session_user(checkout_info=checkout_info)
|
create_vv_course_session_user(checkout_info=checkout_info)
|
||||||
elif transaction_status == "failed":
|
|
||||||
update_checkout_state(checkout_info=checkout_info, state=CheckoutState.FAILED)
|
|
||||||
elif transaction_status == "canceled":
|
|
||||||
update_checkout_state(checkout_info=checkout_info, state=CheckoutState.CANCELED)
|
|
||||||
else:
|
|
||||||
logger.warning(
|
|
||||||
"Unhandled transaction status", transaction_status=transaction_status
|
|
||||||
)
|
|
||||||
|
|
||||||
return JsonResponse({"status": "ok"})
|
return JsonResponse({"status": "ok"})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue