karamoozi1/bank/transactions/views.py

485 lines
12 KiB
Python

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
)