from rest_framework import serializers from apps.transaction.models import TransactionParticipant, ParticipantInfo, TransactionReceipt from apps.course.serializers import CourseDetailSerializer from utils import FileFieldSerializer class ParticipantInfoSerializer(serializers.ModelSerializer): phone_number = serializers.CharField(max_length=30) class Meta: model = ParticipantInfo fields = ['fullname', 'email', 'phone_number', 'gender', 'birthdate'] def validate_phone_number(self, value): return value class TransactionParticipantSerializer(serializers.ModelSerializer): participant_infos = ParticipantInfoSerializer(many=True) class Meta: model = TransactionParticipant fields = ['participant_infos'] def create(self, validated_data): participant_infos_data = validated_data.pop('participant_infos', []) transaction_participant = TransactionParticipant.objects.create(**validated_data) for participant_info_data in participant_infos_data: ParticipantInfo.objects.create(transaction_participant=transaction_participant, **participant_info_data) return transaction_participant class TransactionListSerializer(serializers.ModelSerializer): course = serializers.SerializerMethodField() receipts = serializers.SerializerMethodField() class Meta: model = TransactionParticipant fields = ['id', 'course', 'status', 'price', 'receipts', 'created_at', 'updated_at'] def get_course(self, obj): return CourseDetailSerializer(obj.course, context=self.context).data def get_receipts(self, obj): receipts = obj.receipts.all() return TransactionReceiptSerializer(receipts, many=True, context=self.context).data class TransactionReceiptSerializer(serializers.ModelSerializer): """ Serializer for uploading payment receipts Uses FileFieldSerializer to handle pre-uploaded files from /upload-tmp-media/ """ file = FileFieldSerializer() class Meta: model = TransactionReceipt fields = ['id', 'file', 'description', 'uploaded_at'] read_only_fields = ['id', 'uploaded_at'] class UploadReceiptsSerializer(serializers.Serializer): """ Serializer for uploading multiple receipt files for a transaction. Files should be pre-uploaded using /upload-tmp-media/ endpoint, then their URLs should be sent here. """ files = serializers.ListField( child=FileFieldSerializer(), allow_empty=False, max_length=10, help_text="List of file URLs (max 10 files) - files should be pre-uploaded via /upload-tmp-media/" ) description = serializers.CharField( required=False, allow_blank=True, max_length=1000, help_text="Optional description for the receipts" ) def validate_files(self, files): """ Validate uploaded file URLs """ if len(files) > 10: raise serializers.ValidationError("You can upload a maximum of 10 files.") return files # ============================================================================= # Admin Panel Serializers # ============================================================================= class AdminTransactionReceiptSerializer(serializers.ModelSerializer): file = serializers.SerializerMethodField() class Meta: model = TransactionReceipt fields = ['id', 'file', 'description', 'uploaded_at'] def get_file(self, obj): request = self.context.get('request') if obj.file: if request: return request.build_absolute_uri(obj.file.url) return obj.file.url return None class AdminParticipantInfoSerializer(serializers.ModelSerializer): phone_number = serializers.CharField(read_only=True) class Meta: model = ParticipantInfo fields = ['id', 'fullname', 'email', 'phone_number', 'gender', 'birthdate'] class AdminTransactionSerializer(serializers.ModelSerializer): user_name = serializers.CharField(source='user.fullname', read_only=True) user_email = serializers.CharField(source='user.email', read_only=True) course_title = serializers.SerializerMethodField() receipts = AdminTransactionReceiptSerializer(many=True, read_only=True) participant_infos = AdminParticipantInfoSerializer(many=True, read_only=True) class Meta: model = TransactionParticipant fields = [ 'id', 'user', 'user_name', 'user_email', 'course', 'course_title', 'price', 'status', 'payment_method', 'participant_infos', 'receipts', 'created_at', 'updated_at' ] read_only_fields = [ 'id', 'user', 'user_name', 'user_email', 'course', 'course_title', 'price', 'payment_method', 'participant_infos', 'receipts', 'created_at', 'updated_at' ] def get_course_title(self, obj): if not obj.course: return None request = self.context.get('request') lang = getattr(request, 'LANGUAGE_CODE', None) or 'en' from apps.course.models.course import get_localized_field return get_localized_field(lang, obj.course.title)