diff --git a/tpv/admin.py b/tpv/admin.py index 09315d9..7846fe6 100644 --- a/tpv/admin.py +++ b/tpv/admin.py @@ -1,10 +1,10 @@ from django.contrib import admin -from tpv.models import PaymentTPV +from tpv.models import PaymentTransaction from unfold.admin import ModelAdmin # Register your models here. -@admin.register(PaymentTPV) +@admin.register(PaymentTransaction) class PaymentTPVAdmin(ModelAdmin): list_display = ( "hash", diff --git a/tpv/migrations/0001_initial.py b/tpv/migrations/0001_initial.py index 3a320e1..2966dd4 100644 --- a/tpv/migrations/0001_initial.py +++ b/tpv/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.3 on 2024-03-21 22:43 +# Generated by Django 5.0.3 on 2024-03-24 19:19 import tpv.models import uuid @@ -14,7 +14,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name="PaymentTPV", + name="PaymentTransaction", fields=[ ( "id", diff --git a/tpv/models.py b/tpv/models.py index bd991b7..2b13417 100644 --- a/tpv/models.py +++ b/tpv/models.py @@ -8,7 +8,7 @@ def set_default_metadata(): return {"items": [], "response": None} -class PaymentTPV(models.Model): +class PaymentTransaction(models.Model): class StatusChoices(models.TextChoices): PAID = "PAI", _("Pagado") PENDING = "PEN", _("Pendiente") @@ -62,10 +62,6 @@ class PaymentTPV(models.Model): } """ - def regenerate_uuid(self): - self.hash = uuid4() - self.save() - @property def amount_integer(self) -> int: return int(self.amount * 100) diff --git a/tpv/redsys.py b/tpv/redsys.py index 06efbe8..ed7f7f7 100644 --- a/tpv/redsys.py +++ b/tpv/redsys.py @@ -3,7 +3,7 @@ import json from django.conf import settings from django.urls import reverse -from tpv.models import PaymentTPV +from tpv.models import PaymentTransaction from tpv.utils import compute_signature @@ -43,16 +43,16 @@ class RedsysClient: def get_currency_code(self) -> str: return settings.REDSYS_CURRENCY_CODE - def get_merchant_url_ok_for_order(self, order: PaymentTPV) -> str: - path = reverse("tpv:ok", kwargs={"order": order.hash}) + def get_merchant_url_ok_for_transaction(self, transaction: PaymentTransaction) -> str: + path = reverse("tpv:ok", kwargs={"transaction": transaction.hash}) return f"{settings.REDSYS_TPV_DOMAIN}{path}" - def get_merchant_url_ko_for_order(self, order: PaymentTPV) -> str: - path = reverse("tpv:ko", kwargs={"order": order.hash}) + def get_merchant_url_ko_for_transaction(self, transaction: PaymentTransaction) -> str: + path = reverse("tpv:ko", kwargs={"transaction": transaction.hash}) return f"{settings.REDSYS_TPV_DOMAIN}{path}" - def get_webhook_url_for_order(self, order: PaymentTPV) -> str: - path = reverse("tpv:webhook", kwargs={"order": order.hash}) + def get_webhook_url_for_transaction(self, transaction: PaymentTransaction) -> str: + path = reverse("tpv:webhook", kwargs={"transaction": transaction.hash}) return f"{settings.REDSYS_TPV_DOMAIN}{path}" def get_shared_secret(self) -> str: @@ -62,41 +62,39 @@ class RedsysClient: key = self.get_shared_secret() return compute_signature(str(hash), payload, key).decode() - def get_merchant_parameters_for_order( - self, order: PaymentTPV, transaction_type: int = TransactionTypes.AUTHORIZATION + def get_merchant_parameters_for_transaction( + self, transaction: PaymentTransaction, transaction_type: int = TransactionTypes.AUTHORIZATION ) -> dict: merchant_code = self.get_merchant_code() return { - "DS_MERCHANT_AMOUNT": str(order.amount_integer), + "DS_MERCHANT_AMOUNT": str(transaction.amount_integer), "DS_MERCHANT_CURRENCY": self.get_currency_code(), "DS_MERCHANT_MERCHANTCODE": merchant_code, - "DS_MERCHANT_MERCHANTURL": self.get_webhook_url_for_order(order), # Webhook - "DS_MERCHANT_ORDER": order.hash.hex, + "DS_MERCHANT_MERCHANTURL": self.get_webhook_url_for_transaction(transaction), # Webhook + "DS_MERCHANT_ORDER": transaction.hash.hex, "DS_MERCHANT_TERMINAL": self.get_terminal(), "DS_MERCHANT_TRANSACTIONTYPE": transaction_type, - "DS_MERCHANT_URLKO": self.get_merchant_url_ko_for_order( - order - ), # Página informativa al usuario - Pago erróneo - "DS_MERCHANT_URLOK": self.get_merchant_url_ok_for_order( - order - ), # Página informativa al usuario - Pago confirmado + # Página informativa al usuario - Pago erróneo + "DS_MERCHANT_URLKO": self.get_merchant_url_ko_for_transaction(transaction), + # Página informativa al usuario - Pago confirmado + "DS_MERCHANT_URLOK": self.get_merchant_url_ok_for_transaction(transaction), } - def get_encoded_merchant_parameters_for_order( - self, order: PaymentTPV, transaction_type: int = TransactionTypes.AUTHORIZATION + def get_encoded_merchant_parameters_for_transaction( + self, transaction: PaymentTransaction, transaction_type: int = TransactionTypes.AUTHORIZATION ) -> str: - body = self.get_merchant_parameters_for_order(order, transaction_type) + body = self.get_merchant_parameters_for_transaction(transaction, transaction_type) stringified_body = json.dumps(body) return base64.b64encode(stringified_body.encode()).decode("utf-8") - def get_body_for_order( - self, order: PaymentTPV, transaction_type: int = TransactionTypes.AUTHORIZATION + def get_body_for_transaction( + self, transaction: PaymentTransaction, transaction_type: int = TransactionTypes.AUTHORIZATION ) -> dict: - merchant_parameters = self.get_encoded_merchant_parameters_for_order( - order, transaction_type + merchant_parameters = self.get_encoded_merchant_parameters_for_transaction( + transaction, transaction_type ) - signature = self.get_signature(order.hash.hex, merchant_parameters) + signature = self.get_signature(transaction.hash.hex, merchant_parameters) return { "Ds_MerchantParameters": merchant_parameters, diff --git a/tpv/tests/test_redsys.py b/tpv/tests/test_redsys.py index 64b760d..2c95e05 100644 --- a/tpv/tests/test_redsys.py +++ b/tpv/tests/test_redsys.py @@ -6,7 +6,7 @@ from rest_framework import status from rest_framework.test import APITestCase from django.conf import settings -from tpv.models import PaymentTPV +from tpv.models import PaymentTransaction from tpv.redsys import RedsysClient from tpv.settings import ERROR_CODES @@ -14,7 +14,7 @@ from tpv.settings import ERROR_CODES class TestRedsysTPV(APITestCase): def test_redsys_client(self): amount_to_pay = Decimal("10.00") - order = PaymentTPV.objects.create(amount=amount_to_pay) + transaction = PaymentTransaction.objects.create(amount=amount_to_pay) items = [ { @@ -26,13 +26,13 @@ class TestRedsysTPV(APITestCase): } ] - order.metadata["items"] = items - order.save() + transaction.metadata["items"] = items + transaction.save() client = RedsysClient() - merchant_parameters = client.get_merchant_parameters_for_order(order) + merchant_parameters = client.get_merchant_parameters_for_transaction(transaction) - assert merchant_parameters.get("DS_MERCHANT_ORDER") == order.hash.hex + assert merchant_parameters.get("DS_MERCHANT_ORDER") == transaction.hash.hex assert merchant_parameters.get("DS_MERCHANT_AMOUNT") == str( int(amount_to_pay) * 100 ) @@ -44,11 +44,11 @@ class TestRedsysTPV(APITestCase): == settings.REDSYS_MERCHANT_CODE ) - client.get_body_for_order(order) + client.get_body_for_transaction(transaction) def test_redsys_webhook(self): amount_to_pay = Decimal("10.00") - order = PaymentTPV.objects.create(amount=amount_to_pay) + transaction = PaymentTransaction.objects.create(amount=amount_to_pay) items = [ { @@ -59,19 +59,19 @@ class TestRedsysTPV(APITestCase): "amount_to_pay": str(amount_to_pay), } ] - order.metadata["items"] = items - order.save() + transaction.metadata["items"] = items + transaction.save() response = self.client.get( - reverse("tpv:order_created", kwargs={"order": order.hash}) + reverse("tpv:order_created", kwargs={"transaction": transaction.hash}) ) assert response.status_code == status.HTTP_200_OK redsys_response_data = { "Ds_MerchantCode": "999008881", "Ds_Terminal": "001", - "Ds_Order": order.hash.hex, - "Ds_Amount": str(order.amount_integer), + "Ds_Order": transaction.hash.hex, + "Ds_Amount": str(transaction.amount_integer), "Ds_Currency": "978", "Ds_Date": "01/01/2024", "Ds_Hour": "00:00", @@ -94,7 +94,7 @@ class TestRedsysTPV(APITestCase): ).decode() response = self.client.post( - reverse("tpv:webhook", kwargs={"order": order.hash}), + reverse("tpv:webhook", kwargs={"transaction": transaction.hash}), data={ "Ds_MerchantParameters": b64_merchant_params, "Ds_Signature": settings.REDSYS_SHARED_SECRET, @@ -105,13 +105,13 @@ class TestRedsysTPV(APITestCase): assert response.status_code == status.HTTP_200_OK response = self.client.get( - reverse("tpv:ok", kwargs={"order": order.hash}) + reverse("tpv:ok", kwargs={"transaction": transaction.hash}) ) assert response.status_code == status.HTTP_200_OK def test_redsys_webhook_payment_error(self): amount_to_pay = Decimal("10.00") - order = PaymentTPV.objects.create(amount=amount_to_pay) + transaction = PaymentTransaction.objects.create(amount=amount_to_pay) items = [ { @@ -123,19 +123,19 @@ class TestRedsysTPV(APITestCase): } ] - order.metadata["items"] = items + transaction.metadata["items"] = items - order.save() + transaction.save() response = self.client.get( - reverse("tpv:order_created", kwargs={"order": order.hash}) + reverse("tpv:order_created", kwargs={"transaction": transaction.hash}) ) assert response.status_code == status.HTTP_200_OK redsys_response_data = { "Ds_MerchantCode": "999008881", "Ds_Terminal": "001", - "Ds_Order": order.hash.hex, + "Ds_Order": transaction.hash.hex, "Ds_Amount": "1000", "Ds_Currency": "978", "Ds_Date": "01/01/2024", @@ -160,7 +160,7 @@ class TestRedsysTPV(APITestCase): ).decode() response = self.client.post( - reverse("tpv:webhook", kwargs={"order": order.hash}), + reverse("tpv:webhook", kwargs={"transaction": transaction.hash}), data={ "Ds_MerchantParameters": b64_merchant_params, "Ds_Signature": settings.REDSYS_SHARED_SECRET, @@ -169,11 +169,11 @@ class TestRedsysTPV(APITestCase): ) assert response.status_code == status.HTTP_409_CONFLICT - order.refresh_from_db() - assert str(ERROR_CODES.get("0184")) in order.observations - assert order.status == PaymentTPV.StatusChoices.ERROR + transaction.refresh_from_db() + assert str(ERROR_CODES.get("0184")) in transaction.observations + assert transaction.status == PaymentTransaction.StatusChoices.ERROR response = self.client.get( - reverse("tpv:ko", kwargs={"order": order.hash}) + reverse("tpv:ko", kwargs={"transaction": transaction.hash}) ) assert response.status_code == status.HTTP_200_OK diff --git a/tpv/urls.py b/tpv/urls.py index 5b02f32..050c419 100644 --- a/tpv/urls.py +++ b/tpv/urls.py @@ -1,12 +1,12 @@ from django.urls import path -from tpv.views import order_created, webhook, payment_accepted, payment_rejected +from tpv.views import transaction_created, webhook, payment_accepted, payment_rejected app_name = "tpv" urlpatterns = [ - path("order//", order_created, name="order_created"), - path("order//webhook/", webhook, name="webhook"), - path("order//ok/", payment_accepted, name="ok"), - path("order//ko/", payment_rejected, name="ko"), + path("transaction//", transaction_created, name="order_created"), + path("transaction//webhook/", webhook, name="webhook"), + path("transaction//ok/", payment_accepted, name="ok"), + path("transaction//ko/", payment_rejected, name="ko"), ] diff --git a/tpv/utils.py b/tpv/utils.py index 140be50..48ba8ea 100644 --- a/tpv/utils.py +++ b/tpv/utils.py @@ -10,7 +10,7 @@ from decimal import Decimal from django.utils.text import gettext_lazy as _ from tpv.exceptions import RedsysValidationException, RedsysPaymentException -from tpv.models import PaymentTPV +from tpv.models import PaymentTransaction from tpv.settings import ERROR_CODES @@ -39,7 +39,7 @@ def compare_signatures(signature_1, signature_2): return sig1safe == sig2safe -def validate_payment_for_order(request, order: PaymentTPV) -> Decimal: +def validate_payment_for_transaction(request, transaction: PaymentTransaction) -> Decimal: """ example_response_data = { 'Ds_MerchantCode': '999008881', @@ -64,7 +64,7 @@ def validate_payment_for_order(request, order: PaymentTPV) -> Decimal: } :param request: - :param order: + :param transaction: :return: """ data = request.POST @@ -79,8 +79,8 @@ def validate_payment_for_order(request, order: PaymentTPV) -> Decimal: merchant_params = base64.b64decode(merchant_parameters).decode() result = json.loads(merchant_params) - order_hex = result.get("Ds_Order") - assert order_hex == order.hash.hex + transaction_hex = result.get("Ds_Order") + assert transaction_hex == transaction.hash.hex status_code = result.get("Ds_Response") @@ -94,6 +94,6 @@ def validate_payment_for_order(request, order: PaymentTPV) -> Decimal: return amount -def pay_order(order: PaymentTPV, amount_paid: Decimal): - order.status = PaymentTPV.StatusChoices.PAID - order.save() +def pay_transaction(transaction: PaymentTransaction, amount_paid: Decimal): + transaction.status = PaymentTransaction.StatusChoices.PAID + transaction.save() diff --git a/tpv/views.py b/tpv/views.py index c2e5795..227563c 100644 --- a/tpv/views.py +++ b/tpv/views.py @@ -4,68 +4,68 @@ from django.shortcuts import render, get_object_or_404, redirect from django.http.response import HttpResponse from tpv.forms import UpdateEmailForm -from tpv.models import PaymentTPV +from tpv.models import PaymentTransaction from tpv.redsys import RedsysClient -from tpv.utils import pay_order, validate_payment_for_order +from tpv.utils import pay_transaction, validate_payment_for_transaction from tpv.signals import redsys_payment_accepted, redsys_payment_rejected -def payment_accepted(request, order): - order = get_object_or_404(PaymentTPV, hash=order) +def payment_accepted(request, transaction): + transaction = get_object_or_404(PaymentTransaction, hash=transaction) return render( request, template_name="tpv/order_created.html", context={ - "order": order, + "order": transaction, }, ) -def payment_rejected(request, order): - order = get_object_or_404(PaymentTPV, hash=order) +def payment_rejected(request, transaction): + transaction = get_object_or_404(PaymentTransaction, hash=transaction) return render( request, template_name="tpv/order_created.html", context={ - "order": order, + "order": transaction, }, ) @csrf_exempt -def webhook(request, order): - order = get_object_or_404(PaymentTPV, hash=order) +def webhook(request, transaction): + transaction = get_object_or_404(PaymentTransaction, hash=transaction) try: - amount_paid = validate_payment_for_order(request, order) - pay_order(order, amount_paid) - redsys_payment_accepted.send_robust(PaymentTPV.__class__, hash=order.hash) + amount_paid = validate_payment_for_transaction(request, transaction) + pay_transaction(transaction, amount_paid) + redsys_payment_accepted.send_robust(PaymentTransaction.__class__, hash=transaction.hash) return HttpResponse(status=200) except Exception as e: - order.status = PaymentTPV.StatusChoices.ERROR - order.observations = str(e) - order.save() - redsys_payment_rejected.send_robust(PaymentTPV.__class__, hash=order.hash) + transaction.status = PaymentTransaction.StatusChoices.ERROR + transaction.observations = str(e) + transaction.save() + redsys_payment_rejected.send_robust(PaymentTransaction.__class__, hash=transaction.hash) return HttpResponse(status=409) -def order_created(request, order): - order = get_object_or_404(PaymentTPV, hash=order) +def transaction_created(request, transaction): + transaction = get_object_or_404(PaymentTransaction, hash=transaction) client = RedsysClient() - parameters = client.get_body_for_order(order) + parameters = client.get_body_for_transaction(transaction) return render( request, template_name="tpv/order_created.html", context={ - "form": UpdateEmailForm({"contact_email": order.contact_email}), - "action": reverse("tpv:order_created", kwargs={"order": order.hash}), - "order": order, + "form": UpdateEmailForm({"contact_email": transaction.contact_email}), + "action": reverse("tpv:order_created", kwargs={"transaction": transaction.hash}), + "order": transaction, "signature_version": parameters.get("Ds_SignatureVersion"), "merchant_parameters": parameters.get("Ds_MerchantParameters"), "signature": parameters.get("Ds_Signature"),