From c56140011f0d7eb28659710bc9da980fffc3c9da Mon Sep 17 00:00:00 2001 From: i701 Date: Sat, 20 Sep 2025 21:03:43 +0500 Subject: [PATCH] =?UTF-8?q?refactor:=20add=20src=5Fbank=20attribute=20to?= =?UTF-8?q?=20Payment=20and=20Topup=20model=20=F0=9F=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apibase/settings.py | 2 +- ...6_payment_source_bank_topup_source_bank.py | 22 +++++++++++++++++ billing/models.py | 2 ++ billing/views.py | 24 ++++++++++--------- pyrightconfig.json | 23 +++++++----------- 5 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 billing/migrations/0016_payment_source_bank_topup_source_bank.py diff --git a/apibase/settings.py b/apibase/settings.py index 4ae2955..06dd21b 100644 --- a/apibase/settings.py +++ b/apibase/settings.py @@ -26,7 +26,7 @@ env.read_env(os.path.join(BASE_DIR, ".env")) # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = env("SECRET_KEY", default=get_random_secret_key()) +SECRET_KEY = env("SECRET_KEY", default=get_random_secret_key()) #type: ignore DEBUG = env.bool("DJANGO_DEBUG", default=True) # type: ignore diff --git a/billing/migrations/0016_payment_source_bank_topup_source_bank.py b/billing/migrations/0016_payment_source_bank_topup_source_bank.py new file mode 100644 index 0000000..be187db --- /dev/null +++ b/billing/migrations/0016_payment_source_bank_topup_source_bank.py @@ -0,0 +1,22 @@ +# Generated by Django 5.2 on 2025-09-20 16:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("billing", "0015_topup_payment_type"), + ] + + operations = [ + migrations.AddField( + model_name="payment", + name="source_bank", + field=models.CharField(blank=True, default="", null=True), + ), + migrations.AddField( + model_name="topup", + name="source_bank", + field=models.CharField(blank=True, default="", null=True), + ), + ] diff --git a/billing/models.py b/billing/models.py index 8689f92..e46e3e7 100644 --- a/billing/models.py +++ b/billing/models.py @@ -17,6 +17,7 @@ class Payment(models.Model): ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) mib_reference = models.CharField(default="", null=True, blank=True) + source_bank = models.CharField(default="", null=True, blank=True) number_of_months = models.IntegerField() amount = models.FloatField() paid = models.BooleanField(default=False) @@ -86,6 +87,7 @@ class Topup(models.Model): default="PENDING", ) mib_reference = models.CharField(default="", null=True, blank=True) + source_bank = models.CharField(default="", null=True, blank=True) expires_at = models.DateTimeField(null=True, blank=True) expiry_notification_sent = models.BooleanField(default=False) created_at = models.DateTimeField(default=timezone.now) diff --git a/billing/views.py b/billing/views.py index 592ce0e..7f04b5e 100644 --- a/billing/views.py +++ b/billing/views.py @@ -61,7 +61,7 @@ class InsufficientFundsError(Exception): class ListCreatePaymentView(StaffEditorPermissionMixin, generics.ListCreateAPIView): serializer_class = PaymentSerializer queryset = Payment.objects.all().select_related("user") - filter_backends = [DjangoFilterBackend] + filter_backends = [DjangoFilterBackend] #type: ignore filterset_fields = "__all__" filterset_class = PaymentFilter @@ -74,7 +74,7 @@ class ListCreatePaymentView(StaffEditorPermissionMixin, generics.ListCreateAPIVi Prefetch("devices", queryset=device_qs) ) - if not self.request.user.is_superuser: + if not self.request.user.is_superuser: #type: ignore queryset = queryset.filter(user=self.request.user) return queryset @@ -195,7 +195,7 @@ class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView): {"message": "Payment has already been verified."}, status=status.HTTP_400_BAD_REQUEST, ) - if payment.user != user and not user.is_superuser: + if payment.user != user and not user.is_superuser: #type: ignore return Response( {"message": "You are not authorized to verify this payment."}, status=status.HTTP_403_FORBIDDEN, @@ -356,6 +356,7 @@ class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView): payment.paid_at = timezone.now() payment.method = "TRANSFER" payment.mib_reference = mib_resp["transaction"]["ref"] or "" + payment.source_bank = mib_resp["transaction"]["sourceBank"] or "" payment.save() return PaymentVerificationResponse( message=mib_resp["message"], @@ -381,7 +382,7 @@ class CancelPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView): {"message": "Payment has already been cancelled."}, status=status.HTTP_400_BAD_REQUEST, ) - if instance.user != user and not user.is_superuser: + if instance.user != user and not user.is_superuser: #type: ignore return Response( {"message": "You are not authorized to cancel this payment."}, status=status.HTTP_403_FORBIDDEN, @@ -401,7 +402,7 @@ class CancelPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView): class ListCreateTopupView(StaffEditorPermissionMixin, generics.ListCreateAPIView): queryset = Topup.objects.all().prefetch_related("user") serializer_class = TopupSerializer - filter_backends = [DjangoFilterBackend] + filter_backends = [DjangoFilterBackend] #type: ignore filterset_fields = "__all__" filterset_class = TopupFilter @@ -422,7 +423,7 @@ class ListCreateTopupView(StaffEditorPermissionMixin, generics.ListCreateAPIView def get_queryset(self): queryset = super().get_queryset() - if getattr(self.request.user, "is_admin") or self.request.user.is_superuser: + if getattr(self.request.user, "is_admin") or self.request.user.is_superuser: #type: ignore return queryset return queryset.filter(user=self.request.user) @@ -458,7 +459,7 @@ class TopupDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView): def get_queryset(self): queryset = super().get_queryset() - if getattr(self.request.user, "is_admin") or self.request.user.is_superuser: + if getattr(self.request.user, "is_admin") or self.request.user.is_superuser: #type: ignore return queryset return queryset.filter(user=self.request.user) @@ -498,6 +499,7 @@ class VerifyTopupPaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIVi topup.paid = True topup.mib_reference = mib_resp["transaction"]["ref"] or "" topup.paid_at = mib_resp["transaction"]["trxDate"] + topup.source_bank = mib_resp["transaction"]["sourceBank"] or "" topup.save() return PaymentVerificationResponse( message=mib_resp["message"], @@ -518,7 +520,7 @@ class VerifyTopupPaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIVi {"message": "Payment has already been verified."}, status=status.HTTP_400_BAD_REQUEST, ) - if topup_instance.user != user and not user.is_superuser: + if topup_instance.user != user and not user.is_superuser: #type: ignore return Response( {"message": "You are not allowed to pay for this topup."}, status=status.HTTP_403_FORBIDDEN, @@ -585,7 +587,7 @@ class CancelTopupView(StaffEditorPermissionMixin, generics.UpdateAPIView): if ( instance.user != user and getattr(user, "is_admin") - and not user.is_superuser + and not user.is_superuser #type: ignore ): return Response( {"message": "You are not authorized to delete this topup."}, @@ -653,13 +655,13 @@ class AdminTopupCreateView(StaffEditorPermissionMixin, generics.CreateAPIView): class ListWalletTransactionView(StaffEditorPermissionMixin, generics.ListAPIView): serializer_class = WalletTransactionSerializer queryset = WalletTransaction.objects.all().select_related("user") - filter_backends = [DjangoFilterBackend] + filter_backends = [DjangoFilterBackend] #type: ignore filterset_fields = "__all__" filterset_class = WalletTransactionFilter def get_queryset(self): queryset = super().get_queryset() - if getattr(self.request.user, "is_admin") or self.request.user.is_superuser: + if getattr(self.request.user, "is_admin") or self.request.user.is_superuser: #type: ignore return queryset return queryset.filter(user=self.request.user) diff --git a/pyrightconfig.json b/pyrightconfig.json index caf7dda..afc7e1f 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -1,16 +1,11 @@ { - "venvPath": ".", - "venv": ".venv", - "reportMissingImports": "error", - "include": ["src"], - "typeCheckingMode": "standard", - "reportArgumentType": "warning", - "reportUnusedVariable": "warning", - "reportFunctionMemberAccess": "none", - "exclude": [ - "council-api/**/migrations", - "**/__pycache__", - "src/experimental", - "src/typestubs" - ] + "venvPath": ".", + "venv": ".venv", + "reportMissingImports": "error", + "include": ["src"], + "typeCheckingMode": "standard", + "reportArgumentType": "warning", + "reportUnusedVariable": "warning", + "reportFunctionMemberAccess": "none", + "exclude": ["council-api/**/migrations", "**/__pycache__"] }