You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

267 lines
10 KiB

from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from apps.course.models import Participant, Course
from apps.transaction.models import TransactionParticipant, TransactionReceipt
from apps.transaction.serializers import (
TransactionParticipantSerializer,
TransactionListSerializer,
UploadReceiptsSerializer,
TransactionReceiptSerializer
)
from utils.exceptions import AppAPIException
from apps.account.models import User
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from apps.transaction.doc import (
doc_upload_transaction_receipts,
doc_list_transaction_receipts,
doc_transaction_list,
doc_create_transaction
)
class TransactionParticipantCreateView(generics.CreateAPIView):
queryset = TransactionParticipant.objects.all()
serializer_class = TransactionParticipantSerializer
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
operation_description=doc_create_transaction()
)
def create(self, request, *args, **kwargs):
user = request.user
course_slug = self.kwargs.get('slug') # Get the slug from the URL
try:
course = Course.objects.get(slug=course_slug) # Retrieve the Course object
except Course.DoesNotExist:
raise AppAPIException({'message': "Course not found"}) # Handle course not found
participant_infos = request.data.get('participant_infos', [])
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
statis = TransactionParticipant.TransactionStatus.PENDING
if len(participant_infos) == 1 and (course.final_price == 0 or course.is_free):
participant = participant_infos[0]
if participant.get('email') != user.email:
raise AppAPIException({'message': "The email must be for the requesting user"})
# به جای تغییر user_type، فقط نقش student را اضافه می‌کنیم
if not user.has_role('student'):
user.add_role('student')
# فیلتر کردن برای چک کردن وجود participant
existing_participant = Participant.objects.filter(student=user, course=course).first()
if existing_participant:
participant = existing_participant
else:
participant = Participant.objects.create(student=user, course=course)
statis = TransactionParticipant.TransactionStatus.SUCCESS
transaction_participant = serializer.save(user=user, course=course, price=course.final_price, status=statis)
print(f'---> {type(transaction_participant)}/ {transaction_participant}')
return Response({
'message': 'Transaction Participant created successfully.',
'transaction_id': transaction_participant.id,
'participant_infos': serializer.data['participant_infos']
}, status=status.HTTP_201_CREATED)
class TransactiontListView(generics.ListAPIView):
queryset = TransactionParticipant.objects.all()
serializer_class = TransactionListSerializer
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
operation_description=doc_transaction_list()
)
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.filter(user=self.request.user, is_deleted=False)
return queryset
class SoftDeleteTransactionParticipantView(APIView):
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
operation_summary="Soft delete a transaction participant",
operation_description="Marks a transaction participant as deleted without removing it from the database",
manual_parameters=[
openapi.Parameter(
'id',
openapi.IN_PATH,
description="Transaction Participant ID",
type=openapi.TYPE_INTEGER,
required=True
)
],
responses={
200: openapi.Response(
description="Transaction participant successfully marked as deleted",
examples={
"application/json": {
"success": True,
"message": "Transaction participant successfully marked as deleted"
}
}
),
404: "Transaction participant not found",
403: "Permission denied"
}
)
def delete(self, request, pk):
try:
transaction = TransactionParticipant.objects.get(pk=pk)
if transaction.user == request.user:
transaction.is_deleted = True
transaction.save()
return Response({
"success": True,
"message": "Transaction participant successfully marked as deleted"
}, status=status.HTTP_200_OK)
else:
raise AppAPIException(
detail={'message': "You don't have permission to delete this transaction"},
status_code=status.HTTP_403_FORBIDDEN
)
except TransactionParticipant.DoesNotExist:
raise AppAPIException({'message': "Transaction participant not found"})
class UploadTransactionReceiptsView(APIView):
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
operation_summary="Upload payment receipts for a transaction",
operation_description=doc_upload_transaction_receipts(),
request_body=UploadReceiptsSerializer,
responses={
201: openapi.Response(
description="Receipts uploaded successfully",
examples={
"application/json": {
"success": True,
"message": "Receipts uploaded successfully",
"transaction_status": "waiting_approval",
"receipts": [
{
"id": 1,
"file": "http://example.com/media/receipts/1/receipt.jpg",
"description": "Payment receipt",
"uploaded_at": "2025-12-03T10:30:00Z"
}
]
}
}
),
400: "Invalid data or transaction cannot accept receipts",
403: "Permission denied",
404: "Transaction not found"
}
)
def post(self, request, transaction_id):
try:
transaction = TransactionParticipant.objects.get(pk=transaction_id, is_deleted=False)
except TransactionParticipant.DoesNotExist:
raise AppAPIException({'message': "Transaction not found"})
# Check if user owns this transaction
if transaction.user != request.user:
raise AppAPIException(
detail={'message': "You don't have permission to upload receipts for this transaction"},
status_code=status.HTTP_403_FORBIDDEN
)
# Check if transaction is in a state that can accept receipts
if transaction.status not in [
TransactionParticipant.TransactionStatus.PENDING,
TransactionParticipant.TransactionStatus.WAITING_APPROVAL
]:
raise AppAPIException(
detail={'message': f"Cannot upload receipts for transaction with status '{transaction.status}'"},
status_code=status.HTTP_400_BAD_REQUEST
)
# Validate using serializer
serializer = UploadReceiptsSerializer(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
# Create receipt records
receipts = []
description = serializer.validated_data.get('description', '')
file_urls = serializer.validated_data.get('files', [])
for file_url in file_urls:
receipt = TransactionReceipt.objects.create(
transaction=transaction,
file=file_url,
description=description
)
receipts.append(receipt)
# Update transaction status to waiting_approval
transaction.status = TransactionParticipant.TransactionStatus.WAITING_APPROVAL
transaction.save()
# Serialize receipts for response
receipts_data = TransactionReceiptSerializer(receipts, many=True, context={'request': request}).data
return Response({
'success': True,
'message': 'Receipts uploaded successfully',
'transaction_status': transaction.status,
'receipts': receipts_data
}, status=status.HTTP_201_CREATED)
class TransactionReceiptsListView(generics.ListAPIView):
serializer_class = TransactionReceiptSerializer
permission_classes = [IsAuthenticated]
@swagger_auto_schema(
operation_summary="List receipts for a transaction",
operation_description=doc_list_transaction_receipts(),
manual_parameters=[
openapi.Parameter(
'transaction_id',
openapi.IN_PATH,
description="Transaction ID",
type=openapi.TYPE_INTEGER,
required=True
)
],
responses={
200: TransactionReceiptSerializer(many=True),
403: "Permission denied",
404: "Transaction not found"
}
)
def get_queryset(self):
transaction_id = self.kwargs.get('transaction_id')
try:
transaction = TransactionParticipant.objects.get(pk=transaction_id, is_deleted=False)
except TransactionParticipant.DoesNotExist:
raise AppAPIException({'message': "Transaction not found"})
# Check if user owns this transaction
if transaction.user != self.request.user:
raise AppAPIException(
detail={'message': "You don't have permission to view receipts for this transaction"},
status_code=status.HTTP_403_FORBIDDEN
)
return TransactionReceipt.objects.filter(transaction=transaction)