from decimal import Decimal from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from rest_framework.permissions import IsAuthenticated from rest_framework_simplejwt.authentication import JWTAuthentication from accounts.models import Account from .models import Transaction from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi class IncreaseAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] @swagger_auto_schema( operation_summary="Increase Balance", operation_description="Increase the balance of a selected account", request_body=openapi.Schema( type=openapi.TYPE_OBJECT, required=[ "account_number", "amount" ], properties={ "account_number": openapi.Schema( type=openapi.TYPE_STRING, example="87654321", description="Account Number" ), "amount": openapi.Schema( type=openapi.TYPE_INTEGER, example=5000, description="Amount to increase" ) } ), responses={ 200: openapi.Response( description="Balance increased successfully", examples={ "application/json": { "message": "Balance increased successfully", "balance": 125000 } } ), 404: openapi.Response( description="Account not found", examples={ "application/json": { "message": "Account not found" } } ) }, tags=[ "transaction" ] ) def post(self, request): account_number = request.data["account_number"] amount = int(request.data["amount"]) try: account = Account.objects.get( account_number=account_number, user=request.user ) except Account.DoesNotExist: return Response( { "message": "Account not found" }, status=status.HTTP_404_NOT_FOUND ) account.balance += amount account.save() Transaction.objects.create( account=account, transaction_type="increase", amount=amount ) return Response( { "message": "Balance increased successfully", "balance": account.balance }, status=status.HTTP_200_OK ) class DecreaseAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] @swagger_auto_schema( operation_summary="Decrease Balance", operation_description="Decrease the balance of a selected account", request_body=openapi.Schema( type=openapi.TYPE_OBJECT, required=[ "account_number", "amount" ], properties={ "account_number": openapi.Schema( type=openapi.TYPE_STRING, example="87654321", description="Account Number" ), "amount": openapi.Schema( type=openapi.TYPE_INTEGER, example=5000, description="Amount to decrease" ) } ), responses={ 200: openapi.Response( description="Balance decreased successfully", examples={ "application/json": { "message": "Balance decreased successfully", "balance": 120000 } } ), 400: openapi.Response( description="Insufficient balance" ), 404: openapi.Response( description="Account not found" ) }, tags=["transaction"] ) def post(self, request): account_number = request.data["account_number"] amount = int(request.data["amount"]) try: account = Account.objects.get( account_number=account_number, user=request.user ) except Account.DoesNotExist: return Response( { "message": "Account not found" }, status=status.HTTP_404_NOT_FOUND ) if account.balance < amount: return Response( { "message": "Insufficient balance" }, status=status.HTTP_400_BAD_REQUEST ) account.balance -= amount account.save() Transaction.objects.create( account=account, transaction_type="decrease", amount=amount ) return Response( { "message": "Balance decreased successfully", "balance": account.balance }, status=status.HTTP_200_OK ) class TransferAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] @swagger_auto_schema( operation_summary="Transfer Money", operation_description="Transfer money from one of your accounts to another account", request_body=openapi.Schema( type=openapi.TYPE_OBJECT, required=[ "source_account_number", "destination_account_number", "amount" ], properties={ "source_account_number": openapi.Schema( type=openapi.TYPE_STRING, example="12345678", description="Source account number" ), "destination_account_number": openapi.Schema( type=openapi.TYPE_STRING, example="87654321", description="Destination account number" ), "amount": openapi.Schema( type=openapi.TYPE_INTEGER, example=5000, description="Transfer amount" ) } ), responses={ 200: openapi.Response( description="Transfer successful" ), 400: openapi.Response( description="Insufficient balance" ), 404: openapi.Response( description="Account not found" ) }, tags=["transaction"] ) def post(self, request): amount = int(request.data["amount"]) source_account_number = request.data["source_account_number"] destination_account_number = request.data["destination_account_number"] try: source_account = Account.objects.get( account_number=source_account_number, user=request.user ) except Account.DoesNotExist: return Response( { "message": "Source account not found" }, status=status.HTTP_404_NOT_FOUND ) try: destination_account = Account.objects.get( account_number=destination_account_number ) except Account.DoesNotExist: return Response( { "message": "Destination account not found" }, status=status.HTTP_404_NOT_FOUND ) if source_account.id == destination_account.id: return Response( { "message": "Source and destination accounts cannot be the same" }, status=status.HTTP_400_BAD_REQUEST ) if source_account.balance < amount: return Response( { "message": "Insufficient balance" }, status=status.HTTP_400_BAD_REQUEST ) source_account.balance -= amount destination_account.balance += amount source_account.save() destination_account.save() Transaction.objects.create( account=source_account, transaction_type="transfer", amount=amount ) return Response( { "message": "Transfer successful", "balance": source_account.balance }, status=status.HTTP_200_OK ) class TransactionListAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] @swagger_auto_schema( operation_summary="Get Transactions", operation_description="Get all transactions or filter by account number", manual_parameters=[ openapi.Parameter( "account_number", openapi.IN_QUERY, description="Account Number (optional)", type=openapi.TYPE_STRING, required=False ) ], responses={ 200: openapi.Response( description="Transaction list" ), 404: openapi.Response( description="Account not found" ) }, tags=["transaction"] ) def get(self, request): account_number = request.query_params.get("account_number") if account_number: try: account = Account.objects.get( account_number=account_number, user=request.user ) except Account.DoesNotExist: return Response( { "message": "Account not found" }, status=status.HTTP_404_NOT_FOUND ) transactions = Transaction.objects.filter( account=account ) else: accounts = Account.objects.filter( user=request.user ) transactions = Transaction.objects.filter( account__in=accounts ) data = [] for transaction in transactions: data.append( { "id": transaction.id, "account_number": transaction.account.account_number, "type": transaction.transaction_type, "amount": transaction.amount, "date": transaction.created_at } ) return Response( data, status=status.HTTP_200_OK ) class TransactionDetailAPIView(APIView): authentication_classes = [JWTAuthentication] permission_classes = [IsAuthenticated] @swagger_auto_schema( operation_summary="Get Transaction Detail", operation_description="Get one transaction by id", responses={ 200: openapi.Response( description="Transaction detail" ), 404: openapi.Response( description="Transaction not found" ) }, tags=["transaction"] ) def get(self, request, id): try: transaction = Transaction.objects.get( id=id, account__user=request.user ) except Transaction.DoesNotExist: return Response( { "message": "Transaction not found" }, status=status.HTTP_404_NOT_FOUND ) return Response( { "id": transaction.id, "type": transaction.transaction_type, "amount": transaction.amount, "date": transaction.created_at }, status=status.HTTP_200_OK )