from django.contrib import admin from django.utils.translation import gettext_lazy as _ from django.utils.html import format_html from django.contrib import messages from unfold.admin import ModelAdmin, StackedInline, TabularInline from unfold.decorators import display from apps.transaction.models import TransactionParticipant, ParticipantInfo, TransactionReceipt from apps.course.models import Participant from utils.admin import project_admin_site class ParticipantInfoInline(StackedInline): model = ParticipantInfo extra = 1 fields = ['fullname', 'email', 'phone_number', 'gender', 'birthdate'] # readonly_fields = ['email', 'phone_number'] classes = ['collapse'] tab = True show_change_link = True class TransactionReceiptInline(TabularInline): model = TransactionReceipt extra = 0 fields = ['file', 'description', 'uploaded_at'] readonly_fields = ['uploaded_at'] classes = ['collapse'] tab = True show_change_link = True verbose_name = _('Payment Receipt') verbose_name_plural = _('Payment Receipts') @admin.register(TransactionParticipant) class TransactionParticipantAdmin(ModelAdmin): list_display = ('user', 'course', 'payment_status', 'price_display', 'participant_status', 'receipts_count', 'created_at', 'updated_at') list_filter = ('status', 'course', 'created_at') search_fields = ('user__email', 'course__title') readonly_fields = ['created_at', 'updated_at'] inlines = [ParticipantInfoInline, TransactionReceiptInline] autocomplete_fields = ['user',] show_change_link = True ordering = ('-created_at',) fieldsets = ( (None, { 'fields': ('user', 'course', 'status', 'price') }), (_('Timestamps'), { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) @display(description=_("Payment Status"), ordering="status") def payment_status(self, obj): if obj.status == 'success': return format_html('{}', _("Paid")) elif obj.status == 'failed': return format_html('{}', _("Failed")) elif obj.status == 'waiting_approval': return format_html('{}', _("Waiting Approval")) return format_html('{}', _("Pending")) @display(description=_("Receipts Count")) def receipts_count(self, obj): """Display count of uploaded receipts""" count = obj.receipts.count() if count > 0: return format_html('{} {}', count, _("receipts")) return format_html('{}', _("No receipts")) @display(description=_("Price"), ordering="price") def price_display(self, obj): return format_html('${}', obj.price) @display(description=_("Course Participant Status")) def participant_status(self, obj): """نمایش وضعیت شرکت‌کننده در دوره""" if obj.status == TransactionParticipant.TransactionStatus.SUCCESS: participant_exists = Participant.objects.filter( student=obj.user, course=obj.course ).exists() if participant_exists: return format_html('✓ {}', _("Enrolled")) else: return format_html('⚠ {}', _("Not Enrolled")) else: return format_html('- {}', _("Not Applicable")) def save_model(self, request, obj, form, change): """Override save_model to show messages when participant is created""" if change: # Store the old status before saving old_obj = TransactionParticipant.objects.get(pk=obj.pk) old_status = old_obj.status # Save the object super().save_model(request, obj, form, change) # Check if status changed to SUCCESS if (old_status != TransactionParticipant.TransactionStatus.SUCCESS and obj.status == TransactionParticipant.TransactionStatus.SUCCESS): participant_exists = Participant.objects.filter( student=obj.user, course=obj.course ).exists() if participant_exists: messages.success( request, _("Transaction status updated to SUCCESS. User {user_email} is now enrolled in course '{course_title}'.").format( user_email=obj.user.email, course_title=obj.course.title ) ) else: messages.warning( request, _("Transaction status updated to SUCCESS, but there was an issue enrolling user {user_email} in course '{course_title}'. Please check the logs.").format( user_email=obj.user.email, course_title=obj.course.title ) ) else: super().save_model(request, obj, form, change) def get_queryset(self, request): # Filter out deleted transactions return super().get_queryset(request).filter(is_deleted=False) project_admin_site.register(TransactionParticipant, TransactionParticipantAdmin) @admin.register(TransactionReceipt) class TransactionReceiptAdmin(ModelAdmin): list_display = ('transaction', 'file', 'uploaded_at', 'description_preview') list_filter = ('uploaded_at', 'transaction__status') search_fields = ('transaction__user__email', 'transaction__course__title', 'description') readonly_fields = ['uploaded_at'] autocomplete_fields = ['transaction'] ordering = ('-uploaded_at',) fieldsets = ( (None, { 'fields': ('transaction', 'file', 'description') }), (_('Timestamps'), { 'fields': ('uploaded_at',), 'classes': ('collapse',) }), ) @display(description=_("Description")) def description_preview(self, obj): """Display truncated description""" if obj.description: return obj.description[:50] + '...' if len(obj.description) > 50 else obj.description return '-' project_admin_site.register(TransactionReceipt, TransactionReceiptAdmin)