485 lines
12 KiB
Python
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
|
|
) |