RAPHA-BETHEL BNPS — PROJECT SNAPSHOT
Generated from: /home/dnjill5/raphabethel.org/portal

======================================================================
TOP-LEVEL DIRECTORY STRUCTURE
======================================================================
  FILE  .env
  FILE  .htaccess
  DIR   __pycache__
  DIR   academics
  FILE  add_class6_fee_level.py
  FILE  all_db_backup.json
  DIR   api
  FILE  assign_teachers_complete.py
  DIR   backend
  FILE  check_urls.py
  DIR   communication
  DIR   core
  FILE  db.sqlite3
  FILE  db_backup.json
  FILE  deploy.sh
  FILE  deploy_log.txt
  FILE  deployment_check.py
  DIR   docs
  DIR   finance
  FILE  finance_backup_20260412.json
  FILE  fix_class6_fees.py
  FILE  local_requirements.txt
  FILE  manage.py
  DIR   media
  FILE  migrate_to_prod.py
  FILE  next-steps.py
  DIR   parents
  FILE  passenger_wsgi.py
  DIR   public
  FILE  rb-school-v1.zip
  FILE  rename_student_ids.py
  DIR   reports
  FILE  requirements.txt
  DIR   scripts
  FILE  setup_all_modules.py
  FILE  snapshot_project.py
  DIR   staff
  DIR   static
  DIR   staticfiles
  DIR   students
  DIR   sync
  DIR   templates
  FILE  test_all_models.py
  DIR   tmp

======================================================================
FILE: manage.py
======================================================================
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()


======================================================================
FILE: requirements.txt
======================================================================
# Core
Django>=4.2,<5.0
python-decouple>=3.8

# Database
mysqlclient>=2.2.0

# Static files (production)
whitenoise>=6.6.0

# REST API
djangorestframework>=3.14
django-cors-headers>=4.3
django-filter>=23.5
drf-yasg>=1.21
djangorestframework-simplejwt>=5.3

# Admin UI
django-jazzmin>=2.6

# File handling
Pillow>=10.0
openpyxl>=3.1
pandas>=2.0
numpy>=1.26
reportlab>=4.0

# Utilities
django-extensions>=3.2


######################################################################
# APP: ACADEMICS
######################################################################

======================================================================
FILE: academics/__init__.py
======================================================================


======================================================================
FILE: academics/admin.py
======================================================================
# academics/admin.py
from django.contrib import admin
from .models import SchoolClass, Subject, Attendance, ClassSubject

class ClassSubjectInline(admin.TabularInline):
    """Inline for assigning subjects/teachers directly in class admin"""
    model = ClassSubject
    extra = 2
    raw_id_fields = ['teacher']
    fields = ['subject', 'teacher', 'hours_per_week']

@admin.register(SchoolClass)
class SchoolClassAdmin(admin.ModelAdmin):
    list_display = ['name', 'code', 'level', 'section', 'section_type', 'class_teacher', 'get_student_count']
    list_filter = ['level', 'section_type', 'academic_year']
    search_fields = ['name', 'code']
    inlines = [ClassSubjectInline]
    fieldsets = (
        ('Basic Information', {
            'fields': ('name', 'code', 'level', 'section', 'section_type')
        }),
        ('Academic Details', {
            'fields': ('academic_year', 'capacity', 'room_number')
        }),
        ('Teacher Assignment', {
            'fields': ('class_teacher',),
            'description': 'Select the homeroom/class teacher'
        }),
    )
    
    def get_student_count(self, obj):
        from students.models import Student
        return Student.objects.filter(current_class=obj).count()
    get_student_count.short_description = 'Students'

@admin.register(Subject)
class SubjectAdmin(admin.ModelAdmin):
    list_display = ['name', 'code', 'category']
    list_filter = ['category']
    search_fields = ['name', 'code']

@admin.register(Attendance)
class AttendanceAdmin(admin.ModelAdmin):
    list_display = ['student', 'date', 'school_class', 'status', 'marked_by']
    list_filter = ['status', 'date', 'school_class']
    search_fields = ['student__first_name', 'student__last_name']
    date_hierarchy = 'date'
    raw_id_fields = ['student', 'marked_by']

@admin.register(ClassSubject)
class ClassSubjectAdmin(admin.ModelAdmin):
    """Main admin for managing teacher-subject-class assignments"""
    list_display = ['school_class', 'subject', 'teacher', 'hours_per_week']
    list_filter = ['school_class__section_type', 'subject__category', 'school_class__level']
    search_fields = ['school_class__name', 'subject__name', 'teacher__user__first_name']
    raw_id_fields = ['teacher']
    autocomplete_fields = ['school_class', 'subject']
    
    fieldsets = (
        ('Assignment', {
            'fields': ('school_class', 'subject', 'teacher')
        }),
        ('Schedule', {
            'fields': ('hours_per_week',),
            'classes': ('collapse',)
        }),
    )

======================================================================
FILE: academics/apps.py
======================================================================
from django.apps import AppConfig


class AcademicsConfig(AppConfig):
    name = 'academics'


======================================================================
FILE: academics/attendance_urls.py
======================================================================
# academics/attendance_urls.py
from django.urls import path
from . import views

app_name = 'attendance'

urlpatterns = [
    path('', views.AttendanceListView.as_view(), name='attendance_list'),
    path('mark/', views.AttendanceMarkingView.as_view(), name='mark_attendance'),
    path('report/', views.AttendanceReportView.as_view(), name='attendance_report'),
    path('student/<int:student_id>/', views.StudentAttendanceView.as_view(), name='student_attendance'),
]

======================================================================
FILE: academics/forms.py
======================================================================
# academics/forms.py
from django import forms
from .models import SchoolClass, Subject, Attendance

class SchoolClassForm(forms.ModelForm):
    class Meta:
        model = SchoolClass
        fields = '__all__'
        widgets = {
            'code': forms.TextInput(attrs={'class': 'form-control'}),
            'name': forms.TextInput(attrs={'class': 'form-control'}),
            'level': forms.Select(attrs={'class': 'form-control'}),
            'section': forms.TextInput(attrs={'class': 'form-control'}),
            'section_type': forms.Select(attrs={'class': 'form-control'}),
            'capacity': forms.NumberInput(attrs={'class': 'form-control'}),
            'room_number': forms.TextInput(attrs={'class': 'form-control'}),
            'academic_year': forms.TextInput(attrs={'class': 'form-control'}),
        }

class AttendanceForm(forms.ModelForm):
    class Meta:
        model = Attendance
        fields = ['student', 'date', 'status', 'remarks']
        widgets = {
            'date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'status': forms.Select(attrs={'class': 'form-control'}),
            'remarks': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
        }

======================================================================
FILE: academics/models.py
======================================================================
# academics/models.py
"""
Models for academic management including classes, subjects, and attendance.
"""
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _


class SchoolClass(models.Model):
    """
    Represents a class/grade level in the school.
    
    This model stores information about each class, including its level,
    section, academic year, and assigned teachers. Each class can have
    multiple teachers assigned through the ClassSubject junction model.
    
    Attributes:
        code (str): Unique class identifier (e.g., "CL6-A", "CE1-B")
        name (str): Display name of the class (e.g., "Class 6")
        level (str): Educational level from LEVEL_CHOICES
        section (str): Section letter (A, B, C, etc.)
        section_type (str): Type of section (english, french, bilingual)
        capacity (int): Maximum number of students
        room_number (str): Physical classroom identifier
        academic_year (str): Academic year (e.g., "2025-2026")
        class_teacher (ForeignKey): Reference to the homeroom teacher
        
    Example:
        >>> class_6 = SchoolClass.objects.create(
        ...     code="CL6-A",
        ...     name="Class 6",
        ...     level="class6",
        ...     section="A",
        ...     section_type="english",
        ...     capacity=45
        ... )
    """
    
    LEVEL_CHOICES = [
        ('pre_nursery', 'Pre-Nursery'),
        ('nursery1', 'Nursery 1'),
        ('nursery2', 'Nursery 2'),
        ('moyenne_section', 'Moyenne Section'),
        ('grande_section', 'Grande Section'),
        ('sil', 'SIL'),
        ('cp', 'CP'),
        ('ce1', 'CE1'),
        ('ce2', 'CE2'),
        ('cm1', 'CM1'),
        ('cm2', 'CM2'),
        ('class1', 'Class 1'),
        ('class2', 'Class 2'),
        ('class3', 'Class 3'),
        ('class4', 'Class 4'),
        ('class5', 'Class 5'),
        ('class6', 'Class 6'),
    ]
    
    SECTION_TYPE_CHOICES = [
        ('english', 'English Section'),
        ('french', 'French Section'),
        ('bilingual', 'Bilingual Section'),
    ]
    
    code = models.CharField(
        max_length=20, 
        unique=True, 
        help_text="e.g., CL6-A, CE1-B"
    )
    name = models.CharField(
        max_length=50, 
        blank=True, 
        help_text="Display name of the class"
    )
    level = models.CharField(
        max_length=20, 
        choices=LEVEL_CHOICES
    )
    section = models.CharField(
        max_length=10, 
        blank=True, 
        help_text="A, B, C, etc."
    )
    section_type = models.CharField(
        max_length=20, 
        choices=SECTION_TYPE_CHOICES, 
        default='english'
    )
    capacity = models.PositiveIntegerField(
        default=40
    )
    room_number = models.CharField(
        max_length=10, 
        blank=True
    )
    academic_year = models.CharField(
        max_length=9, 
        default="2025-2026"
    )
    
    # Teacher assignments
    class_teacher = models.ForeignKey(
        'staff.Staff', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='classes_as_teacher',
        limit_choices_to={'role__in': ['teacher', 'class_teacher']}
    )
    
    class Meta:
        verbose_name = "Class"
        verbose_name_plural = "Classes"
        ordering = ['level', 'section']
        indexes = [
            models.Index(fields=['code']),
            models.Index(fields=['level']),
            models.Index(fields=['section_type']),
        ]
    
    def __str__(self):
        """Return string representation of the class."""
        return self.name or f"{self.get_level_display()} {self.section}"
    
    def save(self, *args, **kwargs):
        """
        Save the class, auto-generating name if not provided.
        """
        if not self.name:
            self.name = str(self)
        super().save(*args, **kwargs)
    
    def get_student_count(self):
        """
        Get the number of students currently enrolled in this class.
        
        Returns:
            int: Count of students with current_class = this class.
        """
        from students.models import Student
        return Student.objects.filter(current_class=self).count()
    
    def get_teachers(self):
        """
        Get all teachers assigned to this class through ClassSubject.
        
        Returns:
            QuerySet: QuerySet of Staff objects assigned to this class.
        """
        return self.teachers.all()


class Subject(models.Model):
    """
    Represents a subject taught in the school.
    
    Subjects can be categorized (core, languages, sciences, etc.) and are
    assigned to classes through the ClassSubject junction model.
    
    Attributes:
        code (str): Unique subject code (e.g., "MATH", "ENG")
        name (str): Subject name in English
        name_fr (str): Subject name in French
        category (str): Subject category from CATEGORY_CHOICES
        description (str): Detailed description of the subject
    """
    
    SUBJECT_CATEGORY_CHOICES = [
        ('core', 'Core Subjects'),
        ('languages', 'Languages'),
        ('sciences', 'Sciences'),
        ('humanities', 'Humanities'),
        ('vocational', 'Vocational Studies'),
        ('arts', 'Arts'),
        ('sports', 'Physical Education'),
    ]
    
    code = models.CharField(
        max_length=10, 
        unique=True
    )
    name = models.CharField(
        max_length=100
    )
    name_fr = models.CharField(
        max_length=100, 
        blank=True
    )
    category = models.CharField(
        max_length=20, 
        choices=SUBJECT_CATEGORY_CHOICES, 
        default='core'
    )
    description = models.TextField(
        blank=True
    )
    
    class Meta:
        ordering = ['category', 'name']
    
    def __str__(self):
        """Return the subject name."""
        return self.name


class ClassSubject(models.Model):
    """
    Junction model for classes and subjects with teacher assignment.
    
    This model represents which teacher teaches which subject in which class.
    It allows for multiple teachers per class (different subjects) and
    multiple classes per teacher.
    
    Attributes:
        school_class (ForeignKey): The class being taught
        subject (ForeignKey): The subject being taught
        teacher (ForeignKey): The teacher teaching this subject
        hours_per_week (int): Number of hours allocated weekly
    """
    
    school_class = models.ForeignKey(
        SchoolClass, 
        on_delete=models.CASCADE, 
        related_name='class_subjects'
    )
    subject = models.ForeignKey(
        Subject, 
        on_delete=models.CASCADE, 
        related_name='class_subjects'
    )
    teacher = models.ForeignKey(
        'staff.Staff', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='taught_subjects',
        limit_choices_to={'role__in': ['teacher', 'class_teacher', 'subject_teacher']}
    )
    hours_per_week = models.PositiveIntegerField(
        default=2
    )
    
    class Meta:
        unique_together = ['school_class', 'subject']
        verbose_name = "Class Subject"
        verbose_name_plural = "Class Subjects"
    
    def __str__(self):
        """Return string representation of the assignment."""
        return f"{self.school_class} - {self.subject}"


class Attendance(models.Model):
    """
    Records student attendance for a specific class and date.
    
    This model tracks daily attendance for each student, including status
    (present, absent, late, etc.) and which teacher marked the attendance.
    
    Attributes:
        student (ForeignKey): The student being marked
        date (date): Date of attendance
        school_class (ForeignKey): The class session
        status (str): Attendance status from STATUS_CHOICES
        period (str): Time period (morning, afternoon, full day)
        marked_by (ForeignKey): Teacher who marked attendance
        remarks (str): Additional notes about the attendance
        device_id (str): Device identifier for offline sync
        synced (bool): Whether record is synced with server
        synced_at (datetime): When the record was last synced
    """
    
    STATUS_CHOICES = [
        ('present', 'Present'),
        ('absent', 'Absent'),
        ('late', 'Late'),
        ('excused', 'Excused Absence'),
        ('sick', 'Sick'),
        ('holiday', 'Holiday'),
    ]
    
    PERIOD_CHOICES = [
        ('morning', 'Morning'),
        ('afternoon', 'Afternoon'),
        ('full_day', 'Full Day'),
    ]
    
    student = models.ForeignKey(
        'students.Student', 
        on_delete=models.CASCADE, 
        related_name='attendances'
    )
    date = models.DateField(
        default=timezone.now
    )
    school_class = models.ForeignKey(
        SchoolClass, 
        on_delete=models.CASCADE, 
        related_name='attendances'
    )
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='present'
    )
    period = models.CharField(
        max_length=10, 
        choices=PERIOD_CHOICES, 
        default='full_day'
    )
    
    # Teacher tracking
    marked_by = models.ForeignKey(
        'staff.Staff', 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='attendance_marked'
    )
    remarks = models.CharField(
        max_length=200, 
        blank=True
    )
    
    # For offline sync
    device_id = models.CharField(
        max_length=255, 
        blank=True
    )
    synced = models.BooleanField(
        default=False
    )
    synced_at = models.DateTimeField(
        null=True, 
        blank=True
    )
    
    class Meta:
        unique_together = ['student', 'date', 'period']
        ordering = ['-date', 'student__first_name']
        indexes = [
            models.Index(fields=['date']),
            models.Index(fields=['student', 'date']),
            models.Index(fields=['school_class', 'date']),
        ]
    
    def __str__(self):
        """Return string representation of the attendance record."""
        return f"{self.student} - {self.date} - {self.get_status_display()}"

======================================================================
FILE: academics/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: academics/urls-1.py
======================================================================
# academics/urls.py
from django.urls import path
from . import views

app_name = 'academics'

urlpatterns = [
    # Existing URLs
    path('classes/', views.ClassListView.as_view(), name='class_list'),
    path('classes/<int:pk>/', views.ClassDetailView.as_view(), name='class_detail'),
    path('classes/<int:pk>/students/', views.ClassStudentsView.as_view(), name='class_students'),
    
    # NEW: Teacher Assignment URLs
    path('classes/<int:class_id>/assign-teacher/', views.assign_teacher, name='assign_teacher'),
    path('classes/<int:class_id>/teachers/', views.get_teachers_for_class, name='get_teachers'),
    path('assignments/<int:assignment_id>/remove/', views.remove_teacher_assignment, name='remove_assignment'),
    path('classes/<int:class_id>/bulk-assign/', views.bulk_assign_teachers, name='bulk_assign'),
    
    # Subjects
    path('subjects/', views.SubjectListView.as_view(), name='subject_list'),
    path('subjects/add/', views.SubjectCreateView.as_view(), name='subject_add'),
    path('subjects/<int:pk>/', views.SubjectDetailView.as_view(), name='subject_detail'),
]

======================================================================
FILE: academics/urls.py
======================================================================
# academics/urls.py
from django.urls import path
from . import views

app_name = 'academics'

urlpatterns = [
    # Existing URLs
    path('classes/', views.ClassListView.as_view(), name='class_list'),
    path('classes/add/', views.ClassCreateView.as_view(), name='class_add'),
    path('classes/<int:pk>/', views.ClassDetailView.as_view(), name='class_detail'),
    path('classes/<int:pk>/edit/', views.ClassUpdateView.as_view(), name='class_edit'),
    path('classes/<int:pk>/students/', views.ClassStudentsView.as_view(), name='class_students'),
    
    # NEW: Teacher Assignment URLs
    path('classes/<int:class_id>/assign-teacher/', views.assign_teacher, name='assign_teacher'),
    path('classes/<int:class_id>/set-class-teacher/', views.assign_class_teacher, name='assign_class_teacher'),
    path('classes/<int:class_id>/teachers/', views.get_teachers_for_class, name='get_teachers'),
    path('assignments/<int:assignment_id>/remove/', views.remove_teacher_assignment, name='remove_assignment'),
    path('classes/<int:class_id>/bulk-assign/', views.bulk_assign_teachers, name='bulk_assign'),
    
    # Subjects
    path('subjects/', views.SubjectListView.as_view(), name='subject_list'),
    path('subjects/add/', views.SubjectCreateView.as_view(), name='subject_add'),
    path('subjects/<int:pk>/', views.SubjectDetailView.as_view(), name='subject_detail'),
]

======================================================================
FILE: academics/urls_attendance.py
======================================================================
# academics/attendance_urls.py
from django.urls import path
from . import views

app_name = 'attendance'

urlpatterns = [
    # Attendance
    path('', views.AttendanceListView.as_view(), name='attendance_list'),
    path('mark/', views.AttendanceMarkingView.as_view(), name='mark_attendance'),
    path('report/', views.AttendanceReportView.as_view(), name='attendance_report'),
    path('student/<int:student_id>/', views.StudentAttendanceView.as_view(), name='student_attendance'),
    
    # API
    path('api/today/', views.get_today_attendance, name='today_attendance_api'),
]

======================================================================
FILE: academics/views-1.py
======================================================================
# academics/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.http import JsonResponse
from django.db.models import Count, Q
from datetime import date, timedelta


from .models import SchoolClass, Subject, Attendance, ClassSubject
from students.models import Student
from staff.models import Staff

# ========== CLASS VIEWS ==========

class ClassListView(LoginRequiredMixin, ListView):
    """List all classes"""
    model = SchoolClass
    template_name = 'academics/class_list.html'
    context_object_name = 'classes'
    
    def get_queryset(self):
        return SchoolClass.objects.all().order_by('level', 'section')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        total_students = 0
        english_count = 0
        
        for cls in context['classes']:
            # Count students in each class
            cls.student_count = Student.objects.filter(current_class=cls).count()
            total_students += cls.student_count
            
            # Count teachers (through ClassSubject)
            cls.teacher_count = ClassSubject.objects.filter(
                school_class=cls, teacher__isnull=False
            ).values('teacher').distinct().count()
            
            # Count English section classes
            if cls.section_type == 'english':
                english_count += 1
        
        context['total_students'] = total_students
        context['english_count'] = english_count
        
        return context


class ClassDetailView(LoginRequiredMixin, DetailView):
    """View class details with teachers and students"""
    model = SchoolClass
    template_name = 'academics/class_detail.html'
    context_object_name = 'class'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get students in this class
        students = Student.objects.filter(
            current_class=self.object
        ).order_by('first_name')
        context['students'] = students
        
        # Get all teachers for dropdown
        context['all_teachers'] = Staff.objects.filter(
            is_active=True,
            role__in=['teacher', 'class_teacher', 'subject_teacher']
        ).select_related('user').order_by('user__first_name')
        
        # Get all subjects
        context['all_subjects'] = Subject.objects.all().order_by('name')
        
        # Get teachers for this class (through subject assignments)
        teacher_assignments = ClassSubject.objects.filter(
            school_class=self.object
        ).select_related('subject', 'teacher__user')
        
        # Group by teacher
        teachers_dict = {}
        for assignment in teacher_assignments:
            if assignment.teacher:
                teacher_id = assignment.teacher.id
                if teacher_id not in teachers_dict:
                    teachers_dict[teacher_id] = {
                        'teacher': assignment.teacher,
                        'subjects': [],
                        'assignments': []
                    }
                teachers_dict[teacher_id]['subjects'].append(assignment.subject)
                teachers_dict[teacher_id]['assignments'].append(assignment)
        
        context['teachers'] = list(teachers_dict.values())
        
        # Class teacher (homeroom teacher)
        if self.object.class_teacher:
            context['class_teacher'] = self.object.class_teacher
        
        # Today's attendance
        today = date.today()
        today_attendance = Attendance.objects.filter(
            school_class=self.object,
            date=today
        )
        context['today_attendance'] = today_attendance.count()
        
        if students.count() > 0:
            present_count = today_attendance.filter(status='present').count()
            context['attendance_rate'] = round((present_count / students.count()) * 100, 1)
        else:
            context['attendance_rate'] = 0
        
        # Statistics
        context['total_students'] = students.count()
        context['total_subjects'] = teacher_assignments.count()
        context['total_teachers'] = len(teachers_dict)
        
        return context


class ClassStudentsView(LoginRequiredMixin, DetailView):
    """View students in a class"""
    model = SchoolClass
    template_name = 'academics/class_students.html'
    context_object_name = 'class'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['students'] = Student.objects.filter(
            current_class=self.object
        ).order_by('first_name')
        return context


# ========== SUBJECT VIEWS ==========

class SubjectListView(LoginRequiredMixin, ListView):
    """List all subjects"""
    model = Subject
    template_name = 'academics/subject_list.html'
    context_object_name = 'subjects'
    
    def get_queryset(self):
        return Subject.objects.all().order_by('category', 'name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Subject.SUBJECT_CATEGORY_CHOICES
        return context


class SubjectDetailView(LoginRequiredMixin, DetailView):
    """View subject details"""
    model = Subject
    template_name = 'academics/subject_detail.html'
    context_object_name = 'subject'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get classes where this subject is taught
        context['class_assignments'] = ClassSubject.objects.filter(
            subject=self.object
        ).select_related('school_class', 'teacher')
        
        return context


# ========== TEACHER ASSIGNMENT VIEWS ==========

from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required

@login_required
@require_POST
def assign_teacher(request, class_id):
    """Assign a teacher to teach a subject in a class"""
    try:
        school_class = get_object_or_404(SchoolClass, id=class_id)
        teacher_id = request.POST.get('teacher_id')
        subject_id = request.POST.get('subject_id')
        hours = request.POST.get('hours_per_week', 2)
        
        if not teacher_id or not subject_id:
            messages.error(request, 'Please select both teacher and subject')
            return redirect('academics:class_detail', pk=class_id)
        
        teacher = get_object_or_404(Staff, id=teacher_id)
        subject = get_object_or_404(Subject, id=subject_id)
        
        # Check if assignment already exists
        assignment, created = ClassSubject.objects.get_or_create(
            school_class=school_class,
            subject=subject,
            defaults={
                'teacher': teacher,
                'hours_per_week': hours
            }
        )
        
        if not created:
            # Update existing assignment
            assignment.teacher = teacher
            assignment.hours_per_week = hours
            assignment.save()
            message = f"✅ Updated: {teacher.user.get_full_name()} now teaches {subject.name}"
        else:
            message = f"✅ Assigned: {teacher.user.get_full_name()} to teach {subject.name}"
        
        messages.success(request, message)
        
    except Staff.DoesNotExist:
        messages.error(request, f"Teacher with ID {teacher_id} not found")
    except Subject.DoesNotExist:
        messages.error(request, f"Subject with ID {subject_id} not found")
    except Exception as e:
        messages.error(request, f"Error: {str(e)}")
    
    return redirect('academics:class_detail', pk=class_id)


@login_required
def get_teachers_for_class(request, class_id):
    """API endpoint to get current teacher assignments for a class"""
    try:
        school_class = get_object_or_404(SchoolClass, id=class_id)
        assignments = ClassSubject.objects.filter(
            school_class=school_class
        ).select_related('teacher__user', 'subject')
        
        data = []
        for assignment in assignments:
            if assignment.teacher:
                data.append({
                    'id': assignment.id,
                    'teacher_id': assignment.teacher.id,
                    'teacher_name': assignment.teacher.user.get_full_name(),
                    'subject': assignment.subject.name,
                    'subject_id': assignment.subject.id,
                    'hours': assignment.hours_per_week
                })
        
        return JsonResponse({
            'success': True, 
            'data': data,
            'count': len(data)
        })
        
    except SchoolClass.DoesNotExist:
        return JsonResponse({'success': False, 'error': 'Class not found'})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})


@login_required
@require_POST
def remove_teacher_assignment(request, assignment_id):
    """Remove a teacher-subject-class assignment"""
    try:
        assignment = get_object_or_404(ClassSubject, id=assignment_id)
        class_id = assignment.school_class.id
        subject_name = assignment.subject.name
        teacher_name = assignment.teacher.user.get_full_name() if assignment.teacher else "Unknown"
        
        assignment.delete()
        messages.success(request, f"✅ Removed {teacher_name} from teaching {subject_name}")
        
    except Exception as e:
        messages.error(request, f"Error removing assignment: {str(e)}")
        class_id = request.POST.get('class_id')
    
    return redirect('academics:class_detail', pk=class_id)


@login_required
def bulk_assign_teachers(request, class_id):
    """Bulk assign multiple teachers to a class"""
    if request.method == 'POST':
        # This can be expanded later for CSV upload or multi-select
        messages.info(request, "Bulk assignment feature coming soon!")
        return redirect('academics:class_detail', pk=class_id)
    
    return JsonResponse({'success': False, 'error': 'Method not allowed'})


# ========== ATTENDANCE VIEWS ==========

class AttendanceListView(LoginRequiredMixin, ListView):
    """List attendance records"""
    model = Attendance
    template_name = 'academics/attendance/list.html'
    context_object_name = 'attendances'
    paginate_by = 50
    
    def get_queryset(self):
        queryset = Attendance.objects.all().select_related(
            'student', 'school_class', 'marked_by__user'
        )
        
        # Filter by date
        date_filter = self.request.GET.get('date')
        if date_filter:
            queryset = queryset.filter(date=date_filter)
        else:
            queryset = queryset.filter(date=date.today())
        
        # Filter by class
        class_filter = self.request.GET.get('class')
        if class_filter:
            queryset = queryset.filter(school_class_id=class_filter)
        
        # Filter by status
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        return queryset.order_by('-date', 'school_class', 'student__first_name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['classes'] = SchoolClass.objects.all()
        context['today'] = date.today()
        return context


class AttendanceMarkingView(LoginRequiredMixin, TemplateView):
    """Mark attendance for a class - Teacher Friendly"""
    template_name = 'academics/attendance/mark.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # If teacher is logged in, show only their classes
        if hasattr(self.request.user, 'staff_profile') and self.request.user.staff_profile.is_teacher:
            teacher = self.request.user.staff_profile
            # Get classes this teacher teaches
            teacher_classes = ClassSubject.objects.filter(
                teacher=teacher
            ).values_list('school_class', flat=True).distinct()
            context['classes'] = SchoolClass.objects.filter(id__in=teacher_classes)
        else:
            context['classes'] = SchoolClass.objects.all()
        
        context['today'] = date.today()
        
        class_id = self.request.GET.get('class')
        if class_id:
            selected_class = get_object_or_404(SchoolClass, id=class_id)
            context['selected_class'] = selected_class
            
            # Get students in this class
            students = Student.objects.filter(
                current_class=selected_class,
                status='active'
            ).order_by('first_name')
            context['students'] = students
            
            # Get today's attendance
            attendance_today = Attendance.objects.filter(
                date=date.today(),
                school_class=selected_class
            )
            
            # Create a dictionary for quick lookup
            attendance_dict = {}
            for att in attendance_today:
                attendance_dict[att.student_id] = att.status
            
            context['attendance_dict'] = attendance_dict
            
            # Check if attendance already taken
            context['attendance_taken'] = attendance_today.exists()
        
        return context
    
    def post(self, request, *args, **kwargs):
        class_id = request.POST.get('class_id')
        if not class_id:
            messages.error(request, 'Please select a class')
            return redirect('attendance:mark_attendance')
        
        selected_class = get_object_or_404(SchoolClass, id=class_id)
        students = Student.objects.filter(current_class=selected_class, status='active')
        
        marked_count = 0
        for student in students:
            status = request.POST.get(f'status_{student.id}')
            
            if status:
                attendance, created = Attendance.objects.update_or_create(
                    student=student,
                    date=date.today(),
                    defaults={
                        'school_class': selected_class,
                        'status': status,
                        'marked_by': request.user.staff_profile if hasattr(request.user, 'staff_profile') else None
                    }
                )
                marked_count += 1
        
        messages.success(request, f'✅ Attendance marked for {marked_count} students in {selected_class.name}')
        
        # If teacher, redirect back to their dashboard
        if hasattr(request.user, 'staff_profile') and request.user.staff_profile.is_teacher:
            return redirect('staff:teacher_dashboard')
        
        return redirect(f'/attendance/mark/?class={class_id}')


class AttendanceReportView(LoginRequiredMixin, TemplateView):
    """View attendance reports"""
    template_name = 'academics/attendance/report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get filter parameters
        from_date = self.request.GET.get('from_date')
        to_date = self.request.GET.get('to_date')
        class_id = self.request.GET.get('class')
        
        # Default to current month
        if not from_date:
            from_date = date.today().replace(day=1)
        if not to_date:
            to_date = date.today()
        
        context['classes'] = SchoolClass.objects.all()
        context['from_date'] = from_date
        context['to_date'] = to_date
        
        # Build stats
        stats = []
        classes = SchoolClass.objects.all()
        if class_id:
            classes = classes.filter(id=class_id)
        
        for cls in classes:
            # Get attendance records for this class in date range
            attendances = Attendance.objects.filter(
                school_class=cls,
                date__gte=from_date,
                date__lte=to_date
            )
            
            total = attendances.count()
            if total > 0:
                present = attendances.filter(status='present').count()
                absent = attendances.filter(status='absent').count()
                late = attendances.filter(status='late').count()
                excused = attendances.filter(status='excused').count()
                
                stats.append({
                    'class': cls.name,
                    'total': total,
                    'present': present,
                    'absent': absent,
                    'late': late,
                    'excused': excused,
                    'rate': round((present / total) * 100, 1) if total > 0 else 0
                })
        
        context['stats'] = stats
        
        # Summary stats
        if stats:
            context['total_records'] = sum(s['total'] for s in stats)
            context['total_present'] = sum(s['present'] for s in stats)
            context['overall_rate'] = round(
                (context['total_present'] / context['total_records']) * 100,
                1
            ) if context['total_records'] > 0 else 0
        
        return context


class StudentAttendanceView(LoginRequiredMixin, DetailView):
    """View attendance for a specific student"""
    model = Student
    template_name = 'academics/attendance/student.html'
    context_object_name = 'student'
    
    def get_object(self):
        return get_object_or_404(Student, id=self.kwargs['student_id'])
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get attendance for this student
        attendances = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:60]  # Last 60 days
        
        context['attendances'] = attendances
        
        # Calculate stats
        total = attendances.count()
        if total > 0:
            present = attendances.filter(status='present').count()
            context['attendance_rate'] = round((present / total) * 100, 1)
            context['total_days'] = total
            context['present_days'] = present
            context['absent_days'] = attendances.filter(status='absent').count()
            context['late_days'] = attendances.filter(status='late').count()
        
        return context


# ========== API ENDPOINTS ==========

def get_today_attendance(request):
    """API endpoint for today's attendance"""
    today = date.today()
    total = Attendance.objects.filter(date=today).count()
    present = Attendance.objects.filter(date=today, status='present').count()
    
    return JsonResponse({
        'date': today,
        'total': total,
        'present': present,
        'absent': total - present,
        'rate': round((present / total) * 100, 1) if total > 0 else 0
    })


def get_class_stats(request, class_id):
    """API endpoint for class statistics"""
    school_class = get_object_or_404(SchoolClass, id=class_id)
    
    stats = {
        'class': school_class.name,
        'total_students': Student.objects.filter(current_class=school_class).count(),
        'subjects': ClassSubject.objects.filter(school_class=school_class).count(),
        'today_attendance': Attendance.objects.filter(
            school_class=school_class,
            date=date.today()
        ).count(),
    }
    
    return JsonResponse(stats)

======================================================================
FILE: academics/views-2.py
======================================================================
# academics/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, TemplateView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.http import JsonResponse
from django.urls import reverse_lazy
from django.db.models import Count, Q
from datetime import date, timedelta


from .models import SchoolClass, Subject, Attendance, ClassSubject
from students.models import Student
from staff.models import Staff

# ========== CLASS VIEWS ==========

class ClassListView(LoginRequiredMixin, ListView):
    """List all classes"""
    model = SchoolClass
    template_name = 'academics/class_list.html'
    context_object_name = 'classes'
    
    def get_queryset(self):
        return SchoolClass.objects.all().order_by('level', 'section')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        total_students = 0
        english_count = 0
        
        for cls in context['classes']:
            # Count students in each class
            cls.student_count = Student.objects.filter(current_class=cls).count()
            total_students += cls.student_count
            
            # Count teachers (through ClassSubject)
            cls.teacher_count = ClassSubject.objects.filter(
                school_class=cls, teacher__isnull=False
            ).values('teacher').distinct().count()
            
            # Count English section classes
            if cls.section_type == 'english':
                english_count += 1
        
        context['total_students'] = total_students
        context['english_count'] = english_count
        
        return context


class ClassDetailView(LoginRequiredMixin, DetailView):
    """View class details with teachers and students"""
    model = SchoolClass
    template_name = 'academics/class_detail.html'
    context_object_name = 'class'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get students in this class
        students = Student.objects.filter(
            current_class=self.object
        ).order_by('first_name')
        context['students'] = students
        
        # Get all teachers for dropdown
        context['all_teachers'] = Staff.objects.filter(
            is_active=True,
            role__in=['teacher', 'class_teacher', 'subject_teacher']
        ).select_related('user').order_by('user__first_name')
        
        # Get all subjects
        context['all_subjects'] = Subject.objects.all().order_by('name')
        
        # Get teachers for this class (through subject assignments)
        teacher_assignments = ClassSubject.objects.filter(
            school_class=self.object
        ).select_related('subject', 'teacher__user')
        
        # Group by teacher
        teachers_dict = {}
        for assignment in teacher_assignments:
            if assignment.teacher:
                teacher_id = assignment.teacher.id
                if teacher_id not in teachers_dict:
                    teachers_dict[teacher_id] = {
                        'teacher': assignment.teacher,
                        'subjects': [],
                        'assignments': []
                    }
                teachers_dict[teacher_id]['subjects'].append(assignment.subject)
                teachers_dict[teacher_id]['assignments'].append(assignment)
        
        context['teachers'] = list(teachers_dict.values())
        
        # Class teacher (homeroom teacher)
        if self.object.class_teacher:
            context['class_teacher'] = self.object.class_teacher
        
        # Today's attendance
        today = date.today()
        today_attendance = Attendance.objects.filter(
            school_class=self.object,
            date=today
        )
        context['today_attendance'] = today_attendance.count()
        
        if students.count() > 0:
            present_count = today_attendance.filter(status='present').count()
            context['attendance_rate'] = round((present_count / students.count()) * 100, 1)
        else:
            context['attendance_rate'] = 0
        
        # Statistics
        context['total_students'] = students.count()
        context['total_subjects'] = teacher_assignments.count()
        context['total_teachers'] = len(teachers_dict)
        
        return context


class ClassStudentsView(LoginRequiredMixin, DetailView):
    """View students in a class"""
    model = SchoolClass
    template_name = 'academics/class_students.html'
    context_object_name = 'class'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['students'] = Student.objects.filter(
            current_class=self.object
        ).order_by('first_name')
        return context


# ========== SUBJECT VIEWS ==========

class SubjectListView(LoginRequiredMixin, ListView):
    """List all subjects"""
    model = Subject
    template_name = 'academics/subject_list.html'
    context_object_name = 'subjects'
    
    def get_queryset(self):
        return Subject.objects.all().order_by('category', 'name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Subject.SUBJECT_CATEGORY_CHOICES
        return context


class SubjectDetailView(LoginRequiredMixin, DetailView):
    """View subject details"""
    model = Subject
    template_name = 'academics/subject_detail.html'
    context_object_name = 'subject'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get classes where this subject is taught
        context['class_assignments'] = ClassSubject.objects.filter(
            subject=self.object
        ).select_related('school_class', 'teacher')
        
        return context


class SubjectCreateView(LoginRequiredMixin, CreateView):
    """Create a new subject"""
    model = Subject
    fields = ['code', 'name', 'name_fr', 'category', 'description']
    template_name = 'academics/subject_form.html'
    success_url = reverse_lazy('academics:subject_list')

    def form_valid(self, form):
        messages.success(self.request, f'Subject "{form.instance.name}" created successfully!')
        return super().form_valid(form)


# ========== TEACHER ASSIGNMENT VIEWS ==========

from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required

@login_required
@require_POST
def assign_teacher(request, class_id):
    """Assign a teacher to teach a subject in a class"""
    try:
        school_class = get_object_or_404(SchoolClass, id=class_id)
        teacher_id = request.POST.get('teacher_id')
        subject_id = request.POST.get('subject_id')
        hours = request.POST.get('hours_per_week', 2)
        
        if not teacher_id or not subject_id:
            messages.error(request, 'Please select both teacher and subject')
            return redirect('academics:class_detail', pk=class_id)
        
        teacher = get_object_or_404(Staff, id=teacher_id)
        subject = get_object_or_404(Subject, id=subject_id)
        
        # Check if assignment already exists
        assignment, created = ClassSubject.objects.get_or_create(
            school_class=school_class,
            subject=subject,
            defaults={
                'teacher': teacher,
                'hours_per_week': hours
            }
        )
        
        if not created:
            # Update existing assignment
            assignment.teacher = teacher
            assignment.hours_per_week = hours
            assignment.save()
            message = f"✅ Updated: {teacher.user.get_full_name()} now teaches {subject.name}"
        else:
            message = f"✅ Assigned: {teacher.user.get_full_name()} to teach {subject.name}"
        
        messages.success(request, message)
        
    except Staff.DoesNotExist:
        messages.error(request, f"Teacher with ID {teacher_id} not found")
    except Subject.DoesNotExist:
        messages.error(request, f"Subject with ID {subject_id} not found")
    except Exception as e:
        messages.error(request, f"Error: {str(e)}")
    
    return redirect('academics:class_detail', pk=class_id)


@login_required
def get_teachers_for_class(request, class_id):
    """API endpoint to get current teacher assignments for a class"""
    try:
        school_class = get_object_or_404(SchoolClass, id=class_id)
        assignments = ClassSubject.objects.filter(
            school_class=school_class
        ).select_related('teacher__user', 'subject')
        
        data = []
        for assignment in assignments:
            if assignment.teacher:
                data.append({
                    'id': assignment.id,
                    'teacher_id': assignment.teacher.id,
                    'teacher_name': assignment.teacher.user.get_full_name(),
                    'subject': assignment.subject.name,
                    'subject_id': assignment.subject.id,
                    'hours': assignment.hours_per_week
                })
        
        return JsonResponse({
            'success': True, 
            'data': data,
            'count': len(data)
        })
        
    except SchoolClass.DoesNotExist:
        return JsonResponse({'success': False, 'error': 'Class not found'})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})


@login_required
@require_POST
def remove_teacher_assignment(request, assignment_id):
    """Remove a teacher-subject-class assignment"""
    try:
        assignment = get_object_or_404(ClassSubject, id=assignment_id)
        class_id = assignment.school_class.id
        subject_name = assignment.subject.name
        teacher_name = assignment.teacher.user.get_full_name() if assignment.teacher else "Unknown"
        
        assignment.delete()
        messages.success(request, f"✅ Removed {teacher_name} from teaching {subject_name}")
        
    except Exception as e:
        messages.error(request, f"Error removing assignment: {str(e)}")
        class_id = request.POST.get('class_id')
    
    return redirect('academics:class_detail', pk=class_id)


@login_required
def bulk_assign_teachers(request, class_id):
    """Bulk assign multiple teachers to a class"""
    if request.method == 'POST':
        # This can be expanded later for CSV upload or multi-select
        messages.info(request, "Bulk assignment feature coming soon!")
        return redirect('academics:class_detail', pk=class_id)
    
    return JsonResponse({'success': False, 'error': 'Method not allowed'})


# ========== ATTENDANCE VIEWS ==========

class AttendanceListView(LoginRequiredMixin, ListView):
    """List attendance records"""
    model = Attendance
    template_name = 'academics/attendance/list.html'
    context_object_name = 'attendances'
    paginate_by = 50
    
    def get_queryset(self):
        queryset = Attendance.objects.all().select_related(
            'student', 'school_class', 'marked_by__user'
        )
        
        # Filter by date
        date_filter = self.request.GET.get('date')
        if date_filter:
            queryset = queryset.filter(date=date_filter)
        else:
            queryset = queryset.filter(date=date.today())
        
        # Filter by class
        class_filter = self.request.GET.get('class')
        if class_filter:
            queryset = queryset.filter(school_class_id=class_filter)
        
        # Filter by status
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        return queryset.order_by('-date', 'school_class', 'student__first_name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['classes'] = SchoolClass.objects.all()
        context['today'] = date.today()
        return context


class AttendanceMarkingView(LoginRequiredMixin, TemplateView):
    """Mark attendance for a class - Teacher Friendly"""
    template_name = 'academics/attendance/mark.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # If teacher is logged in, show only their classes
        if hasattr(self.request.user, 'staff_profile') and self.request.user.staff_profile.is_teacher:
            teacher = self.request.user.staff_profile
            # Get classes this teacher teaches
            teacher_classes = ClassSubject.objects.filter(
                teacher=teacher
            ).values_list('school_class', flat=True).distinct()
            context['classes'] = SchoolClass.objects.filter(id__in=teacher_classes)
        else:
            context['classes'] = SchoolClass.objects.all()
        
        context['today'] = date.today()
        
        class_id = self.request.GET.get('class')
        if class_id:
            selected_class = get_object_or_404(SchoolClass, id=class_id)
            context['selected_class'] = selected_class
            
            # Get students in this class
            students = Student.objects.filter(
                current_class=selected_class,
                status='active'
            ).order_by('first_name')
            context['students'] = students
            
            # Get today's attendance
            attendance_today = Attendance.objects.filter(
                date=date.today(),
                school_class=selected_class
            )
            
            # Create a dictionary for quick lookup
            attendance_dict = {}
            for att in attendance_today:
                attendance_dict[att.student_id] = att.status
            
            context['attendance_dict'] = attendance_dict
            
            # Check if attendance already taken
            context['attendance_taken'] = attendance_today.exists()
        
        return context
    
    def post(self, request, *args, **kwargs):
        class_id = request.POST.get('class_id')
        if not class_id:
            messages.error(request, 'Please select a class')
            return redirect('attendance:mark_attendance')
        
        selected_class = get_object_or_404(SchoolClass, id=class_id)
        students = Student.objects.filter(current_class=selected_class, status='active')
        
        marked_count = 0
        for student in students:
            status = request.POST.get(f'status_{student.id}')
            
            if status:
                attendance, created = Attendance.objects.update_or_create(
                    student=student,
                    date=date.today(),
                    defaults={
                        'school_class': selected_class,
                        'status': status,
                        'marked_by': request.user.staff_profile if hasattr(request.user, 'staff_profile') else None
                    }
                )
                marked_count += 1
        
        messages.success(request, f'✅ Attendance marked for {marked_count} students in {selected_class.name}')
        
        # If teacher, redirect back to their dashboard
        if hasattr(request.user, 'staff_profile') and request.user.staff_profile.is_teacher:
            return redirect('staff:teacher_dashboard')
        
        return redirect(f'/attendance/mark/?class={class_id}')


class AttendanceReportView(LoginRequiredMixin, TemplateView):
    """View attendance reports"""
    template_name = 'academics/attendance/report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get filter parameters
        from_date = self.request.GET.get('from_date')
        to_date = self.request.GET.get('to_date')
        class_id = self.request.GET.get('class')
        
        # Default to current month
        if not from_date:
            from_date = date.today().replace(day=1)
        if not to_date:
            to_date = date.today()
        
        context['classes'] = SchoolClass.objects.all()
        context['from_date'] = from_date
        context['to_date'] = to_date
        
        # Build stats
        stats = []
        classes = SchoolClass.objects.all()
        if class_id:
            classes = classes.filter(id=class_id)
        
        for cls in classes:
            # Get attendance records for this class in date range
            attendances = Attendance.objects.filter(
                school_class=cls,
                date__gte=from_date,
                date__lte=to_date
            )
            
            total = attendances.count()
            if total > 0:
                present = attendances.filter(status='present').count()
                absent = attendances.filter(status='absent').count()
                late = attendances.filter(status='late').count()
                excused = attendances.filter(status='excused').count()
                
                stats.append({
                    'class': cls.name,
                    'total': total,
                    'present': present,
                    'absent': absent,
                    'late': late,
                    'excused': excused,
                    'rate': round((present / total) * 100, 1) if total > 0 else 0
                })
        
        context['stats'] = stats
        
        # Summary stats
        if stats:
            context['total_records'] = sum(s['total'] for s in stats)
            context['total_present'] = sum(s['present'] for s in stats)
            context['overall_rate'] = round(
                (context['total_present'] / context['total_records']) * 100,
                1
            ) if context['total_records'] > 0 else 0
        
        return context


class StudentAttendanceView(LoginRequiredMixin, DetailView):
    """View attendance for a specific student"""
    model = Student
    template_name = 'academics/attendance/student.html'
    context_object_name = 'student'
    
    def get_object(self):
        return get_object_or_404(Student, id=self.kwargs['student_id'])
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get attendance for this student
        attendances = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:60]  # Last 60 days
        
        context['attendances'] = attendances
        
        # Calculate stats
        total = attendances.count()
        if total > 0:
            present = attendances.filter(status='present').count()
            context['attendance_rate'] = round((present / total) * 100, 1)
            context['total_days'] = total
            context['present_days'] = present
            context['absent_days'] = attendances.filter(status='absent').count()
            context['late_days'] = attendances.filter(status='late').count()
        
        return context


# ========== API ENDPOINTS ==========

def get_today_attendance(request):
    """API endpoint for today's attendance"""
    today = date.today()
    total = Attendance.objects.filter(date=today).count()
    present = Attendance.objects.filter(date=today, status='present').count()
    
    return JsonResponse({
        'date': today,
        'total': total,
        'present': present,
        'absent': total - present,
        'rate': round((present / total) * 100, 1) if total > 0 else 0
    })


def get_class_stats(request, class_id):
    """API endpoint for class statistics"""
    school_class = get_object_or_404(SchoolClass, id=class_id)
    
    stats = {
        'class': school_class.name,
        'total_students': Student.objects.filter(current_class=school_class).count(),
        'subjects': ClassSubject.objects.filter(school_class=school_class).count(),
        'today_attendance': Attendance.objects.filter(
            school_class=school_class,
            date=date.today()
        ).count(),
    }
    
    return JsonResponse(stats)

======================================================================
FILE: academics/views.py
======================================================================
# academics/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, TemplateView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from core.permissions import ManagementRequiredMixin, TeacherRequiredMixin, BursarRequiredMixin, can, is_teacher
from django.contrib import messages
from django.http import JsonResponse
from django.urls import reverse_lazy
from django.db.models import Count, Q
from datetime import date, timedelta


from .models import SchoolClass, Subject, Attendance, ClassSubject
from students.models import Student
from staff.models import Staff

# ========== CLASS VIEWS ==========

# Curriculum order for each section — used to sort classes correctly.
# Key = code prefix (before the dash, uppercased). Value = sort position.
# e.g.  "NUR1-A" → prefix "NUR1" → English position 1
#        "SIL-A"  → prefix "SIL"  → Bilingual position 4
#        "CM2-A"  → prefix "CM2"  → French position 2
_CLASS_ORDER = {
    'english': {
        'NUR1': 1, 'NUR2': 2,
        'CL1': 3, 'CL2': 4, 'CL3': 5, 'CL4': 6, 'CL5': 7, 'CL6': 8,
    },
    'bilingual': {
        # Pre-Nursery / Petite Section
        'PRE': 1, 'PS': 1,
        # Nursery 1 / Moyenne Section
        'MS': 2, 'NUR1B': 2,
        # Nursery 2 / Grande Section
        'GS': 3, 'NUR2B': 3,
        # C1 / SIL
        'SIL': 4,
        # C2 / CP
        'CP': 5,
        # C3 / CE1
        'CE1': 6,
        # C4 / CE2
        'CE2': 7,
    },
    'french': {
        'CM1': 1, 'CM2': 2,
    },
}

_SECTION_GROUP = {'english': 0, 'bilingual': 1, 'french': 2}


def _class_sort_key(cls):
    """Sort key: (section_group, curriculum_position, name)."""
    section  = getattr(cls, 'section_type', 'english')
    prefix   = (cls.code or '').upper().split('-')[0]
    position = _CLASS_ORDER.get(section, {}).get(prefix, 99)
    return (_SECTION_GROUP.get(section, 9), position, cls.name)


class ClassListView(LoginRequiredMixin, ListView):
    """List all classes — grouped by section in curriculum order."""
    model = SchoolClass
    template_name = 'academics/class_list.html'
    context_object_name = 'classes'

    def get_queryset(self):
        # Annotate student & teacher counts in one DB hit each
        return SchoolClass.objects.annotate(
            student_count=Count(
                'students',
                filter=Q(students__status='active'),
                distinct=True
            ),
            teacher_count=Count(
                'class_subjects__teacher',
                filter=Q(class_subjects__teacher__isnull=False),
                distinct=True
            ),

        ).select_related('class_teacher__user').order_by('name')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        all_classes = list(context['classes'])

        # Split into sections and apply curriculum ordering
        english_classes   = sorted(
            [c for c in all_classes if c.section_type == 'english'],
            key=_class_sort_key
        )
        bilingual_classes = sorted(
            [c for c in all_classes if c.section_type == 'bilingual'],
            key=_class_sort_key
        )
        french_classes    = sorted(
            [c for c in all_classes if c.section_type == 'french'],
            key=_class_sort_key
        )

        context['english_classes']   = english_classes
        context['bilingual_classes'] = bilingual_classes
        context['french_classes']    = french_classes

        # Summary stats
        context['total_students']      = sum(c.student_count for c in all_classes)
        context['english_count']       = sum(c.student_count for c in english_classes)
        context['unassigned_teachers'] = sum(
            1 for c in all_classes if not c.class_teacher_id
        )

        return context


class ClassDetailView(LoginRequiredMixin, DetailView):
    """View class details with teachers and students"""
    model = SchoolClass
    template_name = 'academics/class_detail.html'
    context_object_name = 'class'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get students in this class
        students = Student.objects.filter(
            current_class=self.object
        ).order_by('first_name')
        context['students'] = students
        
        # Get all teachers for dropdown
        context['all_teachers'] = Staff.objects.filter(
            is_active=True,
            role__in=['teacher', 'class_teacher', 'subject_teacher']
        ).select_related('user').order_by('user__first_name')
        
        # Get all subjects
        context['all_subjects'] = Subject.objects.all().order_by('name')
        
        # Get teachers for this class (through subject assignments)
        teacher_assignments = ClassSubject.objects.filter(
            school_class=self.object
        ).select_related('subject', 'teacher__user')
        
        # Group by teacher
        teachers_dict = {}
        for assignment in teacher_assignments:
            if assignment.teacher:
                teacher_id = assignment.teacher.id
                if teacher_id not in teachers_dict:
                    teachers_dict[teacher_id] = {
                        'teacher': assignment.teacher,
                        'subjects': [],
                        'assignments': []
                    }
                teachers_dict[teacher_id]['subjects'].append(assignment.subject)
                teachers_dict[teacher_id]['assignments'].append(assignment)
        
        context['teachers'] = list(teachers_dict.values())
        
        # Class teacher (homeroom teacher)
        if self.object.class_teacher:
            context['class_teacher'] = self.object.class_teacher
        
        # Today's attendance
        today = date.today()
        today_attendance = Attendance.objects.filter(
            school_class=self.object,
            date=today
        )
        context['today_attendance'] = today_attendance.count()
        
        if students.count() > 0:
            present_count = today_attendance.filter(status='present').count()
            context['attendance_rate'] = round((present_count / students.count()) * 100, 1)
        else:
            context['attendance_rate'] = 0
        
        # Statistics
        context['total_students'] = students.count()
        context['total_subjects'] = teacher_assignments.count()
        context['total_teachers'] = len(teachers_dict)
        
        return context


class ClassStudentsView(LoginRequiredMixin, DetailView):
    """View students in a class"""
    model = SchoolClass
    template_name = 'academics/class_students.html'
    context_object_name = 'class'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['students'] = Student.objects.filter(
            current_class=self.object
        ).order_by('first_name')
        return context


# ========== SUBJECT VIEWS ==========

class ClassCreateView(ManagementRequiredMixin, CreateView):
    permission_denied_message = "Only administrators can create classes."
    """Add a new school class"""
    model = SchoolClass
    fields = ['name', 'code', 'level', 'section', 'section_type', 'capacity', 'room_number', 'academic_year', 'class_teacher']
    template_name = 'academics/class_form.html'
    success_url = reverse_lazy('academics:class_list')

class ClassUpdateView(ManagementRequiredMixin, UpdateView):
    permission_denied_message = "Only administrators can edit classes."
    """Edit an existing school class"""
    model = SchoolClass
    fields = ['name', 'code', 'level', 'section', 'section_type', 'capacity', 'room_number', 'academic_year', 'class_teacher']
    template_name = 'academics/class_form.html'

    def get_success_url(self):
        return reverse_lazy('academics:class_detail', kwargs={'pk': self.object.pk})


class SubjectListView(LoginRequiredMixin, ListView):
    """List all subjects"""
    model = Subject
    template_name = 'academics/subject_list.html'
    context_object_name = 'subjects'
    
    def get_queryset(self):
        return Subject.objects.all().order_by('category', 'name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Subject.SUBJECT_CATEGORY_CHOICES
        return context


class SubjectDetailView(LoginRequiredMixin, DetailView):
    """View subject details"""
    model = Subject
    template_name = 'academics/subject_detail.html'
    context_object_name = 'subject'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get classes where this subject is taught
        context['class_assignments'] = ClassSubject.objects.filter(
            subject=self.object
        ).select_related('school_class', 'teacher')
        
        return context


class SubjectCreateView(ManagementRequiredMixin, CreateView):
    permission_denied_message = "Only administrators can manage subjects."
    """Create a new subject"""
    model = Subject
    fields = ['code', 'name', 'name_fr', 'category', 'description']
    template_name = 'academics/subject_form.html'
    success_url = reverse_lazy('academics:subject_list')

    def form_valid(self, form):
        messages.success(self.request, f'Subject "{form.instance.name}" created successfully!')
        return super().form_valid(form)


# ========== TEACHER ASSIGNMENT VIEWS ==========

from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required

@login_required
@require_POST
def assign_teacher(request, class_id):
    """Assign a teacher to teach a subject in a class"""
    try:
        school_class = get_object_or_404(SchoolClass, id=class_id)
        teacher_id = request.POST.get('teacher_id')
        subject_id = request.POST.get('subject_id')
        hours = request.POST.get('hours_per_week', 2)
        
        if not teacher_id or not subject_id:
            messages.error(request, 'Please select both teacher and subject')
            return redirect('academics:class_detail', pk=class_id)
        
        teacher = get_object_or_404(Staff, id=teacher_id)
        subject = get_object_or_404(Subject, id=subject_id)
        
        # Check if assignment already exists
        assignment, created = ClassSubject.objects.get_or_create(
            school_class=school_class,
            subject=subject,
            defaults={
                'teacher': teacher,
                'hours_per_week': hours
            }
        )
        
        if not created:
            # Update existing assignment
            assignment.teacher = teacher
            assignment.hours_per_week = hours
            assignment.save()
            message = f"✅ Updated: {teacher.user.get_full_name()} now teaches {subject.name}"
        else:
            message = f"✅ Assigned: {teacher.user.get_full_name()} to teach {subject.name}"
        
        messages.success(request, message)
        
    except Staff.DoesNotExist:
        messages.error(request, f"Teacher with ID {teacher_id} not found")
    except Subject.DoesNotExist:
        messages.error(request, f"Subject with ID {subject_id} not found")
    except Exception as e:
        messages.error(request, f"Error: {str(e)}")
    
    return redirect('academics:class_detail', pk=class_id)


@login_required
def get_teachers_for_class(request, class_id):
    """API endpoint to get current teacher assignments for a class"""
    try:
        school_class = get_object_or_404(SchoolClass, id=class_id)
        assignments = ClassSubject.objects.filter(
            school_class=school_class
        ).select_related('teacher__user', 'subject')
        
        data = []
        for assignment in assignments:
            if assignment.teacher:
                data.append({
                    'id': assignment.id,
                    'teacher_id': assignment.teacher.id,
                    'teacher_name': assignment.teacher.user.get_full_name(),
                    'subject': assignment.subject.name,
                    'subject_id': assignment.subject.id,
                    'hours': assignment.hours_per_week
                })
        
        return JsonResponse({
            'success': True, 
            'data': data,
            'count': len(data)
        })
        
    except SchoolClass.DoesNotExist:
        return JsonResponse({'success': False, 'error': 'Class not found'})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})


@login_required
@require_POST
def remove_teacher_assignment(request, assignment_id):
    """Remove a teacher-subject-class assignment"""
    try:
        assignment = get_object_or_404(ClassSubject, id=assignment_id)
        class_id = assignment.school_class.id
        subject_name = assignment.subject.name
        teacher_name = assignment.teacher.user.get_full_name() if assignment.teacher else "Unknown"
        
        assignment.delete()
        messages.success(request, f"✅ Removed {teacher_name} from teaching {subject_name}")
        
    except Exception as e:
        messages.error(request, f"Error removing assignment: {str(e)}")
        class_id = request.POST.get('class_id')
    
    return redirect('academics:class_detail', pk=class_id)


@login_required
def bulk_assign_teachers(request, class_id):
    """Bulk assign multiple teachers to a class"""
    if request.method == 'POST':
        # This can be expanded later for CSV upload or multi-select
        messages.info(request, "Bulk assignment feature coming soon!")
        return redirect('academics:class_detail', pk=class_id)
    
    return JsonResponse({'success': False, 'error': 'Method not allowed'})


@login_required
def assign_class_teacher(request, class_id):
    """Assign or change the homeroom/class teacher for a class (SchoolClass.class_teacher FK)"""
    school_class = get_object_or_404(SchoolClass, id=class_id)

    if request.method == 'POST':
        teacher_id = request.POST.get('teacher_id')
        if teacher_id == '' or teacher_id is None:
            # Allow clearing the assignment
            old_name = school_class.class_teacher.user.get_full_name() if school_class.class_teacher else None
            school_class.class_teacher = None
            school_class.save()
            if old_name:
                messages.success(request, f"Removed {old_name} as class teacher for {school_class.name}.")
            return redirect('academics:class_detail', pk=class_id)

        teacher = get_object_or_404(Staff, id=teacher_id)
        school_class.class_teacher = teacher
        school_class.save()
        messages.success(request, f"✅ {teacher.user.get_full_name()} is now the class teacher for {school_class.name}.")
        return redirect('academics:class_detail', pk=class_id)

    # GET — show the assignment form
    teachers = Staff.objects.filter(
        role__in=['teacher', 'class_teacher'],
        is_active=True
    ).select_related('user').order_by('user__first_name')
    return render(request, 'academics/assign_class_teacher.html', {
        'school_class': school_class,
        'teachers': teachers,
        'current_teacher': school_class.class_teacher,
    })


# ========== ATTENDANCE VIEWS ==========

class AttendanceListView(LoginRequiredMixin, ListView):
    """List attendance records"""
    model = Attendance
    template_name = 'academics/attendance/list.html'
    context_object_name = 'attendances'
    paginate_by = 50
    
    def get_queryset(self):
        queryset = Attendance.objects.all().select_related(
            'student', 'school_class', 'marked_by__user'
        )
        
        # Filter by date
        date_filter = self.request.GET.get('date')
        if date_filter:
            queryset = queryset.filter(date=date_filter)
        else:
            queryset = queryset.filter(date=date.today())
        
        # Filter by class
        class_filter = self.request.GET.get('class')
        if class_filter:
            queryset = queryset.filter(school_class_id=class_filter)
        
        # Filter by status
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        return queryset.order_by('-date', 'school_class', 'student__first_name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['classes'] = SchoolClass.objects.all()
        context['today'] = date.today()
        return context


class AttendanceMarkingView(TeacherRequiredMixin, TemplateView):
    """Mark attendance for a class - Teacher Friendly"""
    template_name = 'academics/attendance/mark.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # If teacher is logged in, show only their classes
        if hasattr(self.request.user, 'staff_profile') and self.request.user.staff_profile.is_teacher:
            teacher = self.request.user.staff_profile
            # Classes via subject assignments (ClassSubject)
            subject_class_ids = ClassSubject.objects.filter(
                teacher=teacher
            ).values_list('school_class', flat=True)
            # Classes where this teacher is the assigned class teacher (SchoolClass.class_teacher)
            homeroom_class_ids = SchoolClass.objects.filter(
                class_teacher=teacher
            ).values_list('id', flat=True)
            # Union both sources
            from django.db.models import Q
            context['classes'] = SchoolClass.objects.filter(
                Q(id__in=subject_class_ids) | Q(id__in=homeroom_class_ids)
            ).distinct().order_by('level', 'section')
        else:
            context['classes'] = SchoolClass.objects.all()
        
        context['today'] = date.today()
        
        class_id = self.request.GET.get('class')
        if class_id:
            selected_class = get_object_or_404(SchoolClass, id=class_id)
            context['selected_class'] = selected_class
            
            # Get students in this class
            students = Student.objects.filter(
                current_class=selected_class,
                status='active'
            ).order_by('first_name')
            context['students'] = students
            
            # Get today's attendance
            attendance_today = Attendance.objects.filter(
                date=date.today(),
                school_class=selected_class
            )
            
            # Create a dictionary for quick lookup
            attendance_dict = {}
            for att in attendance_today:
                attendance_dict[att.student_id] = att.status
            
            context['attendance_dict'] = attendance_dict
            
            # Check if attendance already taken
            context['attendance_taken'] = attendance_today.exists()
        
        return context
    
    def post(self, request, *args, **kwargs):
        class_id = request.POST.get('class_id')
        if not class_id:
            messages.error(request, 'Please select a class')
            return redirect('attendance:mark_attendance')
        
        selected_class = get_object_or_404(SchoolClass, id=class_id)
        students = Student.objects.filter(current_class=selected_class, status='active')
        
        marked_count = 0
        for student in students:
            status = request.POST.get(f'status_{student.id}')
            
            if status:
                attendance, created = Attendance.objects.update_or_create(
                    student=student,
                    date=date.today(),
                    defaults={
                        'school_class': selected_class,
                        'status': status,
                        'marked_by': request.user.staff_profile if hasattr(request.user, 'staff_profile') else None
                    }
                )
                marked_count += 1
        
        messages.success(request, f'✅ Attendance marked for {marked_count} students in {selected_class.name}')
        
        # If teacher, redirect back to their dashboard
        if hasattr(request.user, 'staff_profile') and request.user.staff_profile.is_teacher:
            return redirect('staff:teacher_dashboard')
        
        return redirect(f'/attendance/mark/?class={class_id}')


class AttendanceReportView(TeacherRequiredMixin, TemplateView):
    """View attendance reports"""
    template_name = 'academics/attendance/report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get filter parameters
        from_date = self.request.GET.get('from_date')
        to_date = self.request.GET.get('to_date')
        class_id = self.request.GET.get('class')
        
        # Default to current month
        if not from_date:
            from_date = date.today().replace(day=1)
        if not to_date:
            to_date = date.today()
        
        context['classes'] = SchoolClass.objects.all()
        context['from_date'] = from_date
        context['to_date'] = to_date
        
        # Build stats
        stats = []
        classes = SchoolClass.objects.all()
        if class_id:
            classes = classes.filter(id=class_id)
        
        for cls in classes:
            # Get attendance records for this class in date range
            attendances = Attendance.objects.filter(
                school_class=cls,
                date__gte=from_date,
                date__lte=to_date
            )
            
            total = attendances.count()
            if total > 0:
                present = attendances.filter(status='present').count()
                absent = attendances.filter(status='absent').count()
                late = attendances.filter(status='late').count()
                excused = attendances.filter(status='excused').count()
                
                stats.append({
                    'class': cls.name,
                    'total': total,
                    'present': present,
                    'absent': absent,
                    'late': late,
                    'excused': excused,
                    'rate': round((present / total) * 100, 1) if total > 0 else 0
                })
        
        context['stats'] = stats
        
        # Summary stats
        if stats:
            context['total_records'] = sum(s['total'] for s in stats)
            context['total_present'] = sum(s['present'] for s in stats)
            context['overall_rate'] = round(
                (context['total_present'] / context['total_records']) * 100,
                1
            ) if context['total_records'] > 0 else 0
        
        return context


class StudentAttendanceView(LoginRequiredMixin, DetailView):
    """View attendance for a specific student"""
    model = Student
    template_name = 'academics/attendance/student.html'
    context_object_name = 'student'
    
    def get_object(self):
        return get_object_or_404(Student, id=self.kwargs['student_id'])
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get attendance for this student
        attendances = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:60]  # Last 60 days
        
        context['attendances'] = attendances
        
        # Calculate stats
        total = attendances.count()
        if total > 0:
            present = attendances.filter(status='present').count()
            context['attendance_rate'] = round((present / total) * 100, 1)
            context['total_days'] = total
            context['present_days'] = present
            context['absent_days'] = attendances.filter(status='absent').count()
            context['late_days'] = attendances.filter(status='late').count()
        
        return context


# ========== API ENDPOINTS ==========

def get_today_attendance(request):
    """API endpoint for today's attendance"""
    today = date.today()
    total = Attendance.objects.filter(date=today).count()
    present = Attendance.objects.filter(date=today, status='present').count()
    
    return JsonResponse({
        'date': today,
        'total': total,
        'present': present,
        'absent': total - present,
        'rate': round((present / total) * 100, 1) if total > 0 else 0
    })


def get_class_stats(request, class_id):
    """API endpoint for class statistics"""
    school_class = get_object_or_404(SchoolClass, id=class_id)
    
    stats = {
        'class': school_class.name,
        'total_students': Student.objects.filter(current_class=school_class).count(),
        'subjects': ClassSubject.objects.filter(school_class=school_class).count(),
        'today_attendance': Attendance.objects.filter(
            school_class=school_class,
            date=date.today()
        ).count(),
    }
    
    return JsonResponse(stats)

======================================================================
FILE: academics/templatetags/academics_tags.py
======================================================================
# academics/templatetags/academics_tags.py
from django import template

register = template.Library()

@register.filter
def get_item(dictionary, key):
    """Get dictionary item by key"""
    if dictionary and isinstance(dictionary, dict):
        return dictionary.get(key)
    return None


######################################################################
# APP: API
######################################################################

======================================================================
FILE: api/__init__.py
======================================================================
# api/__init__.py
# This file makes Python treat the directory as a package

======================================================================
FILE: api/admin.py
======================================================================
from django.contrib import admin

# Register your models here.


======================================================================
FILE: api/apps.py
======================================================================
from django.apps import AppConfig


class ApiConfig(AppConfig):
    name = 'api'


======================================================================
FILE: api/models.py
======================================================================
from django.db import models

# Create your models here.


======================================================================
FILE: api/serializers.py
======================================================================
# api/serializers.py
from rest_framework import serializers
from students.models import Student, ParentGuardian
from academics.models import SchoolClass, Subject, Attendance
from finance.models import FeeStructure, Invoice, Payment
from staff.models import Staff

class StudentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = '__all__'

class StaffSerializer(serializers.ModelSerializer):
    full_name = serializers.SerializerMethodField()
    
    class Meta:
        model = Staff
        fields = ['id', 'employee_id', 'full_name', 'role', 'department', 'phone_number', 'email']
    
    def get_full_name(self, obj):
        return obj.user.get_full_name()

class SchoolClassSerializer(serializers.ModelSerializer):
    class Meta:
        model = SchoolClass
        fields = '__all__'

class InvoiceSerializer(serializers.ModelSerializer):
    student_name = serializers.SerializerMethodField()
    
    class Meta:
        model = Invoice
        fields = '__all__'
    
    def get_student_name(self, obj):
        return str(obj.student)

======================================================================
FILE: api/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: api/urls.py
======================================================================
# api/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register(r'students', views.StudentViewSet)
router.register(r'staff', views.StaffViewSet)
router.register(r'classes', views.ClassViewSet)
router.register(r'invoices', views.InvoiceViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('dashboard/', views.DashboardStats.as_view(), name='api_dashboard'),
    path('auth/', include('rest_framework.urls')),
]

======================================================================
FILE: api/views.py
======================================================================
# api/views.py
from rest_framework import viewsets, permissions, generics
from rest_framework.response import Response
from rest_framework.views import APIView
from django.db.models import Count, Sum
from datetime import date

from students.models import Student
from staff.models import Staff
from academics.models import SchoolClass, Attendance
from finance.models import Invoice, Payment
from .serializers import (
    StudentSerializer, StaffSerializer, 
    SchoolClassSerializer, InvoiceSerializer
)

class StudentViewSet(viewsets.ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer
    permission_classes = [permissions.IsAuthenticated]

class StaffViewSet(viewsets.ModelViewSet):
    queryset = Staff.objects.all()
    serializer_class = StaffSerializer
    permission_classes = [permissions.IsAuthenticated]

class ClassViewSet(viewsets.ModelViewSet):
    queryset = SchoolClass.objects.all()
    serializer_class = SchoolClassSerializer
    permission_classes = [permissions.IsAuthenticated]

class InvoiceViewSet(viewsets.ModelViewSet):
    queryset = Invoice.objects.all()
    serializer_class = InvoiceSerializer
    permission_classes = [permissions.IsAuthenticated]

class DashboardStats(APIView):
    permission_classes = [permissions.IsAuthenticated]
    
    def get(self, request):
        data = {
            'total_students': Student.objects.count(),
            'total_staff': Staff.objects.count(),
            'total_classes': SchoolClass.objects.count(),
            'today_attendance': Attendance.objects.filter(date=date.today()).count(),
            'pending_invoices': Invoice.objects.filter(status='pending').count(),
            'total_revenue': Payment.objects.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0,
        }
        return Response(data)


######################################################################
# APP: BACKEND
######################################################################

======================================================================
FILE: backend/__init__.py
======================================================================


======================================================================
FILE: backend/asgi.py
======================================================================
"""
ASGI config for backend project.

It exposes the ASGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')

application = get_asgi_application()


======================================================================
FILE: backend/settings.py
======================================================================
"""
Django settings for school management system.
"""
import os
from pathlib import Path
from decouple import config, Csv

BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY  = '[REDACTED]'
DEBUG = config('DEBUG', default=True, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='127.0.0.1,localhost', cast=Csv())

# Application definition
INSTALLED_APPS = [
    'jazzmin',  # Must be before django.contrib.admin
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # Local apps - Use FULL path from manage.py
    'core',
    'students',
    'staff',
    'academics',
    'finance',
    'communication',
    'parents',
    'reports',
    'api',
    'sync',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'backend.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'templates'),  # Add this line
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'core.context_processors.permissions',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'backend.wsgi.application'

# Database
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

# Password validation
AUTH_PASSWORD_VALIDATORS  = '[REDACTED]'
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True

# Static files (CSS, JavaScript, Images)
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')  # For production
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),  # Your custom static directory
]

# Media files (Uploaded files)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

# Default primary key field type
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# Add at the bottom of the file
LOGIN_URL = 'staff:login'  # Where to redirect if not logged in
LOGIN_REDIRECT_URL = 'staff:teacher_dashboard'  # Where teachers go after login
LOGOUT_REDIRECT_URL = 'home'  # Where to go after logout


# 1. Update settings to use custom user model
# Add this to backend/settings.py:
AUTH_USER_MODEL = 'core.CustomUser'

# Jazzmin settings
JAZZMIN_SETTINGS = {
    "site_title": "Rapha-Bethel BNPS",
    "site_header": "Rapha-Bethel",
    "site_brand": "Rapha-Bethel BNPS",
    "site_logo": "admin/img/logo-yellow.jpeg",
    "login_logo": "admin/img/Rapha-Bethel-Logo1.png",
    "login_logo_css": "max-height: 20px; width: auto;", # Adjust height and width as needed
    "welcome_sign": "Welcome to Rapha-Bethel BNPS School Management",
    "copyright": "Vi-2s-Dk Foundation",
    "search_model": ["students.Student", "academics.SchoolClass"],
    "topmenu_links": [
        {"name": "Dashboard", "url": "admin:index", "permissions": ["auth.view_user"]},
        {"name": "Staff Portal", "url": "/staff/dashboard/", "new_window": False},
        {"name": "School Website", "url": "https://RaphaBethel.org/BNPS", "new_window": True},
    ],
    "show_sidebar": True,
    "navigation_expanded": True,
    "icons": {
        "auth": "fas fa-users-cog",
        "auth.user": "fas fa-user",
        "auth.Group": "fas fa-users",
        "students.Student": "fas fa-user-graduate",
        "students.ParentGuardian": "fas fa-user-friends",
        "academics.SchoolClass": "fas fa-chalkboard-teacher",
        "academics.Attendance": "fas fa-clipboard-check",
        "finance.FeeStructure": "fas fa-money-bill-wave",
        "finance.Invoice": "fas fa-file-invoice",
        "communication.Announcement": "fas fa-bullhorn",
    },
    "default_icon_parents": "fas fa-chevron-circle-right",
    "default_icon_children": "fas fa-circle",
}

======================================================================
FILE: backend/settings_production.py
======================================================================
"""
Production settings for Rapha-Bethel BNPS
InMotion Hosting — cPanel / Passenger WSGI
Domain: https://raphabethel.org/portal
"""
import os
from pathlib import Path
from decouple import config, Csv

BASE_DIR = Path(__file__).resolve().parent.parent

# This tells Django all URLs are prefixed with /portal
FORCE_SCRIPT_NAME = '/portal'

SECRET_KEY  = '[REDACTED]'
DEBUG = False
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='raphabethel.org,www.raphabethel.org', cast=Csv())

INSTALLED_APPS = [
    'jazzmin',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'core',
    'students',
    'staff',
    'academics',
    'finance',
    'communication',
    'parents',
    'reports',
    'api',
    'sync',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',   # serves static files in production
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'backend.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'core.context_processors.permissions',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'backend.wsgi.application'

# ── MySQL (InMotion cPanel database) ────────────────────────────
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME':     config('DB_NAME',     default='dnjill5_bnps'),
        'USER':     config('DB_USER',     default='dnjill5_bnps'),
        'PASSWORD': config('DB_PASSWORD'),
        'HOST':     config('DB_HOST',     default='localhost'),
        'PORT':     config('DB_PORT',     default='3306'),
        'OPTIONS': {
            'charset': 'utf8mb4',
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }
}

AUTH_PASSWORD_VALIDATORS  = '[REDACTED]'
    {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
    {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
    {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
    {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Africa/Douala'
USE_I18N = True
USE_TZ = True

# ── Static & Media ───────────────────────────────────────────────
STATIC_URL  = '/portal/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
# STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedStaticFilesStorage'

# This prevents the "MissingFileError" during collectstatic
WHITENOISE_MANIFEST_STRICT = False

MEDIA_URL  = '/portal/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
AUTH_USER_MODEL = 'core.CustomUser'

LOGIN_URL             = 'staff:login'
LOGIN_REDIRECT_URL    = 'staff:teacher_dashboard'
LOGOUT_REDIRECT_URL   = 'home'

# ── Security (HTTPS) ────────────────────────────────────────────
SECURE_PROXY_SSL_HEADER      = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT          = True
SESSION_COOKIE_SECURE        = True
CSRF_COOKIE_SECURE           = True
SECURE_HSTS_SECONDS          = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_BROWSER_XSS_FILTER    = True
X_FRAME_OPTIONS              = 'SAMEORIGIN'   # needed for Django admin iframes

# ── Jazzmin ─────────────────────────────────────────────────────
JAZZMIN_SETTINGS = {
    "site_title":    "Rapha-Bethel BNPS",
    "site_header":   "Rapha-Bethel",
    "site_brand":    "Rapha-Bethel BNPS",
    "site_logo":     "admin/img/logo-yellow.jpeg",
    "login_logo":    "admin/img/Rapha-Bethel-Logo1.png",
    "welcome_sign":  "Welcome to Rapha-Bethel BNPS School Management",
    "copyright":     "Vi-2s-Dk Foundation",
    "search_model":  ["students.Student", "academics.SchoolClass"],
    "topmenu_links": [
        {"name": "Dashboard",    "url": "admin:index", "permissions": ["auth.view_user"]},
        {"name": "Staff Portal", "url": "/portal", "new_window": False},
        {"name": "School Website", "url": "https://RaphaBethel.org/BNPS", "new_window": True},
    ],
    "show_sidebar": True,
    "navigation_expanded": True,
    "icons": {
        "auth":                     "fas fa-users-cog",
        "auth.user":                "fas fa-user",
        "auth.Group":               "fas fa-users",
        "students.Student":         "fas fa-user-graduate",
        "students.ParentGuardian":  "fas fa-user-friends",
        "academics.SchoolClass":    "fas fa-chalkboard-teacher",
        "academics.Attendance":     "fas fa-clipboard-check",
        "finance.FeeStructure":     "fas fa-money-bill-wave",
        "finance.Invoice":          "fas fa-file-invoice",
        "communication.Announcement": "fas fa-bullhorn",
    },
    "default_icon_parents":  "fas fa-chevron-circle-right",
    "default_icon_children": "fas fa-circle",
}

======================================================================
FILE: backend/urls-1.py
======================================================================
# backend/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from core.views import HomeView, DashboardView
urlpatterns = [
    # Home & Dashboard
    path('', HomeView.as_view(), name='home'),
    path('dashboard/', DashboardView.as_view(), name='dashboard'),    
    # Students
    path('students/', include('students.urls')),
    # Staff
    path('staff/', include('staff.urls')),    
    # Academics
    path('academics/', include('academics.urls')),
    path('attendance/', include('academics.attendance_urls')),  # THIS LINE IS CRITICAL
    # path('attendance/', include('academics.urls_attendance')),
    # Finance
    path('finance/', include('finance.urls')),    
    # Parents
    path('parents/', include('parents.urls')),    
    # Reports
    path('reports/', include('reports.urls')),    
    # Communication
    path('communication/', include('communication.urls')),    
    # Admin
    path('admin/', admin.site.urls), ]
if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

======================================================================
FILE: backend/urls.py
======================================================================
# backend/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from core.views import HomeView, DashboardView
urlpatterns = [
    # Home & Dashboard
    path('', HomeView.as_view(), name='home'),
    path('dashboard/', DashboardView.as_view(), name='dashboard'),    
    # Students
    path('students/', include('students.urls')),
    # Staff
    path('staff/', include('staff.urls')),    
    # Academics
    path('academics/', include('academics.urls')),
    path('attendance/', include('academics.attendance_urls')),  # THIS LINE IS CRITICAL
    # path('attendance/', include('academics.urls_attendance')),
    # Finance
    path('finance/', include('finance.urls')),    
    # Parents
    path('parents/', include('parents.urls')),    
    # Reports
    path('reports/', include('reports.urls')),    
    # Communication
    path('communication/', include('communication.urls')),
    # API
    path('api/', include('api.urls')),
    # Admin
    path('admin/', admin.site.urls), ]
if settings.DEBUG:
    import os
    # Serve from the actual static source dir during development
    static_source = settings.STATICFILES_DIRS[0] if settings.STATICFILES_DIRS else settings.STATIC_ROOT
    urlpatterns += static(settings.STATIC_URL, document_root=static_source)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

======================================================================
FILE: backend/urls_production.py
======================================================================
# backend/urls.py  (production-ready — works at /school/ sub-path)
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from core.views import HomeView, DashboardView

urlpatterns = [
    path('', HomeView.as_view(), name='home'),
    path('dashboard/', DashboardView.as_view(), name='dashboard'),
    path('students/', include('students.urls')),
    path('staff/', include('staff.urls')),
    path('academics/', include('academics.urls')),
    path('attendance/', include('academics.attendance_urls')),
    path('finance/', include('finance.urls')),
    path('parents/', include('parents.urls')),
    path('reports/', include('reports.urls')),
    path('communication/', include('communication.urls')),
    path('api/', include('api.urls')),
    path('admin/', admin.site.urls),
]

# Serve media files via Django — required on InMotion shared hosting
# where Apache cannot be configured to serve /portal/media/ directly
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

handler403 = 'core.views.handler_403'
handler404 = 'core.views.handler_404'

======================================================================
FILE: backend/wsgi.py
======================================================================
"""
WSGI config for backend project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/
"""

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')

application = get_wsgi_application()



######################################################################
# APP: COMMUNICATION
######################################################################

======================================================================
FILE: communication/__init__.py
======================================================================


======================================================================
FILE: communication/admin.py
======================================================================
# communication/admin.py
from django.contrib import admin
from .models import SMSMessage, Announcement

@admin.register(SMSMessage)
class SMSMessageAdmin(admin.ModelAdmin):
    list_display = ['message_type', 'message', 'status', 'sent_time']
    list_filter = ['message_type', 'status']
    search_fields = ['message']

@admin.register(Announcement)
class AnnouncementAdmin(admin.ModelAdmin):
    list_display = ['title', 'audience', 'priority', 'publish_date', 'is_published']
    list_filter = ['audience', 'priority', 'is_published']
    search_fields = ['title', 'content']
    date_hierarchy = 'publish_date'

======================================================================
FILE: communication/apps.py
======================================================================
# communication/apps.py
from django.apps import AppConfig

class CommunicationConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'communication'
    verbose_name = 'Communication'

======================================================================
FILE: communication/forms.py
======================================================================
# communication/forms.py
from django import forms
from .models import Announcement, SMSMessage

class AnnouncementForm(forms.ModelForm):
    class Meta:
        model = Announcement
        fields = ['title', 'content', 'audience', 'priority', 'publish_date', 'is_published']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
            'audience': forms.Select(attrs={'class': 'form-control'}),
            'priority': forms.Select(attrs={'class': 'form-control'}),
            'publish_date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
        }

class SMSComposeForm(forms.Form):
    message_type = forms.ChoiceField(choices=SMSMessage.MESSAGE_TYPE_CHOICES, widget=forms.Select(attrs={'class': 'form-control'}))
    message = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3}))
    recipients = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)

======================================================================
FILE: communication/models.py
======================================================================
# communication/models.py
"""
Models for school communication including SMS and announcements.
"""
from django.db import models
from django.utils.translation import gettext_lazy as _


class SMSMessage(models.Model):
    """
    Represents an SMS message sent to parents or staff.
    
    This model tracks SMS communications, including message type,
    content, recipients, and delivery status. It supports bulk messaging
    to multiple phone numbers.
    
    Attributes:
        message_type (str): Type of message from MESSAGE_TYPE_CHOICES
        message (str): The SMS text content
        phone_numbers (list): JSON list of recipient phone numbers
        status (str): Delivery status from STATUS_CHOICES
        sent_time (datetime): When the message was sent
    """
    
    MESSAGE_TYPE_CHOICES = [
        ('attendance', _('Attendance Alert')),
        ('fee_reminder', _('Fee Reminder')),
        ('exam', _('Exam Notice')),
        ('meeting', _('Parent Meeting')),
        ('emergency', _('Emergency Alert')),
        ('general', _('General Announcement')),
    ]
    
    STATUS_CHOICES = [
        ('draft', _('Draft')),
        ('sent', _('Sent')),
        ('failed', _('Failed')),
    ]
    
    message_type = models.CharField(
        max_length=20, 
        choices=MESSAGE_TYPE_CHOICES
    )
    message = models.TextField()
    phone_numbers = models.JSONField(
        default=list
    )
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='draft'
    )
    sent_time = models.DateTimeField(
        null=True, 
        blank=True
    )
    
    class Meta:
        verbose_name = "SMS Message"
        verbose_name_plural = "SMS Messages"
        ordering = ['-sent_time']
    
    def __str__(self):
        """Return string representation of the SMS message."""
        if self.sent_time:
            return f"{self.get_message_type_display()} - {self.sent_time.date()}"
        return f"{self.get_message_type_display()} - Draft"
    
    def recipient_count(self):
        """
        Get the number of recipients for this message.
        
        Returns:
            int: Number of phone numbers in the recipients list.
        """
        return len(self.phone_numbers)


class Announcement(models.Model):
    """
    Represents an announcement posted to the school community.
    
    Announcements can be targeted to specific audiences (all, students,
    parents, teachers) and have different priority levels. They can be
    published immediately or saved as drafts.
    
    Attributes:
        title (str): Announcement title
        content (str): Full announcement text
        audience (str): Target audience from AUDIENCE_CHOICES
        priority (str): Priority level from PRIORITY_CHOICES
        publish_date (date): When the announcement should be published
        is_published (bool): Whether the announcement is live
    """
    
    PRIORITY_CHOICES = [
        ('low', _('Low')),
        ('normal', _('Normal')),
        ('high', _('High')),
        ('urgent', _('Urgent')),
    ]
    
    AUDIENCE_CHOICES = [
        ('all', _('Everyone')),
        ('students', _('Students')),
        ('parents', _('Parents')),
        ('teachers', _('Teachers')),
    ]
    
    title = models.CharField(
        max_length=200
    )
    content = models.TextField()
    audience = models.CharField(
        max_length=20, 
        choices=AUDIENCE_CHOICES, 
        default='all'
    )
    priority = models.CharField(
        max_length=20, 
        choices=PRIORITY_CHOICES, 
        default='normal'
    )
    publish_date = models.DateField()
    is_published = models.BooleanField(
        default=True
    )
    
    class Meta:
        ordering = ['-publish_date', '-priority']
        verbose_name = "Announcement"
        verbose_name_plural = "Announcements"
    
    def __str__(self):
        """Return the announcement title."""
        return self.title
    
    def days_until_publish(self):
        """
        Calculate days until the announcement is published.
        
        Returns:
            int: Days until publish date (negative if already published).
        """
        from django.utils import timezone
        delta = self.publish_date - timezone.now().date()
        return delta.days

======================================================================
FILE: communication/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: communication/urls-1.py
======================================================================
# communication/urls.py
from django.urls import path
from . import views

app_name = 'communication'

urlpatterns = [
    # Announcements
    path('announcements/', views.AnnouncementListView.as_view(), name='announcement_list'),
    path('announcements/<int:pk>/', views.AnnouncementDetailView.as_view(), name='announcement_detail'),
    
    # SMS
    path('sms/', views.SMSMessageListView.as_view(), name='sms_list'),
    path('sms/compose/', views.SMSComposeView.as_view(), name='sms_compose'),
    path('sms/<int:pk>/', views.SMSMessageDetailView.as_view(), name='sms_detail'),
    
    # Parent Communication
    path('parents/', views.ParentCommunicationView.as_view(), name='parent_communication'),
    path('parents/<int:parent_id>/send/', views.send_message_to_parent, name='send_parent_message'),
]

======================================================================
FILE: communication/urls.py
======================================================================
# communication/urls.py
from django.urls import path
from . import views

app_name = 'communication'

urlpatterns = [
    # Announcements
    path('announcements/', views.AnnouncementListView.as_view(), name='announcement_list'),
    path('announcements/create/', views.AnnouncementCreateView.as_view(), name='announcement_create'),
    path('announcements/<int:pk>/', views.AnnouncementDetailView.as_view(), name='announcement_detail'),
    path('announcements/<int:pk>/edit/', views.AnnouncementUpdateView.as_view(), name='announcement_edit'),
    path('announcements/<int:pk>/delete/', views.AnnouncementDeleteView.as_view(), name='announcement_delete'),
    
    # SMS
    path('sms/', views.SMSMessageListView.as_view(), name='sms_list'),
    path('sms/compose/', views.SMSComposeView.as_view(), name='sms_compose'),
    path('sms/<int:pk>/', views.SMSMessageDetailView.as_view(), name='sms_detail'),
    
    # Parent Communication
    path('parents/', views.ParentCommunicationView.as_view(), name='parent_communication'),
    path('parents/<int:parent_id>/send/', views.send_message_to_parent, name='send_parent_message'),
]

======================================================================
FILE: communication/views.py
======================================================================
# communication/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q
from django.http import JsonResponse, HttpResponse
from django.utils import timezone
import csv

from .models import SMSMessage, Announcement
from students.models import Student, ParentGuardian
from staff.models import Staff

# ========== ANNOUNCEMENT VIEWS ==========

class AnnouncementListView(LoginRequiredMixin, ListView):
    """List all announcements"""
    model = Announcement
    template_name = 'communication/announcements.html'
    context_object_name = 'announcements'
    paginate_by = 10
    
    def get_queryset(self):
        queryset = Announcement.objects.all()
        
        # Filter by audience
        audience = self.request.GET.get('audience')
        if audience:
            queryset = queryset.filter(audience=audience)
        
        # Filter by priority
        priority = self.request.GET.get('priority')
        if priority:
            queryset = queryset.filter(priority=priority)
        
        # Filter by published status
        published = self.request.GET.get('published')
        if published == 'published':
            queryset = queryset.filter(is_published=True)
        elif published == 'draft':
            queryset = queryset.filter(is_published=False)
        
        return queryset.order_by('-publish_date', '-priority')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['audience_choices'] = Announcement.AUDIENCE_CHOICES
        context['priority_choices'] = Announcement.PRIORITY_CHOICES
        context['published_count'] = Announcement.objects.filter(is_published=True).count()
        context['draft_count'] = Announcement.objects.filter(is_published=False).count()
        return context

class AnnouncementDetailView(LoginRequiredMixin, DetailView):
    """View announcement details"""
    model = Announcement
    template_name = 'communication/announcement_detail.html'
    context_object_name = 'announcement'

class AnnouncementCreateView(LoginRequiredMixin, CreateView):
    """Create a new announcement"""
    model = Announcement
    fields = ['title', 'content', 'audience', 'priority', 'publish_date', 'is_published']
    template_name = 'communication/announcement_form.html'
    success_url = reverse_lazy('communication:announcement_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Create New Announcement'
        return context
    
    def form_valid(self, form):
        messages.success(self.request, 'Announcement created successfully!')
        return super().form_valid(form)

class AnnouncementUpdateView(LoginRequiredMixin, UpdateView):
    """Update an announcement"""
    model = Announcement
    fields = ['title', 'content', 'audience', 'priority', 'publish_date', 'is_published']
    template_name = 'communication/announcement_form.html'
    success_url = reverse_lazy('communication:announcement_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit: {self.object.title}'
        return context
    
    def form_valid(self, form):
        messages.success(self.request, 'Announcement updated successfully!')
        return super().form_valid(form)

class AnnouncementDeleteView(LoginRequiredMixin, DeleteView):
    """Delete an announcement"""
    model = Announcement
    success_url = reverse_lazy('communication:announcement_list')
    template_name = 'communication/announcement_confirm_delete.html'
    
    def delete(self, request, *args, **kwargs):
        messages.success(request, 'Announcement deleted successfully!')
        return super().delete(request, *args, **kwargs)

def publish_announcement(request, pk):
    """Publish an announcement"""
    announcement = get_object_or_404(Announcement, pk=pk)
    announcement.is_published = True
    announcement.save()
    messages.success(request, f'Announcement "{announcement.title}" published.')
    return redirect('communication:announcement_detail', pk=pk)

def unpublish_announcement(request, pk):
    """Unpublish an announcement"""
    announcement = get_object_or_404(Announcement, pk=pk)
    announcement.is_published = False
    announcement.save()
    messages.success(request, f'Announcement "{announcement.title}" unpublished.')
    return redirect('communication:announcement_detail', pk=pk)

# ========== SMS MESSAGE VIEWS ==========

class SMSMessageListView(LoginRequiredMixin, ListView):
    """List all SMS messages"""
    model = SMSMessage
    template_name = 'communication/sms_list.html'
    context_object_name = 'messages'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = SMSMessage.objects.all()
        
        # Filter by message type
        msg_type = self.request.GET.get('type')
        if msg_type:
            queryset = queryset.filter(message_type=msg_type)
        
        # Filter by status
        status = self.request.GET.get('status')
        if status:
            queryset = queryset.filter(status=status)
        
        return queryset.order_by('-sent_time')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['message_types'] = SMSMessage.MESSAGE_TYPE_CHOICES
        context['status_choices'] = SMSMessage.STATUS_CHOICES
        return context

class SMSMessageDetailView(LoginRequiredMixin, DetailView):
    """View SMS message details"""
    model = SMSMessage
    template_name = 'communication/sms_detail.html'
    context_object_name = 'sms'

class SMSComposeView(LoginRequiredMixin, TemplateView):
    """Compose and send SMS messages"""
    template_name = 'communication/sms_compose.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get recipients based on type
        recipient_type = self.request.GET.get('recipient_type', 'all')
        
        if recipient_type == 'parents':
            context['recipients'] = ParentGuardian.objects.filter(receive_sms=True).select_related('student')
            context['recipient_count'] = ParentGuardian.objects.filter(receive_sms=True).count()
        elif recipient_type == 'staff':
            context['recipients'] = Staff.objects.filter(is_active=True)
            context['recipient_count'] = Staff.objects.filter(is_active=True).count()
        elif recipient_type == 'class':
            class_id = self.request.GET.get('class_id')
            if class_id:
                from academics.models import SchoolClass
                school_class = get_object_or_404(SchoolClass, pk=class_id)
                students = Student.objects.filter(current_class=school_class)
                context['recipients'] = ParentGuardian.objects.filter(student__in=students, receive_sms=True)
                context['recipient_count'] = context['recipients'].count()
                context['selected_class'] = school_class
        else:
            # All parents
            context['recipients'] = ParentGuardian.objects.filter(receive_sms=True)
            context['recipient_count'] = ParentGuardian.objects.filter(receive_sms=True).count()
        
        context['message_types'] = SMSMessage.MESSAGE_TYPE_CHOICES
        context['recipient_type'] = recipient_type
        
        return context
    
    def post(self, request, *args, **kwargs):
        message_type = request.POST.get('message_type')
        message = request.POST.get('message')
        recipient_ids = request.POST.getlist('recipients')
        
        if not message or not recipient_ids:
            messages.error(request, 'Please enter a message and select recipients.')
            return redirect('communication:sms_compose')
        
        # Get phone numbers
        recipients = ParentGuardian.objects.filter(id__in=recipient_ids)
        phone_numbers = [r.phone for r in recipients if r.phone]
        
        # Create SMS record
        sms = SMSMessage.objects.create(
            message_type=message_type,
            message=message,
            phone_numbers=phone_numbers,
            status='sent',
            sent_time=timezone.now()
        )
        
        # In a real app, you'd integrate with an SMS gateway here
        # For now, we'll just simulate sending
        
        messages.success(request, f'SMS sent to {len(phone_numbers)} recipients!')
        return redirect('communication:sms_detail', pk=sms.pk)

# ========== PARENT COMMUNICATION ==========

class ParentCommunicationView(LoginRequiredMixin, TemplateView):
    """Parent communication dashboard"""
    template_name = 'communication/parent_communication.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get students with parent contacts
        students = Student.objects.filter(status='active').prefetch_related('parents')
        
        parent_list = []
        for student in students:
            parents = student.parents.all()
            for parent in parents:
                parent_list.append({
                    'student': student,
                    'parent': parent,
                    'phone': parent.phone,
                    'email': parent.email,
                    'preferred_language': parent.preferred_language,
                    'receive_sms': parent.receive_sms
                })
        
        context['parents'] = parent_list
        context['total_parents'] = len(parent_list)
        
        return context

def send_message_to_parent(request, parent_id):
    """Send a message to a specific parent"""
    parent = get_object_or_404(ParentGuardian, pk=parent_id)
    
    if request.method == 'POST':
        message = request.POST.get('message')
        message_type = request.POST.get('message_type', 'general')
        
        if message and parent.phone:
            # Create SMS record
            sms = SMSMessage.objects.create(
                message_type=message_type,
                message=message,
                phone_numbers=[parent.phone],
                status='sent',
                sent_time=timezone.now()
            )
            
            messages.success(request, f'Message sent to {parent.get_full_name()}')
            return redirect('communication:sms_detail', pk=sms.pk)
    
    return render(request, 'communication/parent_message_form.html', {'parent': parent})

# ========== API ENDPOINTS ==========

def get_announcement_stats(request):
    """API endpoint for announcement statistics"""
    stats = {
        'total': Announcement.objects.count(),
        'published': Announcement.objects.filter(is_published=True).count(),
        'draft': Announcement.objects.filter(is_published=False).count(),
        'by_audience': list(Announcement.objects.values('audience').annotate(count=Count('id'))),
        'by_priority': list(Announcement.objects.values('priority').annotate(count=Count('id'))),
    }
    return JsonResponse(stats)

def get_sms_stats(request):
    """API endpoint for SMS statistics"""
    stats = {
        'total': SMSMessage.objects.count(),
        'sent': SMSMessage.objects.filter(status='sent').count(),
        'failed': SMSMessage.objects.filter(status='failed').count(),
        'by_type': list(SMSMessage.objects.values('message_type').annotate(count=Count('id'))),
    }
    return JsonResponse(stats)


######################################################################
# APP: CORE
######################################################################

======================================================================
FILE: core/__init__.py
======================================================================


======================================================================
FILE: core/admin.py
======================================================================
# core/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser, School

@admin.register(CustomUser)
class CustomUserAdmin(UserAdmin):
    list_display = ['username', 'email', 'first_name', 'last_name', 'user_type', 'is_staff']
    list_filter = ['user_type', 'is_staff', 'is_superuser']
    fieldsets = UserAdmin.fieldsets + (
        ('Additional Info', {'fields': ('user_type', 'phone', 'mobile_money_number', 
                                        'employee_id', 'access_level', 'oversees_section', 
                                        'financial_access', 'is_primary_contact')}),
    )

@admin.register(School)
class SchoolAdmin(admin.ModelAdmin):
    list_display = ['name', 'code', 'city', 'quarter', 'phone', 'principal_name']
    search_fields = ['name', 'code', 'city']

======================================================================
FILE: core/apps.py
======================================================================
from django.apps import AppConfig


class CoreConfig(AppConfig):
    name = 'core'


======================================================================
FILE: core/context_processors.py
======================================================================
# core/context_processors.py
"""
Injects permission helpers into every template context.
Usage in templates:  {% if perms_can.student_add %}  or  {{ user_role }}
"""
from core.permissions import can, get_role_level, SUPPORT_ROLES, TEACHER_ROLES, MANAGEMENT_ROLES


class _PermProxy:
    """Allows {{ perms_can.student_add }} syntax in templates."""
    def __init__(self, user):
        self._user = user

    def __getattr__(self, action):
        return can(self._user, action)

    # also support {{ perms_can.student_add }} via dict-like access
    def __getitem__(self, action):
        return can(self._user, action)


def permissions(request):
    if not request.user.is_authenticated:
        return {}

    user = request.user
    role = getattr(getattr(user, 'staff_profile', None), 'role', None)
    level = get_role_level(user)

    return {
        'perms_can':      _PermProxy(user),
        'user_role':      role or ('superuser' if user.is_superuser else ''),
        'user_level':     level,
        'is_management':  level >= 70,
        'is_teacher_role': role in TEACHER_ROLES if role else False,
        'is_bursar_role': level >= 80,
        'is_head_role':   level >= 90,
        'is_support_only': role in SUPPORT_ROLES if role else False,
    }


======================================================================
FILE: core/forms.py
======================================================================
# core/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser

class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = ('username', 'email', 'first_name', 'last_name', 'user_type')

class CustomUserChangeForm(UserChangeForm):
    class Meta:
        model = CustomUser
        fields = ('username', 'email', 'first_name', 'last_name', 'user_type', 
                 'phone', 'is_active', 'is_staff')

======================================================================
FILE: core/mixins-1.py
======================================================================
# core/mixins.py
from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from django.contrib import messages

class RoleRequiredMixin:
    """Mixin to restrict access based on role"""
    required_role = None
    required_roles = []
    
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('login')
        
        if request.user.is_superuser:
            return super().dispatch(request, *args, **kwargs)
        
        if not hasattr(request.user, 'staff_profile'):
            messages.error(request, "You don't have a staff profile.")
            return redirect('home')
        
        staff = request.user.staff_profile
        
        if self.required_role and staff.role != self.required_role:
            raise PermissionDenied
        
        if self.required_roles and staff.role not in self.required_roles:
            raise PermissionDenied
        
        return super().dispatch(request, *args, **kwargs)

class SchoolRequiredMixin:
    """Mixin to ensure user belongs to a school"""
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('login')
        
        if request.user.is_superuser:
            return super().dispatch(request, *args, **kwargs)
        
        if hasattr(request.user, 'staff_profile') and request.user.staff_profile.school:
            return super().dispatch(request, *args, **kwargs)
        
        messages.error(request, "You are not associated with any school.")
        return redirect('home')

======================================================================
FILE: core/mixins.py
======================================================================
# core/mixins.py  — re-exports from permissions for backward compat
from core.permissions import (
    RoleRequiredMixin, ManagementRequiredMixin, HeadRequiredMixin,
    BursarRequiredMixin, TeacherRequiredMixin, SupportDashboardMixin,
    can, get_role_level, is_teacher, is_support_only,
)


======================================================================
FILE: core/models.py
======================================================================
# core/models.py
"""
Core models for the school management system including custom user and school.
"""
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import gettext_lazy as _


class CustomUser(AbstractUser):
    """
    Custom user model for the school management system.
    
    Extends Django's AbstractUser to add school-specific fields and role-based
    access control. This model handles all user types including administrators,
    teachers, parents, and support staff.
    
    Attributes:
        user_type (str): Type of user from USER_TYPE_CHOICES
        phone (str): Primary phone number
        mobile_money_number (str): Mobile money account for payments
        profile_picture (ImageField): User's profile photo
        employee_id (str): Unique identifier for staff members
        teacher_id (str): Specific identifier for teachers
        access_level (int): Numeric level for permission hierarchy
        oversees_section (str): Section managed by head teachers
        financial_access (bool): Whether user can access financial data
        is_primary_contact (bool): For parents, whether this is primary contact
    """
    
    USER_TYPE_CHOICES = [
        ('super_admin', 'Super Administrator'),
        ('proprietor', 'Proprietor'),
        ('school_admin', 'School Administrator'),
        ('head_master', 'Head Master'),
        ('head_mistress', 'Head Mistress'),
        ('bursar', 'Bursar/Accountant'),
        ('teacher', 'Teacher'),
        ('class_teacher', 'Class Teacher'),
        ('subject_teacher', 'Subject Teacher'),
        ('parent', 'Parent/Guardian'),
        ('secretary', 'Secretary'),
        ('driver', 'Driver'),
        ('cleaner', 'Cleaner'),
        ('canteen', 'Canteen Staff'),
        ('security', 'Security'),
        ('support', 'Support Staff'),
    ]
    
    SECTION_CHOICES = [
        ('english', 'English Section'),
        ('french', 'French Section'),
        ('bilingual', 'Bilingual Section'),
        ('nursery', 'Nursery Section'),
        ('none', 'None'),
    ]
    
    user_type = models.CharField(
        max_length=20, 
        choices=USER_TYPE_CHOICES, 
        default='teacher'
    )
    phone = models.CharField(
        max_length=20, 
        blank=True
    )
    mobile_money_number = models.CharField(
        max_length=20, 
        blank=True
    )
    profile_picture = models.ImageField(
        upload_to='profiles/', 
        blank=True, 
        null=True
    )
    
    # Staff/Teacher fields
    employee_id = models.CharField(
        max_length=20, 
        blank=True, 
        unique=True, 
        null=True
    )
    teacher_id = models.CharField(
        max_length=20, 
        blank=True
    )
    
    # Role-based access control
    access_level = models.IntegerField(
        default=1, 
        help_text="Higher number = more access"
    )
    oversees_section = models.CharField(
        max_length=20, 
        choices=SECTION_CHOICES, 
        default='none'
    )
    financial_access = models.BooleanField(
        default=False
    )
    
    # Parent-specific fields
    is_primary_contact = models.BooleanField(
        default=False
    )
    
    class Meta:
        verbose_name = _("User")
        verbose_name_plural = _("Users")
        indexes = [
            models.Index(fields=['user_type']),
            models.Index(fields=['employee_id']),
        ]
    
    def __str__(self):
        """Return string representation of the user."""
        return f"{self.get_full_name() or self.username} ({self.get_user_type_display()})"
    
    def get_full_name(self):
        """
        Return the full name of the user.
        
        Returns:
            str: Combined first and last name, or username if not available.
        """
        full_name = super().get_full_name()
        return full_name if full_name else self.username
    
    def has_financial_access(self):
        """
        Check if user has permission to access financial data.
        
        Returns:
            bool: True if user has financial access by role or permission.
        """
        return self.financial_access or self.user_type in ['super_admin', 'proprietor', 'bursar']
    
    def is_head_teacher(self):
        """
        Check if user is a head teacher (master or mistress).
        
        Returns:
            bool: True if user is head_master or head_mistress.
        """
        return self.user_type in ['head_master', 'head_mistress']
    
    def get_accessible_sections(self):
        """
        Get list of sections this user has access to.
        
        Returns:
            list: Section codes that the user can access.
        """
        if self.user_type in ['super_admin', 'proprietor']:
            return dict(self.SECTION_CHOICES).keys()
        if self.is_head_teacher():
            return [self.oversees_section]
        return []


class School(models.Model):
    """
    Represents the school institution itself.
    
    This model stores information about the school, including contact details,
    academic settings, and configuration options. Multiple schools can be
    managed in a single installation (for school groups/chains).
    
    Attributes:
        name (str): Official school name
        code (str): Unique school code
        address (str): Physical address
        city (str): City location
        quarter (str): Neighborhood/district
        phone (str): Main contact number
        email (str): General email address
        website (URLField): School website URL
        principal_name (str): Name of principal/head teacher
        principal_phone (str): Principal's contact number
        academic_year (str): Current academic year
        current_term (int): Current term (1, 2, or 3)
        is_bilingual (bool): Whether school offers bilingual education
        default_language (str): Primary language of instruction
        offline_mode (bool): Whether offline sync is enabled
        mobile_money_enabled (bool): Whether mobile payments are accepted
        sms_alerts (bool): Whether SMS notifications are active
    """
    
    name = models.CharField(
        max_length=200
    )
    code = models.CharField(
        max_length=20, 
        unique=True
    )
    address = models.TextField()
    city = models.CharField(
        max_length=100, 
        default="Douala"
    )
    quarter = models.CharField(
        max_length=100, 
        blank=True
    )
    phone = models.CharField(
        max_length=20
    )
    email = models.EmailField(
        blank=True
    )
    website = models.URLField(
        blank=True
    )
    principal_name = models.CharField(
        max_length=100
    )
    principal_phone = models.CharField(
        max_length=20, 
        blank=True
    )
    
    # Academic Settings
    academic_year = models.CharField(
        max_length=9, 
        default="2025-2026"
    )
    current_term = models.PositiveSmallIntegerField(
        default=1, 
        choices=[(1, 'Term 1'), (2, 'Term 2'), (3, 'Term 3')]
    )
    is_bilingual = models.BooleanField(
        default=True
    )
    default_language = models.CharField(
        max_length=10, 
        choices=[('fr', 'French'), ('en', 'English'), ('both', 'Bilingual')],
        default='both'
    )
    
    # Technical Settings
    offline_mode = models.BooleanField(
        default=True
    )
    mobile_money_enabled = models.BooleanField(
        default=True
    )
    sms_alerts = models.BooleanField(
        default=True
    )
    
    class Meta:
        verbose_name = _("School")
        verbose_name_plural = _("Schools")
    
    def __str__(self):
        """Return string representation of the school."""
        return f"{self.name} - {self.quarter or self.city}"
    
    def get_full_address(self):
        """
        Get the complete formatted address.
        
        Returns:
            str: Complete address including quarter and city.
        """
        parts = [self.address]
        if self.quarter:
            parts.append(self.quarter)
        parts.append(self.city)
        return ", ".join(parts)

======================================================================
FILE: core/permissions-1.py
======================================================================
# core/permissions.py
"""
Permission constants and helpers for Rapha-Bethel BNPS
"""

ROLE_HIERARCHY = {
    'proprietor': 100,
    'head_master': 90,
    'head_mistress': 90,
    'bursar': 80,
    'admin': 70,
    'teacher': 60,
    'class_teacher': 60,
    'subject_teacher': 50,
    'assistant': 40,
    'support': 30,
}

def has_permission(user, required_level):
    """Check if user has required permission level"""
    if user.is_superuser:
        return True
    if hasattr(user, 'staff_profile'):
        return ROLE_HIERARCHY.get(user.staff_profile.role, 0) >= required_level
    return False

======================================================================
FILE: core/permissions.py
======================================================================
# core/permissions.py
"""
Role-based permission system for Rapha-Bethel BNPS
=====================================================
ROLE HIERARCHY (higher = more access)
  superuser   : 999  — developer, full access
  proprietor  : 100  — school owner, full access
  head_master : 90   — English section head, all school ops
  head_mistress:90   — French section head, all school ops
  bursar      : 80   — finance full access, read others
  admin       : 70   — office admin, most ops except finance delete
  class_teacher:60   — own class students + attendance + SMS to class parents
  teacher     : 60   — same as class_teacher
  subject_teacher:50 — own subjects, attendance, read own class students
  assistant_teacher:45 — mark attendance only, read students
  secretary   : 40   — read most, create announcements
  support     : 20   — (driver/cleaner/security/canteen) own leave/attendance only
  parent      : 0    — parent portal only (separate login)
"""

from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin

ROLE_HIERARCHY = {
    'proprietor':       100,
    'head_master':       90,
    'head_mistress':     90,
    'bursar':            80,
    'admin':             70,
    'class_teacher':     60,
    'teacher':           60,
    'subject_teacher':   50,
    'assistant_teacher': 45,
    'secretary':         40,
    'driver':            20,
    'cleaner':           20,
    'canteen':           20,
    'security':          20,
    'support':           20,
    'other':             20,
}

# Permission levels for each action category
PERM = {
    # Students
    'student_view_all':    65,   # admin+
    'student_view_class':  45,   # teachers see own class
    'student_add':         70,   # admin+
    'student_edit':        70,
    'student_delete':      90,   # head+
    'student_import':      70,
    'parent_manage':       70,

    # Academics
    'class_view':          45,
    'class_manage':        70,   # admin+
    'subject_view':        45,
    'subject_manage':      70,
    'attendance_mark':     45,   # all teachers
    'attendance_view_all': 70,
    'teacher_assign':      70,

    # Finance
    'finance_view_own_student': 45,  # teachers see fee status only
    'finance_view':        80,   # bursar+
    'finance_manage':      80,
    'finance_delete':      90,
    'expense_approve':     80,

    # Communication
    'announcement_view':   20,
    'announcement_create': 60,   # teachers+ can create
    'announcement_manage': 70,   # admin+ can edit/delete others
    'sms_send':            60,   # teachers+ (class parents only)
    'sms_view_all':        70,

    # Staff
    'staff_view':          70,
    'staff_manage':        80,
    'staff_delete':        90,
    'leave_own':           20,   # everyone can manage own leave
    'leave_approve':       80,
    'staff_attendance_mark': 80,

    # Reports
    'report_academic':     60,
    'report_attendance':   60,
    'report_financial':    80,
    'report_custom':       80,

    # Admin
    'django_admin':        90,
    'import_export':       70,
}

SUPPORT_ROLES = {'driver', 'cleaner', 'canteen', 'security', 'support', 'other'}
TEACHER_ROLES = {'teacher', 'class_teacher', 'subject_teacher', 'assistant_teacher'}
MANAGEMENT_ROLES = {'proprietor', 'head_master', 'head_mistress', 'admin', 'bursar'}


def get_role_level(user):
    if user.is_superuser:
        return 999
    if hasattr(user, 'staff_profile') and user.staff_profile:
        return ROLE_HIERARCHY.get(user.staff_profile.role, 0)
    return 0


def can(user, action):
    """Check if user can perform action."""
    return get_role_level(user) >= PERM.get(action, 999)


def is_support_only(user):
    if user.is_superuser: return False
    if not hasattr(user, 'staff_profile'): return False
    return user.staff_profile.role in SUPPORT_ROLES


def is_teacher(user):
    if not hasattr(user, 'staff_profile'): return False
    return user.staff_profile.role in TEACHER_ROLES


# ── MIXINS ──────────────────────────────────────────────────────

class RoleRequiredMixin(LoginRequiredMixin):
    """Base mixin — set required_level or required_roles on the view."""
    required_level = 0
    required_roles = None  # optional list of exact role strings
    permission_denied_message = "You don't have permission to access this page."

    def dispatch(self, request, *args, **kwargs):
        response = super().dispatch(request, *args, **kwargs)
        # LoginRequiredMixin may have redirected already
        if not request.user.is_authenticated:
            return response

        level = get_role_level(request.user)

        if self.required_roles:
            if not request.user.is_superuser:
                role = getattr(getattr(request.user, 'staff_profile', None), 'role', None)
                if role not in self.required_roles:
                    return self._deny(request)

        elif level < self.required_level:
            return self._deny(request)

        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

    def _deny(self, request):
        messages.error(request, self.permission_denied_message)
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            from django.http import JsonResponse
            return JsonResponse({'error': self.permission_denied_message}, status=403)
        return redirect('staff:staff_dashboard')


class ManagementRequiredMixin(RoleRequiredMixin):
    required_level = 70
    permission_denied_message = "Only administrators and above can do this."


class HeadRequiredMixin(RoleRequiredMixin):
    required_level = 90
    permission_denied_message = "Only the Head Teacher or Proprietor can do this."


class BursarRequiredMixin(RoleRequiredMixin):
    required_level = 80
    permission_denied_message = "Finance access is restricted to the Bursar and above."


class TeacherRequiredMixin(RoleRequiredMixin):
    required_level = 45
    permission_denied_message = "This area is for teaching staff only."


class SupportDashboardMixin(LoginRequiredMixin):
    """Redirect support-only staff to their limited dashboard."""
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('staff:login')
        if is_support_only(request.user):
            from django.urls import reverse
            if request.path != reverse('staff:staff_dashboard'):
                messages.info(request, "Your account has limited access.")
                return redirect('staff:staff_dashboard')
        return super().dispatch(request, *args, **kwargs)


======================================================================
FILE: core/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: core/urls.py
======================================================================
# core/urls.py
from django.urls import path
from . import views

app_name = 'core'

urlpatterns = [
    # Add core-specific URLs here if needed
]

======================================================================
FILE: core/views-1.py
======================================================================
# core/views.py
from django.shortcuts import render
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from students.models import Student
from academics.models import SchoolClass, Attendance, Subject
from finance.models import Invoice, Payment
from communication.models import Announcement
from datetime import date, timedelta
from django.db.models import Sum, Count

class DashboardView(LoginRequiredMixin, TemplateView):
    template_name = 'dashboard.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Basic stats
        today = date.today()
        context['total_students'] = Student.objects.count()
        context['total_classes'] = SchoolClass.objects.count()
        context['total_subjects'] = Subject.objects.count()
        
        # Today's attendance
        context['today_attendance'] = Attendance.objects.filter(date=today).count()
        present_today = Attendance.objects.filter(date=today, status='present').count()
        context['attendance_rate'] = round((present_today / context['today_attendance'] * 100) if context['today_attendance'] > 0 else 0, 1)
        
        # Finance stats
        context['total_revenue'] = Payment.objects.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0
        context['pending_invoices'] = Invoice.objects.filter(status='pending').count()
        context['overdue_invoices'] = Invoice.objects.filter(status='overdue').count()
        
        # Recent data
        context['recent_students'] = Student.objects.order_by('-created_at')[:5]
        context['recent_announcements'] = Announcement.objects.order_by('-publish_date')[:3]
        context['upcoming_birthdays'] = Student.objects.filter(
            date_of_birth__month=today.month,
            date_of_birth__day__gte=today.day
        ).order_by('date_of_birth')[:5]
        
        # Chart data (you can use Chart.js later)
        last_7_days = [today - timedelta(days=i) for i in range(6, -1, -1)]
        attendance_data = []
        for day in last_7_days:
            count = Attendance.objects.filter(date=day).count()
            attendance_data.append(count)
        
        context['attendance_labels'] = [d.strftime('%a') for d in last_7_days]
        context['attendance_data'] = attendance_data
        
        return context
    
class HomeView(TemplateView):
    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['school_name'] = "Rapha-Bethel School BNPS"
        return context

======================================================================
FILE: core/views.py
======================================================================
# core/views.py
from django.shortcuts import render
from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from students.models import Student
from academics.models import SchoolClass, Attendance, Subject
from finance.models import Invoice, Payment
from communication.models import Announcement
from datetime import date, timedelta
from django.db.models import Sum, Count

class DashboardView(LoginRequiredMixin, TemplateView):
    template_name = 'dashboard.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Basic stats
        today = date.today()
        context['total_students'] = Student.objects.count()
        context['total_classes'] = SchoolClass.objects.count()
        context['total_subjects'] = Subject.objects.count()
        
        # Today's attendance
        context['today_attendance'] = Attendance.objects.filter(date=today).count()
        present_today = Attendance.objects.filter(date=today, status='present').count()
        context['attendance_rate'] = round((present_today / context['today_attendance'] * 100) if context['today_attendance'] > 0 else 0, 1)
        
        # Finance stats
        context['total_revenue'] = Payment.objects.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0
        context['pending_invoices'] = Invoice.objects.filter(status='pending').count()
        context['overdue_invoices'] = Invoice.objects.filter(status='overdue').count()
        
        # Recent data
        context['recent_students'] = Student.objects.order_by('-created_at')[:5]
        context['recent_announcements'] = Announcement.objects.order_by('-publish_date')[:3]
        context['upcoming_birthdays'] = Student.objects.filter(
            date_of_birth__month=today.month,
            date_of_birth__day__gte=today.day
        ).order_by('date_of_birth')[:5]
        
        # Chart data (you can use Chart.js later)
        last_7_days = [today - timedelta(days=i) for i in range(6, -1, -1)]
        attendance_data = []
        for day in last_7_days:
            count = Attendance.objects.filter(date=day).count()
            attendance_data.append(count)
        
        context['attendance_labels'] = [d.strftime('%a') for d in last_7_days]
        context['attendance_data'] = attendance_data
        
        return context
    
class HomeView(TemplateView):
    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['school_name'] = "Rapha-Bethel School BNPS"
        return context

def handler_403(request, exception=None):
    return render(request, '403.html', {'exception': str(exception) if exception else None}, status=403)

def handler_404(request, exception=None):
    return render(request, '404.html', {}, status=404)



######################################################################
# APP: FINANCE
######################################################################

======================================================================
FILE: finance/__init__.py
======================================================================


======================================================================
FILE: finance/admin.py
======================================================================
# finance/admin.py
from django.contrib import admin
from .models import (
    FeeStructure, SchoolItemPrice, StudentEnrollmentFee,
    Invoice, InvoiceItem, Payment, PaymentReminder,
    Discount, StudentDiscount, ExpenseCategory, Expense, FinancialReport
)


# ---------------------------------------------------------------------------
# FeeStructure
# ---------------------------------------------------------------------------

@admin.register(FeeStructure)
class FeeStructureAdmin(admin.ModelAdmin):
    list_display  = [
        'name', 'section', 'class_group',
        'registration_new', 'registration_old',
        'total_fees', 'installment_1', 'installment_2',
        'academic_year', 'is_active',
    ]
    list_filter   = ['section', 'class_group', 'academic_year', 'is_active']
    search_fields = ['name', 'description']
    list_editable = ['is_active']
    filter_horizontal = ['specific_classes']
    date_hierarchy    = 'created_at'

    fieldsets = (
        ('Identity', {
            'fields': ('name', 'section', 'class_group', 'academic_year', 'is_active'),
        }),
        ('Registration Fees', {
            'description': 'Registration fee differs for new vs returning pupils.',
            'fields': ('registration_new', 'registration_old'),
        }),
        ('Annual Tuition & Installments', {
            'description': 'total_fees must equal installment_1 + installment_2.',
            'fields': ('total_fees', 'installment_1', 'installment_2'),
        }),
        ('Optional Class Links', {
            'fields': ('specific_classes',),
            'classes': ('collapse',),
        }),
        ('Notes', {
            'fields': ('description',),
            'classes': ('collapse',),
        }),
        ('Metadata', {
            'fields': ('created_by', 'created_at', 'updated_at'),
            'classes': ('collapse',),
        }),
    )
    readonly_fields = ['created_at', 'updated_at']


# ---------------------------------------------------------------------------
# SchoolItemPrice
# ---------------------------------------------------------------------------

@admin.register(SchoolItemPrice)
class SchoolItemPriceAdmin(admin.ModelAdmin):
    list_display  = ['name', 'item_type', 'price', 'academic_year', 'is_active']
    list_filter   = ['item_type', 'academic_year', 'is_active']
    list_editable = ['is_active']
    search_fields = ['name']


# ---------------------------------------------------------------------------
# StudentEnrollmentFee
# ---------------------------------------------------------------------------

@admin.register(StudentEnrollmentFee)
class StudentEnrollmentFeeAdmin(admin.ModelAdmin):
    list_display  = [
        'student', 'fee_structure', 'academic_year',
        'is_new_pupil', 'registration_fee', 'total_fees',
        'installment_1_due', 'installment_2_due',
    ]
    list_filter   = ['academic_year', 'is_new_pupil', 'fee_structure__section']
    search_fields = ['student__first_name', 'student__last_name', 'student__student_id']
    readonly_fields = ['registration_fee', 'total_fees', 'created_at']


# ---------------------------------------------------------------------------
# Invoice
# ---------------------------------------------------------------------------

class InvoiceItemInline(admin.TabularInline):
    model  = InvoiceItem
    extra  = 1
    fields = ['description', 'quantity', 'unit_price', 'discount', 'total']
    readonly_fields = ['total']


class PaymentInline(admin.TabularInline):
    model  = Payment
    extra  = 0
    readonly_fields = ['payment_number', 'created_at']
    fields = ['payment_number', 'amount', 'payment_method', 'payment_date', 'status']


@admin.register(Invoice)
class InvoiceAdmin(admin.ModelAdmin):
    list_display  = [
        'invoice_number', 'student', 'academic_year', 'invoice_type',
        'total_amount', 'amount_paid', 'balance', 'status', 'due_date',
    ]
    list_filter   = ['status', 'academic_year', 'invoice_type', 'issue_date']
    search_fields = ['invoice_number', 'student__first_name', 'student__last_name']
    readonly_fields = ['invoice_number', 'balance', 'created_at', 'updated_at']
    inlines       = [InvoiceItemInline, PaymentInline]
    date_hierarchy = 'issue_date'

    fieldsets = (
        ('Invoice Information', {
            'fields': ('invoice_number', 'student', 'enrollment_fee', 'academic_year', 'invoice_type'),
        }),
        ('Dates', {
            'fields': ('issue_date', 'due_date'),
        }),
        ('Amounts', {
            'fields': ('total_amount', 'amount_paid', 'balance'),
        }),
        ('Status & Notes', {
            'fields': ('status', 'notes'),
        }),
        ('Metadata', {
            'fields': ('created_by', 'created_at', 'updated_at', 'last_reminder_sent'),
            'classes': ('collapse',),
        }),
    )


# ---------------------------------------------------------------------------
# Payment
# ---------------------------------------------------------------------------

@admin.register(Payment)
class PaymentAdmin(admin.ModelAdmin):
    list_display  = [
        'payment_number', 'invoice', 'student', 'amount',
        'payment_method', 'payment_date', 'status',
    ]
    list_filter   = ['payment_method', 'status', 'payment_date']
    search_fields = ['payment_number', 'invoice__invoice_number', 'student__first_name']
    readonly_fields = ['payment_number', 'created_at', 'updated_at']
    date_hierarchy = 'payment_date'

    fieldsets = (
        ('Payment Information', {
            'fields': ('payment_number', 'invoice', 'student', 'amount'),
        }),
        ('Payment Details', {
            'fields': ('payment_method', 'payment_date', 'transaction_id'),
        }),
        ('Mobile Money', {
            'fields': ('mobile_money_provider', 'mobile_money_number'),
            'classes': ('collapse',),
        }),
        ('Bank / Cheque', {
            'fields': ('bank_name', 'cheque_number'),
            'classes': ('collapse',),
        }),
        ('Receipt', {
            'fields': ('receipt_number', 'receipt_issued', 'receipt_issued_date'),
        }),
        ('Status & Notes', {
            'fields': ('status', 'notes'),
        }),
        ('Metadata', {
            'fields': ('received_by', 'created_at', 'updated_at'),
            'classes': ('collapse',),
        }),
    )


# ---------------------------------------------------------------------------
# Discount / StudentDiscount
# ---------------------------------------------------------------------------

@admin.register(Discount)
class DiscountAdmin(admin.ModelAdmin):
    list_display  = ['name', 'discount_type', 'value', 'applies_to', 'is_active']
    list_filter   = ['discount_type', 'applies_to', 'is_active']
    search_fields = ['name', 'description']
    filter_horizontal = ['specific_fees']


@admin.register(StudentDiscount)
class StudentDiscountAdmin(admin.ModelAdmin):
    list_display  = ['student', 'discount', 'academic_year', 'approved_by']
    list_filter   = ['academic_year']
    search_fields = ['student__first_name', 'student__last_name']


# ---------------------------------------------------------------------------
# Expenses
# ---------------------------------------------------------------------------

@admin.register(ExpenseCategory)
class ExpenseCategoryAdmin(admin.ModelAdmin):
    list_display  = ['name', 'name_fr', 'is_active']
    list_filter   = ['is_active']
    search_fields = ['name']


@admin.register(Expense)
class ExpenseAdmin(admin.ModelAdmin):
    list_display  = [
        'expense_number', 'category', 'description',
        'amount', 'expense_date', 'payment_method',
    ]
    list_filter   = ['category', 'payment_method', 'expense_date']
    search_fields = ['expense_number', 'description', 'vendor']
    date_hierarchy = 'expense_date'
    readonly_fields = ['expense_number', 'created_at', 'updated_at']


# ---------------------------------------------------------------------------
# Financial Report
# ---------------------------------------------------------------------------

@admin.register(FinancialReport)
class FinancialReportAdmin(admin.ModelAdmin):
    list_display  = [
        'title', 'report_type', 'start_date', 'end_date',
        'total_revenue', 'total_expenses', 'net_profit',
    ]
    list_filter   = ['report_type', 'generated_at']
    readonly_fields = ['generated_at']

======================================================================
FILE: finance/apps.py
======================================================================
from django.apps import AppConfig


class FinanceConfig(AppConfig):
    name = 'finance'


======================================================================
FILE: finance/forms.py
======================================================================
# finance/forms.py
from django import forms
from .models import (
    FeeStructure, SchoolItemPrice, StudentEnrollmentFee,
    Invoice, Payment, Expense
)


# ---------------------------------------------------------------------------
# FeeStructure form — matches the new model fields exactly
# ---------------------------------------------------------------------------

class FeeStructureForm(forms.ModelForm):
    class Meta:
        model = FeeStructure
        fields = [
            'section', 'class_group', 'academic_year',
            'registration_new', 'registration_old',
            'total_fees', 'installment_1', 'installment_2',
            'specific_classes', 'is_active', 'description',
        ]
        widgets = {
            'section':          forms.Select(attrs={'class': 'form-select'}),
            'class_group':      forms.Select(attrs={'class': 'form-select'}),
            'academic_year':    forms.TextInput(attrs={'class': 'form-control'}),
            'registration_new': forms.NumberInput(attrs={'class': 'form-control'}),
            'registration_old': forms.NumberInput(attrs={'class': 'form-control'}),
            'total_fees':       forms.NumberInput(attrs={'class': 'form-control'}),
            'installment_1':    forms.NumberInput(attrs={'class': 'form-control'}),
            'installment_2':    forms.NumberInput(attrs={'class': 'form-control'}),
            'description':      forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
        }
        help_texts = {
            'total_fees':    'Must equal Installment 1 + Installment 2.',
            'class_group':   'Select the row from the fee table this structure represents.',
        }

    def clean(self):
        cleaned = super().clean()
        total   = cleaned.get('total_fees')
        inst1   = cleaned.get('installment_1')
        inst2   = cleaned.get('installment_2')
        if total and inst1 and inst2:
            if inst1 + inst2 != total:
                raise forms.ValidationError(
                    f'Installment 1 ({inst1:,}) + Installment 2 ({inst2:,}) '
                    f'must equal Total Fees ({total:,}).'
                )
        return cleaned


# ---------------------------------------------------------------------------
# SchoolItemPrice form — uniforms, sportswear, report card, pullovers
# ---------------------------------------------------------------------------

class SchoolItemPriceForm(forms.ModelForm):
    class Meta:
        model = SchoolItemPrice
        fields = ['item_type', 'name', 'price', 'academic_year', 'is_active', 'description']
        widgets = {
            'item_type':    forms.Select(attrs={'class': 'form-select'}),
            'name':         forms.TextInput(attrs={'class': 'form-control'}),
            'price':        forms.NumberInput(attrs={'class': 'form-control'}),
            'academic_year': forms.TextInput(attrs={'class': 'form-control'}),
            'description':  forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
        }


# ---------------------------------------------------------------------------
# StudentEnrollmentFee form
# ---------------------------------------------------------------------------

class StudentEnrollmentFeeForm(forms.ModelForm):
    class Meta:
        model = StudentEnrollmentFee
        fields = [
            'student', 'fee_structure', 'academic_year',
            'is_new_pupil', 'installment_1_due', 'installment_2_due', 'notes',
        ]
        widgets = {
            'student':          forms.Select(attrs={'class': 'form-select'}),
            'fee_structure':    forms.Select(attrs={'class': 'form-select'}),
            'academic_year':    forms.TextInput(attrs={'class': 'form-control'}),
            'installment_1_due': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'installment_2_due': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'notes':            forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
        }
        help_texts = {
            'is_new_pupil': 'Tick for new admissions (reg. fee = 15,000 XAF). '
                            'Untick for returning pupils (reg. fee = 10,000 XAF).',
        }


# ---------------------------------------------------------------------------
# Invoice form — uses invoice_type instead of term
# ---------------------------------------------------------------------------

class InvoiceForm(forms.ModelForm):
    class Meta:
        model = Invoice
        fields = [
            'student', 'academic_year', 'invoice_type',
            'enrollment_fee', 'due_date', 'notes',
        ]
        widgets = {
            'student':       forms.Select(attrs={'class': 'form-select'}),
            'academic_year': forms.TextInput(attrs={'class': 'form-control'}),
            'invoice_type':  forms.Select(attrs={'class': 'form-select'}),
            'enrollment_fee': forms.Select(attrs={'class': 'form-select'}),
            'due_date':      forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'notes':         forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
        }


# ---------------------------------------------------------------------------
# Payment form — unchanged except cheque_number replaces check
# ---------------------------------------------------------------------------

class PaymentForm(forms.ModelForm):
    class Meta:
        model = Payment
        fields = [
            'invoice', 'amount', 'payment_method', 'payment_date',
            'mobile_money_provider', 'mobile_money_number',
            'transaction_id', 'bank_name', 'cheque_number', 'notes',
        ]
        widgets = {
            'invoice':               forms.Select(attrs={'class': 'form-select'}),
            'amount':                forms.NumberInput(attrs={'class': 'form-control'}),
            'payment_method':        forms.Select(attrs={'class': 'form-select'}),
            'payment_date':          forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'mobile_money_provider': forms.Select(attrs={'class': 'form-select'}),
            'mobile_money_number':   forms.TextInput(attrs={'class': 'form-control'}),
            'transaction_id':        forms.TextInput(attrs={'class': 'form-control'}),
            'bank_name':             forms.TextInput(attrs={'class': 'form-control'}),
            'cheque_number':         forms.TextInput(attrs={'class': 'form-control'}),
            'notes':                 forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
        }


# ---------------------------------------------------------------------------
# Expense form — no changes needed
# ---------------------------------------------------------------------------

class ExpenseForm(forms.ModelForm):
    class Meta:
        model = Expense
        fields = [
            'category', 'description', 'amount', 'expense_date',
            'payment_method', 'vendor', 'notes', 'receipt_file',
        ]
        widgets = {
            'category':     forms.Select(attrs={'class': 'form-select'}),
            'description':  forms.TextInput(attrs={'class': 'form-control'}),
            'amount':       forms.NumberInput(attrs={'class': 'form-control'}),
            'expense_date': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
            'payment_method': forms.Select(attrs={'class': 'form-select'}),
            'vendor':       forms.TextInput(attrs={'class': 'form-control'}),
            'notes':        forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
        }

======================================================================
FILE: finance/models.py
======================================================================
# finance/models.py
"""
Finance models aligned with the actual Rapha-Bethel BNPS fee structure:

ANGLO SECTION:
  Pre-Nursery:  Registration (New 15,000 / Old 10,000), Fees 130,000  → 1st 70,000 / 2nd 60,000
  Nursery 1&2:  Registration (New 15,000 / Old 10,000), Fees  95,000  → 1st 50,000 / 2nd 45,000
  Primary 1-5:  Registration (New 15,000 / Old 10,000), Fees  80,000  → 1st 45,000 / 2nd 35,000
  Primary 6:    Registration (New 15,000 / Old 10,000), Fees 145,000  → 1st 85,000 / 2nd 60,000

BILINGUAL SECTION:
  Maternelle (Moyenne & Grande): Registration (New 15,000 / Old 10,000), Fees 110,000 → 1st 60,000 / 2nd 50,000
  SIL–CM1:  Registration (New 15,000 / Old 10,000), Fees 100,000 → 1st 50,000 / 2nd 50,000
  CM2:       Registration (New 15,000 / Old 10,000), Fees 145,000 → 1st 85,000 / 2nd 60,000

EXTRA / OTHER INCOMES (sold items):
  Uniforms:    5,000 XAF
  Sportswear:  3,500 XAF
  Report Card: 1,000 XAF
  Pullovers:   5,000 XAF
"""

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.core.validators import MinValueValidator
from django.utils import timezone
from students.models import Student
from academics.models import SchoolClass
from core.models import CustomUser
from .utils import generate_invoice_number


# ---------------------------------------------------------------------------
# SECTION & CLASS-LEVEL HELPERS
# (Mirrors the handwritten fee table exactly)
# ---------------------------------------------------------------------------

class SchoolSection(models.TextChoices):
    ANGLO    = 'anglo',    _('Anglo Section')
    BILINGUAL = 'bilingual', _('Bilingual Section')


class FeeClassGroup(models.TextChoices):
    """
    Groups that share the same fee tier (matches the handwritten table rows).
    """
    # Anglo groups
    PRE_NURSERY  = 'pre_nursery',  _('Pre-Nursery (Anglo)')
    NURSERY      = 'nursery',      _('Nursery 1 & 2 (Anglo)')
    PRIMARY_1_5  = 'primary_1_5',  _('Primary 1–5 (Anglo)')
    PRIMARY_6    = 'primary_6',    _('Primary 6 (Anglo)')
    # Bilingual groups
    MATERNELLE   = 'maternelle',   _('Maternelle / Moyenne & Grande Section (Bilingual)')
    SIL_CM1      = 'sil_cm1',      _('SIL – CM1 (Bilingual)')
    CM2          = 'cm2',          _('CM2 (Bilingual)')


# ---------------------------------------------------------------------------
# FeeStructure — one row per class-group, per academic year
# ---------------------------------------------------------------------------

class FeeStructure(models.Model):
    """
    Defines the official fee schedule for a class group and academic year.

    Each row maps directly to one row in the handwritten fee table and holds:
      • registration_new  — registration fee for NEW pupils
      • registration_old  — registration fee for OLD (returning) pupils
      • total_fees        — total annual school fees (tuition)
      • installment_1     — 1st installment amount
      • installment_2     — 2nd installment amount
      • section           — Anglo or Bilingual
      • class_group       — which tier/row of the fee table

    The constraint  installment_1 + installment_2 == total_fees  is enforced
    in clean() and highlighted in the admin.

    Additional fee types (uniform, sportswear, report card, pullover) are
    handled by the SchoolItemPrice model below.

    Attributes:
        name (str): Human-readable label, e.g. "Primary 1-5 (Anglo) 2025-2026"
        section (str): Anglo or Bilingual
        class_group (str): Fee tier from FeeClassGroup
        academic_year (str): e.g. "2025-2026"
        registration_new (Decimal): Registration fee for new pupils (XAF)
        registration_old (Decimal): Registration fee for old/returning pupils (XAF)
        total_fees (Decimal): Total annual school fees (XAF)
        installment_1 (Decimal): First installment amount (XAF)
        installment_2 (Decimal): Second installment amount (XAF)
        specific_classes (M2M): Optionally pin to exact SchoolClass records
        is_active (bool): Whether this row is currently in use
        description (str): Free-text notes
        created_by (FK): Staff who created/last edited the record
        created_at / updated_at: Timestamps
    """

    name = models.CharField(
        max_length=150,
        blank=True,
        verbose_name=_("Fee Structure Name"),
        help_text=_("Auto-generated if left blank")
    )

    section = models.CharField(
        max_length=20,
        choices=SchoolSection.choices,
        default=SchoolSection.ANGLO,
        verbose_name=_("School Section"),
    )

    class_group = models.CharField(
        max_length=20,
        choices=FeeClassGroup.choices,
        verbose_name=_("Class Group / Fee Tier"),
        help_text=_(
            "Select the row from the fee table this structure represents. "
            "e.g. 'Primary 1–5 (Anglo)'"
        ),
    )

    academic_year = models.CharField(
        max_length=9,
        default="2025-2026",
        verbose_name=_("Academic Year"),
        help_text=_("e.g. 2025-2026"),
    )

    # ── Registration fees ────────────────────────────────────────────────────
    registration_new = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=15000,
        validators=[MinValueValidator(0)],
        verbose_name=_("Registration Fee — New Pupil (XAF)"),
        help_text=_("From fee table: 15,000 XAF for new pupils"),
    )

    registration_old = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=10000,
        validators=[MinValueValidator(0)],
        verbose_name=_("Registration Fee — Old/Returning Pupil (XAF)"),
        help_text=_("From fee table: 10,000 XAF for returning pupils"),
    )

    # ── Annual school fees ───────────────────────────────────────────────────
    total_fees = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        validators=[MinValueValidator(0)],
        verbose_name=_("Total Annual Fees (XAF)"),
        help_text=_(
            "The 'Fees' column in the table — full-year tuition. "
            "Must equal installment_1 + installment_2."
        ),
    )

    installment_1 = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        validators=[MinValueValidator(0)],
        verbose_name=_("1st Installment (XAF)"),
    )

    installment_2 = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        validators=[MinValueValidator(0)],
        verbose_name=_("2nd Installment (XAF)"),
    )

    # ── Optional: pin to specific class records ──────────────────────────────
    specific_classes = models.ManyToManyField(
        SchoolClass,
        blank=True,
        verbose_name=_("Specific Classes"),
        related_name='fee_structures',
        help_text=_(
            "Optionally link to exact class records (e.g. CP-A, CP-B). "
            "Leave blank to apply to the whole class group."
        ),
    )

    # ── Admin / metadata ─────────────────────────────────────────────────────
    is_active = models.BooleanField(
        default=True,
        verbose_name=_("Active"),
    )

    description = models.TextField(
        blank=True,
        verbose_name=_("Notes"),
    )

    created_by = models.ForeignKey(
        CustomUser,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='fee_structures_created',
        verbose_name=_("Created By"),
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        null=True,
        blank=True,
        verbose_name=_("Created At"),
    )

    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Updated At"),
    )

    class Meta:
        verbose_name = _("Fee Structure")
        verbose_name_plural = _("Fee Structures")
        ordering = ['academic_year', 'section', 'class_group']
        unique_together = [['section', 'class_group', 'academic_year']]
        indexes = [
            models.Index(fields=['academic_year', 'section', 'class_group']),
            models.Index(fields=['is_active']),
        ]

    # ── Lifecycle ─────────────────────────────────────────────────────────────
    def save(self, *args, **kwargs):
        if not self.name:
            self.name = (
                f"{self.get_class_group_display()} — {self.academic_year}"
            )
        super().save(*args, **kwargs)

    def clean(self):
        from django.core.exceptions import ValidationError
        if self.installment_1 and self.installment_2 and self.total_fees:
            if self.installment_1 + self.installment_2 != self.total_fees:
                raise ValidationError(
                    _("Installment 1 + Installment 2 must equal Total Fees. "
                      f"({self.installment_1} + {self.installment_2} ≠ {self.total_fees})")
                )

    def __str__(self):
        return self.name or f"{self.get_class_group_display()} ({self.academic_year})"

    # ── Helper methods ────────────────────────────────────────────────────────
    def get_registration_fee(self, is_new_pupil: bool) -> int:
        """
        Return the correct registration fee for new or returning pupils.

        Args:
            is_new_pupil: True if the student is enrolling for the first time.

        Returns:
            int: Registration amount in XAF.
        """
        return int(self.registration_new if is_new_pupil else self.registration_old)

    def display_total(self) -> str:
        """Return formatted total fees string."""
        return f"{int(self.total_fees):,} XAF"

    def display_installments(self) -> str:
        """Return a human-readable installment summary."""
        return (
            f"1st: {int(self.installment_1):,} XAF  |  "
            f"2nd: {int(self.installment_2):,} XAF"
        )

    @classmethod
    def get_defaults(cls):
        """
        Return the canonical fee data from the handwritten tables so it can
        be loaded via a data migration or management command.

        Returns:
            list[dict]: One dict per row ready for get_or_create().
        """
        return [
            # ── ANGLO SECTION ──────────────────────────────────────────────
            {
                'section': 'anglo', 'class_group': 'pre_nursery',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 130000, 'installment_1': 70000, 'installment_2': 60000,
            },
            {
                'section': 'anglo', 'class_group': 'nursery',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 95000, 'installment_1': 50000, 'installment_2': 45000,
            },
            {
                'section': 'anglo', 'class_group': 'primary_1_5',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 80000, 'installment_1': 45000, 'installment_2': 35000,
            },
            {
                'section': 'anglo', 'class_group': 'primary_6',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 145000, 'installment_1': 85000, 'installment_2': 60000,
            },
            # ── BILINGUAL SECTION ──────────────────────────────────────────
            {
                'section': 'bilingual', 'class_group': 'maternelle',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 110000, 'installment_1': 60000, 'installment_2': 50000,
            },
            {
                'section': 'bilingual', 'class_group': 'sil_cm1',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 100000, 'installment_1': 60000, 'installment_2': 40000,
            },
            {
                'section': 'bilingual', 'class_group': 'cm2',
                'registration_new': 15000, 'registration_old': 10000,
                'total_fees': 145000, 'installment_1': 85000, 'installment_2': 60000,
            },
        ]


# ---------------------------------------------------------------------------
# SchoolItemPrice — uniforms, sportswear, report cards, pullovers
# (Image 2: "Extra / Other Incomes")
# ---------------------------------------------------------------------------

class SchoolItemPrice(models.Model):
    """
    Selling prices for school items such as uniforms and sportswear.

    These are the items listed under "Extra / Other Incomes" in the
    handwritten document (Image 2):
      - Uniforms:    5,000 XAF
      - Sportswear:  3,500 XAF
      - Report Card: 1,000 XAF
      - Pullovers:   5,000 XAF

    Attributes:
        item_type (str): Item category from ITEM_TYPE_CHOICES
        name (str): Display label (e.g. "School Uniform – Blue")
        price (Decimal): Current selling price in XAF
        academic_year (str): Year this price applies to
        is_active (bool): Whether the item is currently on sale
        description (str): Optional notes
        updated_at (datetime): Last price-change timestamp
    """

    ITEM_TYPE_CHOICES = [
        ('uniform',     _('Uniform')),
        ('sportswear',  _('Sportswear')),
        ('report_card', _('Report Card')),
        ('pullover',    _('Pullover')),
        ('other',       _('Other')),
    ]

    item_type = models.CharField(
        max_length=20,
        choices=ITEM_TYPE_CHOICES,
        verbose_name=_("Item Type"),
    )

    name = models.CharField(
        max_length=100,
        verbose_name=_("Item Name"),
        help_text=_("e.g. 'School Uniform', 'Sportswear Kit'"),
    )

    price = models.DecimalField(
        max_digits=8,
        decimal_places=0,
        validators=[MinValueValidator(0)],
        verbose_name=_("Selling Price (XAF)"),
    )

    academic_year = models.CharField(
        max_length=9,
        default="2025-2026",
        verbose_name=_("Academic Year"),
    )

    is_active = models.BooleanField(
        default=True,
        verbose_name=_("Available for Sale"),
    )

    description = models.TextField(
        blank=True,
        verbose_name=_("Description / Notes"),
    )

    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Last Updated"),
    )

    class Meta:
        verbose_name = _("School Item Price")
        verbose_name_plural = _("School Item Prices")
        ordering = ['item_type', 'name']
        unique_together = [['item_type', 'academic_year']]

    def __str__(self):
        return f"{self.name} — {int(self.price):,} XAF ({self.academic_year})"

    def display_price(self) -> str:
        return f"{int(self.price):,} XAF"

    @classmethod
    def get_defaults(cls):
        """
        Return the canonical item prices from Image 2.

        Returns:
            list[dict]: One dict per item ready for get_or_create().
        """
        return [
            {'item_type': 'uniform',     'name': 'Uniform',     'price': 5000},
            {'item_type': 'sportswear',  'name': 'Sportswear',  'price': 3500},
            {'item_type': 'report_card', 'name': 'Report Card', 'price': 1000},
            {'item_type': 'pullover',    'name': 'Pullover',    'price': 5000},
        ]


# ---------------------------------------------------------------------------
# StudentEnrollmentFee — per-student record of registration + tuition
# ---------------------------------------------------------------------------

class StudentEnrollmentFee(models.Model):
    """
    Records the fee obligation for one student for one academic year.

    Created when a student is admitted or re-enrolled. It references the
    correct FeeStructure row and stores whether the student is new or
    returning so the right registration fee is applied automatically.

    Attributes:
        student (FK): The enrolled student
        fee_structure (FK): The FeeStructure row that applies
        academic_year (str): Academic year
        is_new_pupil (bool): True = new admission (15,000 reg fee), False = returning (10,000)
        registration_fee (Decimal): Actual registration amount (auto-set on save)
        total_fees (Decimal): Total annual tuition (copied from fee_structure)
        installment_1_due (date): Due date for first installment
        installment_2_due (date): Due date for second installment
        notes (str): Additional notes
        created_at (datetime): Record creation timestamp
    """

    student = models.ForeignKey(
        Student,
        on_delete=models.CASCADE,
        related_name='enrollment_fees',
        verbose_name=_("Student"),
    )

    fee_structure = models.ForeignKey(
        FeeStructure,
        on_delete=models.PROTECT,
        related_name='enrollment_fees',
        verbose_name=_("Fee Structure"),
        help_text=_("Select the correct class-group fee tier for this student"),
    )

    academic_year = models.CharField(
        max_length=9,
        default="2025-2026",
        verbose_name=_("Academic Year"),
    )

    is_new_pupil = models.BooleanField(
        default=False,
        verbose_name=_("New Pupil?"),
        help_text=_(
            "Tick for new admissions (registration = 15,000 XAF). "
            "Untick for returning pupils (registration = 10,000 XAF)."
        ),
    )

    # Auto-filled from fee_structure on save
    registration_fee = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=0,
        verbose_name=_("Registration Fee Applied (XAF)"),
    )

    total_fees = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=0,
        verbose_name=_("Total Annual Fees (XAF)"),
    )

    installment_1_due = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("1st Installment Due Date"),
    )

    installment_2_due = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("2nd Installment Due Date"),
    )

    notes = models.TextField(
        blank=True,
        verbose_name=_("Notes"),
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        null=True,
        blank=True,
    )

    class Meta:
        verbose_name = _("Student Enrollment Fee")
        verbose_name_plural = _("Student Enrollment Fees")
        unique_together = [['student', 'academic_year']]
        ordering = ['-academic_year', 'student__last_name']

    def save(self, *args, **kwargs):
        """Auto-populate registration_fee and total_fees from fee_structure."""
        if self.fee_structure_id:
            self.registration_fee = self.fee_structure.get_registration_fee(self.is_new_pupil)
            self.total_fees = self.fee_structure.total_fees
        super().save(*args, **kwargs)

    def __str__(self):
        tag = "New" if self.is_new_pupil else "Returning"
        return (
            f"{self.student.get_full_name()} — "
            f"{self.fee_structure.get_class_group_display()} — "
            f"{self.academic_year} ({tag})"
        )

    @property
    def total_due(self) -> int:
        """Total amount the student owes: registration + tuition."""
        return int(self.registration_fee) + int(self.total_fees)


# ---------------------------------------------------------------------------
# Invoice — issued to a student for a term or for registration
# ---------------------------------------------------------------------------

class Invoice(models.Model):
    """
    Invoice issued to a student, covering one or more fee obligations.

    Possible invoice types:
      • 'registration'  — one-off registration fee (new or old pupil)
      • 'installment_1' — first tuition installment
      • 'installment_2' — second tuition installment
      • 'item_sale'     — uniform, sportswear, report card, pullover
      • 'other'         — miscellaneous

    The balance and status are recalculated automatically on save whenever
    a Payment is posted.

    Attributes:
        invoice_number (str): Unique auto-generated identifier (INV-YYYY-NNNN)
        student (FK): Student this invoice belongs to
        enrollment_fee (FK): The enrollment record this invoice is for (optional)
        invoice_type (str): Category of invoice
        academic_year (str): Academic year
        issue_date (date): Date issued
        due_date (date): Payment due date
        total_amount (Decimal): Amount due
        amount_paid (Decimal): Amount received so far
        balance (Decimal): Remaining amount (auto-calculated)
        status (str): Draft / Sent / Partial / Paid / Overdue / Cancelled
        notes (str): Free-text notes
        created_by (FK): Staff who created the invoice
        created_at / updated_at: Timestamps
        last_reminder_sent (date): Date of last payment reminder
    """

    INVOICE_TYPE_CHOICES = [
        ('registration',  _('Registration Fee')),
        ('installment_1', _('1st Installment (Tuition)')),
        ('installment_2', _('2nd Installment (Tuition)')),
        ('item_sale',     _('School Item Sale')),
        ('other',         _('Other')),
    ]

    STATUS_CHOICES = [
        ('draft',     _('Draft')),
        ('sent',      _('Sent')),
        ('partial',   _('Partially Paid')),
        ('paid',      _('Paid')),
        ('overdue',   _('Overdue')),
        ('cancelled', _('Cancelled')),
    ]

    invoice_number = models.CharField(
        max_length=20,
        unique=True,
        default=generate_invoice_number,
        verbose_name=_("Invoice Number"),
    )

    student = models.ForeignKey(
        Student,
        on_delete=models.CASCADE,
        related_name='invoices',
        verbose_name=_("Student"),
    )

    enrollment_fee = models.ForeignKey(
        StudentEnrollmentFee,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='invoices',
        verbose_name=_("Enrollment Fee Record"),
        help_text=_("Link to the student's enrollment fee for this year"),
    )

    invoice_type = models.CharField(
        max_length=20,
        choices=INVOICE_TYPE_CHOICES,
        default='installment_1',
        verbose_name=_("Invoice Type"),
    )

    academic_year = models.CharField(
        max_length=9,
        default="2025-2026",
        verbose_name=_("Academic Year"),
    )

    issue_date = models.DateField(
        default=timezone.now,
        verbose_name=_("Issue Date"),
    )

    due_date = models.DateField(
        verbose_name=_("Due Date"),
    )

    total_amount = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        verbose_name=_("Total Amount (XAF)"),
    )

    amount_paid = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=0,
        verbose_name=_("Amount Paid (XAF)"),
    )

    balance = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=0,
        verbose_name=_("Balance (XAF)"),
    )

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='draft',
        verbose_name=_("Status"),
    )

    notes = models.TextField(
        blank=True,
        verbose_name=_("Notes"),
    )

    created_by = models.ForeignKey(
        CustomUser,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='invoices_created',
        verbose_name=_("Created By"),
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        null=True,
        blank=True,
        verbose_name=_("Created At"),
    )

    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Updated At"),
    )

    last_reminder_sent = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Last Reminder Sent"),
    )

    class Meta:
        verbose_name = _("Invoice")
        verbose_name_plural = _("Invoices")
        ordering = ['-issue_date', 'student__last_name']
        indexes = [
            models.Index(fields=['invoice_number']),
            models.Index(fields=['student', 'academic_year']),
            models.Index(fields=['status']),
            models.Index(fields=['due_date']),
        ]

    def save(self, *args, **kwargs):
        """Recalculate balance and auto-update status."""
        self.balance = self.total_amount - self.amount_paid

        if self.amount_paid >= self.total_amount:
            self.status = 'paid'
        elif self.amount_paid > 0:
            self.status = 'partial'
        elif self.due_date and self.due_date < timezone.now().date() and self.amount_paid == 0:
            self.status = 'overdue'

        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.invoice_number} — {self.student} — {self.get_invoice_type_display()}"

    @property
    def is_overdue(self) -> bool:
        return self.due_date < timezone.now().date() and self.balance > 0

    @property
    def payment_percentage(self) -> float:
        if self.total_amount == 0:
            return 0.0
        return round(float(self.amount_paid) / float(self.total_amount) * 100, 1)


# ---------------------------------------------------------------------------
# InvoiceItem — line items on an invoice
# ---------------------------------------------------------------------------

class InvoiceItem(models.Model):
    """
    Individual line item on an invoice.

    Can reference either a FeeStructure row or a SchoolItemPrice for
    uniform / sportswear / report-card / pullover sales.

    Attributes:
        invoice (FK): Parent invoice
        fee_structure (FK): Optional link to a FeeStructure (tuition fees)
        school_item (FK): Optional link to a SchoolItemPrice (item sales)
        description (str): Label shown on the invoice
        quantity (int): Units sold/charged
        unit_price (Decimal): Price per unit in XAF
        discount (Decimal): Discount off this line
        total (Decimal): Auto-calculated (qty × unit_price − discount)
    """

    invoice = models.ForeignKey(
        Invoice,
        on_delete=models.CASCADE,
        related_name='items',
        verbose_name=_("Invoice"),
    )

    fee_structure = models.ForeignKey(
        FeeStructure,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_("Fee Structure"),
    )

    school_item = models.ForeignKey(
        SchoolItemPrice,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_("School Item"),
        help_text=_("For uniform / sportswear / report card / pullover sales"),
    )

    description = models.CharField(
        max_length=200,
        verbose_name=_("Description"),
    )

    quantity = models.PositiveIntegerField(
        default=1,
        verbose_name=_("Quantity"),
    )

    unit_price = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        verbose_name=_("Unit Price (XAF)"),
    )

    discount = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        default=0,
        verbose_name=_("Discount (XAF)"),
    )

    total = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        verbose_name=_("Total (XAF)"),
    )

    class Meta:
        verbose_name = _("Invoice Item")
        verbose_name_plural = _("Invoice Items")

    def save(self, *args, **kwargs):
        self.total = (self.quantity * self.unit_price) - self.discount
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.description} × {self.quantity} = {int(self.total):,} XAF"


# ---------------------------------------------------------------------------
# Payment
# ---------------------------------------------------------------------------

class Payment(models.Model):
    """
    Records a payment made against an invoice.

    Supports cash, mobile money (MTN/Orange), bank transfer, and cheque.
    On save, the parent invoice's amount_paid and status are updated.

    Attributes:
        payment_number (str): Unique auto-generated identifier (PAY-YYYY-NNNN)
        invoice (FK): Invoice being paid
        student (FK): Student making the payment
        amount (Decimal): Amount paid in XAF
        payment_method (str): Cash / Mobile Money / Bank Transfer / Cheque
        payment_date (date): Date of payment
        mobile_money_provider (str): MTN or Orange (if mobile money)
        mobile_money_number (str): MoMo account used
        transaction_id (str): Bank / MoMo transaction reference
        bank_name (str): Bank name (if bank transfer)
        cheque_number (str): Cheque number (if cheque)
        status (str): Pending / Completed / Failed / Cancelled / Refunded
        receipt_number (str): Receipt number issued
        receipt_issued (bool): Whether receipt was printed/issued
        receipt_issued_date (date): Date receipt was issued
        notes (str): Free-text notes
        received_by (FK): Staff who accepted payment
        created_at / updated_at: Timestamps
    """

    PAYMENT_METHOD_CHOICES = [
        ('cash',          _('Cash')),
        ('mobile_money',  _('Mobile Money (MTN / Orange)')),
        ('bank_transfer', _('Bank Transfer')),
        ('cheque',        _('Cheque')),
        ('other',         _('Other')),
    ]

    PAYMENT_STATUS_CHOICES = [
        ('pending',   _('Pending')),
        ('completed', _('Completed')),
        ('failed',    _('Failed')),
        ('cancelled', _('Cancelled')),
        ('refunded',  _('Refunded')),
    ]

    MOBILE_MONEY_PROVIDERS = [
        ('mtn',           _('MTN Mobile Money')),
        ('orange',        _('Orange Money')),
        ('express_union', _('Express Union')),
        ('other',         _('Other')),
    ]

    payment_number = models.CharField(
        max_length=20,
        unique=True,
        blank=True,
        verbose_name=_("Payment Number"),
    )

    invoice = models.ForeignKey(
        Invoice,
        on_delete=models.CASCADE,
        related_name='payments',
        verbose_name=_("Invoice"),
    )

    student = models.ForeignKey(
        Student,
        on_delete=models.CASCADE,
        related_name='payments',
        verbose_name=_("Student"),
    )

    amount = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        validators=[MinValueValidator(1)],
        verbose_name=_("Amount (XAF)"),
    )

    payment_method = models.CharField(
        max_length=20,
        choices=PAYMENT_METHOD_CHOICES,
        verbose_name=_("Payment Method"),
    )

    payment_date = models.DateField(
        default=timezone.now,
        verbose_name=_("Payment Date"),
    )

    mobile_money_provider = models.CharField(
        max_length=20,
        choices=MOBILE_MONEY_PROVIDERS,
        blank=True,
        verbose_name=_("Mobile Money Provider"),
    )

    mobile_money_number = models.CharField(
        max_length=20,
        blank=True,
        verbose_name=_("Mobile Money Number"),
    )

    transaction_id = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Transaction ID / Reference"),
    )

    bank_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Bank Name"),
    )

    cheque_number = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Cheque Number"),
    )

    status = models.CharField(
        max_length=20,
        choices=PAYMENT_STATUS_CHOICES,
        default='pending',
        verbose_name=_("Status"),
    )

    receipt_number = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Receipt Number"),
    )

    receipt_issued = models.BooleanField(
        default=False,
        verbose_name=_("Receipt Issued"),
    )

    receipt_issued_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Receipt Issued Date"),
    )

    notes = models.TextField(
        blank=True,
        verbose_name=_("Notes"),
    )

    received_by = models.ForeignKey(
        CustomUser,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='payments_received',
        verbose_name=_("Received By"),
    )

    created_at = models.DateTimeField(
        auto_now_add=True,
        null=True,
        blank=True,
        verbose_name=_("Created At"),
    )

    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Updated At"),
    )

    class Meta:
        verbose_name = _("Payment")
        verbose_name_plural = _("Payments")
        ordering = ['-payment_date', '-created_at']
        indexes = [
            models.Index(fields=['payment_number']),
            models.Index(fields=['invoice', 'status']),
            models.Index(fields=['payment_date']),
            models.Index(fields=['student']),
        ]

    def save(self, *args, **kwargs):
        """Auto-generate payment number; update invoice totals on completion."""
        if not self.payment_number:
            year = timezone.now().year
            last = Payment.objects.filter(
                payment_number__startswith=f"PAY-{year}"
            ).order_by('-id').first()
            new_num = (int(last.payment_number.split('-')[-1]) + 1) if last else 1
            self.payment_number = f"PAY-{year}-{new_num:04d}"

        super().save(*args, **kwargs)

        if self.status == 'completed':
            total_paid = (
                Payment.objects.filter(invoice=self.invoice, status='completed')
                .aggregate(total=models.Sum('amount'))['total'] or 0
            )
            self.invoice.amount_paid = total_paid
            self.invoice.save()

    def __str__(self):
        return f"{self.payment_number} — {int(self.amount):,} XAF — {self.payment_date}"


# ---------------------------------------------------------------------------
# PaymentReminder
# ---------------------------------------------------------------------------

class PaymentReminder(models.Model):
    """
    Tracks payment reminders sent to parents for overdue invoices.

    Attributes:
        invoice (FK): Invoice being reminded about
        reminder_type (str): SMS / Email / WhatsApp / Call / Letter
        sent_to (str): Phone number or email address
        sent_date (datetime): When the reminder was sent
        sent_by (FK): Staff who sent the reminder
        response (str): Any response received
    """

    REMINDER_TYPE_CHOICES = [
        ('sms',       _('SMS')),
        ('email',     _('Email')),
        ('whatsapp',  _('WhatsApp')),
        ('call',      _('Phone Call')),
        ('letter',    _('Physical Letter')),
    ]

    invoice = models.ForeignKey(
        Invoice,
        on_delete=models.CASCADE,
        related_name='reminders',
        verbose_name=_("Invoice"),
    )

    reminder_type = models.CharField(
        max_length=20,
        choices=REMINDER_TYPE_CHOICES,
        verbose_name=_("Reminder Type"),
    )

    sent_to = models.CharField(
        max_length=100,
        verbose_name=_("Sent To"),
    )

    sent_date = models.DateTimeField(
        auto_now_add=True,
        null=True,
        blank=True,
        verbose_name=_("Sent Date"),
    )

    sent_by = models.ForeignKey(
        CustomUser,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_("Sent By"),
    )

    response = models.TextField(
        blank=True,
        verbose_name=_("Response"),
    )

    class Meta:
        verbose_name = _("Payment Reminder")
        verbose_name_plural = _("Payment Reminders")
        ordering = ['-sent_date']

    def __str__(self):
        date_str = self.sent_date.date() if self.sent_date else "pending"
        return f"{self.get_reminder_type_display()} to {self.sent_to} on {date_str}"


# ---------------------------------------------------------------------------
# Discount / StudentDiscount
# ---------------------------------------------------------------------------

class Discount(models.Model):
    """
    Discount definitions (sibling discount, staff-child discount, etc.).

    Attributes:
        name (str): Discount name in English
        name_fr (str): Discount name in French
        discount_type (str): Percentage or fixed XAF amount
        value (Decimal): Numeric discount value
        applies_to (str): All fees / Tuition only / Specific fees
        specific_fees (M2M): Specific FeeStructure rows if applicable
        description (str): Notes
        is_active (bool): Whether discount is currently available
    """

    DISCOUNT_TYPE_CHOICES = [
        ('percentage', _('Percentage (%)')),
        ('fixed',      _('Fixed Amount (XAF)')),
    ]

    APPLIES_TO_CHOICES = [
        ('all_fees',      _('All Fees')),
        ('tuition_only',  _('Tuition Only')),
        ('specific_fees', _('Specific Fee Rows')),
    ]

    name = models.CharField(max_length=100, verbose_name=_("Discount Name"))
    name_fr = models.CharField(max_length=100, blank=True, verbose_name=_("Discount Name (French)"))
    discount_type = models.CharField(max_length=20, choices=DISCOUNT_TYPE_CHOICES, default='percentage')
    value = models.DecimalField(max_digits=5, decimal_places=0, verbose_name=_("Value"))
    applies_to = models.CharField(max_length=20, choices=APPLIES_TO_CHOICES, default='all_fees')
    specific_fees = models.ManyToManyField(FeeStructure, blank=True, verbose_name=_("Specific Fee Rows"))
    description = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        verbose_name = _("Discount")
        verbose_name_plural = _("Discounts")

    def __str__(self):
        symbol = "%" if self.discount_type == 'percentage' else " XAF"
        return f"{self.name} — {int(self.value)}{symbol}"


class StudentDiscount(models.Model):
    """
    Applies a Discount to a specific student for a given academic year.

    Attributes:
        student (FK): Student receiving the discount
        discount (FK): Discount being applied
        academic_year (str): Academic year
        reason (str): Justification
        approved_by (FK): Authorising staff member
        created_at (datetime): When the discount was applied
    """

    student = models.ForeignKey(
        Student, on_delete=models.CASCADE, related_name='discounts', verbose_name=_("Student")
    )
    discount = models.ForeignKey(
        Discount, on_delete=models.CASCADE, verbose_name=_("Discount")
    )
    academic_year = models.CharField(max_length=9, default="2025-2026", verbose_name=_("Academic Year"))
    reason = models.CharField(max_length=200, blank=True, verbose_name=_("Reason"))
    approved_by = models.ForeignKey(
        CustomUser, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='approved_discounts', verbose_name=_("Approved By")
    )
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)

    class Meta:
        verbose_name = _("Student Discount")
        verbose_name_plural = _("Student Discounts")
        unique_together = [['student', 'discount', 'academic_year']]

    def __str__(self):
        return f"{self.student} — {self.discount} ({self.academic_year})"


# ---------------------------------------------------------------------------
# Expense tracking
# ---------------------------------------------------------------------------

class ExpenseCategory(models.Model):
    name = models.CharField(max_length=100, unique=True, verbose_name=_("Category Name"))
    name_fr = models.CharField(max_length=100, blank=True, verbose_name=_("Category Name (French)"))
    description = models.TextField(blank=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        verbose_name = _("Expense Category")
        verbose_name_plural = _("Expense Categories")
        ordering = ['name']

    def __str__(self):
        return self.name


class Expense(models.Model):
    """
    Records a school expenditure.

    Attributes:
        expense_number (str): Auto-generated (EXP-YYYY-NNNN)
        category (FK): Expense category
        description (str): What was purchased / paid
        amount (Decimal): Amount in XAF
        expense_date (date): Date of expense
        payment_method (str): Cash / Mobile Money / Bank / Cheque
        receipt_number (str): Reference on physical receipt
        vendor (str): Supplier / payee name
        notes (str): Additional notes
        approved_by (FK): Authorising staff
        receipt_file (FileField): Scanned/photographed receipt
        created_by (FK): Staff who entered the record
        created_at / updated_at: Timestamps
    """

    PAYMENT_METHOD_CHOICES = [
        ('cash',          _('Cash')),
        ('mobile_money',  _('Mobile Money')),
        ('bank_transfer', _('Bank Transfer')),
        ('cheque',        _('Cheque')),
    ]

    expense_number = models.CharField(max_length=20, unique=True, blank=True, verbose_name=_("Expense Number"))
    category = models.ForeignKey(ExpenseCategory, on_delete=models.PROTECT, related_name='expenses')
    description = models.CharField(max_length=200, verbose_name=_("Description"))
    amount = models.DecimalField(max_digits=10, decimal_places=0, verbose_name=_("Amount (XAF)"))
    expense_date = models.DateField(default=timezone.now, verbose_name=_("Date"))
    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHOD_CHOICES, default='cash')
    receipt_number = models.CharField(max_length=50, blank=True)
    vendor = models.CharField(max_length=100, blank=True, verbose_name=_("Vendor/Payee"))
    notes = models.TextField(blank=True)
    approved_by = models.ForeignKey(
        CustomUser, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='approved_expenses'
    )
    receipt_file = models.FileField(upload_to='expenses/receipts/', null=True, blank=True)
    created_by = models.ForeignKey(
        CustomUser, on_delete=models.SET_NULL, null=True, blank=True,
        related_name='expenses_created'
    )
    created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = _("Expense")
        verbose_name_plural = _("Expenses")
        ordering = ['-expense_date']

    def save(self, *args, **kwargs):
        if not self.expense_number:
            year = timezone.now().year
            last = Expense.objects.filter(expense_number__startswith=f"EXP-{year}").order_by('-id').first()
            new_num = (int(last.expense_number.split('-')[-1]) + 1) if last else 1
            self.expense_number = f"EXP-{year}-{new_num:04d}"
        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.expense_number} — {int(self.amount):,} XAF — {self.expense_date}"


class FinancialReport(models.Model):
    """
    Stores generated financial summary reports.

    Attributes:
        title (str): Report title
        report_type (str): Daily / Weekly / Monthly / Termly / Annual / Custom
        start_date (date): Period start
        end_date (date): Period end
        total_revenue (Decimal): Total income in XAF
        total_expenses (Decimal): Total outgoings in XAF
        net_profit (Decimal): Revenue minus expenses
        report_file (FileField): Generated PDF/Excel file
        generated_by (FK): User who triggered report generation
        generated_at (datetime): Timestamp
        notes (str): Additional comments
    """

    REPORT_TYPE_CHOICES = [
        ('daily',   _('Daily Report')),
        ('weekly',  _('Weekly Report')),
        ('monthly', _('Monthly Report')),
        ('termly',  _('Termly Report')),
        ('annual',  _('Annual Report')),
        ('custom',  _('Custom Date Range')),
    ]

    title = models.CharField(max_length=200, verbose_name=_("Report Title"))
    report_type = models.CharField(max_length=20, choices=REPORT_TYPE_CHOICES)
    start_date = models.DateField()
    end_date = models.DateField()
    total_revenue = models.DecimalField(max_digits=12, decimal_places=0, default=0)
    total_expenses = models.DecimalField(max_digits=12, decimal_places=0, default=0)
    net_profit = models.DecimalField(max_digits=12, decimal_places=0, default=0)
    report_file = models.FileField(upload_to='reports/financial/', null=True, blank=True)
    generated_by = models.ForeignKey(
        CustomUser, on_delete=models.SET_NULL, null=True, blank=True
    )
    generated_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
    notes = models.TextField(blank=True)

    class Meta:
        verbose_name = _("Financial Report")
        verbose_name_plural = _("Financial Reports")
        ordering = ['-generated_at']

    def __str__(self):
        return f"{self.title} — {self.start_date} to {self.end_date}"

======================================================================
FILE: finance/signals.py
======================================================================
# finance/signals.py
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from .models import Invoice, Payment
from .utils import generate_invoice_number

@receiver(pre_save, sender=Invoice)
def set_invoice_number(sender, instance, **kwargs):
    """Generate invoice number before saving"""
    if not instance.invoice_number:
        from .utils import generate_invoice_number
        instance.invoice_number = generate_invoice_number()

@receiver(post_save, sender=Payment)
def update_invoice_on_payment(sender, instance, created, **kwargs):
    """Update invoice amount_paid when payment is saved"""
    if instance.status == 'completed':
        invoice = instance.invoice
        from django.db.models import Sum
        total_paid = Payment.objects.filter(
            invoice=invoice,
            status='completed'
        ).aggregate(Sum('amount'))['amount__sum'] or 0
        invoice.amount_paid = total_paid
        invoice.save()

======================================================================
FILE: finance/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: finance/urls-1.py
======================================================================
# finance/urls.py
from django.urls import path
from . import views

app_name = 'finance'

urlpatterns = [
    # Invoices
    path('invoices/', views.InvoiceListView.as_view(), name='invoice_list'),
    path('invoices/<int:pk>/', views.InvoiceDetailView.as_view(), name='invoice_detail'),
    path('invoices/create/', views.InvoiceCreateView.as_view(), name='invoice_create'),
    path('invoices/<int:pk>/edit/', views.InvoiceUpdateView.as_view(), name='invoice_edit'),
    path('invoices/<int:pk>/delete/', views.InvoiceDeleteView.as_view(), name='invoice_delete'),
    path('invoices/export/', views.export_invoices_csv, name='export_invoices'),    
    # Payments
    path('payments/', views.PaymentListView.as_view(), name='payment_list'),
    path('payments/add/', views.PaymentCreateView.as_view(), name='payment_add'),
    path('payments/<int:pk>/', views.PaymentDetailView.as_view(), name='payment_detail'),
    path('payments/export/', views.export_payments_csv, name='export_payments'),    
    # Fee Structure
    path('fees/', views.FeeStructureListView.as_view(), name='fee_list'),
    path('fees/<int:pk>/', views.FeeStructureDetailView.as_view(), name='fee_detail'),    
    # Reports
    path('reports/', views.FinancialReportsView.as_view(), name='financial_reports'),
    path('reports/generate/', views.generate_financial_report, name='generate_report'),    
    # Bursar Dashboard
    path('bursar/', views.BursarDashboardView.as_view(), name='bursar_dashboard'),    
    # API
    path('api/stats/', views.get_finance_stats, name='finance_stats'),
]

======================================================================
FILE: finance/urls.py
======================================================================
# finance/urls.py
from django.urls import path
from . import views

app_name = 'finance'

urlpatterns = [

    # ── Bursar Dashboard ────────────────────────────────────────────────────
    path('bursar/', views.BursarDashboardView.as_view(), name='bursar_dashboard'),

    # ── Fee Structures ──────────────────────────────────────────────────────
    path('fees/',                    views.FeeStructureListView.as_view(),   name='fee_list'),
    path('fees/add/',                views.FeeStructureCreateView.as_view(), name='fee_add'),
    path('fees/<int:pk>/',           views.FeeStructureDetailView.as_view(), name='fee_detail'),
    path('fees/<int:pk>/edit/',      views.FeeStructureUpdateView.as_view(), name='fee_edit'),
    path('fees/<int:pk>/delete/',    views.FeeStructureDeleteView.as_view(), name='fee_delete'),

    # ── School Item Prices (uniforms, sportswear, report card, pullovers) ───
    path('school-items/',            views.SchoolItemPriceListView.as_view(),   name='school_item_list'),
    path('school-items/add/',        views.SchoolItemPriceCreateView.as_view(), name='school_item_add'),
    path('school-items/<int:pk>/edit/', views.SchoolItemPriceUpdateView.as_view(), name='school_item_edit'),

    # ── Student Enrollment Fees ─────────────────────────────────────────────
    path('enrollment-fees/',         views.StudentEnrollmentFeeListView.as_view(),   name='enrollment_fee_list'),
    path('enrollment-fees/add/',     views.StudentEnrollmentFeeCreateView.as_view(), name='enrollment_fee_add'),

    # ── Invoices ────────────────────────────────────────────────────────────
    path('invoices/',                views.InvoiceListView.as_view(),   name='invoice_list'),
    path('invoices/create/',         views.InvoiceCreateView.as_view(), name='invoice_create'),
    path('invoices/bulk/',           views.BulkInvoiceGenerateView.as_view(), name='bulk_invoice'),
    path('invoices/export/',         views.export_invoices_csv,         name='export_invoices'),
    path('invoices/<int:pk>/',       views.InvoiceDetailView.as_view(), name='invoice_detail'),
    path('invoices/<int:pk>/edit/',  views.InvoiceUpdateView.as_view(), name='invoice_edit'),
    path('invoices/<int:pk>/delete/', views.InvoiceDeleteView.as_view(), name='invoice_delete'),
    path('invoices/<int:pk>/send/',  views.mark_invoice_as_sent,        name='invoice_send'),
    path('invoices/<int:pk>/remind/', views.send_payment_reminder,      name='invoice_remind'),

    # ── Payments ────────────────────────────────────────────────────────────
    path('payments/',                views.PaymentListView.as_view(),   name='payment_list'),
    path('payments/add/',            views.PaymentCreateView.as_view(), name='payment_add'),
    path('payments/export/',         views.export_payments_csv,         name='export_payments'),
    path('payments/<int:pk>/',       views.PaymentDetailView.as_view(), name='payment_detail'),
    path('payments/<int:pk>/edit/',  views.PaymentUpdateView.as_view(), name='payment_edit'),
    path('payments/<int:pk>/receipt/', views.generate_receipt,          name='generate_receipt'),

    # ── Expenses ────────────────────────────────────────────────────────────
    path('expenses/',                views.ExpenseListView.as_view(),   name='expense_list'),
    path('expenses/add/',            views.ExpenseCreateView.as_view(), name='expense_add'),
    path('expenses/<int:pk>/edit/',  views.ExpenseUpdateView.as_view(), name='expense_edit'),
    path('expenses/<int:pk>/approve/', views.approve_expense,           name='expense_approve'),
    path('expenses/categories/',     views.ExpenseCategoryListView.as_view(), name='expense_categories'),

    # ── Discounts ───────────────────────────────────────────────────────────
    path('discounts/',               views.DiscountListView.as_view(),        name='discount_list'),
    path('discounts/add/',           views.DiscountCreateView.as_view(),      name='discount_add'),
    path('discounts/student/add/',   views.StudentDiscountCreateView.as_view(), name='student_discount_add'),

    # ── Reports ─────────────────────────────────────────────────────────────
    path('reports/',                 views.FinancialReportsView.as_view(),    name='financial_reports'),
    path('reports/generate/',        views.generate_financial_report,         name='generate_report'),

    # ── API ─────────────────────────────────────────────────────────────────
    path('api/stats/',               views.get_finance_stats,                 name='finance_stats'),
]

======================================================================
FILE: finance/utils.py
======================================================================
# finance/utils.py (create this new file)
from django.utils import timezone

def generate_invoice_number():
    """Generate a unique invoice number"""
    from .models import Invoice
    
    year = timezone.now().year
    last_invoice = Invoice.objects.filter(
        invoice_number__startswith=f"INV-{year}"
    ).order_by('-id').first()
    
    if last_invoice and last_invoice.invoice_number:
        try:
            last_num = int(last_invoice.invoice_number.split('-')[-1])
            new_num = last_num + 1
        except (ValueError, IndexError):
            new_num = 1
    else:
        new_num = 1
    
    return f"INV-{year}-{new_num:04d}"

======================================================================
FILE: finance/views.py
======================================================================
# finance/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from core.permissions import BursarRequiredMixin, ManagementRequiredMixin, can
from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q, Sum, Count
from django.http import JsonResponse, HttpResponse
from django.utils import timezone
from datetime import datetime, timedelta, date as date_type
import csv

from .models import (
    FeeStructure, SchoolItemPrice, StudentEnrollmentFee,
    Invoice, InvoiceItem, Payment,
    PaymentReminder, Discount, StudentDiscount,
    ExpenseCategory, Expense, FinancialReport
)
from students.models import Student
from academics.models import SchoolClass
from core.models import CustomUser


# ============================================================
# FEE STRUCTURE VIEWS
# ============================================================

class FeeStructureListView(LoginRequiredMixin, ListView):
    """List all fee structures grouped by section."""
    model = FeeStructure
    template_name = 'finance/fee_structure.html'
    context_object_name = 'fees'
    paginate_by = 20

    def get_queryset(self):
        qs = FeeStructure.objects.all()

        year = self.request.GET.get('academic_year')
        if year:
            qs = qs.filter(academic_year=year)

        section = self.request.GET.get('section')
        if section:
            qs = qs.filter(section=section)

        active = self.request.GET.get('active')
        if active == 'active':
            qs = qs.filter(is_active=True)
        elif active == 'inactive':
            qs = qs.filter(is_active=False)

        return qs.order_by('-academic_year', 'section', 'class_group')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['section_choices'] = FeeStructure._meta.get_field('section').choices
        context['academic_years'] = (
            FeeStructure.objects.values_list('academic_year', flat=True).distinct()
        )
        return context


class FeeStructureDetailView(LoginRequiredMixin, DetailView):
    """View a single fee structure row."""
    model = FeeStructure
    template_name = 'finance/fee_detail.html'
    context_object_name = 'fee'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['applicable_classes'] = self.object.specific_classes.all()
        return context


class FeeStructureCreateView(BursarRequiredMixin, CreateView):
    """Create a new fee structure row."""
    model = FeeStructure
    fields = [
        'section', 'class_group', 'academic_year',
        'registration_new', 'registration_old',
        'total_fees', 'installment_1', 'installment_2',
        'specific_classes', 'is_active', 'description',
    ]
    template_name = 'finance/fee_form.html'
    success_url = reverse_lazy('finance:fee_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Add New Fee Structure'
        return context

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        messages.success(self.request, 'Fee structure created successfully!')
        return super().form_valid(form)


class FeeStructureUpdateView(BursarRequiredMixin, UpdateView):
    """Edit an existing fee structure."""
    model = FeeStructure
    fields = [
        'section', 'class_group', 'academic_year',
        'registration_new', 'registration_old',
        'total_fees', 'installment_1', 'installment_2',
        'specific_classes', 'is_active', 'description',
    ]
    template_name = 'finance/fee_form.html'
    success_url = reverse_lazy('finance:fee_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.name}'
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Fee structure updated successfully!')
        return super().form_valid(form)


class FeeStructureDeleteView(BursarRequiredMixin, DeleteView):
    """Delete a fee structure."""
    model = FeeStructure
    success_url = reverse_lazy('finance:fee_list')
    template_name = 'finance/fee_confirm_delete.html'

    def delete(self, request, *args, **kwargs):
        messages.success(request, 'Fee structure deleted.')
        return super().delete(request, *args, **kwargs)


# ============================================================
# SCHOOL ITEM PRICE VIEWS  (uniforms, sportswear, etc.)
# ============================================================

class SchoolItemPriceListView(BursarRequiredMixin, ListView):
    """List all school item prices."""
    model = SchoolItemPrice
    template_name = 'finance/school_item_list.html'
    context_object_name = 'items'

    def get_queryset(self):
        return SchoolItemPrice.objects.all().order_by('item_type', 'name')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['item_type_choices'] = SchoolItemPrice.ITEM_TYPE_CHOICES
        return context


class SchoolItemPriceCreateView(BursarRequiredMixin, CreateView):
    """Add a new school item price."""
    model = SchoolItemPrice
    fields = ['item_type', 'name', 'price', 'academic_year', 'is_active', 'description']
    template_name = 'finance/school_item_form.html'
    success_url = reverse_lazy('finance:school_item_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Add School Item Price'
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Item price saved.')
        return super().form_valid(form)


class SchoolItemPriceUpdateView(BursarRequiredMixin, UpdateView):
    """Edit a school item price."""
    model = SchoolItemPrice
    fields = ['item_type', 'name', 'price', 'academic_year', 'is_active', 'description']
    template_name = 'finance/school_item_form.html'
    success_url = reverse_lazy('finance:school_item_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.name}'
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Item price updated.')
        return super().form_valid(form)


# ============================================================
# STUDENT ENROLLMENT FEE VIEWS
# ============================================================

class StudentEnrollmentFeeListView(BursarRequiredMixin, ListView):
    """List all student enrollment fee records."""
    model = StudentEnrollmentFee
    template_name = 'finance/enrollment_fee_list.html'
    context_object_name = 'enrollment_fees'
    paginate_by = 30

    def get_queryset(self):
        qs = StudentEnrollmentFee.objects.select_related('student', 'fee_structure')

        year = self.request.GET.get('academic_year')
        if year:
            qs = qs.filter(academic_year=year)

        search = self.request.GET.get('q')
        if search:
            qs = qs.filter(
                Q(student__first_name__icontains=search) |
                Q(student__last_name__icontains=search) |
                Q(student__student_id__icontains=search)
            )
        return qs.order_by('student__last_name', 'student__first_name')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['academic_years'] = (
            StudentEnrollmentFee.objects.values_list('academic_year', flat=True).distinct()
        )
        return context


class StudentEnrollmentFeeCreateView(BursarRequiredMixin, CreateView):
    """Create a student enrollment fee record."""
    model = StudentEnrollmentFee
    fields = [
        'student', 'fee_structure', 'academic_year',
        'is_new_pupil', 'installment_1_due', 'installment_2_due', 'notes',
    ]
    template_name = 'finance/enrollment_fee_form.html'
    success_url = reverse_lazy('finance:enrollment_fee_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Enroll Student — Assign Fee Structure'
        context['fee_structures'] = FeeStructure.objects.filter(is_active=True)
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Enrollment fee record created.')
        return super().form_valid(form)


# ============================================================
# INVOICE VIEWS
# ============================================================

class InvoiceListView(LoginRequiredMixin, ListView):
    """List all invoices with search and filtering."""
    model = Invoice
    template_name = 'finance/invoices.html'
    context_object_name = 'invoices'
    paginate_by = 20

    def get_queryset(self):
        qs = Invoice.objects.all().select_related('student', 'created_by')

        search = self.request.GET.get('q')
        if search:
            qs = qs.filter(
                Q(invoice_number__icontains=search) |
                Q(student__first_name__icontains=search) |
                Q(student__last_name__icontains=search)
            )

        status = self.request.GET.get('status')
        if status:
            qs = qs.filter(status=status)

        year = self.request.GET.get('academic_year')
        if year:
            qs = qs.filter(academic_year=year)

        # Filter by invoice_type (replaces old 'term' filter)
        invoice_type = self.request.GET.get('invoice_type')
        if invoice_type:
            qs = qs.filter(invoice_type=invoice_type)

        return qs.order_by('-issue_date')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_invoices'] = Invoice.objects.count()
        context['total_amount']   = Invoice.objects.aggregate(Sum('total_amount'))['total_amount__sum'] or 0
        context['total_paid']     = Invoice.objects.aggregate(Sum('amount_paid'))['amount_paid__sum'] or 0
        context['total_balance']  = context['total_amount'] - context['total_paid']
        context['status_choices']       = Invoice.STATUS_CHOICES
        context['invoice_type_choices'] = Invoice.INVOICE_TYPE_CHOICES
        context['academic_years'] = Invoice.objects.values_list('academic_year', flat=True).distinct()
        context['today'] = timezone.now().date()
        return context


class InvoiceDetailView(LoginRequiredMixin, DetailView):
    """View a single invoice."""
    model = Invoice
    template_name = 'finance/invoice_detail.html'
    context_object_name = 'invoice'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['items']    = self.object.items.all()
        context['payments'] = self.object.payments.all().order_by('-payment_date')
        context['reminders'] = self.object.reminders.all().order_by('-sent_date')
        return context


class InvoiceCreateView(BursarRequiredMixin, CreateView):
    """Create a new invoice."""
    model = Invoice
    fields = [
        'student', 'enrollment_fee', 'academic_year', 'invoice_type',
        'due_date', 'total_amount', 'notes',
    ]
    template_name = 'finance/invoice_form.html'
    success_url = reverse_lazy('finance:invoice_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Create New Invoice'
        context['students'] = Student.objects.filter(status='active')
        return context

    def form_valid(self, form):
        form.instance.balance    = form.instance.total_amount
        form.instance.created_by = self.request.user
        form.instance.status     = 'draft'
        messages.success(self.request, 'Invoice created successfully!')
        return super().form_valid(form)


class InvoiceUpdateView(BursarRequiredMixin, UpdateView):
    """Edit an existing invoice."""
    model = Invoice
    fields = ['due_date', 'notes', 'status']
    template_name = 'finance/invoice_form.html'
    success_url = reverse_lazy('finance:invoice_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit Invoice {self.object.invoice_number}'
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Invoice updated successfully!')
        return super().form_valid(form)


class InvoiceDeleteView(BursarRequiredMixin, DeleteView):
    """Delete an invoice."""
    model = Invoice
    success_url = reverse_lazy('finance:invoice_list')
    template_name = 'finance/invoice_confirm_delete.html'

    def delete(self, request, *args, **kwargs):
        messages.success(request, 'Invoice deleted.')
        return super().delete(request, *args, **kwargs)


def mark_invoice_as_sent(request, pk):
    invoice = get_object_or_404(Invoice, pk=pk)
    invoice.status = 'sent'
    invoice.save()
    messages.success(request, f'Invoice {invoice.invoice_number} marked as sent.')
    return redirect('finance:invoice_detail', pk=pk)


def send_payment_reminder(request, pk):
    invoice = get_object_or_404(Invoice, pk=pk)
    if request.method == 'POST':
        reminder_type = request.POST.get('reminder_type')
        sent_to       = request.POST.get('sent_to')
        PaymentReminder.objects.create(
            invoice=invoice,
            reminder_type=reminder_type,
            sent_to=sent_to,
            sent_by=request.user,
        )
        invoice.last_reminder_sent = timezone.now().date()
        invoice.save()
        messages.success(request, f'Reminder sent to {sent_to}.')
    return redirect('finance:invoice_detail', pk=pk)


# ============================================================
# PAYMENT VIEWS
# ============================================================

class PaymentListView(LoginRequiredMixin, ListView):
    """List all payments."""
    model = Payment
    template_name = 'finance/payments.html'
    context_object_name = 'payments'
    paginate_by = 20

    def get_queryset(self):
        qs = Payment.objects.all().select_related('invoice', 'student', 'received_by')

        from_date = self.request.GET.get('from_date')
        to_date   = self.request.GET.get('to_date')
        if from_date:
            qs = qs.filter(payment_date__gte=from_date)
        if to_date:
            qs = qs.filter(payment_date__lte=to_date)

        method = self.request.GET.get('method')
        if method:
            qs = qs.filter(payment_method=method)

        status = self.request.GET.get('status')
        if status:
            qs = qs.filter(status=status)

        return qs.order_by('-payment_date')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_payments']  = Payment.objects.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0
        context['payment_count']   = Payment.objects.filter(status='completed').count()
        context['payment_methods'] = Payment.PAYMENT_METHOD_CHOICES
        context['status_choices']  = Payment.PAYMENT_STATUS_CHOICES
        return context


class PaymentDetailView(LoginRequiredMixin, DetailView):
    model = Payment
    template_name = 'finance/payment_detail.html'
    context_object_name = 'payment'


class PaymentCreateView(BursarRequiredMixin, CreateView):
    """Record a new payment."""
    model = Payment
    fields = [
        'invoice', 'amount', 'payment_method', 'payment_date',
        'mobile_money_provider', 'mobile_money_number',
        'transaction_id', 'bank_name', 'cheque_number',
        'notes', 'status',
    ]
    template_name = 'finance/payment_form.html'
    success_url = reverse_lazy('finance:payment_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Record New Payment'
        invoice_id = self.request.GET.get('invoice')
        if invoice_id:
            context['selected_invoice'] = get_object_or_404(Invoice, pk=invoice_id)
        return context

    def form_valid(self, form):
        form.instance.student     = form.instance.invoice.student
        form.instance.received_by = self.request.user
        messages.success(self.request, 'Payment recorded successfully!')
        return super().form_valid(form)


class PaymentUpdateView(BursarRequiredMixin, UpdateView):
    model = Payment
    fields = ['status', 'notes', 'receipt_issued', 'receipt_number']
    template_name = 'finance/payment_form.html'
    success_url = reverse_lazy('finance:payment_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Update Payment {self.object.payment_number}'
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Payment updated!')
        return super().form_valid(form)


def generate_receipt(request, pk):
    """Generate and display a printable receipt for a payment."""
    payment = get_object_or_404(Payment, pk=pk)

    if not payment.receipt_issued:
        payment.receipt_issued      = True
        payment.receipt_issued_date = timezone.now().date()
        if not payment.receipt_number:
            payment.receipt_number = f"RCT-{payment.payment_number}"
        payment.save()

    items = payment.invoice.items.all() if hasattr(payment.invoice, 'items') else []

    context = {
        'payment': payment,
        'items':   items,
        'amount_in_words': _amount_in_words(payment.amount),
    }
    return render(request, 'finance/receipt.html', context)


# ============================================================
# EXPENSE VIEWS
# ============================================================

class ExpenseListView(LoginRequiredMixin, ListView):
    model = Expense
    template_name = 'finance/expense_list.html'
    context_object_name = 'expenses'
    paginate_by = 20

    def get_queryset(self):
        qs = Expense.objects.all().select_related('category', 'approved_by', 'created_by')

        from_date = self.request.GET.get('from_date')
        to_date   = self.request.GET.get('to_date')
        if from_date:
            qs = qs.filter(expense_date__gte=from_date)
        if to_date:
            qs = qs.filter(expense_date__lte=to_date)

        category = self.request.GET.get('category')
        if category:
            qs = qs.filter(category_id=category)

        return qs.order_by('-expense_date')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_expenses'] = Expense.objects.aggregate(Sum('amount'))['amount__sum'] or 0
        context['categories']     = ExpenseCategory.objects.all()
        return context


class ExpenseCreateView(BursarRequiredMixin, CreateView):
    model = Expense
    fields = ['category', 'description', 'amount', 'expense_date', 'payment_method', 'vendor', 'notes', 'receipt_file']
    template_name = 'finance/expense_form.html'
    success_url = reverse_lazy('finance:expense_list')

    def form_valid(self, form):
        form.instance.created_by = self.request.user
        messages.success(self.request, 'Expense recorded successfully!')
        return super().form_valid(form)


class ExpenseUpdateView(BursarRequiredMixin, UpdateView):
    model = Expense
    fields = ['description', 'amount', 'payment_method', 'vendor', 'notes']
    template_name = 'finance/expense_form.html'
    success_url = reverse_lazy('finance:expense_list')

    def form_valid(self, form):
        messages.success(self.request, 'Expense updated!')
        return super().form_valid(form)


def approve_expense(request, pk):
    expense = get_object_or_404(Expense, pk=pk)
    expense.approved_by = request.user
    expense.save()
    messages.success(request, 'Expense approved.')
    return redirect('finance:expense_list')


# ============================================================
# EXPENSE CATEGORY VIEWS (unchanged — already correct)
# ============================================================

class ExpenseCategoryListView(BursarRequiredMixin, TemplateView):
    template_name = 'finance/expense_categories.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = ExpenseCategory.objects.all().order_by('name')
        return context

    def post(self, request, *args, **kwargs):
        action = request.POST.get('action')

        if action == 'seed':
            defaults = [
                ('Salaries & Wages',        'Salaires et traitements',    'Staff salaries, bonuses and allowances'),
                ('Teaching Materials',       'Matériel pédagogique',       'Textbooks, exercise books, chalk, markers'),
                ('Stationery & Supplies',    'Papeterie et fournitures',   'Office and administrative supplies'),
                ('Utilities',               'Services publics',            'Electricity, water, internet, telephone'),
                ('Maintenance & Repairs',   'Entretien et réparations',   'Building, equipment and vehicle repairs'),
                ('Transport',               'Transport',                   'School bus fuel, maintenance and driver costs'),
                ('Canteen & Catering',      'Cantine et restauration',    'Food supplies and canteen operations'),
                ('Uniforms & Sportswear',   'Uniformes et tenues',        'School uniform procurement'),
                ('Exams & Certificates',    'Examens et diplômes',        'Exam fees, printing and certification costs'),
                ('Events & Activities',     'Événements et activités',    'School celebrations, sports day, excursions'),
                ('IT & Technology',         'Informatique et technologie', 'Computers, printers, software'),
                ('Cleaning & Sanitation',   'Nettoyage et hygiène',       'Cleaning supplies and sanitation'),
                ('Security',                'Sécurité',                   'Security staff and equipment'),
                ('Bank & Admin Charges',    'Frais bancaires et admin',   'Bank fees, government levies, admin costs'),
                ('Miscellaneous',           'Divers',                     'Other expenses not categorised above'),
            ]
            created = 0
            for name, name_fr, desc in defaults:
                _, was_created = ExpenseCategory.objects.get_or_create(
                    name=name,
                    defaults={'name_fr': name_fr, 'description': desc, 'is_active': True}
                )
                if was_created:
                    created += 1
            if created:
                messages.success(request, f'✓ {created} default categor{"ies" if created != 1 else "y"} added.')
            else:
                messages.info(request, 'All default categories already exist.')

        elif action == 'add':
            name        = request.POST.get('name', '').strip()
            name_fr     = request.POST.get('name_fr', '').strip()
            description = request.POST.get('description', '').strip()
            if not name:
                messages.error(request, 'Category name is required.')
            elif ExpenseCategory.objects.filter(name__iexact=name).exists():
                messages.error(request, f'A category named "{name}" already exists.')
            else:
                ExpenseCategory.objects.create(name=name, name_fr=name_fr, description=description)
                messages.success(request, f'Category "{name}" added.')

        elif action == 'delete':
            pk  = request.POST.get('pk')
            cat = get_object_or_404(ExpenseCategory, pk=pk)
            if cat.expenses.exists():
                messages.error(request, f'Cannot delete "{cat.name}" — it has existing expenses.')
            else:
                cat.delete()
                messages.success(request, 'Category deleted.')

        elif action == 'toggle':
            pk  = request.POST.get('pk')
            cat = get_object_or_404(ExpenseCategory, pk=pk)
            cat.is_active = not cat.is_active
            cat.save()
            messages.success(request, f'"{cat.name}" {"activated" if cat.is_active else "deactivated"}.')

        return redirect('finance:expense_categories')


# ============================================================
# DISCOUNT VIEWS
# ============================================================

class DiscountListView(LoginRequiredMixin, ListView):
    model = Discount
    template_name = 'finance/discount_list.html'
    context_object_name = 'discounts'


class DiscountCreateView(BursarRequiredMixin, CreateView):
    model = Discount
    fields = ['name', 'name_fr', 'discount_type', 'value', 'applies_to', 'specific_fees', 'description', 'is_active']
    template_name = 'finance/discount_form.html'
    success_url = reverse_lazy('finance:discount_list')


class StudentDiscountCreateView(BursarRequiredMixin, CreateView):
    model = StudentDiscount
    fields = ['student', 'discount', 'academic_year', 'reason']
    template_name = 'finance/student_discount_form.html'
    success_url = reverse_lazy('finance:student_discount_list')

    def form_valid(self, form):
        form.instance.approved_by = self.request.user
        messages.success(self.request, 'Discount applied to student.')
        return super().form_valid(form)


# ============================================================
# BURSAR DASHBOARD
# ============================================================

class BursarDashboardView(LoginRequiredMixin, TemplateView):
    template_name = 'finance/bursar_dashboard.html'

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('login')
        if hasattr(request.user, 'staff_profile'):
            allowed = ['bursar', 'proprietor', 'admin', 'head_master', 'head_mistress']
            if request.user.staff_profile.role in allowed:
                return super().dispatch(request, *args, **kwargs)
        messages.error(request, "You don't have permission to access the bursar dashboard.")
        return redirect('dashboard')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        today     = timezone.now().date()
        first_day = today.replace(day=1)

        context['total_revenue'] = Payment.objects.filter(
            status='completed'
        ).aggregate(Sum('amount'))['amount__sum'] or 0

        context['monthly_revenue'] = Payment.objects.filter(
            status='completed', payment_date__gte=first_day
        ).aggregate(Sum('amount'))['amount__sum'] or 0

        context['pending_invoices'] = Invoice.objects.filter(status__in=['sent', 'partial']).count()
        context['overdue_invoices'] = Invoice.objects.filter(status='overdue').count()

        context['recent_payments'] = Payment.objects.filter(
            status='completed'
        ).select_related('student').order_by('-payment_date')[:10]

        context['upcoming_due'] = Invoice.objects.filter(
            status__in=['sent', 'partial'],
            due_date__gte=today,
            due_date__lte=today + timedelta(days=7),
        ).select_related('student')[:10]

        context['monthly_expenses'] = Expense.objects.filter(
            expense_date__gte=first_day
        ).aggregate(Sum('amount'))['amount__sum'] or 0

        context['net_income'] = context['monthly_revenue'] - context['monthly_expenses']

        # Chart: last 6 months
        labels, data = [], []
        for i in range(5, -1, -1):
            month = today - timedelta(days=30 * i)
            rev = Payment.objects.filter(
                status='completed',
                payment_date__year=month.year,
                payment_date__month=month.month,
            ).aggregate(Sum('amount'))['amount__sum'] or 0
            labels.append(month.strftime('%b %Y'))
            data.append(float(rev))

        context['chart_labels'] = labels
        context['chart_data']   = data
        return context


# ============================================================
# FINANCIAL REPORTS
# ============================================================

class FinancialReportsView(LoginRequiredMixin, TemplateView):
    template_name = 'finance/reports.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_revenue']  = Payment.objects.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0
        context['total_expenses'] = Expense.objects.aggregate(Sum('amount'))['amount__sum'] or 0
        context['outstanding']    = Invoice.objects.filter(
            status__in=['sent', 'partial', 'overdue']
        ).aggregate(Sum('balance'))['balance__sum'] or 0

        payment_methods = {}
        for code, label in Payment.PAYMENT_METHOD_CHOICES:
            total = Payment.objects.filter(
                status='completed', payment_method=code
            ).aggregate(Sum('amount'))['amount__sum'] or 0
            if total > 0:
                payment_methods[label] = float(total)
        context['payment_methods'] = payment_methods
        context['recent_reports']  = FinancialReport.objects.all().order_by('-generated_at')[:5]
        return context


def generate_financial_report(request):
    if request.method == 'POST':
        report_type  = request.POST.get('report_type')
        start_date   = request.POST.get('start_date')
        end_date     = request.POST.get('end_date')

        total_revenue  = Payment.objects.filter(
            status='completed', payment_date__gte=start_date, payment_date__lte=end_date
        ).aggregate(Sum('amount'))['amount__sum'] or 0

        total_expenses = Expense.objects.filter(
            expense_date__gte=start_date, expense_date__lte=end_date
        ).aggregate(Sum('amount'))['amount__sum'] or 0

        report = FinancialReport.objects.create(
            title=f"{report_type.title()} Report {start_date} to {end_date}",
            report_type=report_type,
            start_date=start_date,
            end_date=end_date,
            total_revenue=total_revenue,
            total_expenses=total_expenses,
            net_profit=total_revenue - total_expenses,
            generated_by=request.user,
        )
        messages.success(request, f'Report generated: {report.title}')
    return redirect('finance:financial_reports')


# ============================================================
# EXPORT FUNCTIONS
# ============================================================

def export_invoices_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="invoices_export.csv"'
    writer = csv.writer(response)
    writer.writerow([
        'Invoice #', 'Student', 'Academic Year', 'Type',
        'Issue Date', 'Due Date', 'Total', 'Paid', 'Balance', 'Status',
    ])
    for inv in Invoice.objects.select_related('student').all():
        writer.writerow([
            inv.invoice_number,
            str(inv.student),
            inv.academic_year,
            inv.get_invoice_type_display(),   # was get_term_display()
            inv.issue_date,
            inv.due_date,
            inv.total_amount,
            inv.amount_paid,
            inv.balance,
            inv.get_status_display(),
        ])
    return response


def export_payments_csv(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="payments_export.csv"'
    writer = csv.writer(response)
    writer.writerow(['Payment #', 'Invoice #', 'Student', 'Amount', 'Method', 'Date', 'Status'])
    for p in Payment.objects.select_related('invoice', 'student').all():
        writer.writerow([
            p.payment_number,
            p.invoice.invoice_number,
            str(p.student),
            p.amount,
            p.get_payment_method_display(),
            p.payment_date,
            p.get_status_display(),
        ])
    return response


# ============================================================
# API ENDPOINT
# ============================================================

def get_finance_stats(request):
    stats = {
        'total_revenue':    float(Payment.objects.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0),
        'pending_invoices': Invoice.objects.filter(status='sent').count(),
        'overdue_invoices': Invoice.objects.filter(status='overdue').count(),
        'paid_invoices':    Invoice.objects.filter(status='paid').count(),
        'total_expenses':   float(Expense.objects.aggregate(Sum('amount'))['amount__sum'] or 0),
        'by_payment_method': list(
            Payment.objects.values('payment_method')
            .annotate(total=Sum('amount'))
            .filter(status='completed')
        ),
    }
    return JsonResponse(stats)


# ============================================================
# RECEIPT — helper + view
# ============================================================

def _amount_in_words(amount):
    ones = ['', 'one', 'two', 'three', 'four', 'five', 'six', 'seven',
            'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen',
            'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']
    tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty',
            'sixty', 'seventy', 'eighty', 'ninety']

    def _below_1000(n):
        if n == 0:
            return ''
        elif n < 20:
            return ones[n]
        elif n < 100:
            return tens[n // 10] + (' ' + ones[n % 10] if n % 10 else '')
        else:
            return ones[n // 100] + ' hundred' + (' ' + _below_1000(n % 100) if n % 100 else '')

    n = int(amount)
    if n == 0:
        return 'zero francs'
    parts = []
    if n >= 1_000_000:
        parts.append(_below_1000(n // 1_000_000) + ' million')
        n %= 1_000_000
    if n >= 1_000:
        parts.append(_below_1000(n // 1_000) + ' thousand')
        n %= 1_000
    if n > 0:
        parts.append(_below_1000(n))
    return ' '.join(parts).strip().capitalize() + ' francs CFA'


# ============================================================
# BULK INVOICE GENERATION
# ============================================================

# Map class levels to fee tier class_group keys in the new model
NURSERY_LEVELS  = {'pre_nursery', 'nursery1', 'nursery2', 'moyenne_section', 'grande_section'}
PRIMARY_LEVELS  = {'sil', 'cp', 'ce1', 'ce2', 'cm1', 'cm2', 'class1', 'class2', 'class3', 'class4', 'class5'}
CLASS6_LEVEL    = 'class6'

# Map each class level to its fee class_group key in the new FeeStructure model
LEVEL_TO_CLASS_GROUP = {
    'pre_nursery':      'pre_nursery',
    'nursery1':         'nursery',
    'nursery2':         'nursery',
    'moyenne_section':  'maternelle',
    'grande_section':   'maternelle',
    'sil':              'sil_cm1',
    'cp':               'sil_cm1',
    'ce1':              'sil_cm1',
    'ce2':              'sil_cm1',
    'cm1':              'sil_cm1',
    'cm2':              'cm2',
    'class1':           'primary_1_5',
    'class2':           'primary_1_5',
    'class3':           'primary_1_5',
    'class4':           'primary_1_5',
    'class5':           'primary_1_5',
    'class6':           'primary_6',
}

LEVEL_TO_SECTION = {
    'pre_nursery': 'anglo', 'nursery1': 'anglo', 'nursery2': 'anglo',
    'class1': 'anglo', 'class2': 'anglo', 'class3': 'anglo',
    'class4': 'anglo', 'class5': 'anglo', 'class6': 'anglo',
    'moyenne_section': 'bilingual', 'grande_section': 'bilingual',
    'sil': 'bilingual', 'cp': 'bilingual', 'ce1': 'bilingual',
    'ce2': 'bilingual', 'cm1': 'bilingual', 'cm2': 'bilingual',
}


def _get_fee_for_student(student, invoice_type, academic_year):
    """
    Return the FeeStructure that applies to this student, or None.
    Uses the new class_group + section model instead of fee_type/class_level.
    """
    if not student.current_class:
        return None
    level       = student.current_class.level
    class_group = LEVEL_TO_CLASS_GROUP.get(level)
    section     = student.current_class.section_type  # 'english', 'french', 'bilingual'

    # Map section_type to FeeStructure section field
    # french section uses bilingual fees; english uses anglo
    fee_section = 'bilingual' if section in ('bilingual', 'french') else 'anglo'

    # Special case: pre_nursery in bilingual/french section maps to maternelle tier
    if level == 'pre_nursery' and section in ('bilingual', 'french'):
        class_group = 'maternelle'

    return FeeStructure.objects.filter(
        is_active=True,
        academic_year=academic_year,
        section=fee_section,
        class_group=class_group,
    ).first()


def _invoice_amount_for_type(fee, invoice_type, is_new_pupil=False):
    """Return the correct XAF amount for the given invoice_type."""
    if invoice_type == 'registration':
        return fee.get_registration_fee(is_new_pupil)
    if invoice_type == 'installment_1':
        return int(fee.installment_1)
    if invoice_type == 'installment_2':
        return int(fee.installment_2)
    return int(fee.total_fees)


def _build_year_choices():
    current = timezone.now().year
    return [f"{y}-{y+1}" for y in range(current - 3, current + 8)]


def _filter_students_by_scope(active_students, scope, class_ids):
    if scope == 'nursery':
        return active_students.filter(current_class__level__in=NURSERY_LEVELS)
    if scope == 'primary':
        return active_students.filter(current_class__level__in=PRIMARY_LEVELS)
    if scope == 'class6':
        return active_students.filter(current_class__level=CLASS6_LEVEL)
    if scope == 'english':
        return active_students.filter(current_class__section_type='english')
    if scope == 'bilingual':
        return active_students.filter(current_class__section_type='bilingual')
    if scope == 'french':
        return active_students.filter(current_class__section_type='french')
    if scope == 'specific' and class_ids:
        return active_students.filter(current_class__id__in=class_ids)
    return active_students


class BulkInvoiceGenerateView(BursarRequiredMixin, TemplateView):
    """
    Generate invoices for all active students for a given invoice_type/academic_year.
    Shows a preview; creates on confirmed POST.
    Skips students who already have an invoice of the same type/year.
    """
    template_name = 'finance/bulk_invoice.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        current = timezone.now().year
        context['year_choices']  = _build_year_choices()
        context['default_year']  = f"{current}-{current+1}"
        context['all_classes']   = SchoolClass.objects.all().order_by('level', 'section')
        context['invoice_type_choices'] = Invoice.INVOICE_TYPE_CHOICES
        return context

    def post(self, request, *args, **kwargs):
        academic_year = request.POST.get('academic_year', '').strip()
        invoice_type  = request.POST.get('invoice_type', '').strip()
        due_date      = request.POST.get('due_date', '').strip()
        scope         = request.POST.get('scope', 'all')
        class_ids     = request.POST.getlist('class_ids')
        confirmed     = request.POST.get('confirmed') == 'yes'

        if not academic_year or not invoice_type or not due_date:
            messages.error(request, 'Academic year, invoice type, and due date are all required.')
            return redirect('finance:bulk_invoice')

        try:
            due_date_obj = date_type.fromisoformat(due_date)
        except (ValueError, TypeError):
            messages.error(request, 'Invalid due date.')
            return redirect('finance:bulk_invoice')

        due_date_str = due_date_obj.isoformat()

        active_students = Student.objects.filter(
            status='active'
        ).select_related('current_class').order_by('current_class__level', 'last_name')

        active_students = _filter_students_by_scope(active_students, scope, class_ids)

        preview    = []
        skip_count = 0

        for student in active_students:
            # Skip if this invoice type already exists for this student/year
            existing = Invoice.objects.filter(
                student=student,
                academic_year=academic_year,
                invoice_type=invoice_type,
            ).first()
            if existing:
                skip_count += 1
                continue

            fee = _get_fee_for_student(student, invoice_type, academic_year)
            if not fee:
                continue

            # Check if there's an enrollment record to determine new/returning
            enrollment = StudentEnrollmentFee.objects.filter(
                student=student, academic_year=academic_year
            ).first()
            is_new = enrollment.is_new_pupil if enrollment else False

            amount = _invoice_amount_for_type(fee, invoice_type, is_new)

            preview.append({
                'student':      student,
                'fee':          fee,
                'amount':       amount,
                'is_new_pupil': is_new,
            })

        if not confirmed:
            context = self.get_context_data()
            context.update({
                'preview':        preview,
                'skip_count':     skip_count,
                'academic_year':  academic_year,
                'invoice_type':   invoice_type,
                'due_date':       due_date_str,
                'scope':          scope,
                'class_ids':      class_ids,
                'total_to_create': len(preview),
                'total_amount':   sum(p['amount'] for p in preview),
            })
            return self.render_to_response(context)

        # ── Confirmed: create invoices ──────────────────────────────────────
        created_count = 0
        for item in preview:
            student = item['student']
            amount  = item['amount']
            fee     = item['fee']

            enrollment = StudentEnrollmentFee.objects.filter(
                student=student, academic_year=academic_year
            ).first()

            invoice = Invoice.objects.create(
                student=student,
                enrollment_fee=enrollment,
                academic_year=academic_year,
                invoice_type=invoice_type,
                due_date=due_date_obj,
                total_amount=amount,
                balance=amount,
                amount_paid=0,
                status='draft',
                created_by=request.user,
            )

            # Line item description based on type
            desc_map = {
                'registration':  f"Registration Fee ({'New' if item['is_new_pupil'] else 'Returning'} Pupil)",
                'installment_1': '1st Installment — Tuition Fee',
                'installment_2': '2nd Installment — Tuition Fee',
            }
            description = desc_map.get(invoice_type, invoice_type.replace('_', ' ').title())

            InvoiceItem.objects.create(
                invoice=invoice,
                fee_structure=fee,
                description=description,
                quantity=1,
                unit_price=amount,
                discount=0,
                total=amount,
            )
            created_count += 1

        messages.success(
            request,
            f'✓ {created_count} invoice{"s" if created_count != 1 else ""} created for '
            f'{academic_year} — {invoice_type.replace("_", " ").title()}. '
            f'{skip_count} student{"s" if skip_count != 1 else ""} skipped (already invoiced).'
        )
        return redirect('finance:invoice_list')

======================================================================
FILE: finance/management/__init__.py
======================================================================


======================================================================
FILE: finance/management/commands/__init__.py
======================================================================


======================================================================
FILE: finance/management/commands/seed_fee_structure.py
======================================================================
"""
Management command: seed_fee_structure
Usage:  python manage.py seed_fee_structure [--year 2025-2026]

Loads the official fee table into FeeStructure and SchoolItemPrice
so staff don't have to type them in manually.

Place this file at:
  finance/management/commands/seed_fee_structure.py
(create __init__.py files in management/ and commands/ if not present)
"""
from django.core.management.base import BaseCommand
from finance.models import FeeStructure, SchoolItemPrice


class Command(BaseCommand):
    help = "Seed the database with the official Anglo & Bilingual fee structure"

    def add_arguments(self, parser):
        parser.add_argument(
            '--year',
            default='2025-2026',
            help='Academic year to seed, e.g. 2025-2026 (default: 2025-2026)',
        )

    def handle(self, *args, **options):
        year = options['year']

        self.stdout.write(self.style.MIGRATE_HEADING(
            f"\n📋 Seeding fee structure for {year} …\n"
        ))

        # ── Fee Structures ─────────────────────────────────────────────────
        defaults_list = FeeStructure.get_defaults()
        created_count = 0

        for data in defaults_list:
            obj, created = FeeStructure.objects.update_or_create(
                section=data['section'],
                class_group=data['class_group'],
                academic_year=year,
                defaults={
                    'registration_new':  data['registration_new'],
                    'registration_old':  data['registration_old'],
                    'total_fees':        data['total_fees'],
                    'installment_1':     data['installment_1'],
                    'installment_2':     data['installment_2'],
                    'is_active':         True,
                },
            )
            label = "✅ Created" if created else "🔄 Updated"
            self.stdout.write(f"  {label}: {obj}")
            if created:
                created_count += 1

        self.stdout.write("")

        # ── School Item Prices ─────────────────────────────────────────────
        item_defaults = SchoolItemPrice.get_defaults()
        item_created = 0

        for data in item_defaults:
            obj, created = SchoolItemPrice.objects.update_or_create(
                item_type=data['item_type'],
                academic_year=year,
                defaults={
                    'name':      data['name'],
                    'price':     data['price'],
                    'is_active': True,
                },
            )
            label = "✅ Created" if created else "🔄 Updated"
            self.stdout.write(f"  {label}: {obj}")
            if created:
                item_created += 1

        self.stdout.write(self.style.SUCCESS(
            f"\n🎉 Done! "
            f"{created_count} fee structure(s) and {item_created} item price(s) created.\n"
        ))


######################################################################
# APP: PARENTS
######################################################################

======================================================================
FILE: parents/__init__.py
======================================================================
# parents/__init__.py
# This file makes Python treat the directory as a package

======================================================================
FILE: parents/apps.py
======================================================================
# parents/apps.py
from django.apps import AppConfig

class ParentsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'parents'
    verbose_name = 'Parent Portal'

======================================================================
FILE: parents/forms.py
======================================================================
# parents/forms.py
from django import forms
from django.contrib.auth.forms import AuthenticationForm

class ParentLoginForm(AuthenticationForm):
    username = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Username'}))
    password = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Password'}))

======================================================================
FILE: parents/models.py
======================================================================
# parents/models.py
"""
Parent portal models for parent-specific functionality.
"""
from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()


# Note: The main Parent/Guardian model is in students/models.py as ParentGuardian
# This file contains additional parent-specific models for the parent portal


class ParentFeedback(models.Model):
    """
    Stores feedback submitted by parents through the parent portal.
    
    This model allows parents to submit feedback, suggestions, or concerns
    directly through the portal, which can be reviewed by administrators.
    
    Attributes:
        parent (ForeignKey): The parent submitting feedback
        subject (str): Subject/title of the feedback
        message (str): Detailed feedback message
        submitted_at (datetime): When feedback was submitted
        is_read (bool): Whether feedback has been read by staff
        response (str): Staff response to feedback
        responded_at (datetime): When response was sent
        responded_by (ForeignKey): Staff member who responded
    """
    
    parent = models.ForeignKey(
        'students.ParentGuardian',
        on_delete=models.CASCADE,
        related_name='feedbacks'
    )
    subject = models.CharField(
        max_length=200
    )
    message = models.TextField()
    submitted_at = models.DateTimeField(
        auto_now_add=True
    )
    is_read = models.BooleanField(
        default=False
    )
    
    # Response fields
    response = models.TextField(
        blank=True
    )
    responded_at = models.DateTimeField(
        null=True,
        blank=True
    )
    responded_by = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='feedback_responses'
    )
    
    class Meta:
        verbose_name = "Parent Feedback"
        verbose_name_plural = "Parent Feedbacks"
        ordering = ['-submitted_at']
        indexes = [
            models.Index(fields=['submitted_at']),
            models.Index(fields=['is_read']),
        ]
    
    def __str__(self):
        """Return string representation of the feedback."""
        return f"{self.parent} - {self.subject} ({self.submitted_at.date()})"
    
    def mark_as_read(self):
        """
        Mark this feedback as read.
        
        Returns:
            bool: True if successfully marked as read.
        """
        self.is_read = True
        self.save(update_fields=['is_read'])
        return True


class ParentNotification(models.Model):
    """
    Stores notifications sent to parents through the parent portal.
    
    This model tracks notifications sent to specific parents, including
    read status and delivery confirmation.
    
    Attributes:
        parent (ForeignKey): Parent receiving the notification
        title (str): Notification title
        message (str): Notification content
        sent_at (datetime): When notification was sent
        is_read (bool): Whether parent has read the notification
        read_at (datetime): When notification was read
        notification_type (str): Type of notification from TYPE_CHOICES
        link (str): Optional link to related content
    """
    
    TYPE_CHOICES = [
        ('fee_reminder', 'Fee Reminder'),
        ('attendance_alert', 'Attendance Alert'),
        ('exam_notice', 'Exam Notice'),
        ('event', 'School Event'),
        ('general', 'General Announcement'),
    ]
    
    parent = models.ForeignKey(
        'students.ParentGuardian',
        on_delete=models.CASCADE,
        related_name='notifications'
    )
    title = models.CharField(
        max_length=200
    )
    message = models.TextField()
    sent_at = models.DateTimeField(
        auto_now_add=True
    )
    is_read = models.BooleanField(
        default=False
    )
    read_at = models.DateTimeField(
        null=True,
        blank=True
    )
    notification_type = models.CharField(
        max_length=20,
        choices=TYPE_CHOICES,
        default='general'
    )
    link = models.CharField(
        max_length=200,
        blank=True
    )
    
    class Meta:
        verbose_name = "Parent Notification"
        verbose_name_plural = "Parent Notifications"
        ordering = ['-sent_at']
        indexes = [
            models.Index(fields=['sent_at']),
            models.Index(fields=['is_read']),
            models.Index(fields=['notification_type']),
        ]
    
    def __str__(self):
        """Return string representation of the notification."""
        return f"{self.parent} - {self.title}"
    
    def mark_as_read(self):
        """
        Mark this notification as read.
        
        Returns:
            bool: True if successfully marked as read.
        """
        from django.utils import timezone
        self.is_read = True
        self.read_at = timezone.now()
        self.save(update_fields=['is_read', 'read_at'])
        return True


class ParentSession(models.Model):
    """
    Tracks parent login sessions for the parent portal.
    
    This model helps monitor parent activity and can be used for
    security auditing and analytics.
    
    Attributes:
        parent (ForeignKey): Parent who logged in
        login_time (datetime): When parent logged in
        logout_time (datetime): When parent logged out
        ip_address (str): IP address used for login
        user_agent (str): Browser/device information
        is_active (bool): Whether session is still active
    """
    
    parent = models.ForeignKey(
        'students.ParentGuardian',
        on_delete=models.CASCADE,
        related_name='sessions'
    )
    login_time = models.DateTimeField(
        auto_now_add=True
    )
    logout_time = models.DateTimeField(
        null=True,
        blank=True
    )
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.TextField(blank=True)
    is_active = models.BooleanField(
        default=True
    )
    
    class Meta:
        verbose_name = "Parent Session"
        verbose_name_plural = "Parent Sessions"
        ordering = ['-login_time']
    
    def __str__(self):
        """Return string representation of the session."""
        return f"{self.parent} - {self.login_time.date()}"
    
    def end_session(self):
        """
        End this parent session.
        
        Returns:
            bool: True if session ended successfully.
        """
        from django.utils import timezone
        self.is_active = False
        self.logout_time = timezone.now()
        self.save(update_fields=['is_active', 'logout_time'])
        return True

======================================================================
FILE: parents/urls.py
======================================================================
# parents/urls.py
from django.urls import path
from . import views

app_name = 'parents'

urlpatterns = [
    # Authentication
    path('login/', views.ParentLoginView.as_view(), name='parent_login'),
    path('logout/', views.ParentLogoutView.as_view(), name='parent_logout'),
    
    # Dashboard
    path('', views.ParentDashboardView.as_view(), name='parent_dashboard'),
    
    # Student Views
    path('student/<int:pk>/', views.ParentStudentDetailView.as_view(), name='parent_student_detail'),
    path('student/<int:pk>/attendance/', views.ParentStudentAttendanceView.as_view(), name='parent_student_attendance'),
    path('student/<int:pk>/fees/', views.ParentStudentFeesView.as_view(), name='parent_student_fees'),
    path('student/<int:pk>/reports/', views.ParentStudentReportsView.as_view(), name='parent_student_reports'),
    
    # Messages
    path('messages/', views.ParentMessagesView.as_view(), name='parent_messages'),
    path('messages/<int:pk>/', views.ParentMessageDetailView.as_view(), name='parent_message_detail'),
    
    # Profile
    path('profile/', views.ParentProfileView.as_view(), name='parent_profile'),
    path('profile/edit/', views.ParentProfileEditView.as_view(), name='parent_profile_edit'),
]

======================================================================
FILE: parents/views.py
======================================================================
# parents/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, TemplateView, FormView
from django.views.generic.edit import CreateView, UpdateView, DeleteView  # ADD THIS LINE
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import AuthenticationForm  # ADD THIS IMPORT

from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q, Sum
from django.http import JsonResponse
from django.utils import timezone
from datetime import date, timedelta

from students.models import Student, ParentGuardian
from academics.models import Attendance
from finance.models import Invoice, Payment
from communication.models import Announcement, SMSMessage

# ========== PARENT AUTHENTICATION ==========

class ParentLoginView(FormView):
    """Parent login view"""
    template_name = 'parents/login.html'
    form_class = AuthenticationForm  # Add this if you're using it
    success_url = reverse_lazy('parents:parent_dashboard')
    
    def form_valid(self, form):
        username = self.request.POST.get('username')
        password = self.request.POST.get('password')
        
        user = authenticate(self.request, username=username, password=password)
        
        if user is not None and hasattr(user, 'parent_profile'):
            login(self.request, user)
            return super().form_valid(form)
        else:
            messages.error(self.request, 'Invalid credentials or not a parent account.')
            return self.form_invalid(form)

class ParentLogoutView(LoginRequiredMixin, TemplateView):
    """Parent logout view"""
    template_name = 'parents/logout.html'
    
    def get(self, request, *args, **kwargs):
        logout(request)
        messages.success(request, 'You have been logged out successfully.')
        return redirect('parents:parent_login')

# ========== PARENT DASHBOARD ==========

class ParentDashboardView(LoginRequiredMixin, TemplateView):
    """Parent dashboard showing all linked students"""
    template_name = 'parents/dashboard.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get the parent profile
        if hasattr(self.request.user, 'parent_profile'):
            parent = self.request.user.parent_profile
        else:
            # If user is staff/admin, allow them to view as parent
            parent = ParentGuardian.objects.filter(email=self.request.user.email).first()
        
        if parent:
            # Get students linked to this parent
            students = Student.objects.filter(parents=parent)
            context['students'] = students
            context['parent'] = parent
            
            # Get recent announcements
            context['announcements'] = Announcement.objects.filter(
                is_published=True,
                audience__in=['all', 'parents']
            ).order_by('-publish_date')[:5]
            
            # Get pending payments across all students
            total_due = 0
            for student in students:
                due = Invoice.objects.filter(
                    student=student,
                    status__in=['sent', 'partial', 'overdue']
                ).aggregate(Sum('balance'))['balance__sum'] or 0
                total_due += due
            
            context['total_due'] = total_due
            
        return context

# ========== STUDENT VIEWS FOR PARENTS ==========

class ParentStudentDetailView(LoginRequiredMixin, DetailView):
    """View student details for parent"""
    model = Student
    template_name = 'parents/student_detail.html'
    context_object_name = 'student'
    
    def get_queryset(self):
        # Ensure parent can only see their own students
        if hasattr(self.request.user, 'parent_profile'):
            return Student.objects.filter(parents=self.request.user.parent_profile)
        return Student.objects.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get attendance summary
        today = date.today()
        month_start = today.replace(day=1)
        
        attendance_this_month = Attendance.objects.filter(
            student=self.object,
            date__gte=month_start
        )
        
        total_days = attendance_this_month.count()
        present_days = attendance_this_month.filter(status='present').count()
        
        context['attendance_rate'] = round((present_days / total_days) * 100, 1) if total_days > 0 else 0
        context['present_days'] = present_days
        context['total_days'] = total_days
        
        # Get recent attendance
        context['recent_attendance'] = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:10]
        
        return context

class ParentStudentAttendanceView(LoginRequiredMixin, DetailView):
    """View student attendance for parent"""
    model = Student
    template_name = 'parents/student_attendance.html'
    context_object_name = 'student'
    
    def get_queryset(self):
        if hasattr(self.request.user, 'parent_profile'):
            return Student.objects.filter(parents=self.request.user.parent_profile)
        return Student.objects.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get date range
        year = self.request.GET.get('year', date.today().year)
        month = self.request.GET.get('month', date.today().month)
        
        start_date = date(int(year), int(month), 1)
        if month == 12:
            end_date = date(int(year) + 1, 1, 1) - timedelta(days=1)
        else:
            end_date = date(int(year), int(month) + 1, 1) - timedelta(days=1)
        
        # Get attendance for the month
        attendances = Attendance.objects.filter(
            student=self.object,
            date__gte=start_date,
            date__lte=end_date
        ).order_by('date')
        
        context['attendances'] = attendances
        context['selected_year'] = year
        context['selected_month'] = month
        context['months'] = [
            (1, 'January'), (2, 'February'), (3, 'March'),
            (4, 'April'), (5, 'May'), (6, 'June'),
            (7, 'July'), (8, 'August'), (9, 'September'),
            (10, 'October'), (11, 'November'), (12, 'December')
        ]
        context['years'] = range(2020, date.today().year + 2)
        
        return context

class ParentStudentFeesView(LoginRequiredMixin, DetailView):
    """View student fees for parent"""
    model = Student
    template_name = 'parents/student_fees.html'
    context_object_name = 'student'
    
    def get_queryset(self):
        if hasattr(self.request.user, 'parent_profile'):
            return Student.objects.filter(parents=self.request.user.parent_profile)
        return Student.objects.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get all invoices for this student
        invoices = Invoice.objects.filter(student=self.object).order_by('-issue_date')
        context['invoices'] = invoices
        
        # Get payments
        payments = Payment.objects.filter(student=self.object).order_by('-payment_date')
        context['payments'] = payments
        
        # Summary
        total_invoiced = invoices.aggregate(Sum('total_amount'))['total_amount__sum'] or 0
        total_paid = payments.filter(status='completed').aggregate(Sum('amount'))['amount__sum'] or 0
        
        context['total_invoiced'] = total_invoiced
        context['total_paid'] = total_paid
        context['balance_due'] = total_invoiced - total_paid
        
        return context

class ParentStudentReportsView(LoginRequiredMixin, DetailView):
    """View student reports for parent"""
    model = Student
    template_name = 'parents/student_reports.html'
    context_object_name = 'student'
    
    def get_queryset(self):
        if hasattr(self.request.user, 'parent_profile'):
            return Student.objects.filter(parents=self.request.user.parent_profile)
        return Student.objects.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # This would link to generated reports
        # For now, we'll just show available report types
        context['report_types'] = [
            {'name': 'Term Report', 'url': '#'},
            {'name': 'Annual Report', 'url': '#'},
            {'name': 'Attendance Summary', 'url': '#'},
        ]
        
        return context

# ========== PARENT MESSAGES ==========

class ParentMessagesView(LoginRequiredMixin, ListView):
    """View messages for parent"""
    template_name = 'parents/messages.html'
    context_object_name = 'messages'
    
    def get_queryset(self):
        if hasattr(self.request.user, 'parent_profile'):
            parent = self.request.user.parent_profile
            # Find SMS messages sent to this parent's phone
            return SMSMessage.objects.filter(
                phone_numbers__contains=[parent.phone]
            ).order_by('-sent_time')
        return SMSMessage.objects.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['unread_count'] = 0  # You could add an "is_read" field to track this
        return context

class ParentMessageDetailView(LoginRequiredMixin, DetailView):
    """View message details"""
    model = SMSMessage
    template_name = 'parents/message_detail.html'
    context_object_name = 'message'
    
    def get_queryset(self):
        if hasattr(self.request.user, 'parent_profile'):
            parent = self.request.user.parent_profile
            return SMSMessage.objects.filter(phone_numbers__contains=[parent.phone])
        return SMSMessage.objects.none()

# ========== PARENT PROFILE ==========

class ParentProfileView(LoginRequiredMixin, DetailView):
    """View parent profile"""
    template_name = 'parents/profile.html'
    context_object_name = 'parent'
    
    def get_object(self):
        if hasattr(self.request.user, 'parent_profile'):
            return self.request.user.parent_profile
        return get_object_or_404(ParentGuardian, email=self.request.user.email)

class ParentProfileEditView(LoginRequiredMixin, UpdateView):
    """Edit parent profile"""
    model = ParentGuardian
    fields = ['phone', 'alternate_phone', 'email', 'address', 'occupation', 'employer']
    template_name = 'parents/profile_edit.html'
    success_url = reverse_lazy('parents:parent_profile')
    
    def get_object(self):
        if hasattr(self.request.user, 'parent_profile'):
            return self.request.user.parent_profile
        return get_object_or_404(ParentGuardian, email=self.request.user.email)
    
    def form_valid(self, form):
        messages.success(self.request, 'Profile updated successfully!')
        return super().form_valid(form)


######################################################################
# APP: REPORTS
######################################################################

======================================================================
FILE: reports/__init__.py
======================================================================
# reports/__init__.py
# This file makes Python treat the directory as a package

======================================================================
FILE: reports/admin.py
======================================================================
# reports/admin.py
from django.contrib import admin
# Register your models here if you create any report models

# If you have FinancialReport model from finance, you might want to register it here

======================================================================
FILE: reports/apps.py
======================================================================
# reports/apps.py
from django.apps import AppConfig

class ReportsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'reports'
    verbose_name = 'Reports'

======================================================================
FILE: reports/forms.py
======================================================================
# reports/forms.py
from django import forms

class ReportGenerationForm(forms.Form):
    REPORT_TYPES = [
        ('academic', 'Academic Report'),
        ('attendance', 'Attendance Report'),
        ('financial', 'Financial Report'),
    ]
    
    report_type = forms.ChoiceField(choices=REPORT_TYPES, widget=forms.Select(attrs={'class': 'form-control'}))
    from_date = forms.DateField(widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}))
    to_date = forms.DateField(widget=forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}))
    format = forms.ChoiceField(choices=[('pdf', 'PDF'), ('csv', 'CSV')], widget=forms.Select(attrs={'class': 'form-control'}))

======================================================================
FILE: reports/models.py
======================================================================
# reports/models.py
"""
Models for storing and managing generated reports.
"""
from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()


class SavedReport(models.Model):
    """
    Stores generated reports for later access and reference.
    
    This model saves reports that have been generated so they can be
    accessed again without regenerating. Reports can be of different types
    (academic, attendance, financial) and store the parameters used to
    generate them.
    
    Attributes:
        title (str): Descriptive title of the report
        report_type (str): Type of report from REPORT_TYPES choices
        generated_by (ForeignKey): User who generated the report
        generated_at (datetime): Timestamp when report was generated
        file (FileField): The actual report file (PDF, Excel, etc.)
        parameters (JSONField): JSON object containing generation parameters
            (date ranges, class filters, etc.)
    """
    
    REPORT_TYPES = [
        ('academic', 'Academic Report'),
        ('attendance', 'Attendance Report'),
        ('financial', 'Financial Report'),
    ]
    
    title = models.CharField(
        max_length=200
    )
    report_type = models.CharField(
        max_length=20, 
        choices=REPORT_TYPES
    )
    generated_by = models.ForeignKey(
        User, 
        on_delete=models.CASCADE
    )
    generated_at = models.DateTimeField(
        auto_now_add=True
    )
    file = models.FileField(
        upload_to='reports/'
    )
    parameters = models.JSONField(
        default=dict
    )
    
    class Meta:
        verbose_name = "Saved Report"
        verbose_name_plural = "Saved Reports"
        ordering = ['-generated_at']
        indexes = [
            models.Index(fields=['report_type']),
            models.Index(fields=['generated_at']),
        ]
    
    def __str__(self):
        """Return string representation of the saved report."""
        return f"{self.title} - {self.generated_at.date()}"
    
    def get_parameters_display(self):
        """
        Get a human-readable representation of the report parameters.
        
        Returns:
            str: Formatted string showing the key parameters used.
        """
        if not self.parameters:
            return "No parameters"
        
        param_strings = []
        for key, value in self.parameters.items():
            param_strings.append(f"{key.replace('_', ' ').title()}: {value}")
        
        return ", ".join(param_strings)

======================================================================
FILE: reports/urls.py
======================================================================
# reports/urls.py
from django.urls import path
from . import views

app_name = 'reports'

urlpatterns = [
    # Academic Reports
    path('academic/', views.AcademicReportView.as_view(), name='academic_report'),
    path('academic/class/<int:class_id>/', views.ClassReportView.as_view(), name='class_report'),
    path('academic/student/<int:pk>/', views.StudentReportView.as_view(), name='student_report'),
    path('academic/generate/', views.generate_academic_report, name='generate_academic_report'),    
    # Attendance Reports
    path('attendance/', views.AttendanceReportView.as_view(), name='attendance_report'),
    path('attendance/class/<int:class_id>/', views.ClassAttendanceReportView.as_view(), name='class_attendance_report'),
    path('attendance/export/', views.export_attendance_report, name='export_attendance_report'),    
    # Financial Reports
    path('financial/', views.FinancialReportView.as_view(), name='financial_report'),
    path('financial/term/<int:term>/', views.TermFinancialReportView.as_view(), name='term_financial_report'),
    path('financial/year/<str:year>/', views.YearlyFinancialReportView.as_view(), name='yearly_financial_report'),
    path('financial/export/', views.export_financial_report, name='export_financial_report'),    
    # Custom Reports
    path('custom/', views.CustomReportView.as_view(), name='custom_report'),
    path('custom/generate/', views.generate_custom_report, name='generate_custom_report'),    
    # Exports
    path('export/pdf/<str:report_type>/<int:report_id>/', views.export_report_pdf, name='export_report_pdf'),
    path('export/excel/<str:report_type>/<int:report_id>/', views.export_report_excel, name='export_report_excel'),
]

======================================================================
FILE: reports/views.py
======================================================================
# reports/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import TemplateView, ListView, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.http import HttpResponse, JsonResponse, FileResponse
from django.db.models import Count, Sum, Avg, Q
from django.utils import timezone
from datetime import date, timedelta, datetime
import csv
import io

from students.models import Student
from academics.models import SchoolClass, Attendance, Subject
from finance.models import Invoice, Payment, Expense, ExpenseCategory
from staff.models import Staff

# ========== ACADEMIC REPORTS ==========

class AcademicReportView(LoginRequiredMixin, TemplateView):
    """Academic reports dashboard"""
    template_name = 'reports/academic.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['classes'] = SchoolClass.objects.all()
        context['terms'] = [1, 2, 3]
        context['years'] = range(2020, date.today().year + 2)
        return context

class ClassReportView(LoginRequiredMixin, TemplateView):
    """Generate class report"""
    template_name = 'reports/class_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        class_id = self.kwargs.get('class_id')
        term = self.request.GET.get('term', 1)
        year = self.request.GET.get('year', date.today().year)
        
        school_class = SchoolClass.objects.get(id=class_id)
        students = Student.objects.filter(current_class=school_class).order_by('first_name')
        
        context['class'] = school_class
        context['students'] = students
        context['term'] = term
        context['year'] = year
        
        # Get attendance statistics for each student
        student_stats = []
        for student in students:
            attendances = Attendance.objects.filter(
                student=student,
                date__year=year
            )
            
            total = attendances.count()
            present = attendances.filter(status='present').count()
            
            student_stats.append({
                'student': student,
                'total_days': total,
                'present': present,
                'absent': attendances.filter(status='absent').count(),
                'late': attendances.filter(status='late').count(),
                'attendance_rate': round((present / total) * 100, 1) if total > 0 else 0
            })
        
        context['student_stats'] = student_stats
        
        return context

class StudentReportView(LoginRequiredMixin, DetailView):
    """Generate individual student report"""
    model = Student
    template_name = 'reports/student_report.html'
    context_object_name = 'student'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        term = self.request.GET.get('term', 1)
        year = self.request.GET.get('year', date.today().year)
        
        # Attendance for the period
        attendances = Attendance.objects.filter(
            student=self.object,
            date__year=year
        )
        
        total = attendances.count()
        present = attendances.filter(status='present').count()
        
        context['attendance'] = {
            'total': total,
            'present': present,
            'absent': attendances.filter(status='absent').count(),
            'late': attendances.filter(status='late').count(),
            'rate': round((present / total) * 100, 1) if total > 0 else 0
        }
        
        # Fee summary
        invoices = Invoice.objects.filter(student=self.object)
        total_invoiced = invoices.aggregate(Sum('total_amount'))['total_amount__sum'] or 0
        total_paid = Payment.objects.filter(
            student=self.object,
            status='completed'
        ).aggregate(Sum('amount'))['amount__sum'] or 0
        
        context['fees'] = {
            'invoiced': total_invoiced,
            'paid': total_paid,
            'balance': total_invoiced - total_paid
        }
        
        context['term'] = term
        context['year'] = year
        
        return context

def generate_academic_report(request):
    """Generate and download academic report"""
    if request.method == 'POST':
        report_type = request.POST.get('report_type')
        class_id = request.POST.get('class_id')
        term = request.POST.get('term')
        year = request.POST.get('year')
        
        # Create CSV response
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = f'attachment; filename="academic_report_{year}_term{term}.csv"'
        
        writer = csv.writer(response)
        
        if report_type == 'class' and class_id:
            school_class = SchoolClass.objects.get(id=class_id)
            students = Student.objects.filter(current_class=school_class)
            
            writer.writerow(['Student ID', 'Name', 'Attendance %', 'Status'])
            
            for student in students:
                # Calculate attendance
                attendances = Attendance.objects.filter(
                    student=student,
                    date__year=year
                )
                total = attendances.count()
                present = attendances.filter(status='present').count()
                rate = round((present / total) * 100, 1) if total > 0 else 0
                
                writer.writerow([
                    student.student_id,
                    student.get_full_name(),
                    rate,
                    student.status
                ])
        
        messages.success(request, 'Report generated successfully!')
        return response
    
    return redirect('reports:academic_report')

# ========== ATTENDANCE REPORTS ==========

class AttendanceReportView(LoginRequiredMixin, TemplateView):
    """Attendance reports"""
    template_name = 'reports/attendance_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        from_date = self.request.GET.get('from_date')
        to_date = self.request.GET.get('to_date')
        class_id = self.request.GET.get('class')
        
        if not from_date:
            from_date = date.today().replace(day=1)
        if not to_date:
            to_date = date.today()
        
        context['from_date'] = from_date
        context['to_date'] = to_date
        context['classes'] = SchoolClass.objects.all()
        
        # Build statistics
        classes = SchoolClass.objects.all()
        if class_id:
            classes = classes.filter(id=class_id)
        
        stats = []
        for cls in classes:
            attendances = Attendance.objects.filter(
                school_class=cls,
                date__gte=from_date,
                date__lte=to_date
            )
            
            total = attendances.count()
            if total > 0:
                present = attendances.filter(status='present').count()
                stats.append({
                    'class': cls.name,
                    'class_id': cls.id,
                    'total': total,
                    'present': present,
                    'absent': attendances.filter(status='absent').count(),
                    'late': attendances.filter(status='late').count(),
                    'rate': round((present / total) * 100, 1)
                })
        
        context['stats'] = stats
        
        # Overall statistics
        all_attendances = Attendance.objects.filter(
            date__gte=from_date,
            date__lte=to_date
        )
        total_all = all_attendances.count()
        if total_all > 0:
            context['overall_rate'] = round(
                (all_attendances.filter(status='present').count() / total_all) * 100, 1
            )
        
        return context

class ClassAttendanceReportView(LoginRequiredMixin, TemplateView):
    """Attendance report for a specific class"""
    template_name = 'reports/class_attendance_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        class_id = self.kwargs.get('class_id')
        month = self.request.GET.get('month', date.today().month)
        year = self.request.GET.get('year', date.today().year)
        
        school_class = SchoolClass.objects.get(id=class_id)
        students = Student.objects.filter(current_class=school_class)
        
        # Get all days in the month
        start_date = date(int(year), int(month), 1)
        if month == 12:
            end_date = date(int(year) + 1, 1, 1) - timedelta(days=1)
        else:
            end_date = date(int(year), int(month) + 1, 1) - timedelta(days=1)
        
        days = [start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1)]
        
        # Get attendance for each student
        today = date.today()
        attendance_data = []
        for student in students:
            student_attendance = []
            for day in days:
                is_weekend = day.weekday() >= 5          # Saturday=5, Sunday=6
                is_future  = day > today

                att = Attendance.objects.filter(
                    student=student,
                    date=day
                ).first()

                if att:
                    status = att.status
                elif is_weekend:
                    status = 'weekend'
                elif is_future:
                    status = 'future'
                else:
                    status = 'no_record'   # school day with no entry taken yet

                student_attendance.append({
                    'date': day,
                    'status': status,
                    'is_weekend': is_weekend,
                    'is_future': is_future,
                })

            attendance_data.append({
                'student': student,
                'attendance': student_attendance
            })
        
        context['class'] = school_class
        context['attendance_data'] = attendance_data
        context['days'] = days
        context['month'] = int(month)
        context['year'] = int(year)
        context['months'] = [
            (1,'January'),(2,'February'),(3,'March'),(4,'April'),
            (5,'May'),(6,'June'),(7,'July'),(8,'August'),
            (9,'September'),(10,'October'),(11,'November'),(12,'December'),
        ]
        
        return context

def export_attendance_report(request):
    """Export attendance report as CSV"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="attendance_report.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Date', 'Class', 'Student', 'Status', 'Remarks'])
    
    from_date = request.GET.get('from_date')
    to_date = request.GET.get('to_date')
    
    attendances = Attendance.objects.filter(
        date__gte=from_date,
        date__lte=to_date
    ).select_related('student', 'school_class')
    
    for att in attendances:
        writer.writerow([
            att.date,
            att.school_class.name,
            str(att.student),
            att.get_status_display(),
            att.remarks
        ])
    
    return response

# ========== FINANCIAL REPORTS ==========

class FinancialReportView(LoginRequiredMixin, TemplateView):
    """Financial reports dashboard"""
    template_name = 'reports/financial_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        from_date = self.request.GET.get('from_date')
        to_date = self.request.GET.get('to_date')
        
        if not from_date:
            from_date = date.today().replace(day=1)
        if not to_date:
            to_date = date.today()
        
        context['from_date'] = from_date
        context['to_date'] = to_date
        
        # Revenue
        payments = Payment.objects.filter(
            status='completed',
            payment_date__gte=from_date,
            payment_date__lte=to_date
        )
        context['total_revenue'] = payments.aggregate(Sum('amount'))['amount__sum'] or 0
        
        # Expenses
        expenses = Expense.objects.filter(
            expense_date__gte=from_date,
            expense_date__lte=to_date
        )
        context['total_expenses'] = expenses.aggregate(Sum('amount'))['amount__sum'] or 0
        
        context['net_profit'] = context['total_revenue'] - context['total_expenses']
        
        # Revenue by payment method
        by_method = []
        for method_code, method_name in Payment.PAYMENT_METHOD_CHOICES:
            total = payments.filter(payment_method=method_code).aggregate(Sum('amount'))['amount__sum'] or 0
            if total > 0:
                by_method.append({
                    'method': method_name,
                    'total': total
                })
        context['by_method'] = by_method
        
        # Expenses by category
        by_category = []
        for category in ExpenseCategory.objects.all():
            total = expenses.filter(category=category).aggregate(Sum('amount'))['amount__sum'] or 0
            if total > 0:
                by_category.append({
                    'category': category.name,
                    'total': total
                })
        context['by_category'] = by_category
        
        return context

class TermFinancialReportView(LoginRequiredMixin, TemplateView):
    """Financial report for a specific term"""
    template_name = 'reports/term_financial_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        term = self.kwargs.get('term')
        year = self.request.GET.get('year', date.today().year)
        
        # Define term dates (you'd need to configure these)
        term_dates = {
            1: {'start': f'{year}-09-01', 'end': f'{year}-12-20'},
            2: {'start': f'{year+1}-01-10', 'end': f'{year+1}-03-30'},
            3: {'start': f'{year+1}-04-15', 'end': f'{year+1}-07-15'},
        }
        
        start_date = term_dates[term]['start']
        end_date = term_dates[term]['end']
        
        context['term'] = term
        context['year'] = year
        context['start_date'] = start_date
        context['end_date'] = end_date
        
        # Get data for this term
        invoices = Invoice.objects.filter(
            academic_year=f"{year}-{year+1}",
            term=term
        )
        
        context['total_invoiced'] = invoices.aggregate(Sum('total_amount'))['total_amount__sum'] or 0
        context['total_collected'] = invoices.aggregate(Sum('amount_paid'))['amount_paid__sum'] or 0
        context['outstanding'] = context['total_invoiced'] - context['total_collected']
        
        return context

class YearlyFinancialReportView(LoginRequiredMixin, TemplateView):
    """Yearly financial report"""
    template_name = 'reports/yearly_financial_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        year = self.kwargs.get('year')
        
        context['year'] = year
        
        # Monthly breakdown
        monthly_data = []
        for month in range(1, 13):
            start_date = date(int(year), month, 1)
            if month == 12:
                end_date = date(int(year) + 1, 1, 1) - timedelta(days=1)
            else:
                end_date = date(int(year), month + 1, 1) - timedelta(days=1)
            
            revenue = Payment.objects.filter(
                status='completed',
                payment_date__gte=start_date,
                payment_date__lte=end_date
            ).aggregate(Sum('amount'))['amount__sum'] or 0
            
            expenses = Expense.objects.filter(
                expense_date__gte=start_date,
                expense_date__lte=end_date
            ).aggregate(Sum('amount'))['amount__sum'] or 0
            
            monthly_data.append({
                'month': start_date.strftime('%B'),
                'revenue': revenue,
                'expenses': expenses,
                'profit': revenue - expenses
            })
        
        context['monthly_data'] = monthly_data
        
        # Yearly totals
        context['total_revenue'] = sum(m['revenue'] for m in monthly_data)
        context['total_expenses'] = sum(m['expenses'] for m in monthly_data)
        context['total_profit'] = context['total_revenue'] - context['total_expenses']
        
        return context

def export_financial_report(request):
    """Export financial report as CSV"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="financial_report.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Date', 'Type', 'Description', 'Amount', 'Category'])
    
    from_date = request.GET.get('from_date')
    to_date = request.GET.get('to_date')
    
    # Payments (revenue)
    payments = Payment.objects.filter(
        status='completed',
        payment_date__gte=from_date,
        payment_date__lte=to_date
    ).select_related('student')
    
    for payment in payments:
        writer.writerow([
            payment.payment_date,
            'Revenue',
            f"Payment from {payment.student}",
            payment.amount,
            payment.get_payment_method_display()
        ])
    
    # Expenses
    expenses = Expense.objects.filter(
        expense_date__gte=from_date,
        expense_date__lte=to_date
    ).select_related('category')
    
    for expense in expenses:
        writer.writerow([
            expense.expense_date,
            'Expense',
            expense.description,
            -expense.amount,
            expense.category.name
        ])
    
    return response

# ========== CUSTOM REPORTS ==========

class CustomReportView(LoginRequiredMixin, TemplateView):
    """Custom report builder"""
    template_name = 'reports/custom_report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        context['data_sources'] = [
            {'id': 'students', 'name': 'Students'},
            {'id': 'attendance', 'name': 'Attendance'},
            {'id': 'payments', 'name': 'Payments'},
            {'id': 'invoices', 'name': 'Invoices'},
            {'id': 'expenses', 'name': 'Expenses'},
        ]
        
        return context

def generate_custom_report(request):
    """Generate custom report based on selected criteria"""
    if request.method == 'POST':
        data_source = request.POST.get('data_source')
        fields = request.POST.getlist('fields')
        filters = request.POST.get('filters')
        
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = f'attachment; filename="custom_report_{data_source}.csv"'
        
        writer = csv.writer(response)
        
        if data_source == 'students':
            writer.writerow(['ID', 'Name', 'Class', 'Status'])
            for student in Student.objects.all():
                writer.writerow([
                    student.student_id,
                    student.get_full_name(),
                    student.current_class.name if student.current_class else '',
                    student.status
                ])
        
        elif data_source == 'attendance':
            writer.writerow(['Date', 'Student', 'Class', 'Status'])
            for att in Attendance.objects.all().select_related('student', 'school_class')[:1000]:
                writer.writerow([
                    att.date,
                    str(att.student),
                    att.school_class.name,
                    att.get_status_display()
                ])
        
        return response
    
    return redirect('reports:custom_report')

# ========== PDF EXPORT FUNCTIONS (ADD THESE) ==========

def export_report_pdf(request, report_type, report_id):
    """Export report as PDF (placeholder)"""
    # This is a placeholder function
    # In a real application, you would use a library like WeasyPrint or ReportLab
    from django.http import HttpResponse
    from django.template.loader import get_template
    
    # For now, return a simple message
    html = f"<html><body><h1>{report_type} Report {report_id}</h1><p>PDF export coming soon!</p></body></html>"
    
    # In production, you would convert this HTML to PDF
    # from xhtml2pdf import pisa
    # result = io.BytesIO()
    # pdf = pisa.pisaDocument(io.BytesIO(html.encode("UTF-8")), result)
    
    return HttpResponse(html)

def export_report_excel(request, report_type, report_id):
    """Export report as Excel (placeholder)"""
    response = HttpResponse(content_type='application/vnd.ms-excel')
    response['Content-Disposition'] = f'attachment; filename="{report_type}_report_{report_id}.xls"'
    
    writer = csv.writer(response)
    writer.writerow(['Report Type', 'Report ID', 'Generated Date'])
    writer.writerow([report_type, report_id, date.today()])
    
    return response


######################################################################
# APP: SCRIPTS
######################################################################

======================================================================
FILE: scripts/fix_staff_names.py
======================================================================
"""
fix_staff_names.py
==================
Precise one-off fix for all 25 staff records based on exact admin export.
Separates title from first_name, normalises last_name, updates usernames.

HOW TO RUN (from the DEV folder, with venv active):
    python manage.py shell < scripts/fix_staff_names.py

OR on Windows PowerShell:
    Get-Content scripts\fix_staff_names.py | python manage.py shell

Set DRY_RUN = False in this file before running to actually save changes.
After running: notify staff of their new login usernames.
"""
import os, sys, django

# ── Bootstrap Django so this file can also be run standalone ──────────────
# (manage.py shell already does this, but this guard makes it work either way)
if not os.environ.get('DJANGO_SETTINGS_MODULE'):
    # Adjust the path if your settings module is different
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.insert(0, BASE_DIR)
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
    django.setup()

from django.contrib.auth import get_user_model
from staff.models import Staff

User = get_user_model()

DRY_RUN = False   # ← set to False to save changes

# (current_username, title, correct_first, correct_last, new_username)
FIXES = [
    ('MankaN',               'Mme', 'Nchotu',    'Manka',           'nchotu.manka'),
    ('SuperAdmin',           '',    'Super',     'Admin',           'super.admin'),
    ('VitusDk',              '',    'Vitus',     'Dk',              'vitus.dk'),
    ('amadouT',              'Mr',  'Amadou',    'Tijani',          'amadou.tijani'),
    ('carolineA',            'Mme', 'Caroline',  'Ayuk',            'caroline.ayuk'),
    ('chesiL',               'Mme', 'Chesi',     'Landry',          'chesi.landry'),
    ('christelleE',          'Mme', 'Christelle','Ekosso',          'christelle.ekosso'),
    ('ferdinandS',           'Mr',  'Ferdinand', 'Sunyin',          'ferdinand.sunyin'),
    ('ireneM',               'Mme', 'Irene',     'Madjague Toubet', 'irene.madjague_toubet'),
    ('mme.charlottemouil',   'Mme', 'Charlotte', 'Mouil',           'charlotte.mouil'),
    ('mme.dongmoevine',      'Mme', 'Evine',     'Dongmo',          'evine.dongmo'),
    ('mme.epiezita',         'Mme', 'Zita',      'Epie',            'zita.epie'),
    ('mme.fongangnoella',    'Mme', 'Noella',    'Fongang',         'noella.fongang'),
    ('mme.fossemalice',      'Mme', 'Alice',     'Fossem',          'alice.fossem'),
    ('mme.labolongpajosiane','Mme', 'Josiane',   'Labo Longpa',     'josiane.labo_longpa'),
    ('mme.leudjeuliliane',   'Mme', 'Liliane',   'Leudjeu',         'liliane.leudjeu'),
    ('mme.mbachangmelanie',  'Mme', 'Melanie',   'Mbachang',        'melanie.mbachang'),
    ('mme.ngakwenaomi',      'Mme', 'Naomi',     'Ngakwe',          'naomi.ngakwe'),
    ('mme.nguvehacecil',     'Mme', 'Cecil',     'Nguveha',         'cecil.nguveha'),
    ('mme.nkayengamaminatou','Mme', 'Aminatou',  'Nkayengam',       'aminatou.nkayengam'),
    ('mme.nkwainprisca',     'Mme', 'Prisca',    'Nkwain',          'prisca.nkwain'),
    ('mme.tabicynthia',      'Mme', 'Cynthia',   'Tabi',            'cynthia.tabi'),
    ('mr.ndemgordon',        'Mr',  'Gordon',    'Ndem',            'gordon.ndem'),
    ('mr.nebongocelestine',  'Mr',  'Celestine', 'Nebongo',         'celestine.nebongo'),
    ('sheyA',                'Mme', 'Annie',     'Shey',            'annie.shey'),
]

print(f"\n{'='*60}")
print(f"  {'DRY RUN — no changes saved' if DRY_RUN else 'LIVE — SAVING CHANGES'}")
print(f"  Staff Name Fix ({len(FIXES)} records)")
print(f"{'='*60}\n")

ok = skipped = 0
errors = []

for old_un, title, first, last, new_un in FIXES:
    try:
        user = User.objects.get(username=old_un)
    except User.DoesNotExist:
        if User.objects.filter(username=new_un).exists():
            print(f"  ✓ Already fixed: {new_un}")
            skipped += 1
            continue
        errors.append(f"NOT FOUND: {old_un!r}")
        continue

    try:
        staff = user.staff_profile
    except Exception:
        errors.append(f"No staff profile for: {old_un!r}")
        continue

    changes = []
    if user.first_name != first:     changes.append(f"  first:    {user.first_name!r:22} → {first!r}")
    if user.last_name  != last:      changes.append(f"  last:     {user.last_name!r:22} → {last!r}")
    if user.username   != new_un:    changes.append(f"  username: {user.username!r:22} → {new_un!r}")
    if (staff.title or '') != title: changes.append(f"  title:    {staff.title!r:22} → {title!r}")

    if not changes:
        print(f"  — No change needed: {old_un}")
        skipped += 1
        continue

    print(f"\n  {old_un}")
    for c in changes:
        print(c)

    if not DRY_RUN:
        if new_un != old_un and User.objects.filter(username=new_un).exists():
            errors.append(f"Username collision: {new_un!r} — skipped {old_un}")
            continue
        user.first_name = first
        user.last_name  = last
        user.username   = new_un
        user.save()
        staff.title = title
        staff.save()
        print("  ✓ Saved")

    ok += 1

print(f"\n{'='*60}")
if DRY_RUN:
    print(f"  Dry run complete — {ok} would be updated, {skipped} already correct")
    print(f"  To apply: set DRY_RUN = False then re-run")
else:
    print(f"  Done — {ok} updated, {skipped} already correct")
if errors:
    print(f"\n  Errors ({len(errors)}):")
    for e in errors:
        print(f"    ✗ {e}")
print(f"{'='*60}\n")

======================================================================
FILE: scripts/seed_school_data.py
======================================================================
"""
scripts/seed_school_data.py
===========================
Populates Rapha-Bethel BNPS with real data extracted from the official school flyers.

Run from the project root:
    python manage.py shell < scripts/seed_school_data.py
  or:
    python manage.py runscript seed_school_data   (if django-extensions installed)

Safe to run multiple times — uses get_or_create throughout.
"""

import os, sys, django
# Allow running directly: python scripts/seed_school_data.py
if __name__ == '__main__':
    sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
    django.setup()

from decimal import Decimal
from django.contrib.auth import get_user_model
from core.models import School
from finance.models import FeeStructure
from academics.models import SchoolClass

User = get_user_model()
YEAR = '2025-2026'

print('\n' + '='*60)
print('  Rapha-Bethel BNPS — Data Seed Script')
print('='*60)

# ─────────────────────────────────────────────────────────────
# 1. SCHOOL PROFILE
# ─────────────────────────────────────────────────────────────
print('\n[1] Updating school profile...')

school, _ = School.objects.get_or_create(id=1)
school.name              = 'Rapha-Bethel Bilingual Nursery and Primary School'
school.code              = 'RAPHA-BETHEL'
school.address           = 'Rue des Pavés avant EEC, Feu Rouge Bessengue'
school.city              = 'Douala'
school.quarter           = 'Bessengue'
school.phone             = '+237 670 177 979'
school.email             = 'raphabethel4u@gmail.com'
school.website           = 'https://raphabethel.org/BNPS'
school.academic_year     = YEAR
school.current_term      = 1
school.is_bilingual      = True
school.default_language  = 'both'
school.motto             = 'Work · Morality · Success'
school.save()
print(f'   ✔ School profile updated: {school.name}')

# ─────────────────────────────────────────────────────────────
# 2. FEE STRUCTURES
# ─────────────────────────────────────────────────────────────
# From the flyers:
#
# NURSERY (Maternelle):
#   Instalment 1 (Oct 10):  60 000 XAF
#   Instalment 2 (Feb 10):  40 000 XAF
#   Instalment 3 (Apr 10):  10 000 XAF
#   TOTAL:                 110 000 XAF
#
# CLASS 1 to 5 (SIL au CM2):
#   Instalment 1 (Oct 10):  50 000 XAF
#   Instalment 2 (Feb 10):  40 000 XAF
#   Instalment 3 (Apr 10):  10 000 XAF
#   TOTAL:                 100 000 XAF
#
# CLASS 6 (CM2 in French system):
#   Instalment 1 (Oct 10):  85 000 XAF
#   Instalment 2 (Feb 10):  40 000 XAF
#   Instalment 3 (Apr 10):  20 000 XAF
#   TOTAL:                 145 000 XAF
#
# OTHER FEES (all classes):
#   Registration — New pupils:    15 000 XAF (once)
#   Registration — Old pupils:    10 000 XAF (once)
#   Extra classes 1st & 2nd term: 15 000 XAF (termly)
#   Extra classes 3rd term:       10 000 XAF (termly)
#   Report card:                   1 000 XAF (termly)
#   Exam fee CM2:              To be decided
# ─────────────────────────────────────────────────────────────

print('\n[2] Creating fee structures...')

# Get the CM2 class object for the Class 6 specific fee
cm2_class = SchoolClass.objects.filter(level='class6').first()

# Admin user for created_by (use first superuser)
admin_user = User.objects.filter(is_superuser=True).first()

fees = [
    # ── NURSERY TUITION ──────────────────────────────────────
    dict(
        name='Nursery Tuition — Term 1',
        name_fr='Frais de scolarité Maternelle — 1er Trimestre',
        fee_type='tuition',
        amount=Decimal('60000'),
        payment_frequency='termly',
        class_level='nursery',
        term=1,
        is_mandatory=True,
        description='1st instalment due 10 October',
        description_fr='1ère tranche due le 10 Octobre',
    ),
    dict(
        name='Nursery Tuition — Term 2',
        name_fr='Frais de scolarité Maternelle — 2ème Trimestre',
        fee_type='tuition',
        amount=Decimal('40000'),
        payment_frequency='termly',
        class_level='nursery',
        term=2,
        is_mandatory=True,
        description='2nd instalment due 10 February',
        description_fr='2ème tranche due le 10 Février',
    ),
    dict(
        name='Nursery Tuition — Term 3',
        name_fr='Frais de scolarité Maternelle — 3ème Trimestre',
        fee_type='tuition',
        amount=Decimal('10000'),
        payment_frequency='termly',
        class_level='nursery',
        term=3,
        is_mandatory=True,
        description='3rd instalment due 10 April',
        description_fr='3ème tranche due le 10 Avril',
    ),

    # ── PRIMARY CLASS 1–5 TUITION ────────────────────────────
    dict(
        name='Primary (Class 1–5) Tuition — Term 1',
        name_fr='Frais de scolarité Primaire (SIL–CM2) — 1er Trimestre',
        fee_type='tuition',
        amount=Decimal('50000'),
        payment_frequency='termly',
        class_level='primary',
        term=1,
        is_mandatory=True,
        description='1st instalment due 10 October. Covers SIL, CP, CE1, CE2, CM1, CM2, Class 1–5.',
        description_fr='1ère tranche due le 10 Octobre.',
    ),
    dict(
        name='Primary (Class 1–5) Tuition — Term 2',
        name_fr='Frais de scolarité Primaire (SIL–CM2) — 2ème Trimestre',
        fee_type='tuition',
        amount=Decimal('40000'),
        payment_frequency='termly',
        class_level='primary',
        term=2,
        is_mandatory=True,
        description='2nd instalment due 10 February.',
        description_fr='2ème tranche due le 10 Février.',
    ),
    dict(
        name='Primary (Class 1–5) Tuition — Term 3',
        name_fr='Frais de scolarité Primaire (SIL–CM2) — 3ème Trimestre',
        fee_type='tuition',
        amount=Decimal('10000'),
        payment_frequency='termly',
        class_level='primary',
        term=3,
        is_mandatory=True,
        description='3rd instalment due 10 April.',
        description_fr='3ème tranche due le 10 Avril.',
    ),

    # ── CLASS 6 / CM2 TUITION ────────────────────────────────
    dict(
        name='Class 6 Tuition — Term 1',
        name_fr='Frais de scolarité Classe 6 — 1er Trimestre',
        fee_type='tuition',
        amount=Decimal('85000'),
        payment_frequency='termly',
        class_level='specific',
        term=1,
        is_mandatory=True,
        description='1st instalment due 10 October. Class 6 only.',
        description_fr='1ère tranche due le 10 Octobre. Classe 6 uniquement.',
    ),
    dict(
        name='Class 6 Tuition — Term 2',
        name_fr='Frais de scolarité Classe 6 — 2ème Trimestre',
        fee_type='tuition',
        amount=Decimal('40000'),
        payment_frequency='termly',
        class_level='specific',
        term=2,
        is_mandatory=True,
        description='2nd instalment due 10 February. Class 6 only.',
        description_fr='2ème tranche due le 10 Février. Classe 6 uniquement.',
    ),
    dict(
        name='Class 6 Tuition — Term 3',
        name_fr='Frais de scolarité Classe 6 — 3ème Trimestre',
        fee_type='tuition',
        amount=Decimal('20000'),
        payment_frequency='termly',
        class_level='specific',
        term=3,
        is_mandatory=True,
        description='3rd instalment due 10 April. Class 6 only.',
        description_fr='3ème tranche due le 10 Avril. Classe 6 uniquement.',
    ),

    # ── REGISTRATION ─────────────────────────────────────────
    dict(
        name='Registration Fee — New Pupils',
        name_fr='Frais d\'inscription — Nouveaux élèves',
        fee_type='registration',
        amount=Decimal('15000'),
        payment_frequency='once',
        class_level='all',
        term=1,
        is_mandatory=True,
        description='One-time registration for new pupils. Due at enrollment.',
        description_fr='Inscription unique pour les nouveaux élèves.',
    ),
    dict(
        name='Registration Fee — Returning Pupils',
        name_fr='Frais d\'inscription — Anciens élèves',
        fee_type='registration',
        amount=Decimal('10000'),
        payment_frequency='once',
        class_level='all',
        term=1,
        is_mandatory=True,
        description='Re-registration for returning pupils. Due at start of year.',
        description_fr='Réinscription pour les anciens élèves.',
    ),

    # ── EXTRA CLASSES ─────────────────────────────────────────
    dict(
        name='Extra Classes — Term 1 & 2',
        name_fr='Cours supplémentaires — 1er & 2ème Trimestre',
        fee_type='activity',
        amount=Decimal('15000'),
        payment_frequency='termly',
        class_level='all',
        term=1,
        is_mandatory=False,
        description='Supplementary classes on campus. 15 000 XAF per term for Terms 1 and 2.',
        description_fr='Cours supplémentaires sur le campus.',
    ),
    dict(
        name='Extra Classes — Term 3',
        name_fr='Cours supplémentaires — 3ème Trimestre',
        fee_type='activity',
        amount=Decimal('10000'),
        payment_frequency='termly',
        class_level='all',
        term=3,
        is_mandatory=False,
        description='Supplementary classes on campus. 10 000 XAF for Term 3.',
        description_fr='Cours supplémentaires — 3ème trimestre.',
    ),

    # ── REPORT CARD ───────────────────────────────────────────
    dict(
        name='Report Card Fee',
        name_fr='Frais de bulletin',
        fee_type='other',
        amount=Decimal('1000'),
        payment_frequency='termly',
        class_level='all',
        term=1,
        is_mandatory=True,
        description='Report card production fee — 1 000 XAF per term.',
        description_fr='Frais d\'édition du bulletin — 1 000 XAF par trimestre.',
    ),
]

created_count = 0
updated_count = 0

for fee_data in fees:
    # Separate specific_classes handling
    specific_classes = []
    if fee_data.get('class_level') == 'specific' and cm2_class:
        specific_classes = [cm2_class]

    obj, created = FeeStructure.objects.get_or_create(
        name=fee_data['name'],
        academic_year=YEAR,
        defaults={
            'name_fr':           fee_data.get('name_fr', ''),
            'fee_type':          fee_data['fee_type'],
            'amount':            fee_data['amount'],
            'payment_frequency': fee_data['payment_frequency'],
            'class_level':       fee_data.get('class_level', 'all'),
            'term':              fee_data.get('term', 1),
            'is_mandatory':      fee_data.get('is_mandatory', True),
            'description':       fee_data.get('description', ''),
            'description_fr':    fee_data.get('description_fr', ''),
            'is_active':         True,
            'created_by':        admin_user,
        }
    )

    if specific_classes:
        obj.specific_classes.set(specific_classes)

    if created:
        created_count += 1
        print(f'   + Created: {obj.name} — {obj.amount:,.0f} XAF')
    else:
        updated_count += 1
        print(f'   ~ Exists:  {obj.name}')

print(f'\n   Fee structures: {created_count} created, {updated_count} already existed.')

# ─────────────────────────────────────────────────────────────
# 3. SUMMARY
# ─────────────────────────────────────────────────────────────
print('\n' + '='*60)
print('  SEED COMPLETE')
print('='*60)
print(f'''
School Profile:  {school.name}
Address:         {school.address}
Phone:           {school.phone}
Email:           {school.email}
Academic Year:   {school.academic_year}

Fee Summary (2025-2026):
  Nursery total:       110 000 XAF  (60k + 40k + 10k)
  Class 1–5 total:     100 000 XAF  (50k + 40k + 10k)
  Class 6 total:       145 000 XAF  (85k + 40k + 20k)

  New pupil registration:      15 000 XAF
  Returning pupil registration: 10 000 XAF
  Extra classes (T1 & T2):     15 000 XAF/term
  Extra classes (T3):          10 000 XAF
  Report card:                  1 000 XAF/term

Payment accounts:
  AZZICUL:   N° 02-7215 (in name of child)
  CCA BANK:  10006-0024876980126

School hours:
  Nursery:   Mon–Thu  7:30–13:00,  Fri 7:30–12:00
  Primary:   Mon–Thu  7:30–14:30,  Fri 7:30–12:00
  Office:    Mon–Thu  7:30–15:30,  Fri 7:30–12:00
''')


######################################################################
# APP: STAFF
######################################################################

======================================================================
FILE: staff/__init__.py
======================================================================
# staff/__init__.py
# This file makes Python treat the directory as a package

======================================================================
FILE: staff/admin.py
======================================================================
# staff/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from django.utils.html import format_html
from .models import Staff, TeacherSubject, StaffAttendance, StaffLeave, StaffDocument

User = get_user_model()

class StaffInline(admin.StackedInline):
    model = Staff
    can_delete = False
    verbose_name_plural = 'Staff Profile'
    fk_name = 'user'
    fieldsets = (
        ('Basic Information', {
            'fields': ('employee_id', 'role', 'department', 'school')
        }),
        ('Personal', {
            'fields': ('title', 'date_of_birth', 'gender', 'nationality', 'marital_status')
        }),
        ('Contact', {
            'fields': (
                'phone_country_code', 'phone_number',
                'alt_phone_country_code', 'alternate_phone',
                'email', 'address', 'quarter', 'city',
            )
        }),
        ('Employment', {
            'fields': ('employment_status', 'hire_date', 'contract_end_date')
        }),
        ('Financial', {
            'fields': ('salary', 'bank_name', 'bank_account', 'tax_id', 'social_security'),
            'classes': ('collapse',)
        }),
    )

class CustomUserAdmin(UserAdmin):
    inlines = [StaffInline]
    list_display = ['username', 'email', 'first_name', 'last_name', 'is_staff', 'get_role']
    list_filter = ['is_staff', 'is_superuser', 'staff_profile__role']
    
    def get_role(self, obj):
        if hasattr(obj, 'staff_profile'):
            return obj.staff_profile.get_role_display()
        return '-'
    get_role.short_description = 'Role'
    get_role.admin_order_field = 'staff_profile__role'

# Unregister default User admin and register custom
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)

@admin.register(Staff)
class StaffAdmin(admin.ModelAdmin):
    list_display = ['employee_id', 'photo_thumbnail', 'get_full_name', 'role', 'department', 'phone_number', 'is_active']
    list_filter = ['role', 'department', 'employment_status', 'is_active', 'school']
    search_fields = ['employee_id', 'user__first_name', 'user__last_name', 'phone_number', 'email']
    list_editable = ['is_active']
    list_per_page = 25
    
    fieldsets = (
        ('User Account', {
            'fields': ('user', 'employee_id', 'school')
        }),
        ('Personal Information', {
            'fields': ('title', 'date_of_birth', 'gender', 'nationality', 'marital_status', 'photo')
        }),
        ('Contact Details', {
            'fields': (
                'phone_country_code', 'phone_number',
                'alt_phone_country_code', 'alternate_phone',
                'email', 'address', 'quarter', 'city',
            )
        }),
        ('Emergency Contact', {
            'fields': (
                'emergency_contact_name',
                'emergency_phone_country_code', 'emergency_contact_phone',
                'emergency_contact_relationship',
            ),
            'classes': ('collapse',)
        }),
        ('Employment Details', {
            'fields': ('role', 'department', 'employment_status', 'hire_date', 'contract_end_date')
        }),
        ('Qualifications', {
            'fields': ('qualifications', 'specialization', 'years_of_experience'),
            'classes': ('collapse',)
        }),
        ('Financial Information', {
            'fields': ('salary', 'bank_name', 'bank_account', 'bank_branch', 'tax_id', 'social_security'),
            'classes': ('collapse',)
        }),
        ('Documents', {
            'fields': ('cv_file', 'contract_file', 'id_document', 'diplomas'),
            'classes': ('collapse',)
        }),
        ('System', {
            'fields': ('is_active', 'notes', 'imported_from', 'original_data'),
            'classes': ('collapse',)
        }),
    )
    
    readonly_fields = ['employee_id', 'created_at', 'updated_at']
    
    def photo_thumbnail(self, obj):
        if obj.photo:
            return format_html('<img src="{}" width="50" height="50" style="border-radius: 50%;" />', obj.photo.url)
        return format_html('<div style="width:50px;height:50px;background:#4CAF50;border-radius:50%;display:flex;align-items:center;justify-content:center;color:white;font-weight:bold;">{}</div>', 
                         obj.user.first_name[0] if obj.user.first_name else '?')
    photo_thumbnail.short_description = 'Photo'
    
    def get_full_name(self, obj):
        return obj.get_display_name() or obj.user.get_full_name()
    get_full_name.short_description = 'Full Name'
    get_full_name.admin_order_field = 'user__first_name'
    
    actions = ['export_as_csv', 'deactivate_staff', 'send_welcome_email']
    
    def export_as_csv(self, request, queryset):
        import csv
        from django.http import HttpResponse
        
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="staff_export.csv"'
        
        writer = csv.writer(response)
        writer.writerow(['Employee ID', 'Title', 'Full Name', 'Role', 'Department', 'Phone', 'Email', 'Status'])
        
        for staff in queryset:
            writer.writerow([
                staff.employee_id,
                staff.title,
                staff.user.get_full_name(),
                staff.get_role_display(),
                staff.get_department_display(),
                f"{staff.phone_country_code} {staff.phone_number}".strip() if staff.phone_number else '',
                staff.email,
                'Active' if staff.is_active else 'Inactive'
            ])
        
        return response
    export_as_csv.short_description = "Export selected staff as CSV"
    
    def deactivate_staff(self, request, queryset):
        queryset.update(is_active=False)
        self.message_user(request, f"{queryset.count()} staff members deactivated.")
    deactivate_staff.short_description = "Deactivate selected staff"
    
    def send_welcome_email(self, request, queryset):
        for staff in queryset:
            # Add email sending logic here
            pass
        self.message_user(request, f"Welcome emails sent to {queryset.count()} staff members.")
    send_welcome_email.short_description = "Send welcome email"

@admin.register(StaffAttendance)
class StaffAttendanceAdmin(admin.ModelAdmin):
    list_display = ['staff', 'date', 'check_in_time', 'check_out_time', 'status']
    list_filter = ['status', 'date']
    search_fields = ['staff__user__first_name', 'staff__user__last_name', 'staff__employee_id']
    date_hierarchy = 'date'

@admin.register(StaffLeave)
class StaffLeaveAdmin(admin.ModelAdmin):
    list_display = ['staff', 'leave_type', 'start_date', 'end_date', 'days_requested', 'status']
    list_filter = ['leave_type', 'status']
    search_fields = ['staff__user__first_name', 'staff__user__last_name']
    date_hierarchy = 'start_date'
    
    actions = ['approve_leaves', 'reject_leaves']
    
    def approve_leaves(self, request, queryset):
        from django.utils import timezone
        queryset.update(status='approved', approved_by=request.user.staff_profile, approved_date=timezone.now().date())
        self.message_user(request, f"{queryset.count()} leave requests approved.")
    approve_leaves.short_description = "Approve selected leave requests"
    
    def reject_leaves(self, request, queryset):
        queryset.update(status='rejected')
        self.message_user(request, f"{queryset.count()} leave requests rejected.")
    reject_leaves.short_description = "Reject selected leave requests"

======================================================================
FILE: staff/apps.py
======================================================================
# staff/apps.py
from django.apps import AppConfig

class StaffConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'staff'
    verbose_name = 'Staff Management'

    def ready(self):
        import staff.signals  # noqa

======================================================================
FILE: staff/forms.py
======================================================================
# staff/forms.py
from django import forms
from django.contrib.auth import get_user_model
from .models import Staff, StaffLeave, StaffAttendance

User = get_user_model()


class StaffUserForm(forms.ModelForm):
    """Form for creating/updating the Django User account linked to a staff member.

    Notes:
        - Do NOT put title/honorific (Mr, Mme, Dr) in First Name.
        - First Name: given name only, e.g. 'Annie'
        - Last Name: family name only, e.g. 'Shey'
        - Username: auto-suggested as firstname.lastname (no title)
    """
    password = forms.CharField(widget=forms.PasswordInput, required=False,
                               help_text="Leave blank to keep existing password")
    confirm_password = forms.CharField(widget=forms.PasswordInput, required=False,
                                       label="Confirm Password")

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'password']
        labels = {
            'first_name': 'First Name (given name only — no title)',
            'last_name':  'Last Name (family name)',
        }
        help_texts = {
            'username':   "Format: firstname.lastname — e.g. annie.shey",
            'first_name': "⚠️ Do NOT write 'Mme Annie' — write 'Annie' only. Set title in the Staff Profile below.",
        }

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get('password')
        confirm  = cleaned_data.get('confirm_password')
        if password and password != confirm:
            raise forms.ValidationError("Passwords do not match")
        return cleaned_data

    def save(self, commit=True):
        user = super().save(commit=False)
        password = self.cleaned_data.get('password')
        if password:
            user.set_password(password)
        if commit:
            user.save()
        return user


class StaffForm(forms.ModelForm):
    """Form for the Staff profile record (not the User account).

    Sensitive payroll fields (salary, bank_account, tax_id, social_security)
    are excluded — edit those via the Django admin only.
    """

    class Meta:
        model = Staff
        # Explicit safe list — keeps salary/bank/tax out of the web form
        fields = [
            'title',
            'school',
            'date_of_birth', 'gender', 'nationality', 'marital_status',
            'phone_country_code', 'phone_number',
            'alt_phone_country_code', 'alternate_phone',
            'email', 'address', 'quarter', 'city',
            'emergency_contact_name',
            'emergency_phone_country_code', 'emergency_contact_phone',
            'emergency_contact_relationship',
            'role', 'department', 'employment_status',
            'hire_date', 'contract_end_date',
            'qualifications', 'specialization', 'years_of_experience',
            'subjects_taught', 'is_class_teacher', 'homeroom_class',
            'bank_name', 'bank_branch',
            'photo', 'cv_file', 'contract_file', 'id_document', 'diplomas',
            'is_active', 'notes',
        ]
        widgets = {
            'date_of_birth':    forms.DateInput(attrs={'type': 'date'}),
            'hire_date':        forms.DateInput(attrs={'type': 'date'}),
            'contract_end_date':forms.DateInput(attrs={'type': 'date'}),
            'address':          forms.Textarea(attrs={'rows': 3}),
            'notes':            forms.Textarea(attrs={'rows': 3}),
            'qualifications':   forms.Textarea(attrs={'rows': 3}),
            'phone_country_code':           forms.Select(attrs={'class': 'phone-code-select'}),
            'alt_phone_country_code':       forms.Select(attrs={'class': 'phone-code-select'}),
            'emergency_phone_country_code': forms.Select(attrs={'class': 'phone-code-select'}),
            'phone_number':           forms.TextInput(attrs={'placeholder': '670177979'}),
            'alternate_phone':        forms.TextInput(attrs={'placeholder': '670177979'}),
            'emergency_contact_phone':forms.TextInput(attrs={'placeholder': '670177979'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['date_of_birth'].required = False
        self.fields['phone_number'].required = False
        self.fields['email'].required = False
        self.fields['address'].required = False
        self.fields['alternate_phone'].required = False
        self.fields['emergency_contact_phone'].required = False


class StaffLeaveForm(forms.ModelForm):
    """Form for staff leave requests."""

    class Meta:
        model = StaffLeave
        fields = ['leave_type', 'start_date', 'end_date', 'reason']
        widgets = {
            'start_date': forms.DateInput(attrs={'type': 'date'}),
            'end_date':   forms.DateInput(attrs={'type': 'date'}),
            'reason':     forms.Textarea(attrs={'rows': 3}),
        }

    def clean(self):
        cleaned_data = super().clean()
        start = cleaned_data.get('start_date')
        end   = cleaned_data.get('end_date')
        if start and end and end < start:
            raise forms.ValidationError("End date cannot be before start date")
        return cleaned_data


class StaffAttendanceForm(forms.ModelForm):
    """Form for staff attendance."""

    class Meta:
        model = StaffAttendance
        fields = ['staff', 'date', 'check_in_time', 'check_out_time', 'status', 'remarks']
        widgets = {
            'date':           forms.DateInput(attrs={'type': 'date'}),
            'check_in_time':  forms.TimeInput(attrs={'type': 'time'}),
            'check_out_time': forms.TimeInput(attrs={'type': 'time'}),
        }


class StaffImportForm(forms.Form):
    """Form for importing staff from Excel/CSV."""
    file = forms.FileField(
        label='Excel / CSV File',
        help_text=(
            'Columns required: Title, First Name, Last Name, Role, Department, '
            'Phone, Email, Hire Date. '
            'Title column: Mr, Mme, Mrs, Dr etc. — NOT inside First Name.'
        )
    )

    def clean_file(self):
        file = self.cleaned_data['file']
        if not file.name.endswith(('.xlsx', '.xls', '.csv')):
            raise forms.ValidationError('Please upload an Excel or CSV file')
        return file


class StaffSearchForm(forms.Form):
    """Form for searching/filtering the staff list."""
    q = forms.CharField(
        required=False,
        widget=forms.TextInput(attrs={'placeholder': 'Search by name, ID, or phone…'})
    )
    role = forms.ChoiceField(
        required=False,
        choices=[('', 'All Roles')] + Staff.ROLE_CHOICES
    )
    department = forms.ChoiceField(
        required=False,
        choices=[('', 'All Departments')] + Staff.DEPARTMENT_CHOICES
    )
    status = forms.ChoiceField(
        required=False,
        choices=[('', 'All Status'), ('active', 'Active'), ('inactive', 'Inactive')]
    )

======================================================================
FILE: staff/models.py
======================================================================
# staff/models.py
"""
Staff management models for teachers, administrators, and support staff.
"""
from django.db import models
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
from core.models import School

User = get_user_model()


class Staff(models.Model):
    """
    Complete Staff Model for Rapha-Bethel BNPS.
    
    This model extends the user model with staff-specific information including
    employment details, qualifications, contact information, and role-based
    assignments. It handles all staff types from teachers to support staff.
    
    Attributes:
        user (OneToOneField): Link to the Django user account
        school (ForeignKey): School this staff member belongs to
        employee_id (str): Unique staff identifier
        date_of_birth (date): Staff member's birth date
        gender (str): Gender from GENDER_CHOICES
        nationality (str): Staff member's nationality
        marital_status (str): Marital status
        phone_number (str): Primary contact number
        alternate_phone (str): Secondary contact number
        email (str): Email address
        address (str): Residential address
        quarter (str): Neighborhood/district
        city (str): City of residence
        emergency_contact_name (str): Name of emergency contact
        emergency_contact_phone (str): Emergency contact number
        emergency_contact_relationship (str): Relationship to emergency contact
        role (str): Staff role from ROLE_CHOICES
        department (str): Department from DEPARTMENT_CHOICES
        employment_status (str): Current employment status
        hire_date (date): Date of employment start
        contract_end_date (date): End of contract date
        qualifications (str): Educational and professional qualifications
        specialization (str): Area of specialization
        years_of_experience (int): Total years of experience
        subjects_taught (ManyToManyField): Subjects this teacher teaches
        is_class_teacher (bool): Whether staff is a class teacher
        homeroom_class (ForeignKey): Class this teacher is responsible for
        salary (Decimal): Monthly salary in XAF
        bank_name (str): Bank name for salary deposits
        bank_account (str): Bank account number
        bank_branch (str): Bank branch location
        tax_id (str): Tax identification number
        social_security (str): Social security number
        photo (ImageField): Staff profile photo
        cv_file (FileField): CV/resume document
        contract_file (FileField): Employment contract
        id_document (FileField): ID document
        diplomas (FileField): Diplomas and certificates
        created_at (datetime): When record was created
        updated_at (datetime): When record was last updated
        is_active (bool): Whether staff is currently active
        notes (str): Additional notes
        imported_from (str): Source of import if applicable
        original_data (JSONField): Original imported data
    """
    
    # Role Choices based on your Excel data
    ROLE_CHOICES = [
        ('proprietor', 'Proprietor'),
        ('head_master', 'Head Master'),
        ('head_mistress', 'Head Mistress'),
        ('bursar', 'Bursar'),
        ('admin', 'Administrator'),
        ('teacher', 'Teacher'),
        ('class_teacher', 'Class Teacher'),
        ('subject_teacher', 'Subject Teacher'),
        ('assistant_teacher', 'Assistant Teacher'),
        ('secretary', 'Secretary'),
        ('driver', 'Driver'),
        ('cleaner', 'Cleaner'),
        ('canteen', 'Canteen Staff'),
        ('security', 'Security'),
        ('support', 'Support Staff'),
        ('other', 'Other'),
    ]
    
    # Department Choices
    DEPARTMENT_CHOICES = [
        ('admin', 'Administration'),
        ('english', 'English Section'),
        ('french', 'French Section'),
        ('bilingual', 'Bilingual Section'),
        ('nursery', 'Nursery Section'),
        ('finance', 'Finance'),
        ('support', 'Support Staff'),
        ('transport', 'Transport'),
    ]
    
    # Employment Status
    EMPLOYMENT_STATUS = [
        ('permanent', 'Permanent'),
        ('contract', 'Contract'),
        ('probation', 'Probation'),
        ('intern', 'Intern'),
        ('volunteer', 'Volunteer'),
        ('part_time', 'Part Time'),
        ('casual', 'Casual'),
    ]
    
    # Gender Choices
    GENDER_CHOICES = [
        ('M', 'Male'),
        ('F', 'Female'),
        ('O', 'Other'),
    ]
    
    # Title / Honorific choices
    TITLE_CHOICES = [
        ('', '—'),
        ('Mr', 'Mr'),
        ('Mrs', 'Mrs'),
        ('Mme', 'Mme'),
        ('Ms', 'Ms'),
        ('Dr', 'Dr'),
        ('Prof', 'Prof'),
        ('Rev', 'Rev'),
        ('Sis', 'Sis'),
    ]

    # Phone number: accepts local format (e.g. 670177979) — no +237 required.
    # Country code is stored separately in phone_country_code.
    phone_regex = RegexValidator(
        regex=r'^\d{6,15}$',
        message="Enter digits only, e.g. 670177979 — no spaces, dashes, or country code"
    )

    # Country code dropdown choices
    COUNTRY_CODE_CHOICES = [
        ('+237', '+237 \U0001f1e8\U0001f1f2 Cameroon'),
        ('+234', '+234 \U0001f1f3\U0001f1ec Nigeria'),
        ('+241', '+241 \U0001f1ec\U0001f1e6 Gabon'),
        ('+242', '+242 \U0001f1e8\U0001f1ec Congo-Brazzaville'),
        ('+243', '+243 \U0001f1e8\U0001f1e9 DR Congo'),
        ('+225', '+225 \U0001f1e8\U0001f1ee Cote d\'Ivoire'),
        ('+233', '+233 \U0001f1ec\U0001f1ed Ghana'),
        ('+221', '+221 \U0001f1f8\U0001f1f3 Senegal'),
        ('+44',  '+44  \U0001f1ec\U0001f1e7 UK'),
        ('+33',  '+33  \U0001f1eb\U0001f1f7 France'),
        ('+1',   '+1   \U0001f1fa\U0001f1f8 US/Canada'),
    ]
    
    # ========== USER LINK ==========
    user = models.OneToOneField(
        User,
        on_delete=models.CASCADE,
        related_name='staff_profile',
        verbose_name=_("User Account")
    )
    
    school = models.ForeignKey(
        School,
        on_delete=models.CASCADE,
        related_name='staff_members',
        default=1,
        verbose_name=_("School")
    )
    
    # ========== PERSONAL INFORMATION ==========
    employee_id = models.CharField(
        max_length=20,
        unique=True,
        verbose_name=_("Employee ID"),
        help_text=_("Unique staff identifier")
    )

    title = models.CharField(
        max_length=10,
        choices=TITLE_CHOICES,
        blank=True,
        default='',
        verbose_name=_("Title/Honorific"),
        help_text=_("e.g. Mr, Mme, Dr — do NOT put this in First Name")
    )

    date_of_birth = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Date of Birth")
    )
    
    gender = models.CharField(
        max_length=1,
        choices=GENDER_CHOICES,
        default='M',
        verbose_name=_("Gender")
    )
    
    nationality = models.CharField(
        max_length=50,
        default="Cameroonian",
        blank=True,
        verbose_name=_("Nationality")
    )
    
    marital_status = models.CharField(
        max_length=20,
        choices=[
            ('single', 'Single'),
            ('married', 'Married'),
            ('divorced', 'Divorced'),
            ('widowed', 'Widowed'),
        ],
        default='single',
        blank=True,
        verbose_name=_("Marital Status")
    )
    
    # ========== CONTACT INFORMATION ==========
    phone_country_code = models.CharField(
        max_length=6,
        choices=COUNTRY_CODE_CHOICES,
        default='+237',
        verbose_name=_("Country Code")
    )
    phone_number = models.CharField(
        validators=[phone_regex],
        max_length=15,
        blank=True,
        verbose_name=_("Phone Number"),
        help_text=_("Local digits only, e.g. 670177979")
    )

    alt_phone_country_code = models.CharField(
        max_length=6,
        choices=COUNTRY_CODE_CHOICES,
        default='+237',
        verbose_name=_("Alt. Country Code")
    )
    alternate_phone = models.CharField(
        validators=[phone_regex],
        max_length=15,
        blank=True,
        verbose_name=_("Alternate Phone Number"),
        help_text=_("Local digits only")
    )

    email = models.EmailField(
        blank=True,
        verbose_name=_("Email Address")
    )

    address = models.TextField(
        blank=True,
        verbose_name=_("Residential Address")
    )

    quarter = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Quarter/Neighborhood"),
        help_text=_("e.g., Bonapriso, Akwa, Bonanjo")
    )

    city = models.CharField(
        max_length=100,
        default="Douala",
        blank=True,
        verbose_name=_("City")
    )

    # ========== EMERGENCY CONTACT ==========
    emergency_contact_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Emergency Contact Name")
    )

    emergency_phone_country_code = models.CharField(
        max_length=6,
        choices=COUNTRY_CODE_CHOICES,
        default='+237',
        verbose_name=_("Emergency Country Code")
    )
    emergency_contact_phone = models.CharField(
        validators=[phone_regex],
        max_length=15,
        blank=True,
        verbose_name=_("Emergency Contact Phone"),
        help_text=_("Local digits only")
    )

    emergency_contact_relationship = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Relationship")
    )
    
    # ========== EMPLOYMENT DETAILS ==========
    role = models.CharField(
        max_length=20,
        choices=ROLE_CHOICES,
        default='teacher',
        verbose_name=_("Role/Position")
    )
    
    department = models.CharField(
        max_length=20,
        choices=DEPARTMENT_CHOICES,
        default='english',
        verbose_name=_("Department")
    )
    
    employment_status = models.CharField(
        max_length=20,
        choices=EMPLOYMENT_STATUS,
        default='contract',
        verbose_name=_("Employment Status")
    )
    
    hire_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Hire Date")
    )
    
    contract_end_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Contract End Date")
    )
    
    # ========== QUALIFICATIONS ==========
    qualifications = models.TextField(
        blank=True,
        verbose_name=_("Qualifications"),
        help_text=_("Degrees, certifications, training")
    )
    
    specialization = models.CharField(
        max_length=200,
        blank=True,
        verbose_name=_("Specialization"),
        help_text=_("Subject area specialization")
    )
    
    years_of_experience = models.PositiveIntegerField(
        default=0,
        verbose_name=_("Years of Experience")
    )
    
    # ========== TEACHER-SPECIFIC FIELDS ==========
    subjects_taught = models.ManyToManyField(
        'academics.Subject',
        through='TeacherSubject',
        blank=True,
        related_name='teachers',
        verbose_name=_("Subjects Taught")
    )
    
    is_class_teacher = models.BooleanField(
        default=False,
        verbose_name=_("Is Class Teacher?")
    )
    
    homeroom_class = models.ForeignKey(
        'academics.SchoolClass',
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name='homeroom_teachers',
        verbose_name=_("Homeroom Class")
    )
    
    # ========== FINANCIAL INFORMATION ==========
    salary = models.DecimalField(
        max_digits=10,
        decimal_places=0,
        null=True,
        blank=True,
        verbose_name=_("Monthly Salary (XAF)")
    )
    
    bank_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Bank Name")
    )
    
    bank_account = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Bank Account Number")
    )
    
    bank_branch = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Bank Branch")
    )
    
    tax_id = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Tax ID / NIU")
    )
    
    social_security = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Social Security Number")
    )
    
    # ========== DOCUMENTS ==========
    photo = models.ImageField(
        upload_to='staff/photos/',
        null=True,
        blank=True,
        verbose_name=_("Profile Photo")
    )
    
    cv_file = models.FileField(
        upload_to='staff/documents/cv/',
        null=True,
        blank=True,
        verbose_name=_("CV/Resume")
    )
    
    contract_file = models.FileField(
        upload_to='staff/documents/contracts/',
        null=True,
        blank=True,
        verbose_name=_("Employment Contract")
    )
    
    id_document = models.FileField(
        upload_to='staff/documents/id/',
        null=True,
        blank=True,
        verbose_name=_("ID Document")
    )
    
    diplomas = models.FileField(
        upload_to='staff/documents/diplomas/',
        null=True,
        blank=True,
        verbose_name=_("Diplomas/Certificates")
    )
    
    # ========== SYSTEM FIELDS ==========
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_("Created At")
    )
    
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Updated At")
    )
    
    is_active = models.BooleanField(
        default=True,
        verbose_name=_("Active")
    )
    
    notes = models.TextField(
        blank=True,
        verbose_name=_("Additional Notes")
    )
    
    # ========== IMPORT TRACKING ==========
    imported_from = models.CharField(
        max_length=100,
        blank=True,
        help_text="Source of import (e.g., 'Staff Excel')"
    )
    
    original_data = models.JSONField(
        null=True,
        blank=True,
        help_text="Original imported data"
    )
    
    class Meta:
        verbose_name = "Staff Member"
        verbose_name_plural = "Staff Members"
        ordering = ['employee_id','role', 'user__first_name', 'user__last_name']
        indexes = [
            models.Index(fields=['employee_id']),
            models.Index(fields=['role']),
            models.Index(fields=['department']),
            models.Index(fields=['is_active']),
        ]
    
    def __str__(self):
        """Return string representation of the staff member."""
        name = self.get_display_name() or self.user.get_full_name()
        return f"{name} - {self.get_role_display()} ({self.employee_id})"

    def get_full_name(self):
        """
        Get the display name including title.

        Returns:
            str: Title + first + last name, e.g. 'Mme Annie Shey'.
        """
        return self.get_display_name() or self.user.get_full_name()
    
    def save(self, *args, **kwargs):
        """
        Save the staff member with auto-generated employee ID.
        
        Generates a unique employee ID based on role prefix if not provided.
        """
        if not self.employee_id:
            prefix = {
                'proprietor': 'PR',
                'head_master': 'HM',
                'head_mistress': 'HM',
                'bursar': 'BR',
                'teacher': 'TCH',
                'class_teacher': 'CT',
                'subject_teacher': 'ST',
                'driver': 'DR',
                'cleaner': 'CL',
            }.get(self.role, 'STF')
            
            last_staff = Staff.objects.filter(employee_id__startswith=prefix).order_by('-id').first()
            if last_staff:
                last_num = int(last_staff.employee_id.split('-')[-1]) if '-' in last_staff.employee_id else 1
                new_num = last_num + 1
            else:
                new_num = 1
            self.employee_id = f"{prefix}-{new_num:04d}"
        
        super().save(*args, **kwargs)
    
    @property
    def is_teacher(self):
        """
        Check if staff member is a teacher.
        
        Returns:
            bool: True if role is teacher-related.
        """
        return self.role in ['teacher', 'class_teacher', 'subject_teacher', 'assistant_teacher']
    
    @property
    def is_admin(self):
        """
        Check if staff member is in administration.
        
        Returns:
            bool: True if role is administrative.
        """
        return self.role in ['proprietor', 'head_master', 'head_mistress', 'bursar', 'admin']
    
    @property
    def is_support(self):
        """
        Check if staff member is support staff.
        
        Returns:
            bool: True if role is support-related.
        """
        return self.role in ['driver', 'cleaner', 'canteen', 'security', 'support']
    
    def get_full_phone(self, which='primary'):
        """Return formatted phone number with country code."""
        if which == 'primary':
            code, num = self.phone_country_code, self.phone_number
        elif which == 'alternate':
            code, num = self.alt_phone_country_code, self.alternate_phone
        else:
            code, num = self.emergency_phone_country_code, self.emergency_contact_phone
        return f"{code} {num}" if num else ""

    def get_display_name(self):
        """Return title + full name, e.g. 'Mme Annie Shey'."""
        parts = [self.title, self.user.first_name, self.user.last_name]
        return " ".join(p for p in parts if p).strip()

    def get_contact_info(self):
        """
        Get formatted contact information.

        Returns:
            str: Formatted string with phone and email information.
        """
        info = []
        if self.phone_number:
            info.append(f"📞 {self.get_full_phone('primary')}")
        if self.alternate_phone:
            info.append(f"📱 {self.get_full_phone('alternate')}")
        if self.email:
            info.append(f"📧 {self.email}")
        return " | ".join(info) if info else "No contact info"


class TeacherSubject(models.Model):
    """
    Junction model for teachers and subjects with class assignments.
    
    This model tracks which teacher teaches which subject, optionally
    in a specific class with hours per week.
    
    Attributes:
        teacher (ForeignKey): Teacher assigned
        subject (ForeignKey): Subject being taught
        class_assigned (ForeignKey): Specific class (optional)
        hours_per_week (int): Hours allocated weekly
    """
    
    teacher = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='teacher_subjects'
    )
    subject = models.ForeignKey(
        'academics.Subject', 
        on_delete=models.CASCADE, 
        related_name='subject_teachers'
    )
    class_assigned = models.ForeignKey(
        'academics.SchoolClass', 
        on_delete=models.CASCADE, 
        null=True, 
        blank=True
    )
    hours_per_week = models.PositiveIntegerField(
        default=2
    )
    
    class Meta:
        unique_together = ['teacher', 'subject', 'class_assigned']
        verbose_name = "Teacher Subject Assignment"
        verbose_name_plural = "Teacher Subject Assignments"
    
    def __str__(self):
        """Return string representation of the assignment."""
        return f"{self.teacher} - {self.subject}"


class StaffAttendance(models.Model):
    """
    Tracks daily attendance for staff members.
    
    Separate from student attendance, this model records when staff
    check in and out, their attendance status, and any remarks.
    
    Attributes:
        staff (ForeignKey): Staff member
        date (date): Date of attendance
        check_in_time (time): Time staff checked in
        check_out_time (time): Time staff checked out
        status (str): Attendance status from STATUS_CHOICES
        remarks (str): Additional notes
    """
    
    STATUS_CHOICES = [
        ('present', 'Present'),
        ('absent', 'Absent'),
        ('late', 'Late'),
        ('leave', 'On Leave'),
        ('sick', 'Sick Leave'),
        ('training', 'Training'),
    ]
    
    staff = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='attendances'
    )
    date = models.DateField()
    check_in_time = models.TimeField(
        null=True, 
        blank=True
    )
    check_out_time = models.TimeField(
        null=True, 
        blank=True
    )
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='present'
    )
    remarks = models.CharField(
        max_length=200, 
        blank=True
    )
    
    class Meta:
        unique_together = ['staff', 'date']
        ordering = ['-date']
        verbose_name = "Staff Attendance"
        verbose_name_plural = "Staff Attendances"
    
    def __str__(self):
        """Return string representation of staff attendance."""
        return f"{self.staff} - {self.date} - {self.get_status_display()}"


class StaffLeave(models.Model):
    """
    Manages staff leave requests and approvals.
    
    This model handles all types of leave requests, tracking the
    approval workflow and leave balances.
    
    Attributes:
        staff (ForeignKey): Staff member requesting leave
        leave_type (str): Type of leave from LEAVE_TYPE_CHOICES
        start_date (date): Leave start date
        end_date (date): Leave end date
        days_requested (int): Number of days requested
        reason (str): Reason for leave
        status (str): Request status from STATUS_CHOICES
        approved_by (ForeignKey): Staff who approved the request
        approved_date (date): Date of approval
        remarks (str): Additional remarks
        created_at (datetime): When request was created
        updated_at (datetime): When request was last updated
    """
    
    LEAVE_TYPE_CHOICES = [
        ('annual', 'Annual Leave'),
        ('sick', 'Sick Leave'),
        ('maternity', 'Maternity Leave'),
        ('paternity', 'Paternity Leave'),
        ('bereavement', 'Bereavement'),
        ('unpaid', 'Unpaid Leave'),
        ('training', 'Training Leave'),
    ]
    
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('approved', 'Approved'),
        ('rejected', 'Rejected'),
        ('cancelled', 'Cancelled'),
    ]
    
    staff = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='leave_requests'
    )
    leave_type = models.CharField(
        max_length=20, 
        choices=LEAVE_TYPE_CHOICES
    )
    start_date = models.DateField()
    end_date = models.DateField()
    days_requested = models.PositiveIntegerField()
    reason = models.TextField()
    status = models.CharField(
        max_length=20, 
        choices=STATUS_CHOICES, 
        default='pending'
    )
    approved_by = models.ForeignKey(
        Staff, 
        on_delete=models.SET_NULL, 
        null=True, 
        blank=True, 
        related_name='approved_leaves'
    )
    approved_date = models.DateField(
        null=True, 
        blank=True
    )
    remarks = models.TextField(
        blank=True
    )
    
    created_at = models.DateTimeField(
        auto_now_add=True
    )
    updated_at = models.DateTimeField(
        auto_now=True
    )
    
    class Meta:
        ordering = ['-created_at']
        verbose_name = "Staff Leave"
        verbose_name_plural = "Staff Leaves"
    
    def __str__(self):
        """Return string representation of leave request."""
        return f"{self.staff} - {self.get_leave_type_display()} ({self.start_date} to {self.end_date})"
    
    def save(self, *args, **kwargs):
        """
        Save leave request with auto-calculated days.
        
        Calculates the number of days based on start and end dates.
        """
        if not self.days_requested:
            self.days_requested = (self.end_date - self.start_date).days + 1
        super().save(*args, **kwargs)


class StaffDocument(models.Model):
    """
    Stores additional documents for staff members.
    
    This model allows uploading and organizing various documents
    related to staff employment and qualifications.
    
    Attributes:
        staff (ForeignKey): Staff member this document belongs to
        document_type (str): Type of document from DOCUMENT_TYPE_CHOICES
        title (str): Document title
        file (FileField): The uploaded file
        uploaded_at (datetime): When document was uploaded
        notes (str): Additional notes about the document
    """
    
    DOCUMENT_TYPE_CHOICES = [
        ('contract', 'Employment Contract'),
        ('diploma', 'Diploma/Certificate'),
        ('id', 'ID Card'),
        ('cv', 'CV/Resume'),
        ('medical', 'Medical Certificate'),
        ('other', 'Other'),
    ]
    
    staff = models.ForeignKey(
        Staff, 
        on_delete=models.CASCADE, 
        related_name='documents'
    )
    document_type = models.CharField(
        max_length=20, 
        choices=DOCUMENT_TYPE_CHOICES
    )
    title = models.CharField(
        max_length=200
    )
    file = models.FileField(
        upload_to='staff/documents/'
    )
    uploaded_at = models.DateTimeField(
        auto_now_add=True
    )
    notes = models.TextField(
        blank=True
    )
    
    class Meta:
        ordering = ['-uploaded_at']
        verbose_name = "Staff Document"
        verbose_name_plural = "Staff Documents"
    
    def __str__(self):
        """Return string representation of the document."""
        return f"{self.staff} - {self.title}"

======================================================================
FILE: staff/signals.py
======================================================================
# staff/signals.py
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
from .models import Staff

User = get_user_model()

@receiver(post_save, sender=User)
def create_staff_profile(sender, instance, created, **kwargs):
    """Create a staff profile when a user is created with staff status"""
    if created and (instance.is_staff or instance.is_superuser):
        Staff.objects.get_or_create(
            user=instance,
            defaults={
                'employee_id': f"STF{instance.id:04d}",
                'school_id': 1,
            }
        )

@receiver(post_save, sender=Staff)
def sync_user_status(sender, instance, **kwargs):
    """Sync staff active status with user account"""
    if instance.user.is_active != instance.is_active:
        instance.user.is_active = instance.is_active
        instance.user.save()

@receiver(pre_save, sender=Staff)
def set_default_employee_id(sender, instance, **kwargs):
    """Set default employee ID if not provided"""
    if not instance.employee_id:
        prefix = {
            'proprietor': 'PR',
            'head_master': 'HM',
            'head_mistress': 'HM',
            'bursar': 'BR',
            'teacher': 'TCH',
        }.get(instance.role, 'STF')
        
        last_staff = Staff.objects.filter(employee_id__startswith=prefix).order_by('-id').first()
        if last_staff:
            last_num = int(last_staff.employee_id.split('-')[-1]) if '-' in last_staff.employee_id else 1
            instance.employee_id = f"{prefix}-{last_num + 1:04d}"
        else:
            instance.employee_id = f"{prefix}-0001"

======================================================================
FILE: staff/tests.py
======================================================================
# staff/tests.py
from django.test import TestCase
from django.contrib.auth import get_user_model
from .models import Staff, StaffLeave

User = get_user_model()

class StaffModelTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username='teststaff',
            password='testpass123',
            first_name='Test',
            last_name='Staff'
        )
        self.staff = Staff.objects.create(
            user=self.user,
            employee_id='STF-0001',
            role='teacher',
            department='english'
        )
    
    def test_staff_creation(self):
        self.assertEqual(self.staff.employee_id, 'STF-0001')
        self.assertEqual(self.staff.get_full_name(), 'Test Staff')
        self.assertTrue(self.staff.is_teacher)
        self.assertFalse(self.staff.is_admin)
    
    def test_staff_str_method(self):
        self.assertEqual(str(self.staff), 'Test Staff - Teacher (STF-0001)')
    
    def test_auto_employee_id(self):
        new_user = User.objects.create_user(username='newstaff', password='pass')
        new_staff = Staff.objects.create(
            user=new_user,
            role='driver'
        )
        self.assertIsNotNone(new_staff.employee_id)
        self.assertTrue(new_staff.employee_id.startswith('DR-'))

======================================================================
FILE: staff/urls-1.py
======================================================================
# staff/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views  # ADD THIS IMPORT
from . import views
app_name = 'staff'
urlpatterns = [
    path('login/', views.CustomStaffLoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    # Main views
    path('', views.StaffListView.as_view(), name='staff_list'),
    path('dashboard/', views.StaffDashboardView.as_view(), name='staff_dashboard'),
    path('teacher-dashboard/', views.TeacherDashboardView.as_view(), name='teacher_dashboard'),
    # CRUD operations
    path('add/', views.StaffCreateView.as_view(), name='staff_add'),
    path('<int:pk>/', views.StaffDetailView.as_view(), name='staff_detail'),
    path('<int:pk>/edit/', views.StaffUpdateView.as_view(), name='staff_edit'),
    path('<int:pk>/delete/', views.StaffDeleteView.as_view(), name='staff_delete'),
    # Import/Export
    path('export/', views.export_staff_csv, name='staff_export'),
    path('import/', views.staff_import, name='staff_import'),
    path('import/sample/', views.download_sample_csv, name='download_sample_csv'),
    # API endpoints
    path('api/stats/', views.get_staff_stats, name='staff_stats'),    
    # Leave management
    path('leave/', views.StaffLeaveListView.as_view(), name='leave_list'),
    path('leave/add/', views.StaffLeaveCreateView.as_view(), name='leave_add'),
    path('leave/<int:pk>/', views.StaffLeaveDetailView.as_view(), name='leave_detail'),    
    # Staff Attendance
    path('attendance/', views.StaffAttendanceListView.as_view(), name='attendance_list'),
    path('attendance/mark/', views.mark_staff_attendance, name='mark_attendance'),
    path('attendance/<int:pk>/', views.StaffAttendanceDetailView.as_view(), name='attendance_detail'),
]

======================================================================
FILE: staff/urls.py
======================================================================
# staff/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views  # ADD THIS IMPORT
from . import views
app_name = 'staff'
urlpatterns = [
    path('login/', views.CustomStaffLoginView.as_view(), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    # Main views
    path('', views.StaffListView.as_view(), name='staff_list'),
    path('dashboard/', views.StaffDashboardView.as_view(), name='staff_dashboard'),
    path('teacher-dashboard/', views.TeacherDashboardView.as_view(), name='teacher_dashboard'),
    # CRUD operations
    path('add/', views.StaffCreateView.as_view(), name='staff_add'),
    path('<int:pk>/', views.StaffDetailView.as_view(), name='staff_detail'),
    path('<int:pk>/edit/', views.StaffUpdateView.as_view(), name='staff_edit'),
    path('<int:pk>/delete/', views.StaffDeleteView.as_view(), name='staff_delete'),
    # Import/Export
    path('export/', views.export_staff_csv, name='staff_export'),
    path('import/', views.staff_import, name='staff_import'),
    path('import/sample/', views.download_sample_csv, name='download_sample_csv'),
    # API endpoints
    path('api/stats/', views.get_staff_stats, name='staff_stats'),    
    # Leave management
    path('leave/', views.StaffLeaveListView.as_view(), name='leave_list'),
    path('leave/add/', views.StaffLeaveCreateView.as_view(), name='leave_add'),
    path('leave/<int:pk>/', views.StaffLeaveDetailView.as_view(), name='leave_detail'),
    path('leave/<int:pk>/edit/', views.StaffLeaveUpdateView.as_view(), name='leave_edit'),    
    # Staff Attendance
    path('attendance/', views.StaffAttendanceListView.as_view(), name='attendance_list'),
    path('attendance/mark/', views.mark_staff_attendance, name='mark_attendance'),
    path('attendance/<int:pk>/', views.StaffAttendanceDetailView.as_view(), name='attendance_detail'),
]

======================================================================
FILE: staff/views-1.py
======================================================================
# staff/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q, Count
from django.http import JsonResponse, HttpResponse
from django.contrib.auth import get_user_model
from datetime import datetime
from datetime import date 
import csv
import io

from .models import Staff, StaffLeave, StaffAttendance, StaffDocument
from core.models import School

User = get_user_model()

# ========== MAIN STAFF VIEWS ==========

class StaffListView(LoginRequiredMixin, ListView):
    """List all staff members"""
    model = Staff
    template_name = 'staff/staff_list.html'
    context_object_name = 'staff_members'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = super().get_queryset().select_related('user', 'school')
        
        # Search
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(user__first_name__icontains=search_query) |
                Q(user__last_name__icontains=search_query) |
                Q(employee_id__icontains=search_query) |
                Q(phone_number__icontains=search_query) |
                Q(user__email__icontains=search_query)
            )
        
        # Filter by role
        role = self.request.GET.get('role')
        if role:
            queryset = queryset.filter(role=role)
        
        # Filter by department
        department = self.request.GET.get('department')
        if department:
            queryset = queryset.filter(department=department)
        
        # Filter by status
        status = self.request.GET.get('status')
        if status == 'active':
            queryset = queryset.filter(is_active=True)
        elif status == 'inactive':
            queryset = queryset.filter(is_active=False)
        
        return queryset.order_by('role', 'user__first_name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_staff'] = Staff.objects.count()
        context['active_staff'] = Staff.objects.filter(is_active=True).count()
        context['role_choices'] = Staff.ROLE_CHOICES
        context['department_choices'] = Staff.DEPARTMENT_CHOICES
        return context

class StaffDetailView(LoginRequiredMixin, DetailView):
    """View staff member details"""
    model = Staff
    template_name = 'staff/staff_detail.html'
    context_object_name = 'staff'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get leave requests
        context['leave_requests'] = StaffLeave.objects.filter(staff=self.object).order_by('-created_at')[:5]
        
        # Get attendance records
        context['attendance'] = StaffAttendance.objects.filter(staff=self.object).order_by('-date')[:30]
        
        # Get documents
        context['documents'] = StaffDocument.objects.filter(staff=self.object)
        
        return context

class StaffCreateView(LoginRequiredMixin, CreateView):
    """Create a new staff member"""
    model = Staff
    fields = [
        'user', 'employee_id', 'role', 'department', 'phone_number', 
        'email', 'address', 'hire_date', 'employment_status', 'is_active'
    ]
    template_name = 'staff/staff_form.html'
    success_url = reverse_lazy('staff:staff_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Add New Staff Member'
        return context
    
    def form_valid(self, form):
        # Set default school
        if not form.instance.school_id:
            school = School.objects.first()
            if school:
                form.instance.school = school
        
        messages.success(self.request, 'Staff member added successfully!')
        return super().form_valid(form)

class StaffUpdateView(LoginRequiredMixin, UpdateView):
    """Update staff member information"""
    model = Staff
    fields = [
        'role', 'department', 'phone_number', 'email', 'address',
        'hire_date', 'employment_status', 'is_active', 'photo'
    ]
    template_name = 'staff/staff_form.html'
    success_url = reverse_lazy('staff:staff_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.user.get_full_name()}'
        return context
    
    def form_valid(self, form):
        messages.success(self.request, 'Staff member updated successfully!')
        return super().form_valid(form)

class StaffDeleteView(LoginRequiredMixin, DeleteView):
    """Deactivate staff member"""
    model = Staff
    success_url = reverse_lazy('staff:staff_list')
    template_name = 'staff/staff_confirm_delete.html'
    
    def delete(self, request, *args, **kwargs):
        staff = self.get_object()
        staff.is_active = False
        staff.user.is_active = False
        staff.user.save()
        staff.save()
        messages.success(request, f'{staff.user.get_full_name()} has been deactivated.')
        return redirect(self.success_url)

class StaffDashboardView(LoginRequiredMixin, TemplateView):
    """Staff dashboard based on role"""
    template_name = 'staff/dashboard.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get current staff profile
        if hasattr(self.request.user, 'staff_profile'):
            staff = self.request.user.staff_profile
            
            # Basic stats
            context['total_staff'] = Staff.objects.count()
            context['active_staff'] = Staff.objects.filter(is_active=True).count()
            context['teachers_count'] = Staff.objects.filter(role__in=['teacher', 'class_teacher', 'subject_teacher']).count()
            context['class_teachers'] = Staff.objects.filter(role='class_teacher').count()
            
            # Leave stats
            context['pending_leaves'] = StaffLeave.objects.filter(status='pending').count()
            context['approved_leaves'] = StaffLeave.objects.filter(status='approved').count()
            
            # Today's attendance
            today = date.today()
            context['today_attendance'] = StaffAttendance.objects.filter(date=today).count()
            
            total_staff_active = Staff.objects.filter(is_active=True).count()
            if total_staff_active > 0:
                present_today = StaffAttendance.objects.filter(date=today, status='present').count()
                context['present_percent'] = round((present_today / total_staff_active) * 100, 1)
            else:
                context['present_percent'] = 0
            
            # Dashboard type based on role
            if staff.role == 'proprietor':
                context['dashboard_type'] = 'proprietor'
                from students.models import Student
                from academics.models import SchoolClass
                from finance.models import Invoice, Payment
                
                context['total_students'] = Student.objects.count()
                context['total_classes'] = SchoolClass.objects.count()
                context['total_parents'] = ParentGuardian.objects.count()
                
                # Monthly revenue
                from datetime import datetime, timedelta
                first_day = today.replace(day=1)
                payments = Payment.objects.filter(
                    payment_date__gte=first_day,
                    status='completed'
                )
                context['monthly_revenue'] = payments.aggregate(Sum('amount'))['amount__sum'] or 0
                context['pending_invoices'] = Invoice.objects.filter(status='pending').count()
                
            elif staff.role in ['head_master', 'head_mistress']:
                context['dashboard_type'] = 'head'
                context['department_name'] = staff.get_department_display()
                
                # Recent activities (you'd need to implement this)
                context['recent_activities'] = []
                
            elif staff.role == 'teacher' or staff.role == 'class_teacher':
                context['dashboard_type'] = 'teacher'
                from academics.models import ClassSubject
                assigned_classes = ClassSubject.objects.filter(teacher=staff).values_list('school_class', flat=True).distinct()
                context['my_classes'] = SchoolClass.objects.filter(id__in=assigned_classes)
                
            else:
                context['dashboard_type'] = 'staff'
            
            # Recent activities (example - you'd need to create an ActivityLog model)
            context['recent_activities'] = []
        
        # Current date and time
        from datetime import datetime
        context['current_date'] = datetime.now()
        context['current_time'] = datetime.now()
        
        return context
    
    # def get_context_data(self, **kwargs):
    #     context = super().get_context_data(**kwargs)
    #     staff = self.request.user.staff_profile
        
    #     context['staff'] = staff
    #     context['total_staff'] = Staff.objects.count()
    #     context['active_staff'] = Staff.objects.filter(is_active=True).count()
        
    #     if staff.role == 'proprietor':
    #         context['dashboard_type'] = 'proprietor'
    #         from students.models import Student
    #         context['total_students'] = Student.objects.count()
    #     elif staff.role in ['head_master', 'head_mistress']:
    #         context['dashboard_type'] = 'head'
    #         context['department_staff'] = Staff.objects.filter(department=staff.department)
    #     elif staff.role == 'bursar':
    #         context['dashboard_type'] = 'bursar'
    #         from finance.models import Invoice
    #         context['pending_invoices'] = Invoice.objects.filter(status='pending').count()
    #     else:
    #         context['dashboard_type'] = 'staff'
        
    #     return context

class TeacherDashboardView(LoginRequiredMixin, TemplateView):
    """Teacher dashboard showing classes and attendance"""
    template_name = 'staff/teacher_dashboard.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        if not hasattr(self.request.user, 'staff_profile'):
            return context
        
        teacher = self.request.user.staff_profile
        
        # Get classes this teacher teaches
        from academics.models import ClassSubject, Attendance
        teacher_assignments = ClassSubject.objects.filter(
            teacher=teacher
        ).select_related('school_class', 'subject')
        
        # Group by class
        classes_dict = {}
        for assignment in teacher_assignments:
            class_id = assignment.school_class.id
            if class_id not in classes_dict:
                classes_dict[class_id] = {
                    'class': assignment.school_class,
                    'subjects': [],
                    'student_count': assignment.school_class.students.count(),
                    'today_attendance_taken': Attendance.objects.filter(
                        school_class=assignment.school_class,
                        date=date.today()
                    ).exists()
                }
            classes_dict[class_id]['subjects'].append(assignment.subject)
        
        context['my_classes'] = list(classes_dict.values())
        context['today'] = date.today()
        
        # Recent attendance by this teacher
        context['recent_attendance'] = Attendance.objects.filter(
            marked_by=teacher
        ).select_related('student').order_by('-date')[:10]
        
        return context
# ========== LEAVE MANAGEMENT ==========

class StaffLeaveListView(LoginRequiredMixin, ListView):
    """List all leave requests"""
    model = StaffLeave
    template_name = 'staff/leave_list.html'
    context_object_name = 'leaves'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = StaffLeave.objects.all().select_related('staff', 'approved_by')
        
        # Filter by status
        status = self.request.GET.get('status')
        if status:
            queryset = queryset.filter(status=status)
        
        # Filter by staff
        staff_id = self.request.GET.get('staff')
        if staff_id:
            queryset = queryset.filter(staff_id=staff_id)
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['pending_count'] = StaffLeave.objects.filter(status='pending').count()
        context['approved_count'] = StaffLeave.objects.filter(status='approved').count()
        return context

class StaffLeaveCreateView(LoginRequiredMixin, CreateView):
    """Create a leave request"""
    model = StaffLeave
    fields = ['leave_type', 'start_date', 'end_date', 'reason']
    template_name = 'staff/leave_form.html'
    success_url = reverse_lazy('staff:leave_list')
    
    def form_valid(self, form):
        form.instance.staff = self.request.user.staff_profile
        form.instance.status = 'pending'
        messages.success(self.request, 'Leave request submitted successfully!')
        return super().form_valid(form)

class StaffLeaveDetailView(LoginRequiredMixin, DetailView):
    """View leave request details"""
    model = StaffLeave
    template_name = 'staff/leave_detail.html'
    context_object_name = 'leave'

def approve_leave(request, pk):
    """Approve a leave request"""
    leave = get_object_or_404(StaffLeave, pk=pk)
    
    if request.method == 'POST':
        leave.status = 'approved'
        leave.approved_by = request.user.staff_profile
        leave.approved_date = datetime.now().date()
        leave.save()
        messages.success(request, 'Leave request approved.')
    
    return redirect('staff:leave_detail', pk=pk)

def reject_leave(request, pk):
    """Reject a leave request"""
    leave = get_object_or_404(StaffLeave, pk=pk)
    
    if request.method == 'POST':
        leave.status = 'rejected'
        leave.save()
        messages.success(request, 'Leave request rejected.')
    
    return redirect('staff:leave_list')

# ========== STAFF ATTENDANCE ==========

# class StaffAttendanceListView(LoginRequiredMixin, ListView):
#     """List staff attendance records"""
#     model = StaffAttendance
#     template_name = 'staff/attendance_list.html'
#     context_object_name = 'attendances'
#     paginate_by = 50
    
#     def get_queryset(self):
#         queryset = StaffAttendance.objects.all().select_related('staff')
        
#         date = self.request.GET.get('date')
#         if date:
#             queryset = queryset.filter(date=date)
        
#         return queryset.order_by('-date')

# def mark_staff_attendance(request):
#     """Mark staff attendance"""
#     if request.method == 'POST':
#         staff_id = request.POST.get('staff_id')
#         status = request.POST.get('status')
#         date = request.POST.get('date')
        
#         if staff_id and status and date:
#             staff = get_object_or_404(Staff, id=staff_id)
#             attendance, created = StaffAttendance.objects.get_or_create(
#                 staff=staff,
#                 date=date,
#                 defaults={'status': status}
#             )
            
#             if not created:
#                 attendance.status = status
#                 attendance.save()
            
#             messages.success(request, f'Attendance marked for {staff.user.get_full_name()}')
        
#         return redirect('staff:attendance_list')
    
#     staff_members = Staff.objects.filter(is_active=True)
#     return render(request, 'staff/mark_attendance.html', {
#         'staff_members': staff_members,
#         'today': datetime.now().date()
#     })

class StaffAttendanceListView(LoginRequiredMixin, ListView):
    """List staff attendance records"""
    model = StaffAttendance
    template_name = 'staff/attendance_list.html'
    context_object_name = 'attendances'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = StaffAttendance.objects.all().select_related('staff__user')
        
        # Filter by date
        date = self.request.GET.get('date')
        if date:
            queryset = queryset.filter(date=date)
        
        # Filter by staff
        staff_id = self.request.GET.get('staff')
        if staff_id:
            queryset = queryset.filter(staff_id=staff_id)
        
        return queryset.order_by('-date')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['staff_members'] = Staff.objects.filter(is_active=True)
        context['today'] = date.today()
        return context

def mark_staff_attendance(request):
    """Mark staff attendance"""
    if request.method == 'POST':
        staff_id = request.POST.get('staff_id')
        status = request.POST.get('status')
        attendance_date = request.POST.get('date', date.today())
        
        if staff_id and status:
            staff = get_object_or_404(Staff, id=staff_id)
            attendance, created = StaffAttendance.objects.update_or_create(
                staff=staff,
                date=attendance_date,
                defaults={'status': status}
            )
            messages.success(request, f'Attendance marked for {staff.user.get_full_name()}')
        
        return redirect('staff:attendance_list')
    
    staff_members = Staff.objects.filter(is_active=True)
    return render(request, 'staff/mark_attendance.html', {
        'staff_members': staff_members,
        'today': datetime.today()
    })

class StaffAttendanceDetailView(LoginRequiredMixin, DetailView):
    """View staff attendance details"""
    model = StaffAttendance
    template_name = 'staff/attendance_detail.html'
    context_object_name = 'attendance'

# ========== IMPORT/EXPORT ==========

def export_staff_csv(request):
    """Export staff to CSV"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="staff_export.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Employee ID', 'Full Name', 'Role', 'Department', 'Phone', 'Email', 'Status', 'Hire Date'])
    
    for staff in Staff.objects.select_related('user').all():
        writer.writerow([
            staff.employee_id,
            staff.user.get_full_name(),
            staff.get_role_display(),
            staff.get_department_display(),
            staff.phone_number,
            staff.user.email,
            'Active' if staff.is_active else 'Inactive',
            staff.hire_date
        ])
    
    return response

def staff_import(request):
    """Import staff from CSV"""
    if request.method == 'POST' and request.FILES.get('file'):
        csv_file = request.FILES['file']
        
        if not csv_file.name.endswith('.csv'):
            messages.error(request, 'Please upload a CSV file')
            return redirect('staff:staff_import')
        
        try:
            decoded_file = csv_file.read().decode('utf-8-sig')
            io_string = io.StringIO(decoded_file)
            reader = csv.DictReader(io_string)
            
            imported = 0
            errors = []
            school = School.objects.first()
            
            if not school:
                messages.error(request, 'No school found. Please create a school first.')
                return redirect('staff:staff_list')
            
            for row_num, row in enumerate(reader, start=2):
                try:
                    first_name = row.get('First Name', '').strip()
                    last_name = row.get('Last Name', '').strip()
                    
                    if not first_name or not last_name:
                        errors.append(f"Row {row_num}: Missing first or last name")
                        continue
                    
                    # Create username
                    username = f"{first_name.lower()}.{last_name.lower()}".replace(' ', '')
                    
                    # Create user
                    user, user_created = User.objects.get_or_create(
                        username=username,
                        defaults={
                            'first_name': first_name,
                            'last_name': last_name,
                            'email': row.get('Email', f"{username}@raphabethel.org"),
                            'is_staff': True,
                        }
                    )
                    
                    # Create staff profile
                    staff, staff_created = Staff.objects.get_or_create(
                        user=user,
                        defaults={
                            'employee_id': f"STF{user.id:04d}",
                            'role': row.get('Role', 'teacher').lower(),
                            'department': row.get('Department', 'english').lower(),
                            'phone_number': row.get('Phone', '').strip(),
                            'school': school,
                            'hire_date': row.get('Hire Date', None),
                            'is_active': True,
                        }
                    )
                    
                    if staff_created:
                        imported += 1
                    
                except Exception as e:
                    errors.append(f"Row {row_num}: {str(e)}")
            
            if errors:
                messages.warning(request, f"Imported {imported} staff with {len(errors)} errors")
            else:
                messages.success(request, f"Successfully imported {imported} staff members!")
            
        except Exception as e:
            messages.error(request, f"Error processing file: {str(e)}")
        
        return redirect('staff:staff_list')
    
    return render(request, 'staff/import.html')

def download_sample_csv(request):
    """Download sample CSV template"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="staff_sample.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['First Name', 'Last Name', 'Role', 'Department', 'Phone', 'Email', 'Hire Date'])
    writer.writerow(['Mme', 'Nchotu Manka', 'proprietor', 'admin', '651437143', 'proprietor@raphabethel.org', '2025-01-01'])
    writer.writerow(['Mr.', 'Ferdinand Sunyin', 'head_master', 'english', '676662567', 'headmaster@raphabethel.org', '2025-01-01'])
    
    return response

def import_sample_data(request):
    """Import sample staff data"""
    school = School.objects.first()
    if not school:
        messages.error(request, 'Please create a school first')
        return redirect('staff:staff_list')
    
    sample_data = [
        {'first': 'Mme', 'last': 'Nchotu Manka', 'role': 'proprietor', 'dept': 'admin', 'phone': '651437143'},
        {'first': 'Mr.', 'last': 'Ferdinand Sunyin', 'role': 'head_master', 'dept': 'english', 'phone': '676662567'},
        {'first': 'Mme', 'last': 'Chesi Landry', 'role': 'bursar', 'dept': 'finance', 'phone': '651620915'},
    ]
    
    imported = 0
    for data in sample_data:
        username = f"{data['first'].lower()}.{data['last'].lower()}".replace(' ', '')
        
        user, _ = User.objects.get_or_create(
            username=username,
            defaults={
                'first_name': data['first'],
                'last_name': data['last'],
                'email': f"{username}@raphabethel.org",
                'is_staff': True,
            }
        )
        
        staff, created = Staff.objects.get_or_create(
            user=user,
            defaults={
                'employee_id': f"STF{user.id:04d}",
                'role': data['role'],
                'department': data['dept'],
                'phone_number': data['phone'],
                'school': school,
                'is_active': True,
            }
        )
        
        if created:
            imported += 1
    
    messages.success(request, f"Imported {imported} sample staff members")
    return redirect('staff:staff_list')

def import_staff_excel(request):
    """Redirect to Excel import"""
    messages.info(request, 'Excel import feature coming soon. Please use CSV for now.')
    return redirect('staff:staff_import')

# Add this custom login view at the top of your file
class CustomStaffLoginView(LoginView):
    """Custom login view that redirects based on user role"""
    template_name = 'staff/login.html'  # You'll need to create this
    
    def get_success_url(self):
        user = self.request.user
        
        # Superusers go to admin
        if user.is_superuser:
            return reverse_lazy('admin:index')
        
        # Check if user has staff profile
        if hasattr(user, 'staff_profile'):
            role = user.staff_profile.role
            
            # Redirect based on role
            if role == 'teacher':
                return reverse_lazy('staff:teacher_dashboard')
            elif role == 'head_master' or role == 'head_mistress':
                return reverse_lazy('staff:staff_dashboard')
            elif role == 'bursar':
                return reverse_lazy('finance:bursar_dashboard')
            elif role == 'proprietor':
                return reverse_lazy('staff:staff_dashboard')
            else:
                return reverse_lazy('staff:staff_list')
        
        # Default fallback
        return reverse_lazy('dashboard')


# ========== API ENDPOINTS ==========

def get_staff_stats(request):
    """API endpoint for staff statistics"""
    stats = {
        'total': Staff.objects.count(),
        'active': Staff.objects.filter(is_active=True).count(),
        'by_role': list(Staff.objects.values('role').annotate(count=Count('id'))),
        'by_department': list(Staff.objects.values('department').annotate(count=Count('id'))),
    }
    return JsonResponse(stats)

======================================================================
FILE: staff/views.py
======================================================================
# staff/views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from core.permissions import ManagementRequiredMixin, BursarRequiredMixin, HeadRequiredMixin, can, is_support_only
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q, Count
from django.http import JsonResponse, HttpResponse
from django.contrib.auth import get_user_model
from datetime import datetime
from datetime import date 
import csv
import io

from .models import Staff, StaffLeave, StaffAttendance, StaffDocument
from .forms import StaffForm, StaffUserForm, StaffLeaveForm, StaffAttendanceForm
from core.models import School

User = get_user_model()

# ========== MAIN STAFF VIEWS ==========

class StaffListView(LoginRequiredMixin, ListView):
    """List all staff members"""
    model = Staff
    template_name = 'staff/staff_list.html'
    context_object_name = 'staff_members'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = super().get_queryset().select_related('user', 'school')
        
        # Search
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(user__first_name__icontains=search_query) |
                Q(user__last_name__icontains=search_query) |
                Q(employee_id__icontains=search_query) |
                Q(phone_number__icontains=search_query) |
                Q(user__email__icontains=search_query)
            )
        
        # Filter by role
        role = self.request.GET.get('role')
        if role:
            queryset = queryset.filter(role=role)
        
        # Filter by department
        department = self.request.GET.get('department')
        if department:
            queryset = queryset.filter(department=department)
        
        # Filter by status
        status = self.request.GET.get('status')
        if status == 'active':
            queryset = queryset.filter(is_active=True)
        elif status == 'inactive':
            queryset = queryset.filter(is_active=False)
        
        return queryset.order_by('role', 'user__first_name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_staff'] = Staff.objects.count()
        context['active_staff'] = Staff.objects.filter(is_active=True).count()
        context['role_choices'] = Staff.ROLE_CHOICES
        context['department_choices'] = Staff.DEPARTMENT_CHOICES
        return context

class StaffDetailView(LoginRequiredMixin, DetailView):
    """View staff member details"""
    model = Staff
    template_name = 'staff/staff_detail.html'
    context_object_name = 'staff'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get leave requests
        context['leave_requests'] = StaffLeave.objects.filter(staff=self.object).order_by('-created_at')[:5]
        
        # Get attendance records
        context['attendance'] = StaffAttendance.objects.filter(staff=self.object).order_by('-date')[:30]
        
        # Get documents
        context['documents'] = StaffDocument.objects.filter(staff=self.object)
        
        return context

class StaffCreateView(ManagementRequiredMixin, CreateView):
    """Create a new staff member — creates User account + Staff profile together."""
    model = Staff
    form_class = StaffForm
    template_name = 'staff/staff_form.html'
    success_url = reverse_lazy('staff:staff_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Add New Staff Member'
        if self.request.POST:
            context['user_form'] = StaffUserForm(self.request.POST)
        else:
            context['user_form'] = StaffUserForm()
        return context

    def form_valid(self, form):
        user_form = StaffUserForm(self.request.POST)
        if not user_form.is_valid():
            return self.render_to_response(self.get_context_data(form=form))
        if not user_form.cleaned_data.get('password'):
            user_form.add_error('password', 'A password is required when creating a new account.')
            return self.render_to_response(self.get_context_data(form=form))
        user = user_form.save()
        form.instance.user = user
        school = School.objects.first()
        if school:
            form.instance.school = school
        messages.success(self.request, f'Staff member {user.get_full_name()} added successfully.')
        return super().form_valid(form)

class StaffUpdateView(ManagementRequiredMixin, UpdateView):
    """Update staff member information — saves both User name fields and Staff profile."""
    model = Staff
    form_class = StaffForm
    template_name = 'staff/staff_form.html'
    success_url = reverse_lazy('staff:staff_list')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.get_full_name()}'
        if self.request.POST:
            context['user_form'] = StaffUserForm(self.request.POST, instance=self.object.user)
        else:
            context['user_form'] = StaffUserForm(instance=self.object.user)
        return context

    def form_valid(self, form):
        user_form = StaffUserForm(self.request.POST, instance=self.object.user)
        if not user_form.is_valid():
            return self.render_to_response(self.get_context_data(form=form))
        user_form.save()
        messages.success(self.request, f'Staff member {self.object.get_full_name()} updated successfully.')
        return super().form_valid(form)


class StaffDeleteView(HeadRequiredMixin, DeleteView):
    """Deactivate staff member"""
    model = Staff
    success_url = reverse_lazy('staff:staff_list')
    template_name = 'staff/staff_confirm_delete.html'
    
    def delete(self, request, *args, **kwargs):
        staff = self.get_object()
        staff.is_active = False
        staff.user.is_active = False
        staff.user.save()
        staff.save()
        messages.success(request, f'{staff.user.get_full_name()} has been deactivated.')
        return redirect(self.success_url)

class StaffDashboardView(LoginRequiredMixin, TemplateView):
    """Staff dashboard based on role — support staff get a limited view"""
    template_name = 'staff/dashboard.html'

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated and hasattr(request.user, 'staff_profile'):
            from core.permissions import is_support_only
            if is_support_only(request.user):
                return self._support_dashboard(request)
        return super().dispatch(request, *args, **kwargs)

    def _support_dashboard(self, request):
        from datetime import date as _date
        from staff.models import StaffAttendance, StaffLeave
        staff = request.user.staff_profile
        today = _date.today()
        month_att = StaffAttendance.objects.filter(
            staff=staff, date__month=today.month, date__year=today.year)
        context = {
            'today': today,
            'my_leaves': StaffLeave.objects.filter(staff=staff).order_by('-start_date')[:5],
            'present_count': month_att.filter(status='present').count(),
            'absent_count':  month_att.filter(status='absent').count(),
            'late_count':    month_att.filter(status='late').count(),
        }
        from django.shortcuts import render as _render
        return _render(request, 'staff/support_dashboard.html', context)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get current staff profile
        if hasattr(self.request.user, 'staff_profile'):
            staff = self.request.user.staff_profile
            
            # Basic stats
            context['total_staff'] = Staff.objects.count()
            context['active_staff'] = Staff.objects.filter(is_active=True).count()
            context['teachers_count'] = Staff.objects.filter(role__in=['teacher', 'class_teacher', 'subject_teacher']).count()
            context['class_teachers'] = Staff.objects.filter(role='class_teacher').count()
            
            # Leave stats
            context['pending_leaves'] = StaffLeave.objects.filter(status='pending').count()
            context['approved_leaves'] = StaffLeave.objects.filter(status='approved').count()
            
            # Today's attendance
            today = date.today()
            context['today_attendance'] = StaffAttendance.objects.filter(date=today).count()
            
            total_staff_active = Staff.objects.filter(is_active=True).count()
            if total_staff_active > 0:
                present_today = StaffAttendance.objects.filter(date=today, status='present').count()
                context['present_percent'] = round((present_today / total_staff_active) * 100, 1)
            else:
                context['present_percent'] = 0
            
            # Dashboard type based on role
            if staff.role == 'proprietor':
                context['dashboard_type'] = 'proprietor'
                from students.models import Student
                from academics.models import SchoolClass
                from finance.models import Invoice, Payment
                
                context['total_students'] = Student.objects.count()
                context['total_classes'] = SchoolClass.objects.count()
                context['total_parents'] = ParentGuardian.objects.count()
                
                # Monthly revenue
                from datetime import datetime, timedelta
                first_day = today.replace(day=1)
                payments = Payment.objects.filter(
                    payment_date__gte=first_day,
                    status='completed'
                )
                context['monthly_revenue'] = payments.aggregate(Sum('amount'))['amount__sum'] or 0
                context['pending_invoices'] = Invoice.objects.filter(status='pending').count()
                
            elif staff.role in ['head_master', 'head_mistress']:
                context['dashboard_type'] = 'head'
                context['department_name'] = staff.get_department_display()
                
                # Recent activities (you'd need to implement this)
                context['recent_activities'] = []
                
            elif staff.role == 'teacher' or staff.role == 'class_teacher':
                context['dashboard_type'] = 'teacher'
                from academics.models import ClassSubject
                assigned_classes = ClassSubject.objects.filter(teacher=staff).values_list('school_class', flat=True).distinct()
                context['my_classes'] = SchoolClass.objects.filter(id__in=assigned_classes)
                
            else:
                context['dashboard_type'] = 'staff'
            
            # Recent activities (example - you'd need to create an ActivityLog model)
            context['recent_activities'] = []
        
        # Current date and time
        from datetime import datetime
        context['current_date'] = datetime.now()
        context['current_time'] = datetime.now()
        
        return context
    
    # def get_context_data(self, **kwargs):
    #     context = super().get_context_data(**kwargs)
    #     staff = self.request.user.staff_profile
        
    #     context['staff'] = staff
    #     context['total_staff'] = Staff.objects.count()
    #     context['active_staff'] = Staff.objects.filter(is_active=True).count()
        
    #     if staff.role == 'proprietor':
    #         context['dashboard_type'] = 'proprietor'
    #         from students.models import Student
    #         context['total_students'] = Student.objects.count()
    #     elif staff.role in ['head_master', 'head_mistress']:
    #         context['dashboard_type'] = 'head'
    #         context['department_staff'] = Staff.objects.filter(department=staff.department)
    #     elif staff.role == 'bursar':
    #         context['dashboard_type'] = 'bursar'
    #         from finance.models import Invoice
    #         context['pending_invoices'] = Invoice.objects.filter(status='pending').count()
    #     else:
    #         context['dashboard_type'] = 'staff'
        
    #     return context

class TeacherDashboardView(LoginRequiredMixin, TemplateView):
    """Teacher dashboard showing classes and attendance"""
    template_name = 'staff/teacher_dashboard.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        if not hasattr(self.request.user, 'staff_profile'):
            return context
        
        teacher = self.request.user.staff_profile
        
        # Get classes this teacher teaches
        from academics.models import ClassSubject, Attendance
        teacher_assignments = ClassSubject.objects.filter(
            teacher=teacher
        ).select_related('school_class', 'subject')
        
        # Group by class
        classes_dict = {}
        for assignment in teacher_assignments:
            class_id = assignment.school_class.id
            if class_id not in classes_dict:
                classes_dict[class_id] = {
                    'class': assignment.school_class,
                    'subjects': [],
                    'student_count': assignment.school_class.students.count(),
                    'today_attendance_taken': Attendance.objects.filter(
                        school_class=assignment.school_class,
                        date=date.today()
                    ).exists()
                }
            classes_dict[class_id]['subjects'].append(assignment.subject)
        
        context['my_classes'] = list(classes_dict.values())
        context['today'] = date.today()
        
        # Recent attendance by this teacher
        context['recent_attendance'] = Attendance.objects.filter(
            marked_by=teacher
        ).select_related('student').order_by('-date')[:10]
        
        return context
# ========== LEAVE MANAGEMENT ==========

class StaffLeaveListView(LoginRequiredMixin, ListView):
    """List all leave requests"""
    model = StaffLeave
    template_name = 'staff/leave_list.html'
    context_object_name = 'leaves'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = StaffLeave.objects.all().select_related('staff', 'approved_by')
        
        # Filter by status
        status = self.request.GET.get('status')
        if status:
            queryset = queryset.filter(status=status)
        
        # Filter by staff
        staff_id = self.request.GET.get('staff')
        if staff_id:
            queryset = queryset.filter(staff_id=staff_id)
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['pending_count'] = StaffLeave.objects.filter(status='pending').count()
        context['approved_count'] = StaffLeave.objects.filter(status='approved').count()
        return context

class StaffLeaveCreateView(LoginRequiredMixin, CreateView):
    """Create a leave request"""
    model = StaffLeave
    fields = ['leave_type', 'start_date', 'end_date', 'reason']
    template_name = 'staff/leave_form.html'
    success_url = reverse_lazy('staff:leave_list')
    
    def form_valid(self, form):
        form.instance.staff = self.request.user.staff_profile
        form.instance.status = 'pending'
        messages.success(self.request, 'Leave request submitted successfully!')
        return super().form_valid(form)

class StaffLeaveUpdateView(LoginRequiredMixin, UpdateView):
    """Edit a pending leave request"""
    model = StaffLeave
    fields = ['leave_type', 'start_date', 'end_date', 'reason']
    template_name = 'staff/leave_form.html'
    success_url = reverse_lazy('staff:leave_list')

    def get_queryset(self):
        # Staff can only edit their own pending requests; admins can edit any
        qs = StaffLeave.objects.filter(status='pending')
        if not self.request.user.is_staff:
            qs = qs.filter(staff=self.request.user.staff_profile)
        return qs

    def form_valid(self, form):
        messages.success(self.request, 'Leave request updated successfully!')
        return super().form_valid(form)


class StaffLeaveDetailView(LoginRequiredMixin, DetailView):
    """View leave request details"""
    model = StaffLeave
    template_name = 'staff/leave_detail.html'
    context_object_name = 'leave'

def approve_leave(request, pk):
    """Approve a leave request"""
    leave = get_object_or_404(StaffLeave, pk=pk)
    
    if request.method == 'POST':
        leave.status = 'approved'
        leave.approved_by = request.user.staff_profile
        leave.approved_date = datetime.now().date()
        leave.save()
        messages.success(request, 'Leave request approved.')
    
    return redirect('staff:leave_detail', pk=pk)

def reject_leave(request, pk):
    """Reject a leave request"""
    leave = get_object_or_404(StaffLeave, pk=pk)
    
    if request.method == 'POST':
        leave.status = 'rejected'
        leave.save()
        messages.success(request, 'Leave request rejected.')
    
    return redirect('staff:leave_list')

# ========== STAFF ATTENDANCE ==========

# class StaffAttendanceListView(LoginRequiredMixin, ListView):
#     """List staff attendance records"""
#     model = StaffAttendance
#     template_name = 'staff/attendance_list.html'
#     context_object_name = 'attendances'
#     paginate_by = 50
    
#     def get_queryset(self):
#         queryset = StaffAttendance.objects.all().select_related('staff')
        
#         date = self.request.GET.get('date')
#         if date:
#             queryset = queryset.filter(date=date)
        
#         return queryset.order_by('-date')

# def mark_staff_attendance(request):
#     """Mark staff attendance"""
#     if request.method == 'POST':
#         staff_id = request.POST.get('staff_id')
#         status = request.POST.get('status')
#         date = request.POST.get('date')
        
#         if staff_id and status and date:
#             staff = get_object_or_404(Staff, id=staff_id)
#             attendance, created = StaffAttendance.objects.get_or_create(
#                 staff=staff,
#                 date=date,
#                 defaults={'status': status}
#             )
            
#             if not created:
#                 attendance.status = status
#                 attendance.save()
            
#             messages.success(request, f'Attendance marked for {staff.user.get_full_name()}')
        
#         return redirect('staff:attendance_list')
    
#     staff_members = Staff.objects.filter(is_active=True)
#     return render(request, 'staff/mark_attendance.html', {
#         'staff_members': staff_members,
#         'today': datetime.now().date()
#     })

class StaffAttendanceListView(LoginRequiredMixin, ListView):
    """List staff attendance records"""
    model = StaffAttendance
    template_name = 'staff/attendance_list.html'
    context_object_name = 'attendances'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = StaffAttendance.objects.all().select_related('staff__user')
        
        # Filter by date
        date = self.request.GET.get('date')
        if date:
            queryset = queryset.filter(date=date)
        
        # Filter by staff
        staff_id = self.request.GET.get('staff')
        if staff_id:
            queryset = queryset.filter(staff_id=staff_id)
        
        return queryset.order_by('-date')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['staff_members'] = Staff.objects.filter(is_active=True)
        context['today'] = date.today()
        return context

def mark_staff_attendance(request):
    """Mark staff attendance"""
    if request.method == 'POST':
        staff_id = request.POST.get('staff_id')
        status = request.POST.get('status')
        attendance_date = request.POST.get('date', date.today())
        
        if staff_id and status:
            staff = get_object_or_404(Staff, id=staff_id)
            attendance, created = StaffAttendance.objects.update_or_create(
                staff=staff,
                date=attendance_date,
                defaults={'status': status}
            )
            messages.success(request, f'Attendance marked for {staff.user.get_full_name()}')
        
        return redirect('staff:attendance_list')
    
    staff_members = Staff.objects.filter(is_active=True)
    return render(request, 'staff/mark_attendance.html', {
        'staff_members': staff_members,
        'today': datetime.today()
    })

class StaffAttendanceDetailView(LoginRequiredMixin, DetailView):
    """View staff attendance details"""
    model = StaffAttendance
    template_name = 'staff/attendance_detail.html'
    context_object_name = 'attendance'

# ========== IMPORT/EXPORT ==========

def export_staff_csv(request):
    """Export staff to CSV"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="staff_export.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Employee ID', 'Full Name', 'Role', 'Department', 'Phone', 'Email', 'Status', 'Hire Date'])
    
    for staff in Staff.objects.select_related('user').all():
        writer.writerow([
            staff.employee_id,
            staff.user.get_full_name(),
            staff.get_role_display(),
            staff.get_department_display(),
            staff.phone_number,
            staff.user.email,
            'Active' if staff.is_active else 'Inactive',
            staff.hire_date
        ])
    
    return response

def staff_import(request):
    """Import staff from CSV"""
    if request.method == 'POST' and request.FILES.get('file'):
        csv_file = request.FILES['file']

        if not csv_file.name.endswith('.csv'):
            messages.error(request, 'Please upload a CSV file')
            return redirect('staff:staff_import')

        # Known honorifics that must never end up in first_name
        HONORIFICS = {'mr', 'mr.', 'mrs', 'mrs.', 'ms', 'ms.', 'mme', 'mme.',
                      'dr', 'dr.', 'prof', 'prof.', 'rev', 'sis'}

        try:
            decoded_file = csv_file.read().decode('utf-8-sig')
            io_string = io.StringIO(decoded_file)
            reader = csv.DictReader(io_string)

            imported = 0
            errors = []
            school = School.objects.first()

            if not school:
                messages.error(request, 'No school found. Please create a school first.')
                return redirect('staff:staff_list')

            for row_num, row in enumerate(reader, start=2):
                try:
                    title      = row.get('Title', '').strip()
                    first_name = row.get('First Name', '').strip()
                    last_name  = row.get('Last Name', '').strip()

                    # Guard: if title column was left empty but someone put
                    # an honorific as the first name, detect and move it
                    if first_name.lower() in HONORIFICS and not title:
                        title = first_name
                        first_name = ''

                    if not first_name or not last_name:
                        errors.append(f"Row {row_num}: Missing first or last name")
                        continue

                    # Username: firstname.lastname (no title, no spaces)
                    username = f"{first_name.lower()}.{last_name.lower()}".replace(' ', '_')

                    # Make username unique if collision
                    base_username = username
                    counter = 1
                    while User.objects.filter(username=username).exists():
                        username = f"{base_username}{counter}"
                        counter += 1

                    user, user_created = User.objects.get_or_create(
                        username=username,
                        defaults={
                            'first_name': first_name,
                            'last_name':  last_name,
                            'email': row.get('Email', f"{username}@raphabethel.org"),
                            'is_staff': True,
                        }
                    )

                    staff, staff_created = Staff.objects.get_or_create(
                        user=user,
                        defaults={
                            'title':       title,
                            'role':        row.get('Role', 'teacher').lower(),
                            'department':  row.get('Department', 'english').lower(),
                            'phone_number': row.get('Phone', '').strip(),
                            'school':      school,
                            'hire_date':   row.get('Hire Date') or None,
                            'is_active':   True,
                        }
                    )

                    if staff_created:
                        imported += 1

                except Exception as e:
                    errors.append(f"Row {row_num}: {str(e)}")

            if errors:
                messages.warning(request, f"Imported {imported} staff with {len(errors)} errors")
            else:
                messages.success(request, f"Successfully imported {imported} staff members!")

        except Exception as e:
            messages.error(request, f"Error processing file: {str(e)}")

        return redirect('staff:staff_list')

    return render(request, 'staff/import.html')

def download_sample_csv(request):
    """Download sample CSV template — Title is a separate column"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="staff_sample.csv"'

    writer = csv.writer(response)
    # Title is now its own column — First Name must not contain the honorific
    writer.writerow(['Title', 'First Name', 'Last Name', 'Role', 'Department', 'Phone', 'Email', 'Hire Date'])
    writer.writerow(['Mme',  'Nchotu',     'Manka',     'proprietor',  'admin',   '651437143', 'proprietor@raphabethel.org',  '2025-01-01'])
    writer.writerow(['Mr',   'Ferdinand',  'Sunyin',    'head_master', 'english', '676662567', 'headmaster@raphabethel.org',  '2025-01-01'])
    writer.writerow(['Mme',  'Annie',      'Shey',      'class_teacher','english','670177979', 'annie.shey@raphabethel.org',  '2025-01-01'])
    writer.writerow(['Mr',   'Landry',     'Chesi',     'bursar',      'finance', '651620915', 'bursar@raphabethel.org',      '2025-01-01'])

    
    return response

def import_sample_data(request):
    """Import sample staff data"""
    school = School.objects.first()
    if not school:
        messages.error(request, 'Please create a school first')
        return redirect('staff:staff_list')
    
    sample_data = [
        {'title': 'Mme', 'first': 'Nchotu',    'last': 'Manka',   'role': 'proprietor',   'dept': 'admin',   'phone': '651437143'},
        {'title': 'Mr',  'first': 'Ferdinand',  'last': 'Sunyin',  'role': 'head_master',  'dept': 'english', 'phone': '676662567'},
        {'title': 'Mme', 'first': 'Landry',     'last': 'Chesi',   'role': 'bursar',       'dept': 'finance', 'phone': '651620915'},
    ]

    imported = 0
    for data in sample_data:
        username = f"{data['first'].lower()}.{data['last'].lower()}".replace(' ', '_')
        
        user, _ = User.objects.get_or_create(
            username=username,
            defaults={
                'first_name': data['first'],
                'last_name':  data['last'],
                'email': f"{username}@raphabethel.org",
                'is_staff': True,
            }
        )

        staff, created = Staff.objects.get_or_create(
            user=user,
            defaults={
                'title':       data.get('title', ''),
                'role':        data['role'],
                'department':  data['dept'],
                'phone_number': data['phone'],
                'school':      school,
                'is_active':   True,
            }
        )
        
        if created:
            imported += 1
    
    messages.success(request, f"Imported {imported} sample staff members")
    return redirect('staff:staff_list')

def import_staff_excel(request):
    """Redirect to Excel import"""
    messages.info(request, 'Excel import feature coming soon. Please use CSV for now.')
    return redirect('staff:staff_import')

# Add this custom login view at the top of your file
class CustomStaffLoginView(LoginView):
    """Custom login view that redirects based on user role"""
    template_name = 'staff/login.html'  # You'll need to create this
    
    def get_success_url(self):
        user = self.request.user
        
        # Superusers go to admin
        if user.is_superuser:
            return reverse_lazy('admin:index')
        
        # Check if user has staff profile
        if hasattr(user, 'staff_profile'):
            role = user.staff_profile.role

            TEACHER_ROLES = {'teacher', 'class_teacher', 'subject_teacher', 'assistant_teacher'}
            SUPPORT_ROLES = {'driver', 'cleaner', 'canteen', 'security', 'support', 'other'}
            MANAGEMENT_ROLES = {'proprietor', 'head_master', 'head_mistress', 'admin'}

            if role in TEACHER_ROLES:
                return reverse_lazy('staff:teacher_dashboard')
            elif role == 'bursar':
                return reverse_lazy('finance:bursar_dashboard')
            elif role in MANAGEMENT_ROLES:
                return reverse_lazy('staff:staff_dashboard')
            elif role in SUPPORT_ROLES:
                return reverse_lazy('staff:teacher_dashboard')  # support lands on teacher_dashboard too
            else:
                return reverse_lazy('staff:staff_dashboard')

        # Default fallback
        return reverse_lazy('dashboard')


# ========== API ENDPOINTS ==========

def get_staff_stats(request):
    """API endpoint for staff statistics"""
    stats = {
        'total': Staff.objects.count(),
        'active': Staff.objects.filter(is_active=True).count(),
        'by_role': list(Staff.objects.values('role').annotate(count=Count('id'))),
        'by_department': list(Staff.objects.values('department').annotate(count=Count('id'))),
    }
    return JsonResponse(stats)

======================================================================
FILE: staff/fixtures/initial_staff.json
======================================================================
[
  {
    "model": "staff.staff",
    "pk": 1,
    "fields": {
      "user": 1,
      "school": 1,
      "employee_id": "PR-0001",
      "role": "proprietor",
      "department": "admin",
      "phone_number": "+237670177979",
      "is_active": true
    }
  }
]

======================================================================
FILE: staff/management/commands/import_staff.py
======================================================================
# staff/management/commands/import_staff.py
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from staff.models import Staff
import pandas as pd
from datetime import datetime

User = get_user_model()

class Command(BaseCommand):
    help = 'Import staff from Excel file'
    
    def add_arguments(self, parser):
        parser.add_argument('excel_file', type=str, help='Path to Excel file')
        parser.add_argument('--sheet', type=str, default='Staff List', help='Sheet name to import')
        parser.add_argument('--preview', action='store_true', help='Preview only, do not import')
    
    def handle(self, *args, **options):
        excel_file = options['excel_file']
        sheet_name = options['sheet']
        preview = options['preview']
        
        try:
            df = pd.read_excel(excel_file, sheet_name=sheet_name)
        except Exception as e:
            self.stdout.write(self.style.ERROR(f'Error reading file: {e}'))
            return
        
        if preview:
            self.stdout.write(self.style.SUCCESS(f'Preview of {sheet_name}:'))
            self.stdout.write(f'Total rows: {len(df)}')
            self.stdout.write('\nFirst 5 rows:')
            self.stdout.write(df.head().to_string())
            return
        
        imported = 0
        errors = []
        
        for index, row in df.iterrows():
            try:
                # Map columns based on your Excel structure
                name = str(row.get('Name', '')).strip()
                if not name:
                    continue
                
                # Parse name
                name_parts = name.split()
                first_name = name_parts[0]
                last_name = ' '.join(name_parts[1:]) if len(name_parts) > 1 else ''
                
                # Create username
                username = name.replace(' ', '').lower()
                
                # Get role from Group column
                role_group = str(row.get('Group', '')).strip().lower()
                role_map = {
                    'super admin': 'proprietor',
                    'admin': 'admin',
                    'teacher': 'teacher',
                }
                role = role_map.get(role_group, 'teacher')
                
                # Get department from Subgroup
                department = str(row.get('Subgroup', '')).strip().lower()
                dept_map = {
                    'primary': 'english',
                    'nursery': 'nursery',
                    'bilingual': 'bilingual',
                    'financial': 'finance',
                }
                department = dept_map.get(department, 'english')
                
                # Create user
                user, created = User.objects.get_or_create(
                    username=username,
                    defaults={
                        'first_name': first_name,
                        'last_name': last_name,
                        'email': f"{username}@raphabethel.org",
                        'is_staff': True,
                    }
                )
                
                # Get phone number
                phone = str(row.get('Contact Number', '')).strip().replace(' ', '')
                
                # Create staff profile
                staff, staff_created = Staff.objects.get_or_create(
                    user=user,
                    defaults={
                        'employee_id': f"STF{user.id:04d}",
                        'role': role,
                        'department': department,
                        'phone_number': phone,
                        'school_id': 1,
                        'is_active': True,
                        'imported_from': excel_file,
                    }
                )
                
                if staff_created:
                    imported += 1
                    self.stdout.write(f'  ✓ Imported: {name} ({role})')
                
            except Exception as e:
                errors.append(f"Row {index + 2}: {str(e)}")
        
        self.stdout.write(self.style.SUCCESS(f'\n✅ Successfully imported {imported} staff members'))
        
        if errors:
            self.stdout.write(self.style.WARNING(f'\n⚠️ {len(errors)} errors occurred:'))
            for error in errors[:5]:
                self.stdout.write(f'  • {error}')

======================================================================
FILE: staff/templatetags/staff_tags.py
======================================================================
# staff/templatetags/staff_tags.py
from django import template

register = template.Library()

@register.filter
def get_role_badge(role):
    """Return appropriate badge class for role"""
    badges = {
        'proprietor': 'badge-danger',
        'head_master': 'badge-warning',
        'head_mistress': 'badge-warning',
        'bursar': 'badge-info',
        'teacher': 'badge-success',
        'driver': 'badge-secondary',
    }
    return badges.get(role, 'badge-primary')

@register.filter
def get_initial(name):
    """Get first letter of name for avatar"""
    if name:
        return name[0].upper()
    return '?'

@register.simple_tag
def staff_count_by_role(role):
    """Get count of staff by role"""
    from staff.models import Staff
    return Staff.objects.filter(role=role, is_active=True).count()


######################################################################
# APP: STUDENTS
######################################################################

======================================================================
FILE: students/__init__.py
======================================================================


======================================================================
FILE: students/admin.py
======================================================================
# students/admin.py
from django.contrib import admin
from django.utils.html import format_html
from .models import Student, ParentGuardian

@admin.register(Student)
class StudentAdmin(admin.ModelAdmin):
    list_display = (
        'student_id', 
        'full_name_display', 
        'age_display', 
        'gender', 
        'current_class', 
        'status_display',
        'contact_info',
        'photo_preview'
    )
    
    list_filter = (
        'status', 
        'gender', 
        'current_class', 
        'city', 
        'quarter',
        'admission_date',
    )
    
    search_fields = (
        'student_id', 
        'first_name', 
        'last_name', 
        'phone_number',
        'email',
        'emergency_contact_name',
        'emergency_contact_phone',
    )
    
    readonly_fields = (
        'age_display',
        'photo_preview',
        'created_at',
        'updated_at',
    )
    
    fieldsets = (
        ('Identification', {
            'fields': (
                'student_id', 
                'first_name', 
                'last_name', 
                'date_of_birth',
                'age_display',
                'gender',
                'photo',
                'photo_preview',
            )
        }),
        
        ('Contact Information', {
            'fields': (
                'home_address',
                'quarter',
                'city',
                'phone_number',
                'email',
            )
        }),
        
        ('Emergency Contact', {
            'fields': (
                'emergency_contact_name',
                'emergency_contact_phone',
                'emergency_contact_relationship',
            )
        }),
        
        ('Medical Information', {
            'fields': (
                'blood_group',
                'allergies',
                'chronic_conditions',
                'medications',
            ),
            'classes': ('collapse',),
        }),
        
        ('School Information', {
            'fields': (
                'admission_date',
                'admission_class',
                'current_class',
                'status',
                'birth_certificate',
            )
        }),
        
        ('Additional Information', {
            'fields': ('notes',),
            'classes': ('collapse',),
        }),
        
        ('Metadata', {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',),
        }),
    )
    
    # Custom methods for display
    def full_name_display(self, obj):
        return obj.get_full_name()
    full_name_display.short_description = 'Name'
    full_name_display.admin_order_field = 'last_name'
    
    def age_display(self, obj):
        return obj.get_age()
    age_display.short_description = 'Age'
    
    def status_display(self, obj):
        colors = {
            'active': 'green',
            'inactive': 'gray',
            'graduated': 'blue',
            'transferred': 'orange',
            'suspended': 'red',
        }
        color = colors.get(obj.status, 'black')
        return format_html(
            '<span style="color: {}; font-weight: bold;">{}</span>',
            color,
            obj.get_status_display()
        )
    status_display.short_description = 'Status'
    
    def contact_info(self, obj):
        return format_html(
            '{}<br>Emergency: {}',
            obj.phone_number if obj.phone_number else 'No phone',
            obj.emergency_contact_phone
        )
    contact_info.short_description = 'Contact Information'
    
    def photo_preview(self, obj):
        if obj.photo:
            return format_html(
                '<img src="{}" width="100" height="100" style="border-radius: 5px;" />',
                obj.photo.url
            )
        return "No photo"
    photo_preview.short_description = 'Photo Preview'


@admin.register(ParentGuardian)
class ParentGuardianAdmin(admin.ModelAdmin):
    list_display = (
        'full_name_display',
        'student_display',
        'relationship',
        'contact_info',
        'mobile_money_info',
        'is_primary_contact_display',
        'communication_preferences',
    )
    
    list_filter = (
        'relationship',
        'is_primary_contact',
        'mobile_money_provider',
        'preferred_language',
        'receive_sms',
        'receive_email',
        'receive_whatsapp',
    )
    
    search_fields = (
        'first_name',
        'last_name',
        'phone',
        'email',
        'student__first_name',
        'student__last_name',
        'student__student_id',
    )
    
    readonly_fields = ('created_at', 'updated_at')
    
    fieldsets = (
        ('Basic Information', {
            'fields': (
                'student',
                'first_name',
                'last_name',
                'relationship',
            )
        }),
        
        ('Contact Information', {
            'fields': (
                'phone',
                'email',
                'address',
            )
        }),
        
        ('Personal Information', {
            'fields': (
                'occupation',
                'employer',
                'education_level',
            ),
            'classes': ('collapse',),
        }),
        
        ('Mobile Money Information', {
            'fields': (
                'mobile_money_number',
                'mobile_money_provider',
            )
        }),
        
        ('Communication Preferences', {
            'fields': (
                'preferred_language',
                'receive_sms',
                'receive_email',
                'receive_whatsapp',
            )
        }),
        
        ('Administrative', {
            'fields': (
                'is_primary_contact',
                'can_pick_up',
                'notes',
            )
        }),
        
        ('Metadata', {
            'fields': ('created_at', 'updated_at'),
            'classes': ('collapse',),
        }),
    )
    
    # Custom methods for display
    def full_name_display(self, obj):
        return obj.get_full_name()
    full_name_display.short_description = 'Parent/Guardian'
    full_name_display.admin_order_field = 'last_name'
    
    def student_display(self, obj):
        return str(obj.student)
    student_display.short_description = 'Student'
    student_display.admin_order_field = 'student__last_name'
    
    def contact_info(self, obj):
        info = f"📞 {obj.phone}"
        if obj.email:
            info += f"<br>📧 {obj.email}"
        return format_html(info)
    contact_info.short_description = 'Contact'
    
    def mobile_money_info(self, obj):
        if obj.mobile_money_provider != 'none' and obj.mobile_money_number:
            return format_html(
                '💰 {}: {}',
                obj.get_mobile_money_provider_display(),
                obj.mobile_money_number
            )
        return "No mobile money"
    mobile_money_info.short_description = 'Mobile Money'
    
    def is_primary_contact_display(self, obj):
        if obj.is_primary_contact:
            return format_html(
                '<span style="color: green; font-weight: bold;">✓ Primary</span>'
            )
        return format_html('<span style="color: gray;">Secondary</span>')
    is_primary_contact_display.short_description = 'Primary'
    
    def communication_preferences(self, obj):
        methods = []
        if obj.receive_sms:
            methods.append('SMS')
        if obj.receive_email:
            methods.append('Email')
        if obj.receive_whatsapp:
            methods.append('WhatsApp')
        
        language = obj.get_preferred_language_display()
        return format_html(
            '{}<br><small>{}</small>',
            ', '.join(methods) if methods else 'None',
            language
        )
    communication_preferences.short_description = 'Communication'

======================================================================
FILE: students/apps.py
======================================================================
from django.apps import AppConfig


class StudentsConfig(AppConfig):
    name = 'students'


======================================================================
FILE: students/models.py
======================================================================
# students/models.py
"""
Student management models for student information and parent/guardian relationships.
"""
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
from academics.models import SchoolClass


class Student(models.Model):
    """
    Student information model for primary schools in Cameroon.
    
    This comprehensive model stores all information about students including
    personal details, contact information, medical information, academic
    history, and emergency contacts.
    
    Attributes:
        student_id (str): Unique student identifier
        first_name (str): Student's first name
        last_name (str): Student's last name
        date_of_birth (date): Student's birth date
        place_of_birth (str): Birth location
        gender (str): Gender from GENDER_CHOICES
        nationality (str): Student's nationality
        home_address (str): Residential address
        quarter (str): Neighborhood/district
        city (str): City of residence
        phone_number (str): Student's phone (if applicable)
        email (str): Student's email (if applicable)
        emergency_contact_name (str): Name of emergency contact
        emergency_contact_phone (str): Emergency contact number
        emergency_contact_relationship (str): Relationship to emergency contact
        blood_group (str): Blood type from choices
        allergies (str): Known allergies
        chronic_conditions (str): Chronic medical conditions
        medications (str): Current medications
        admission_date (date): Date of enrollment
        admission_class (str): Class at admission
        current_class (ForeignKey): Current class
        status (str): Current enrollment status
        photo (ImageField): Student photograph
        birth_certificate (FileField): Birth certificate document
        imported_from (str): Source of import
        original_data (JSONField): Original imported data
        created_at (datetime): When record was created
        updated_at (datetime): When record was last updated
        notes (str): Additional notes
    """
    
    # Gender choices
    GENDER_CHOICES = [
        ('M', _('Male')),
        ('F', _('Female')),
        ('U', _('Unknown/Unspecified')),
    ]
    
    # Student status
    STATUS_CHOICES = [
        ('active', _('Active')),
        ('inactive', _('Inactive')),
        ('graduated', _('Graduated')),
        ('transferred', _('Transferred')),
        ('suspended', _('Suspended')),
        ('withdrawn', _('Withdrawn')),
    ]
    
    CLASS_CHOICES = [
        ('pre_nursery', 'Pre-Nursery'),
        ('nursery1', 'Nursery 1'),
        ('nursery2', 'Nursery 2'),
        ('moyenne_section', 'Moyenne Section'),
        ('grande_section', 'Grande Section'),
        ('sil', 'SIL'),
        ('cp', 'CP'),
        ('ce1', 'CE1'),
        ('ce2', 'CE2'),
        ('cm1', 'CM1'),
        ('cm2', 'CM2'),
        ('class1', 'Class 1'),
        ('class2', 'Class 2'),
        ('class3', 'Class 3'),
        ('class4', 'Class 4'),
        ('class5', 'Class 5'),
        ('class6', 'Class 6'),
    ]
    
    # Cameroonian phone validator
    phone_regex = RegexValidator(
        regex=r'^\+?[1-9]\d{1,14}$',
        message="Phone number must be entered in the format: '+237XXXXXXXXX'."
    )
    
    # ========== IDENTIFICATION ==========
    student_id = models.CharField(
        max_length=20,
        unique=True,
        verbose_name=_("Student ID"),
        help_text=_("Unique identifier for the student (e.g., 2025-001)")
    )
    
    first_name = models.CharField(
        max_length=100,
        verbose_name=_("First Name")
    )
    
    last_name = models.CharField(
        max_length=100,
        verbose_name=_("Last Name")
    )
    
    date_of_birth = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Date of Birth")
    )
    
    place_of_birth = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        verbose_name=_("Place of Birth")
    )
    
    gender = models.CharField(
        max_length=1,
        choices=GENDER_CHOICES,
        default='U',
        blank=True,
        verbose_name=_("Gender")
    )
    
    nationality = models.CharField(
        max_length=50,
        default="Cameroonian",
        blank=True,
        verbose_name=_("Nationality")
    )
    
    # ========== CONTACT INFORMATION ==========
    home_address = models.TextField(
        blank=True,
        verbose_name=_("Home Address")
    )
    
    quarter = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Quarter/Neighborhood"),
        help_text=_("e.g., Bonapriso, Akwa, Bonanjo")
    )
    
    city = models.CharField(
        max_length=100,
        default="Douala",
        blank=True,
        verbose_name=_("City")
    )
    
    phone_number = models.CharField(
        validators=[phone_regex],
        max_length=17,
        blank=True,
        verbose_name=_("Phone Number")
    )
    
    email = models.EmailField(
        blank=True,
        verbose_name=_("Email Address")
    )
    
    # ========== EMERGENCY CONTACT ==========
    emergency_contact_name = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Emergency Contact Name")
    )
    
    emergency_contact_phone = models.CharField(
        validators=[phone_regex],
        max_length=17,
        blank=True,
        verbose_name=_("Emergency Contact Phone")
    )
    
    emergency_contact_relationship = models.CharField(
        max_length=50,
        blank=True,
        verbose_name=_("Relationship"),
        help_text=_("e.g., Father, Mother, Guardian")
    )
    
    # ========== MEDICAL INFORMATION ==========
    blood_group = models.CharField(
        max_length=7,
        blank=True,
        verbose_name=_("Blood Group"),
        choices=[
            ('A+', 'A+'), ('A-', 'A-'),
            ('B+', 'B+'), ('B-', 'B-'),
            ('AB+', 'AB+'), ('AB-', 'AB-'),
            ('O+', 'O+'), ('O-', 'O-'),
            ('unknown', 'Unknown'),
        ],
        default='unknown'
    )
    
    allergies = models.TextField(
        blank=True,
        verbose_name=_("Allergies"),
        help_text=_("List any allergies the student has")
    )
    
    chronic_conditions = models.TextField(
        blank=True,
        verbose_name=_("Chronic Conditions"),
        help_text=_("List any chronic medical conditions")
    )
    
    medications = models.TextField(
        blank=True,
        verbose_name=_("Current Medications"),
        help_text=_("List any medications the student is taking")
    )
    
    # ========== SCHOOL INFORMATION ==========
    admission_date = models.DateField(
        null=True,
        blank=True,
        verbose_name=_("Admission Date")
    )
    
    admission_class = models.CharField(
        max_length=20,
        choices=CLASS_CHOICES,
        blank=True,
        verbose_name=_("Admission Class")
    )
    
    current_class = models.ForeignKey(
        SchoolClass,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        verbose_name=_("Current Class"),
        related_name='students'
    )
    
    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='active',
        verbose_name=_("Status")
    )
    
    # ========== PHOTO & DOCUMENTS ==========
    photo = models.ImageField(
        upload_to='student_photos/',
        blank=True,
        null=True,
        verbose_name=_("Student Photo")
    )
    
    birth_certificate = models.FileField(
        upload_to='documents/birth_certificates/',
        blank=True,
        null=True,
        verbose_name=_("Birth Certificate")
    )
    
    # ========== IMPORT TRACKING ==========
    imported_from = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        help_text="Source of import (e.g., 'Class 6 Excel')"
    )
    
    original_data = models.JSONField(
        blank=True,
        null=True,
        help_text="Original imported data as JSON"
    )
    
    # ========== METADATA ==========
    created_at = models.DateTimeField(
        auto_now_add=True,
        null=True,
        blank=True,
        verbose_name=_("Created At")
    )
    
    updated_at = models.DateTimeField(
        auto_now=True,
        null=True,
        blank=True,
        verbose_name=_("Updated At")
    )
    
    notes = models.TextField(
        blank=True,
        verbose_name=_("Additional Notes")
    )
    
    class Meta:
        verbose_name = _("Student")
        verbose_name_plural = _("Students")
        ordering = ['student_id', 'last_name', 'first_name']
        indexes = [
            models.Index(fields=['student_id']),
            models.Index(fields=['last_name', 'first_name']),
            models.Index(fields=['current_class']),
            models.Index(fields=['status']),
        ]
    
    def __str__(self):
        """Return string representation of the student."""
        return f"{self.student_id} - {self.first_name} {self.last_name}"
    
    def get_full_name(self):
        """
        Return the full name of the student.
        
        Returns:
            str: Combined first and last name.
        """
        return f"{self.first_name} {self.last_name}".strip()
    
    def get_age(self):
        """
        Calculate student's current age based on date of birth.
        
        Returns:
            int or None: Age in years, or None if DOB not set.
        """
        if not self.date_of_birth:
            return None
        from datetime import date
        today = date.today()
        age = today.year - self.date_of_birth.year
        if (today.month, today.day) < (self.date_of_birth.month, self.date_of_birth.day):
            age -= 1
        return age
    
    def is_active(self):
        """
        Check if student is currently active.
        
        Returns:
            bool: True if status is 'active'.
        """
        return self.status == 'active'
    
    def get_emergency_contact_info(self):
        """
        Get formatted emergency contact information.
        
        Returns:
            str: Formatted string with emergency contact details.
        """
        if self.emergency_contact_name and self.emergency_contact_phone:
            rel = f" ({self.emergency_contact_relationship})" if self.emergency_contact_relationship else ""
            return f"{self.emergency_contact_name}{rel}: {self.emergency_contact_phone}"
        return "No emergency contact on file"


class ParentGuardian(models.Model):
    """
    Parent or Guardian information linked to students.
    
    This model stores detailed information about parents and guardians,
    including contact preferences, mobile money details, and authorization
    to pick up students.
    
    Attributes:
        student (ForeignKey): Student this parent is linked to
        first_name (str): Parent's first name
        last_name (str): Parent's last name
        relationship (str): Relationship to student from RELATIONSHIP_CHOICES
        phone (str): Primary phone number
        alternate_phone (str): Secondary phone number
        email (str): Email address
        address (str): Residential address
        occupation (str): Occupation from OCCUPATION_CHOICES
        employer (str): Employer name
        education_level (str): Education level from EDUCATION_CHOICES
        mobile_money_number (str): Mobile money account number
        mobile_money_provider (str): Mobile money provider
        preferred_language (str): Preferred language for communication
        receive_sms (bool): Whether to receive SMS notifications
        receive_email (bool): Whether to receive email notifications
        receive_whatsapp (bool): Whether to receive WhatsApp messages
        is_primary_contact (bool): Whether this is the primary contact
        can_pick_up (bool): Whether authorized to pick up student
        created_at (datetime): When record was created
        updated_at (datetime): When record was last updated
        notes (str): Additional notes
    """
    
    RELATIONSHIP_CHOICES = [
        ('father', _('Father')),
        ('mother', _('Mother')),
        ('guardian', _('Guardian')),
        ('grandparent', _('Grandparent')),
        ('sibling', _('Sibling')),
        ('aunt', _('Aunt')),
        ('uncle', _('Uncle')),
        ('other', _('Other')),
    ]
    
    OCCUPATION_CHOICES = [
        ('teacher', _('Teacher')),
        ('nurse', _('Nurse')),
        ('engineer', _('Engineer')),
        ('doctor', _('Doctor')),
        ('lawyer', _('Lawyer')),
        ('business', _('Business Owner')),
        ('civil_servant', _('Civil Servant')),
        ('farmer', _('Farmer')),
        ('driver', _('Driver')),
        ('trader', _('Trader')),
        ('housewife', _('Housewife')),
        ('other', _('Other')),
    ]
    
    EDUCATION_CHOICES = [
        ('none', _('No Formal Education')),
        ('primary', _('Primary School')),
        ('secondary', _('Secondary School')),
        ('high_school', _('High School')),
        ('university', _('University')),
        ('postgraduate', _('Postgraduate')),
    ]
    
    phone_regex = RegexValidator(
        regex=r'^\+?[1-9]\d{1,14}$',
        message="Phone number must be entered in the format: '+237XXXXXXXXX'."
    )
    
    # ========== BASIC INFORMATION ==========
    student = models.ForeignKey(
        Student,
        on_delete=models.CASCADE,
        related_name='parents',
        verbose_name=_("Student")
    )
    
    first_name = models.CharField(
        max_length=100,
        verbose_name=_("First Name")
    )
    
    last_name = models.CharField(
        max_length=100,
        verbose_name=_("Last Name")
    )
    
    relationship = models.CharField(
        max_length=20,
        choices=RELATIONSHIP_CHOICES,
        verbose_name=_("Relationship to Student")
    )
    
    # ========== CONTACT INFORMATION ==========
    phone = models.CharField(
        validators=[phone_regex],
        max_length=17,
        verbose_name=_("Phone Number")
    )
    
    alternate_phone = models.CharField(
        validators=[phone_regex],
        max_length=17,
        blank=True,
        verbose_name=_("Alternate Phone Number")
    )
    
    email = models.EmailField(
        blank=True,
        verbose_name=_("Email Address")
    )
    
    address = models.TextField(
        blank=True,
        verbose_name=_("Address")
    )
    
    # ========== PERSONAL INFORMATION ==========
    occupation = models.CharField(
        max_length=50,
        choices=OCCUPATION_CHOICES,
        blank=True,
        verbose_name=_("Occupation")
    )
    
    employer = models.CharField(
        max_length=100,
        blank=True,
        verbose_name=_("Employer")
    )
    
    education_level = models.CharField(
        max_length=20,
        choices=EDUCATION_CHOICES,
        blank=True,
        verbose_name=_("Education Level")
    )
    
    # ========== MOBILE MONEY INFORMATION ==========
    mobile_money_number = models.CharField(
        max_length=20,
        blank=True,
        verbose_name=_("Mobile Money Number")
    )
    
    mobile_money_provider = models.CharField(
        max_length=10,
        choices=[
            ('mtn', 'MTN Mobile Money'),
            ('orange', 'Orange Money'),
            ('none', 'None'),
        ],
        default='none',
        verbose_name=_("Mobile Money Provider")
    )
    
    # ========== COMMUNICATION PREFERENCES ==========
    preferred_language = models.CharField(
        max_length=10,
        choices=[
            ('fr', 'French'),
            ('en', 'English'),
            ('both', 'Both'),
        ],
        default='fr',
        verbose_name=_("Preferred Language")
    )
    
    receive_sms = models.BooleanField(
        default=True,
        verbose_name=_("Receive SMS Notifications")
    )
    
    receive_email = models.BooleanField(
        default=False,
        verbose_name=_("Receive Email Notifications")
    )
    
    receive_whatsapp = models.BooleanField(
        default=True,
        verbose_name=_("Receive WhatsApp Messages")
    )
    
    # ========== ADMINISTRATIVE ==========
    is_primary_contact = models.BooleanField(
        default=False,
        verbose_name=_("Primary Contact"),
        help_text=_("Is this the primary contact for the student?")
    )
    
    can_pick_up = models.BooleanField(
        default=True,
        verbose_name=_("Can Pick Up Student"),
        help_text=_("Is this person authorized to pick up the student from school?")
    )
    
    # ========== METADATA ==========
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_("Created At")
    )
    
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_("Updated At")
    )
    
    notes = models.TextField(
        blank=True,
        verbose_name=_("Additional Notes")
    )
    
    class Meta:
        verbose_name = _("Parent/Guardian")
        verbose_name_plural = _("Parents/Guardians")
        ordering = ['student', '-is_primary_contact', 'last_name', 'first_name']
        unique_together = ['student', 'phone']
    
    def __str__(self):
        """Return string representation of the parent/guardian."""
        primary = " (Primary)" if self.is_primary_contact else ""
        return f"{self.first_name} {self.last_name} - {self.get_relationship_display()}{primary}"
    
    def get_full_name(self):
        """
        Return the full name of the parent/guardian.
        
        Returns:
            str: Combined first and last name.
        """
        return f"{self.first_name} {self.last_name}".strip()
    
    def get_contact_info(self):
        """
        Get formatted contact information.
        
        Returns:
            str: Formatted string with all contact details.
        """
        info = []
        if self.phone:
            info.append(f"Phone: {self.phone}")
        if self.alternate_phone:
            info.append(f"Alt: {self.alternate_phone}")
        if self.email:
            info.append(f"Email: {self.email}")
        if self.mobile_money_number and self.mobile_money_provider != 'none':
            info.append(f"MoMo: {self.mobile_money_number} ({self.get_mobile_money_provider_display()})")
        return " | ".join(info)

======================================================================
FILE: students/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: students/urls-1.py
======================================================================
# students/urls.py
from django.urls import path
from . import views

app_name = 'students'

urlpatterns = [
    path('', views.StudentListView.as_view(), name='student_list'),
    path('<int:pk>/', views.StudentDetailView.as_view(), name='student_detail'),
    path('add/', views.StudentCreateView.as_view(), name='student_add'),
    path('<int:pk>/edit/', views.StudentUpdateView.as_view(), name='student_edit'),
    path('<int:pk>/delete/', views.StudentDeleteView.as_view(), name='student_delete'),
    
    # IMPORT/EXPORT URLs - ADD THESE
    path('export/', views.export_students_csv, name='export_students'),
    path('import/', views.import_students_csv, name='import_students_csv'),
    path('import/sample/', views.download_student_sample, name='download_student_sample'),
    path('import/class6-sample/', views.download_class6_sample, name='download_class6_sample'),
]

======================================================================
FILE: students/urls.py
======================================================================
# students/urls.py
from django.urls import path
from . import views

app_name = 'students'

urlpatterns = [
    path('', views.StudentListView.as_view(), name='student_list'),
    path('<int:pk>/', views.StudentDetailView.as_view(), name='student_detail'),
    path('add/', views.StudentCreateView.as_view(), name='student_add'),
    path('<int:pk>/edit/', views.StudentUpdateView.as_view(), name='student_edit'),
    path('<int:pk>/delete/', views.StudentDeleteView.as_view(), name='student_delete'),
    
    # IMPORT/EXPORT URLs - ADD THESE
    path('export/', views.export_students_csv, name='export_students'),
    path('import/', views.import_students_csv, name='import_students_csv'),
    path('import/sample/', views.download_student_sample, name='download_student_sample'),
    path('import/class6-sample/', views.download_class6_sample, name='download_class6_sample'),

    # Parents / Guardians
    path('parents/', views.ParentListView.as_view(), name='parent_list'),
    path('parents/add/', views.ParentCreateView.as_view(), name='parent_add'),
    path('parents/<int:pk>/', views.ParentDetailView.as_view(), name='parent_detail'),
    path('parents/<int:pk>/edit/', views.ParentUpdateView.as_view(), name='parent_edit'),
]

======================================================================
FILE: students/utils.py
======================================================================
# students/utils.py  (add this to your existing utils.py or create it)
"""
Student ID generation — format: RB-YY-NNNN

Examples:
    RB-26-0001   first student admitted in 2026
    RB-26-0053   53rd student admitted in 2026
    RB-27-0001   first student admitted in 2027 (new cohort)

Logic:
    - YY  = last 2 digits of the admission year
    - NNNN = global sequence across ALL years, never resets
             (prevents any ID collision ever)
"""

from datetime import date


def generate_student_id(admission_year=None):
    """
    Generate the next available student ID in RB-YY-NNNN format.

    Args:
        admission_year: int (e.g. 2026). Defaults to current year.

    Returns:
        str  e.g. 'RB-26-0053'
    """
    from students.models import Student   # local import to avoid circular

    if admission_year is None:
        admission_year = date.today().year

    yy = str(admission_year)[-2:]   # '2026' -> '26'

    # Find the highest NNNN across ALL student IDs (not just this year)
    # so the sequence is always globally unique
    last = (
        Student.objects
        .filter(student_id__startswith='RB-')
        .order_by('-student_id')
        .values_list('student_id', flat=True)
        .first()
    )

    if last:
        try:
            # RB-26-0053 -> 53
            seq = int(last.split('-')[-1]) + 1
        except (ValueError, IndexError):
            seq = 1
    else:
        seq = 1

    return f'RB-{yy}-{seq:04d}'

======================================================================
FILE: students/views.py
======================================================================
# students/views.py
from django.shortcuts import render, redirect, get_object_or_404
from .utils import generate_student_id
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse_lazy
from django.db.models import Q, Count
from django.http import JsonResponse, HttpResponse
from django.db import IntegrityError
import csv
import io
import pandas as pd
from datetime import datetime

from .models import Student, ParentGuardian
from academics.models import SchoolClass

# ========== MAIN VIEWS ==========

class StudentListView(LoginRequiredMixin, ListView):
    """List all students with search and filter"""
    model = Student
    template_name = 'students/student_list.html'
    context_object_name = 'students'
    paginate_by = 20
    
    SORT_FIELDS = {
        'name':       ('last_name', 'first_name'),
        '-name':      ('-last_name', '-first_name'),
        'id':         ('student_id',),
        '-id':        ('-student_id',),
        'class':      ('current_class__name', 'last_name'),
        '-class':     ('-current_class__name', 'last_name'),
        'admitted':   ('admission_date',),
        '-admitted':  ('-admission_date',),
        'age':        ('date_of_birth',),
        '-age':       ('-date_of_birth',),
    }

    def get_queryset(self):
        queryset = super().get_queryset().select_related('current_class')

        # Search
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(student_id__icontains=search_query) |
                Q(home_address__icontains=search_query)
            )

        # Filter by class — 'none' shows students with no class assigned
        class_filter = self.request.GET.get('class')
        if class_filter == 'none':
            queryset = queryset.filter(current_class__isnull=True)
        elif class_filter:
            queryset = queryset.filter(current_class_id=class_filter)

        # Filter by status
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)

        # Filter by gender
        gender_filter = self.request.GET.get('gender')
        if gender_filter:
            queryset = queryset.filter(gender=gender_filter)

        # Sorting
        sort = self.request.GET.get('sort', '-admitted')
        order_fields = self.SORT_FIELDS.get(sort, ('-admission_date',))
        queryset = queryset.order_by(*order_fields)

        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        from datetime import date
        today = date.today()

        # Global stats (always full counts)
        context['total_students']  = Student.objects.count()
        context['active_students'] = Student.objects.filter(status='active').count()
        context['unassigned_count'] = Student.objects.filter(current_class__isnull=True).count()
        context['total_classes']   = SchoolClass.objects.filter(
            students__status='active'
        ).distinct().count()
        context['new_this_month']  = Student.objects.filter(
            admission_date__year=today.year,
            admission_date__month=today.month
        ).count()

        # Filtered result count (total across all pages)
        context['filtered_count'] = self.get_queryset().count()

        context['all_classes'] = SchoolClass.objects.all().order_by('name')
        context['current_sort'] = self.request.GET.get('sort', '-admitted')

        # Preserve all current GET params as a string for pagination links
        params = self.request.GET.copy()
        params.pop('page', None)
        context['query_string'] = params.urlencode()
        return context

class StudentDetailView(LoginRequiredMixin, DetailView):
    """View student details"""
    model = Student
    template_name = 'students/student_detail.html'
    context_object_name = 'student'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Get attendance records
        from academics.models import Attendance
        context['attendance_records'] = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:30]
        
        # Get invoice records
        from finance.models import Invoice
        context['invoice_records'] = Invoice.objects.filter(
            student=self.object
        ).order_by('-issue_date')[:10]
        
        # Get parents/guardians
        context['parents'] = ParentGuardian.objects.filter(student=self.object)
        
        return context

class StudentCreateView(LoginRequiredMixin, CreateView):
    """Create a new student"""
    model = Student
    fields = [
        'first_name', 'last_name', 'date_of_birth', 'gender',
        'home_address', 'quarter', 'city', 'phone_number', 'email',
        'emergency_contact_name', 'emergency_contact_phone', 'emergency_contact_relationship',
        'blood_group', 'allergies', 'chronic_conditions', 'medications',
        'admission_date', 'admission_class', 'current_class', 'status',
        'photo', 'birth_certificate', 'notes'
    ]
    template_name = 'students/student_form.html'
    success_url = reverse_lazy('student_list')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Add New Student'
        context['next_student_id'] = generate_student_id()  # preview for the form
        context['classes'] = SchoolClass.objects.all().order_by('name')
        return context
    
    def form_valid(self, form):
        student = form.save(commit=False)
        if not student.student_id:
            student.student_id = generate_student_id()
        student.save()
        messages.success(
            self.request,
            f'Student {student.first_name} {student.last_name} added. '
            f'ID: {student.student_id}'
        )
        return redirect('students:student_detail', pk=student.pk)

class StudentUpdateView(LoginRequiredMixin, UpdateView):
    """Update student information"""
    model = Student
    fields = [
        'first_name', 'last_name', 'date_of_birth', 'gender',
        'home_address', 'quarter', 'city', 'phone_number', 'email',
        'emergency_contact_name', 'emergency_contact_phone', 'emergency_contact_relationship',
        'blood_group', 'allergies', 'chronic_conditions', 'medications',
        'current_class', 'status', 'photo', 'notes'
    ]
    template_name = 'students/student_form.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'Edit {self.object.get_full_name()}'
        context['next_student_id'] = self.object.student_id  # show existing ID when editing
        context['classes'] = SchoolClass.objects.all().order_by('name')
        return context

    def form_valid(self, form):
        messages.success(self.request, 'Student updated successfully!')
        return super().form_valid(form)

    def get_success_url(self):
        return reverse_lazy('students:student_detail', kwargs={'pk': self.object.pk})

class StudentDeleteView(LoginRequiredMixin, DeleteView):
    """Delete a student"""
    model = Student
    success_url = reverse_lazy('student_list')
    template_name = 'students/student_confirm_delete.html'
    
    def delete(self, request, *args, **kwargs):
        student = self.get_object()
        messages.success(request, f'Student {student.get_full_name()} deleted successfully')
        return super().delete(request, *args, **kwargs)

# ========== PARENT/GUARDIAN VIEWS ==========

class ParentListView(LoginRequiredMixin, ListView):
    """List all parents/guardians"""
    model = ParentGuardian
    template_name = 'students/parent_list.html'
    context_object_name = 'parents'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = super().get_queryset().select_related('student')
        
        search_query = self.request.GET.get('q')
        if search_query:
            queryset = queryset.filter(
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(phone__icontains=search_query) |
                Q(student__first_name__icontains=search_query)
            )
        
        return queryset.order_by('last_name', 'first_name')

class ParentDetailView(LoginRequiredMixin, DetailView):
    """View parent/guardian details"""
    model = ParentGuardian
    template_name = 'students/parent_detail.html'
    context_object_name = 'parent'

class ParentCreateView(LoginRequiredMixin, CreateView):
    """Add a new parent/guardian"""
    model = ParentGuardian
    fields = '__all__'
    template_name = 'students/parent_form.html'
    success_url = reverse_lazy('parent_list')

class ParentUpdateView(LoginRequiredMixin, UpdateView):
    """Update parent/guardian information"""
    model = ParentGuardian
    fields = '__all__'
    template_name = 'students/parent_form.html'
    success_url = reverse_lazy('parent_list')

# ========== IMPORT/EXPORT FUNCTIONS ==========

def export_students_csv(request):
    """Export students to CSV"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="students_export.csv"'
    
    writer = csv.writer(response)
    writer.writerow([
        'Student ID', 'First Name', 'Last Name', 'Date of Birth', 'Gender',
        'Class', 'Admission Date', 'Status', 'Parent Name', 'Parent Phone'
    ])
    
    students = Student.objects.select_related('current_class').prefetch_related('parents').all()
    
    for student in students:
        parent = student.parents.filter(is_primary_contact=True).first()
        parent_name = f"{parent.first_name} {parent.last_name}" if parent else ''
        parent_phone = parent.phone if parent else ''
        
        writer.writerow([
            student.student_id,
            student.first_name,
            student.last_name,
            student.date_of_birth,
            student.get_gender_display(),
            student.current_class.name if student.current_class else '',
            student.admission_date,
            student.status,
            parent_name,
            parent_phone
        ])
    
    return response

def import_students_csv(request):
    """Import students from CSV"""
    if request.method == 'POST' and request.FILES.get('file'):
        csv_file = request.FILES['file']
        
        if not csv_file.name.endswith('.csv'):
            messages.error(request, 'Please upload a CSV file')
            return redirect('students:import_students_csv')
        
        try:
            decoded_file = csv_file.read().decode('utf-8-sig')
            io_string = io.StringIO(decoded_file)
            reader = csv.DictReader(io_string)
            
            imported = 0
            errors = []
            
            for row_num, row in enumerate(reader, start=2):
                try:
                    # Normalise headers: strip whitespace, lowercase — handles any capitalisation
                    row_norm = {k.strip().lower(): (v or '').strip() for k, v in row.items()}

                    first_name = (
                        row_norm.get('first name') or row_norm.get('firstname') or
                        row_norm.get('first_name') or row_norm.get('nom') or ''
                    )
                    last_name = (
                        row_norm.get('last name') or row_norm.get('lastname') or
                        row_norm.get('last_name') or row_norm.get('prenom') or
                        row_norm.get('prénom') or ''
                    )

                    if not first_name or not last_name:
                        errors.append(f"Row {row_num}: Missing first or last name")
                        continue
                    
                    # Resolve class — normalised key lookup
                    class_name = (
                        row_norm.get('class') or row_norm.get('classe') or
                        row_norm.get('current class') or ''
                    )
                    override_class_id = request.POST.get('class_id', '').strip()
                    current_class = None

                    if override_class_id:
                        # Staff selected a class in the form — use it for all rows
                        current_class = SchoolClass.objects.filter(pk=override_class_id).first()
                    elif class_name:
                        current_class = SchoolClass.objects.filter(
                            Q(name__icontains=class_name) | Q(code__icontains=class_name)
                        ).first()
                        if not current_class:
                            errors.append(
                                f"Row {row_num}: Class '{class_name}' not found — "
                                f"check the class code matches exactly (e.g. CL6-A, CM2-A)"
                            )
                            continue
                    else:
                        # No class in CSV and no override — block the row
                        errors.append(
                            f"Row {row_num}: {first_name} {last_name} — "
                            f"no Class specified. Add a Class column to the CSV "
                            f"or select a target class in the import form."
                        )
                        continue
                    
                    # Parse date
                    dob_str = row.get('Date of Birth', '')
                    date_of_birth = None
                    if dob_str:
                        try:
                            date_of_birth = datetime.strptime(dob_str, '%Y-%m-%d').date()
                        except ValueError:
                            try:
                                date_of_birth = datetime.strptime(dob_str, '%d/%m/%Y').date()
                            except ValueError:
                                pass
                    
                    # Auto-generate unique student ID — staff never supply this
                    student_id = generate_student_id()

                    # Create student (never use get_or_create — always insert fresh)
                    student = Student.objects.create(
                        student_id=student_id,
                        first_name=first_name,
                        last_name=last_name,
                        date_of_birth=date_of_birth,
                        gender=row.get('Gender', 'U')[:1].upper(),
                        current_class=current_class,
                        admission_date=datetime.now().date(),
                        status='active',
                        imported_from=csv_file.name,
                    )
                    imported += 1

                    # Create parent/guardian if provided — normalised key lookup
                    parent_name = (
                        row_norm.get('parent name') or row_norm.get('parent') or
                        row_norm.get('guardian name') or row_norm.get('guardian') or ''
                    )
                    parent_phone = (
                        row_norm.get('parent phone') or row_norm.get('phone') or
                        row_norm.get('telephone') or row_norm.get('contact') or ''
                    ).replace(' ', '').replace('-', '')

                    if parent_name:
                        # Split "DITCHEWI CHRISTIAN" → first=DITCHEWI last=CHRISTIAN
                        # If only one word, use it as last name
                        parts = parent_name.split(None, 1)  # split on first space only
                        p_first = parts[0] if len(parts) > 1 else ''
                        p_last  = parts[1] if len(parts) > 1 else parts[0]

                        ParentGuardian.objects.create(
                            student=student,
                            first_name=p_first,
                            last_name=p_last,
                            phone=parent_phone or '0000000000',  # phone is required
                            relationship='parent',
                            is_primary_contact=True,
                            receive_sms=True,
                        )
                    
                except Exception as e:
                    errors.append(f"Row {row_num}: {str(e)}")
            
            if errors:
                messages.warning(request, f"Imported {imported} students with {len(errors)} errors")
                for error in errors[:5]:
                    messages.error(request, error)
            else:
                messages.success(request, f"Successfully imported {imported} students!")
            
        except Exception as e:
            messages.error(request, f"Error processing file: {str(e)}")
        
        return redirect('students:student_list')
    
    # GET request - show import form
    classes = SchoolClass.objects.all()
    return render(request, 'students/import.html', {'classes': classes})

def download_student_sample(request):
    """Download sample CSV template"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="student_sample.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['First Name', 'Last Name', 'Date of Birth', 'Gender', 'Class', 'Parent Name', 'Parent Phone'])
    writer.writerow(['John', 'Doe', '2015-05-15', 'M', 'CL5-A', 'Peter Doe', '677889900'])
    writer.writerow(['Jane', 'Smith', '2015-08-22', 'F', 'CL5-A', 'Mary Smith', '699123456'])
    
    return response

def download_class6_sample(request):
    """Download Class 6 style sample"""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="class6_sample.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['NAME', 'DATE OF BIRTH', 'PLACE OF BIRTH', 'SEX'])
    writer.writerow(['ABUEMBAIMBI WISDOM NJI', '22/10/2015', 'DOUALA', 'M'])
    writer.writerow(['ADIGOUM ADEBIAYE NAOMI DEBORAH', '07/07/2015', 'DOUALA', 'F'])
    
    return response

def import_class_from_excel(request, sheet_name):
    """Import a specific class from Excel"""
    try:
        from .import_class_data import import_student_data
        result = import_student_data(
            excel_file="Rapha-Bethel BNPS.xlsx",
            sheet_name=sheet_name,
            class_name=sheet_name
        )
        
        if result['errors']:
            messages.warning(request, f"Imported {result['imported']} students with {len(result['errors'])} errors")
        else:
            messages.success(request, f"Successfully imported {result['imported']} students from {sheet_name}!")
        
    except Exception as e:
        messages.error(request, f"Error importing {sheet_name}: {str(e)}")
    
    return redirect('students:student_list')

def import_all_classes(request):
    """Import all classes from Excel"""
    try:
        from .import_all_classes import import_all_classes
        total = import_all_classes()
        messages.success(request, f"Successfully imported {total} students across all classes!")
    except Exception as e:
        messages.error(request, f"Error importing classes: {str(e)}")
    
    return redirect('students:student_list')

# ========== API ENDPOINTS ==========

def get_student_stats(request):
    """API endpoint for student statistics"""
    stats = {
        'total': Student.objects.count(),
        'active': Student.objects.filter(status='active').count(),
        'by_class': list(Student.objects.values('current_class__name').annotate(count=Count('id'))),
        'by_gender': list(Student.objects.values('gender').annotate(count=Count('id'))),
        'by_status': list(Student.objects.values('status').annotate(count=Count('id'))),
    }
    return JsonResponse(stats)


######################################################################
# APP: SYNC
######################################################################

======================================================================
FILE: sync/__init__.py
======================================================================


======================================================================
FILE: sync/admin.py
======================================================================
from django.contrib import admin

# Register your models here.


======================================================================
FILE: sync/apps.py
======================================================================
from django.apps import AppConfig


class SyncConfig(AppConfig):
    name = 'sync'


======================================================================
FILE: sync/models.py
======================================================================
from django.db import models

# Create your models here.


======================================================================
FILE: sync/tests.py
======================================================================
from django.test import TestCase

# Create your tests here.


======================================================================
FILE: sync/views.py
======================================================================
from django.shortcuts import render

# Create your views here.



######################################################################
# APP: TEMPLATES
######################################################################

======================================================================
FILE: templates/403.html
======================================================================
{% extends 'base.html' %}
{% block title %}Access Denied — Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;text-align:center;padding:2rem">
    <div style="width:80px;height:80px;border-radius:50%;background:#fef2f2;display:flex;align-items:center;justify-content:center;margin-bottom:1.5rem">
        <i class="fas fa-lock" style="font-size:2rem;color:var(--rb-red)"></i>
    </div>
    <h1 style="font-size:1.4rem;font-weight:700;margin-bottom:.5rem">Access Denied</h1>
    <p style="color:#777;max-width:380px;margin-bottom:2rem;font-size:.9rem">
        {{ exception|default:"You don't have permission to view this page. If you believe this is a mistake, please contact your administrator." }}
    </p>
    <div style="display:flex;gap:.75rem;flex-wrap:wrap;justify-content:center">
        <a href="javascript:history.back()" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-1"></i> Go Back
        </a>
        <a href="{% url 'dashboard' %}" class="btn btn-rb-primary">
            <i class="fas fa-th-large me-1"></i> Dashboard
        </a>
    </div>
    {% if user.is_authenticated %}
    <p style="margin-top:2rem;font-size:.78rem;color:#bbb">
        Logged in as <strong>{{ user.get_full_name|default:user.username }}</strong>
        {% if user.staff_profile %} · {{ user.staff_profile.get_role_display }}{% endif %}
    </p>
    {% endif %}
</div>
{% endblock %}


======================================================================
FILE: templates/404.html
======================================================================
{% extends 'base.html' %}
{% block title %}Page Not Found — Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:60vh;text-align:center;padding:2rem">
    <div style="font-size:4rem;font-weight:900;color:#ede8e3;line-height:1;margin-bottom:.5rem">404</div>
    <h1 style="font-size:1.4rem;font-weight:700;margin-bottom:.5rem">Page Not Found</h1>
    <p style="color:#777;max-width:380px;margin-bottom:2rem;font-size:.9rem">
        The page you're looking for doesn't exist or has been moved.
    </p>
    <div style="display:flex;gap:.75rem;flex-wrap:wrap;justify-content:center">
        <a href="javascript:history.back()" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-1"></i> Go Back
        </a>
        <a href="{% url 'dashboard' %}" class="btn btn-rb-primary">
            <i class="fas fa-th-large me-1"></i> Dashboard
        </a>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/base-1.html
======================================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Rapha-Bethel BNPS{% endblock %}</title>
    
    <!-- Bootstrap 5 -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <!-- Custom CSS -->
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/custom.css' %}">
    
    {% block extra_css %}{% endblock %}
</head>
<body>
    {% include 'includes/navbar.html' %}
    
    <div class="container-fluid">
        <div class="row">
            {% if user.is_authenticated %}
            <!-- Sidebar for authenticated users -->
            <nav id="sidebar" class="col-md-3 col-lg-2 d-md-block bg-light sidebar">
                {% include 'includes/sidebar.html' %}
            </nav>
            <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
            {% else %}
            <!-- Full width for non-authenticated -->
            <main class="col-12">
            {% endif %}
                {% block content %}{% endblock %}
            </main>
        </div>
    </div>
    
    {% include 'includes/footer.html' %}
    
    <!-- Bootstrap JS -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <!-- Chart.js -->
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <!-- Custom JS -->
    <script src="{% static 'js/main.js' %}"></script>
    
    {% block extra_js %}{% endblock %}
</body>
</html>

======================================================================
FILE: templates/base-2.html
======================================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <meta name="theme-color" content="#8B0000">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <title>{% block title %}Rapha-Bethel BNPS{% endblock %}</title>

    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">

    {% load static %}
    <link rel="stylesheet" href="{% static 'css/custom.css' %}">
    {% block extra_css %}{% endblock %}
</head>
<body>

{% load static %}

<header class="rb-topbar">
    {% if user.is_authenticated %}
    <button class="rb-menu-toggle" id="sidebarToggle" aria-label="Toggle menu">
        <span></span><span></span><span></span>
    </button>
    {% endif %}
    <a href="/" class="rb-brand">
        <img src="{% static 'admin/img/logo-yellow.jpeg' %}" alt="Logo" onerror="this.style.display='none'">
        <div>
            <span class="rb-brand-text">Rapha-Bethel</span>
            <span class="rb-brand-sub">BNPS · Douala</span>
        </div>
    </a>
    <div class="rb-topbar-actions">
        {% if user.is_authenticated %}
        <a href="{% url 'communication:announcement_list' %}" class="rb-topbar-btn" title="Announcements">
            <i class="fas fa-bullhorn"></i>
        </a>
        <a href="{% url 'dashboard' %}" class="rb-topbar-btn" title="Dashboard">
            <i class="fas fa-th-large"></i>
        </a>
        <div class="rb-avatar">{{ user.get_full_name|default:user.username|first|upper }}</div>
        {% else %}
        <a href="{% url 'staff:login' %}" class="rb-topbar-btn"><i class="fas fa-sign-in-alt"></i></a>
        {% endif %}
    </div>
</header>

{% if user.is_authenticated %}
<div class="rb-overlay" id="sidebarOverlay"></div>
<aside class="rb-sidebar" id="sidebar">
    {% include 'includes/sidebar.html' %}
</aside>

<nav class="rb-bottom-nav" aria-label="Quick navigation">
    <a href="{% url 'dashboard' %}" class="rb-tab {% if request.path == '/dashboard/' %}active{% endif %}">
        <i class="fas fa-th-large"></i><span>Home</span>
    </a>
    <a href="{% url 'students:student_list' %}" class="rb-tab {% if '/students/' in request.path %}active{% endif %}">
        <i class="fas fa-user-graduate"></i><span>Students</span>
    </a>
    {% if user.staff_profile.role in 'bursar,proprietor,admin,head_master,head_mistress' %}
    <a href="{% url 'finance:bursar_dashboard' %}" class="rb-tab {% if '/finance/' in request.path %}active{% endif %}">
        <i class="fas fa-coins"></i><span>Finance</span>
    </a>
    {% else %}
    <a href="{% url 'academics:class_list' %}" class="rb-tab {% if '/academics/' in request.path %}active{% endif %}">
        <i class="fas fa-chalkboard"></i><span>Classes</span>
    </a>
    {% endif %}
    <a href="{% url 'communication:sms_compose' %}" class="rb-tab {% if '/communication/' in request.path %}active{% endif %}">
        <i class="fas fa-comment-sms"></i><span>SMS</span>
    </a>
    <button class="rb-tab" id="mobileMenuBtn"><i class="fas fa-bars"></i><span>Menu</span></button>
</nav>
{% endif %}

<div id="rb-offline-bar"><i class="fas fa-wifi-slash me-1"></i> No internet — limited features</div>

<main class="rb-main-wrap" id="mainContent">
    {% if messages %}
    <div class="mb-3">
        {% for message in messages %}
        <div class="rb-alert rb-alert-{% if message.tags == 'error' %}danger{% elif message.tags == 'warning' %}warning{% elif message.tags == 'success' %}success{% else %}info{% endif %} d-flex align-items-start gap-2 js-auto-dismiss">
            <i class="fas fa-{% if message.tags == 'error' or message.tags == 'danger' %}exclamation-circle{% elif message.tags == 'warning' %}exclamation-triangle{% elif message.tags == 'success' %}check-circle{% else %}info-circle{% endif %} mt-1 flex-shrink-0"></i>
            <div>{{ message }}</div>
            <button type="button" onclick="this.closest('.rb-alert').remove()" style="margin-left:auto;background:none;border:none;cursor:pointer;opacity:.5;font-size:1.1rem;">&times;</button>
        </div>
        {% endfor %}
    </div>
    {% endif %}

    {% block content %}{% endblock %}
</main>

{% include 'includes/footer.html' %}

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="{% static 'js/main.js' %}"></script>
{% block extra_js %}{% endblock %}
</body>
</html>


======================================================================
FILE: templates/base.html
======================================================================
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <meta name="theme-color" content="#8B0000">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <title>{% block title %}Rapha-Bethel BNPS{% endblock %}</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
    {% load static %}
    <link rel="stylesheet" href="{% static 'css/custom.css' %}">
    {% block extra_css %}{% endblock %}
    <!-- Favicons -->
    <link rel="icon" type="image/x-icon"       href="{% static 'img/favicon.ico' %}">
    <link rel="icon" type="image/png" sizes="16x16"  href="{% static 'img/favicon-16.png' %}">
    <link rel="icon" type="image/png" sizes="32x32"  href="{% static 'img/favicon-32.png' %}">
    <link rel="icon" type="image/png" sizes="192x192" href="{% static 'img/favicon-192.png' %}">
    <link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/apple-touch-icon.png' %}">
</head>
<body>
{% load static %}

<!-- TOP BAR -->
<header class="rb-topbar">
    {% if user.is_authenticated %}
    <button class="rb-menu-toggle" id="sidebarToggle" aria-label="Toggle menu">
        <span></span><span></span><span></span>
    </button>
    {% endif %}
    <a href="/portal" class="rb-brand">
        <picture>
            <source srcset="{% static 'admin/img/logo-nav.webp' %}" type="image/webp">
            <img src="{% static 'admin/img/logo-nav.png' %}" alt="Rapha-Bethel" width="34" height="34">
        </picture>
        <div>
            <span class="rb-brand-text">Rapha-Bethel</span>
            <span class="rb-brand-sub">BNPS · Douala</span>
        </div>
    </a>
    <div class="rb-topbar-actions">
        {% if user.is_authenticated %}
        <a href="{% url 'communication:announcement_list' %}" class="rb-topbar-btn" title="Announcements">
            <i class="fas fa-bullhorn"></i>
        </a>
        <a href="{% url 'dashboard' %}" class="rb-topbar-btn" title="Dashboard">
            <i class="fas fa-th-large"></i>
        </a>
        <div class="rb-avatar" title="{{ user.get_full_name|default:user.username }}">
            {{ user.get_full_name|default:user.username|first|upper }}
        </div>
        {% else %}
        <a href="{% url 'staff:login' %}" class="rb-topbar-btn"><i class="fas fa-sign-in-alt"></i></a>
        {% endif %}
    </div>
</header>

{% if user.is_authenticated %}
<div class="rb-overlay" id="sidebarOverlay"></div>
<aside class="rb-sidebar" id="sidebar">{% include 'includes/sidebar.html' %}</aside>

<!-- MOBILE BOTTOM TAB BAR -->
<nav class="rb-bottom-nav" aria-label="Quick navigation">
    <a href="{% url 'dashboard' %}" class="rb-tab {% if request.path == '/dashboard/' %}active{% endif %}">
        <i class="fas fa-th-large"></i><span>Home</span>
    </a>
    <a href="{% url 'students:student_list' %}" class="rb-tab {% if '/students/' in request.path %}active{% endif %}">
        <i class="fas fa-user-graduate"></i><span>Students</span>
    </a>
    {% if user.staff_profile.role in 'bursar,proprietor,admin,head_master,head_mistress' %}
    <a href="{% url 'finance:bursar_dashboard' %}" class="rb-tab {% if '/finance/' in request.path %}active{% endif %}">
        <i class="fas fa-coins"></i><span>Finance</span>
    </a>
    {% else %}
    <a href="{% url 'academics:class_list' %}" class="rb-tab {% if '/academics/' in request.path %}active{% endif %}">
        <i class="fas fa-chalkboard"></i><span>Classes</span>
    </a>
    {% endif %}
    <a href="{% url 'communication:sms_compose' %}" class="rb-tab {% if '/communication/' in request.path %}active{% endif %}">
        <i class="fas fa-comment-sms"></i><span>SMS</span>
    </a>
    <button class="rb-tab" id="mobileMenuBtn"><i class="fas fa-bars"></i><span>Menu</span></button>
</nav>
{% endif %}

<div id="rb-offline-bar"><i class="fas fa-wifi-slash me-1"></i> No internet — limited features</div>

<div class="rb-shell">
<main class="rb-main-wrap" id="mainContent">
    {% if messages %}
    <div class="mb-3">
        {% for message in messages %}
        <div class="rb-alert rb-alert-{% if message.tags == 'error' %}danger{% elif message.tags == 'warning' %}warning{% elif message.tags == 'success' %}success{% else %}info{% endif %} d-flex align-items-start gap-2 js-auto-dismiss">
            <i class="fas fa-{% if message.tags == 'error' or message.tags == 'danger' %}exclamation-circle{% elif message.tags == 'warning' %}exclamation-triangle{% elif message.tags == 'success' %}check-circle{% else %}info-circle{% endif %} mt-1 flex-shrink-0"></i>
            <div style="flex:1">{{ message }}</div>
            <button onclick="this.closest('.rb-alert').remove()" style="background:none;border:none;cursor:pointer;opacity:.5;font-size:1.1rem;padding:0">&times;</button>
        </div>
        {% endfor %}
    </div>
    {% endif %}
    {% block content %}{% endblock %}
</main>

{% include 'includes/footer.html' %}
</div>{# /rb-shell #}

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script src="{% static 'js/main.js' %}"></script>
{% block extra_js %}{% endblock %}
</body>
</html>

======================================================================
FILE: templates/dashboard-1.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Dashboard - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .stat-card {
        transition: transform 0.3s;
        border-radius: 10px;
        overflow: hidden;
    }
    .stat-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.15) !important;
    }
    .stat-icon {
        font-size: 2.5rem;
        opacity: 0.8;
    }
    .progress {
        height: 10px;
        border-radius: 5px;
    }
    .birthday-badge {
        background: linear-gradient(45deg, #FF9800, #FF5722);
        color: white;
        padding: 3px 10px;
        border-radius: 20px;
        font-size: 0.8rem;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Page Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Dashboard</h1>
        <div class="btn-group">
            <button class="btn btn-primary">
                <i class="fas fa-plus"></i> Quick Action
            </button>
        </div>
    </div>

    <!-- Stats Cards -->
    <div class="row">
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
                                Total Students
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_students }}</div>
                            <div class="mt-2 mb-0 text-muted text-xs">
                                <span class="text-success mr-2">
                                    <i class="fas fa-arrow-up"></i> 12%
                                </span>
                                <span>Since last month</span>
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-user-graduate stat-icon text-primary"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
                                Today's Attendance
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ today_attendance }}</div>
                            <div class="mt-2">
                                <div class="progress">
                                    <div class="progress-bar bg-success" role="progressbar" 
                                         style="width: {{ attendance_rate }}%">
                                    </div>
                                </div>
                                <small class="text-muted">{{ attendance_rate }}% Present</small>
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-clipboard-check stat-icon text-success"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
                                Pending Invoices
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ pending_invoices }}</div>
                            <div class="mt-2 mb-0 text-muted text-xs">
                                {% if overdue_invoices > 0 %}
                                <span class="text-danger">
                                    <i class="fas fa-exclamation-triangle"></i> {{ overdue_invoices }} overdue
                                </span>
                                {% else %}
                                <span class="text-success">All invoices are current</span>
                                {% endif %}
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-file-invoice-dollar stat-icon text-warning"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-info text-uppercase mb-1">
                                Total Revenue
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">
                                {{ total_revenue|floatformat:0 }} XAF
                            </div>
                            <div class="mt-2 mb-0 text-muted text-xs">
                                <span class="text-success mr-2">
                                    <i class="fas fa-arrow-up"></i> 8%
                                </span>
                                <span>Since last month</span>
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-money-bill-wave stat-icon text-info"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Charts and Recent Data -->
    <div class="row">
        <!-- Attendance Chart -->
        <div class="col-xl-8 col-lg-7">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                    <h6 class="m-0 font-weight-bold text-primary">Weekly Attendance Trend</h6>
                </div>
                <div class="card-body">
                    <div class="chart-area">
                        <canvas id="attendanceChart" height="300"></canvas>
                    </div>
                </div>
            </div>
        </div>

        <!-- Upcoming Birthdays -->
        <div class="col-xl-4 col-lg-5">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
                    <h6 class="m-0 font-weight-bold text-primary">Upcoming Birthdays</h6>
                </div>
                <div class="card-body">
                    {% if upcoming_birthdays %}
                    <div class="list-group list-group-flush">
                        {% for student in upcoming_birthdays %}
                        <div class="list-group-item d-flex align-items-center">
                            <div class="mr-3">
                                <div class="icon-circle bg-warning">
                                    <i class="fas fa-birthday-cake text-white"></i>
                                </div>
                            </div>
                            <div class="flex-grow-1">
                                <div class="font-weight-bold">{{ student.first_name }} {{ student.last_name }}</div>
                                <div class="text-muted small">
                                    {{ student.date_of_birth|date:"F d" }} • {{ student.current_class|default:"No Class" }}
                                </div>
                            </div>
                            <span class="birthday-badge">{{ student.date_of_birth|date:"d M" }}</span>
                        </div>
                        {% endfor %}
                    </div>
                    {% else %}
                    <p class="text-muted text-center py-4">No upcoming birthdays</p>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>

    <!-- Recent Students & Announcements -->
    <div class="row">
        <!-- Recent Students -->
        <div class="col-lg-6 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Recent Admissions</h6>
                </div>
                <div class="card-body">
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>Student</th>
                                    <th>Admission Date</th>
                                    <th>Class</th>
                                    <th>Status</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for student in recent_students %}
                                <tr>
                                    <td>
                                        <strong>{{ student.first_name }} {{ student.last_name }}</strong><br>
                                        <small class="text-muted">{{ student.student_id }}</small>
                                    </td>
                                    <td>{{ student.admission_date|date:"d M Y" }}</td>
                                    <td>
                                        {% if student.current_class %}
                                        <span class="badge badge-info">{{ student.current_class }}</span>
                                        {% else %}
                                        <span class="badge badge-secondary">Not Assigned</span>
                                        {% endif %}
                                    </td>
                                    <td>
                                        {% if student.status == 'active' %}
                                        <span class="badge badge-success">Active</span>
                                        {% else %}
                                        <span class="badge badge-warning">{{ student.status|title }}</span>
                                        {% endif %}
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>

        <!-- Recent Announcements -->
        <div class="col-lg-6 mb-4">
            <div class="card shadow">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Recent Announcements</h6>
                    <a href="/admin/communication/announcement/add/" class="btn btn-sm btn-primary">
                        <i class="fas fa-plus"></i> New
                    </a>
                </div>
                <div class="card-body">
                    {% for announcement in recent_announcements %}
                    <div class="mb-3 pb-3 border-bottom">
                        <h6 class="font-weight-bold">{{ announcement.title }}</h6>
                        <p class="text-muted small mb-2">{{ announcement.content|truncatewords:20 }}</p>
                        <div class="d-flex justify-content-between align-items-center">
                            <small class="text-muted">
                                <i class="far fa-clock"></i> {{ announcement.publish_date|timesince }} ago
                            </small>
                            <span class="badge badge-{{ announcement.priority }}">
                                {{ announcement.get_priority_display }}
                            </span>
                        </div>
                    </div>
                    {% empty %}
                    <p class="text-muted text-center py-4">No announcements yet</p>
                    {% endfor %}
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Attendance Chart
document.addEventListener('DOMContentLoaded', function() {
    const ctx = document.getElementById('attendanceChart').getContext('2d');
    const attendanceChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: {{ attendance_labels|safe }},
            datasets: [{
                label: 'Attendance',
                data: {{ attendance_data }},
                borderColor: '#4e73df',
                backgroundColor: 'rgba(78, 115, 223, 0.05)',
                pointRadius: 3,
                pointBackgroundColor: '#4e73df',
                pointBorderColor: '#4e73df',
                pointHoverRadius: 5,
                fill: true,
                tension: 0.4
            }]
        },
        options: {
            maintainAspectRatio: false,
            scales: {
                x: {
                    grid: {
                        display: false
                    }
                },
                y: {
                    beginAtZero: true,
                    ticks: {
                        precision: 0
                    }
                }
            },
            plugins: {
                legend: {
                    display: false
                }
            }
        }
    });
    
    // Add animation to stats cards
    document.querySelectorAll('.stat-card').forEach(card => {
        card.addEventListener('mouseenter', function() {
            this.style.transform = 'translateY(-5px)';
        });
        card.addEventListener('mouseleave', function() {
            this.style.transform = 'translateY(0)';
        });
    });
});
</script>
{% endblock %}

======================================================================
FILE: templates/dashboard.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Dashboard — Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
.dash-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; }
@media (min-width: 480px) { .dash-grid-2 { grid-template-columns: 1fr 1fr; } }
@media (min-width: 768px) { .dash-grid-4 { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 768px) { .dash-grid-2-1 { grid-template-columns: 2fr 1fr; } }

.kpi { background:#fff; border-radius:12px; padding:1rem 1.1rem; border:1px solid #ede8e3; box-shadow:0 1px 4px rgba(0,0,0,.07); display:flex; align-items:center; gap:0.9rem; }
.kpi-icon { width:46px;height:46px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0; }
.kpi-icon.blue   { background:#eff6ff; color:#3b82f6; }
.kpi-icon.green  { background:#f0fdf4; color:#22c55e; }
.kpi-icon.gold   { background:#fffbeb; color:var(--rb-gold); }
.kpi-icon.red    { background:#fef2f2; color:var(--rb-red); }
.kpi-label { font-size:0.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:#999;margin-bottom:2px; }
.kpi-value { font-size:1.5rem;font-weight:700;color:#1a1a1a;line-height:1; }
.kpi-sub { font-size:0.72rem;color:#aaa;margin-top:3px; }
.kpi-progress { height:4px;border-radius:4px;background:#f0ebe5;margin-top:6px; }
.kpi-progress-bar { height:100%;border-radius:4px;background:linear-gradient(90deg,#22c55e,#16a34a); }

.rb-section-title { font-size:0.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.6px;color:#999;margin:0 0 0.75rem; }

.chart-wrap { position:relative; height:200px; }
@media (min-width:600px) { .chart-wrap { height:240px; } }

.birthday-row { display:flex;align-items:center;gap:0.75rem;padding:0.6rem 0;border-bottom:1px solid #f5f0ea; }
.birthday-row:last-child { border-bottom:none; }
.birthday-avatar { width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,#fbbf24,#f59e0b);color:#fff;font-weight:700;font-size:0.85rem;display:flex;align-items:center;justify-content:center;flex-shrink:0; }
.birthday-name { font-weight:600;font-size:0.85rem;line-height:1.2; }
.birthday-meta { font-size:0.75rem;color:#aaa; }
.birthday-badge { margin-left:auto;background:#fef9c3;color:#854d0e;border-radius:20px;padding:0.15rem 0.55rem;font-size:0.7rem;font-weight:700;flex-shrink:0; }

.admit-row { display:flex;align-items:center;gap:0.75rem;padding:0.65rem 0;border-bottom:1px solid #f5f0ea; }
.admit-row:last-child { border-bottom:none; }
.admit-avatar { width:34px;height:34px;border-radius:8px;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-red));color:#fff;font-weight:700;font-size:0.85rem;display:flex;align-items:center;justify-content:center;flex-shrink:0; }
.admit-name { font-weight:600;font-size:0.85rem;line-height:1.2; }
.admit-meta { font-size:0.75rem;color:#aaa; }

.announce-item { padding:0.75rem 0;border-bottom:1px solid #f5f0ea; }
.announce-item:last-child { border-bottom:none; }
.announce-title { font-weight:600;font-size:0.875rem;margin-bottom:0.2rem; }
.announce-body { font-size:0.8rem;color:#777;margin-bottom:0.35rem; }
.announce-meta { display:flex;align-items:center;justify-content:space-between;gap:0.5rem; }
.priority-high   { background:#fee2e2;color:#991b1b;border-radius:20px;padding:.1rem .5rem;font-size:.68rem;font-weight:700; }
.priority-medium { background:#fef9c3;color:#854d0e;border-radius:20px;padding:.1rem .5rem;font-size:.68rem;font-weight:700; }
.priority-low    { background:#f0fdf4;color:#166534;border-radius:20px;padding:.1rem .5rem;font-size:.68rem;font-weight:700; }
.priority-urgent { background:#7f1d1d;color:#fff;border-radius:20px;padding:.1rem .5rem;font-size:.68rem;font-weight:700; }

.quick-action { display:flex;align-items:center;gap:0.65rem;padding:.65rem .85rem;border-radius:10px;background:#fff;border:1px solid #ede8e3;text-decoration:none;color:#333;font-size:.875rem;font-weight:500;transition:all .15s;min-height:48px; }
.quick-action:hover { border-color:var(--rb-red);color:var(--rb-red);background:#fff5f5;transform:translateX(3px); }
.quick-action i { width:20px;text-align:center;color:var(--rb-red);flex-shrink:0; }
</style>
{% endblock %}

{% block content %}
<!-- Page header -->
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">Dashboard</h1>
        <p class="rb-page-subtitle">School overview &middot; {% now "l, d N Y" %}</p>
    </div>
    <a href="{% url 'communication:announcement_create' %}" class="btn btn-rb-primary btn-sm">
        <i class="fas fa-plus me-1"></i> Announcement
    </a>
</div>

<!-- KPI CARDS -->
<div class="dash-grid dash-grid-2 dash-grid-4 mb-4">
    <div class="kpi">
        <div class="kpi-icon blue"><i class="fas fa-user-graduate"></i></div>
        <div>
            <div class="kpi-label">Students</div>
            <div class="kpi-value">{{ total_students }}</div>
            <div class="kpi-sub">{{ total_classes }} class{{ total_classes|pluralize:"es" }}</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon green"><i class="fas fa-clipboard-check"></i></div>
        <div style="flex:1;min-width:0">
            <div class="kpi-label">Today's Attendance</div>
            <div class="kpi-value">{{ attendance_rate }}%</div>
            <div class="kpi-progress"><div class="kpi-progress-bar" style="width:{{ attendance_rate }}%"></div></div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon gold"><i class="fas fa-file-invoice-dollar"></i></div>
        <div>
            <div class="kpi-label">Pending Invoices</div>
            <div class="kpi-value">{{ pending_invoices }}</div>
            {% if overdue_invoices > 0 %}
            <div class="kpi-sub" style="color:var(--rb-red)"><i class="fas fa-exclamation-circle"></i> {{ overdue_invoices }} overdue</div>
            {% else %}
            <div class="kpi-sub" style="color:#22c55e"><i class="fas fa-check-circle"></i> None overdue</div>
            {% endif %}
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon red"><i class="fas fa-coins"></i></div>
        <div>
            <div class="kpi-label">Total Revenue</div>
            <div class="kpi-value" style="font-size:1.1rem">{{ total_revenue|floatformat:0 }}</div>
            <div class="kpi-sub">XAF collected</div>
        </div>
    </div>
</div>

<!-- CHART + BIRTHDAYS -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <!-- Attendance trend -->
    <div class="card">
        <div class="card-header d-flex align-items-center justify-content-between">
            <span class="rb-section-title mb-0">7-Day Attendance Trend</span>
            <a href="{% url 'reports:attendance_report' %}" class="btn btn-sm btn-outline-secondary" style="font-size:.75rem;padding:.2rem .6rem">Full Report</a>
        </div>
        <div class="card-body">
            <div class="chart-wrap">
                <canvas id="attendanceChart"></canvas>
            </div>
        </div>
    </div>

    <!-- Upcoming birthdays -->
    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">🎂 Birthdays This Month</span></div>
        <div class="card-body" style="padding-top:.5rem">
            {% if upcoming_birthdays %}
                {% for s in upcoming_birthdays %}
                <div class="birthday-row">
                    <div class="birthday-avatar">{{ s.first_name|first }}{{ s.last_name|first }}</div>
                    <div>
                        <div class="birthday-name">{{ s.first_name }} {{ s.last_name }}</div>
                        <div class="birthday-meta">{{ s.current_class|default:"No class" }}</div>
                    </div>
                    <span class="birthday-badge">{{ s.date_of_birth|date:"d M" }}</span>
                </div>
                {% endfor %}
            {% else %}
                <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No birthdays this month</p>
            {% endif %}
        </div>
    </div>
</div>

<!-- RECENT ADMISSIONS + ANNOUNCEMENTS -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <!-- Recent students -->
    <div class="card">
        <div class="card-header d-flex align-items-center justify-content-between">
            <span class="rb-section-title mb-0">Recent Admissions</span>
            <a href="{% url 'students:student_list' %}" class="btn btn-sm btn-outline-secondary" style="font-size:.75rem;padding:.2rem .6rem">All Students</a>
        </div>
        <div class="card-body" style="padding-top:.5rem">
            {% for s in recent_students %}
            <div class="admit-row">
                <div class="admit-avatar">{{ s.first_name|first }}{{ s.last_name|first }}</div>
                <div style="flex:1;min-width:0">
                    <div class="admit-name">{{ s.first_name }} {{ s.last_name }}</div>
                    <div class="admit-meta">{{ s.student_id }} &middot; {{ s.admission_date|date:"d M Y" }}</div>
                </div>
                {% if s.status == 'active' %}
                <span class="rb-badge rb-badge-green">Active</span>
                {% elif s.current_class %}
                <span class="rb-badge rb-badge-blue">{{ s.current_class }}</span>
                {% else %}
                <span class="rb-badge rb-badge-gray">Unassigned</span>
                {% endif %}
            </div>
            {% empty %}
            <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No recent admissions</p>
            {% endfor %}
        </div>
    </div>

    <!-- Announcements + Quick Actions stacked -->
    <div style="display:flex;flex-direction:column;gap:1rem">
        <div class="card">
            <div class="card-header d-flex align-items-center justify-content-between">
                <span class="rb-section-title mb-0">Announcements</span>
                <a href="{% url 'communication:announcement_list' %}" style="font-size:.75rem;color:var(--rb-red)">View all</a>
            </div>
            <div class="card-body" style="padding-top:.5rem">
                {% for ann in recent_announcements %}
                <div class="announce-item">
                    <div class="announce-title">{{ ann.title }}</div>
                    <div class="announce-body">{{ ann.content|truncatewords:12 }}</div>
                    <div class="announce-meta">
                        <span style="font-size:.72rem;color:#bbb"><i class="far fa-clock"></i> {{ ann.publish_date|timesince }} ago</span>
                        <span class="priority-{{ ann.priority }}">{{ ann.get_priority_display }}</span>
                    </div>
                </div>
                {% empty %}
                <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No announcements</p>
                {% endfor %}
            </div>
        </div>

        <div class="card">
            <div class="card-header"><span class="rb-section-title mb-0">Quick Actions</span></div>
            <div class="card-body" style="display:flex;flex-direction:column;gap:.5rem;padding-top:.6rem">
                <a href="{% url 'students:student_add' %}" class="quick-action"><i class="fas fa-user-plus"></i> Add Student</a>
                <a href="{% url 'finance:payment_add' %}" class="quick-action"><i class="fas fa-money-bill-wave"></i> Record Payment</a>
                <a href="{% url 'communication:sms_compose' %}" class="quick-action"><i class="fas fa-comment-sms"></i> Send SMS</a>
                <a href="{% url 'reports:academic_report' %}" class="quick-action"><i class="fas fa-chart-bar"></i> View Reports</a>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
(function(){
    const ctx = document.getElementById('attendanceChart');
    if (!ctx) return;
    new Chart(ctx, {
        type: 'line',
        data: {
            labels: {{ attendance_labels|safe }},
            datasets: [{
                label: 'Students Present',
                data: {{ attendance_data|safe }},
                borderColor: '#8B0000',
                backgroundColor: 'rgba(139,0,0,.08)',
                pointBackgroundColor: '#8B0000',
                pointRadius: 4,
                pointHoverRadius: 6,
                fill: true,
                tension: 0.4,
                borderWidth: 2
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            plugins: { legend: { display: false } },
            scales: {
                x: { grid: { display: false }, ticks: { font: { size: 11 } } },
                y: { beginAtZero: true, ticks: { precision: 0, font: { size: 11 } }, grid: { color: '#f5f0ea' } }
            }
        }
    });
})();
</script>
{% endblock %}


======================================================================
FILE: templates/home-1.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Welcome to Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="hero-section text-center py-5">
    <div class="container">
        <img src="{% static 'admin/img/logo-red.jpeg' %}" alt="Rapha-Bethel BNPS Logo" class="mb-4" height="120">
        <h1 class="display-4 fw-bold text-primary">Welcome to Rapha-Bethel BNPS</h1>
        <p class="lead">Comprehensive School Management System</p>
        
        <div class="row mt-5">
            <div class="col-md-4 mb-4">
                <div class="card h-100 shadow">
                    <div class="card-body text-center">
                        <i class="fas fa-user-graduate fa-3x text-primary mb-3"></i>
                        <h3>Student Management</h3>
                        <p>Track student information, attendance, and academic progress</p>
                    </div>
                </div>
            </div>
            
            <div class="col-md-4 mb-4">
                <div class="card h-100 shadow">
                    <div class="card-body text-center">
                        <i class="fas fa-chalkboard-teacher fa-3x text-success mb-3"></i>
                        <h3>Academic Management</h3>
                        <p>Manage classes, subjects, and academic schedules</p>
                    </div>
                </div>
            </div>
            
            <div class="col-md-4 mb-4">
                <div class="card h-100 shadow">
                    <div class="card-body text-center">
                        <i class="fas fa-money-bill-wave fa-3x text-warning mb-3"></i>
                        <h3>Finance Management</h3>
                        <p>Handle fees, invoices, and financial reporting</p>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="mt-5">
            {% if user.is_authenticated %}
            <a href="{% url 'dashboard' %}" class="btn btn-primary btn-lg px-5">
                <i class="fas fa-tachometer-alt"></i> Go to Dashboard
            </a>
            {% else %}
            <a href="{% url 'admin:login' %}" class="btn btn-primary btn-lg px-5 me-3">
                <i class="fas fa-sign-in-alt"></i> Staff Login
            </a>
            <a href="#" class="btn btn-outline-primary btn-lg px-5">
                <i class="fas fa-info-circle"></i> Learn More
            </a>
            {% endif %}
        </div>
    </div>
</div>

<div class="container py-5">
    <h2 class="text-center mb-5">School Features</h2>
    <div class="row">
        <div class="col-lg-6">
            <ul class="list-group list-group-flush">
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Student Registration & Management
                </li>
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Attendance Tracking
                </li>
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Grade Management
                </li>
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Fee Collection & Invoicing
                </li>
            </ul>
        </div>
        <div class="col-lg-6">
            <ul class="list-group list-group-flush">
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Parent Communication
                </li>
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Staff Management
                </li>
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Library Management
                </li>
                <li class="list-group-item">
                    <i class="fas fa-check text-success me-2"></i>
                    Reports & Analytics
                </li>
            </ul>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/home.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Rapha-Bethel BNPS — School Management{% endblock %}

{% block extra_css %}
<style>
/* Home page — unauthenticated landing */
.home-wrap {
    min-height: calc(100vh - var(--rb-nav-h));
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2rem 1.25rem;
    background: linear-gradient(160deg, #fdf8f3 0%, #f2ebe2 100%);
}
.home-card {
    width: 100%;
    max-width: 420px;
    background: #fff;
    border-radius: 16px;
    box-shadow: 0 8px 40px rgba(0,0,0,.12);
    overflow: hidden;
}
.home-card-header {
    background: linear-gradient(135deg, var(--rb-red-dark), var(--rb-red));
    padding: 2rem 2rem 1.5rem;
    text-align: center;
    position: relative;
}
.home-card-header::after {
    content: '';
    position: absolute;
    bottom: -1px; left: 0; right: 0;
    height: 20px;
    background: #fff;
    border-radius: 16px 16px 0 0;
}
.home-logo {
    width: 88px; height: 132px;
    object-fit: contain;
    filter: drop-shadow(0 4px 12px rgba(0,0,0,.3));
    margin-bottom: 1rem;
}
.home-school-name {
    color: #fff;
    font-size: 1.2rem;
    font-weight: 700;
    line-height: 1.2;
    margin: 0;
}
.home-school-sub {
    color: rgba(255,255,255,.75);
    font-size: 0.8rem;
    margin-top: 0.25rem;
}
.home-card-body { padding: 1.5rem 2rem 2rem; }
.home-card-body h2 {
    font-size: 1.1rem;
    font-weight: 700;
    color: #1a1a1a;
    margin-bottom: 0.35rem;
}
.home-card-body p {
    font-size: 0.85rem;
    color: #888;
    margin-bottom: 1.5rem;
}
.btn-login {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.85rem 1rem;
    border-radius: 10px;
    font-weight: 600;
    font-size: 0.95rem;
    text-decoration: none;
    transition: all .2s;
    min-height: 50px;
    margin-bottom: 0.75rem;
}
.btn-login-staff {
    background: linear-gradient(135deg, var(--rb-red-dark), var(--rb-red));
    color: #fff;
    border: none;
}
.btn-login-staff:hover { background: linear-gradient(135deg, var(--rb-red), var(--rb-red-light)); color: #fff; transform: translateY(-1px); box-shadow: 0 4px 16px rgba(139,0,0,.3); }
.btn-login-parent {
    background: #fff;
    color: var(--rb-red);
    border: 2px solid var(--rb-red);
}
.btn-login-parent:hover { background: #fff5f5; color: var(--rb-red); transform: translateY(-1px); }
.home-meta {
    text-align: center;
    font-size: 0.75rem;
    color: #bbb;
    margin-top: 1.25rem;
}

/* If authenticated — show a fast-redirect card instead */
.home-auth-wrap {
    text-align: center;
    padding: 3rem 1.25rem;
}
.home-auth-wrap h1 { font-size: 1.4rem; font-weight: 700; margin-bottom: 0.5rem; }
.home-auth-wrap p { color: #888; font-size: 0.9rem; margin-bottom: 1.5rem; }

/* Quick-stat pills (shown when authenticated) */
.quick-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin-bottom: 1.5rem;
}
.quick-pill {
    background: #fff;
    border: 1px solid #ede8e3;
    border-radius: 20px;
    padding: 0.35rem 0.9rem;
    font-size: 0.82rem;
    font-weight: 600;
    color: #444;
    display: flex;
    align-items: center;
    gap: 0.4rem;
}
.quick-pill i { color: var(--rb-red); }
</style>
{% endblock %}

{% block content %}
{% if user.is_authenticated %}
<!-- Authenticated: fast-forward to dashboard -->
<div class="home-auth-wrap">
    <picture>
        <source srcset="{% static 'admin/img/logo-nav.webp' %}" type="image/webp">
        <img src="{% static 'admin/img/logo-nav.png' %}" alt="Logo" width="56" height="56" style="border-radius:12px;margin-bottom:1rem;">
    </picture>
    <h1>Welcome back, {{ user.get_full_name|default:user.username }}</h1>
    <p>You're signed in to the Rapha-Bethel School Management System.</p>
    <a href="{% url 'dashboard' %}" class="btn btn-rb-primary btn-lg px-5">
        <i class="fas fa-th-large me-2"></i> Go to Dashboard
    </a>
        <div class="home-meta mt-3">
            <form method="post" action="{% url 'staff:logout' %}" style="margin:0;display:inline">
                {% csrf_token %}
                <button type="submit" style="background:none;border:none;color:#bbb;cursor:pointer;font-size:.75rem;padding:0">Sign out</button>
            </form>
        </div>
</div>

{% else %}
<!-- Unauthenticated: clean login landing -->
<div class="home-wrap">
    <div class="home-card">
        <div class="home-card-header">
            <picture>
                <source srcset="{% static 'admin/img/logo-hero.webp' %}" type="image/webp">
                <img src="{% static 'admin/img/logo-hero.png' %}" alt="Rapha-Bethel BNPS" class="home-logo">
            </picture>
            <p class="home-school-name">Rapha-Bethel BNPS</p>
            <p class="home-school-sub">Bilingual Nursery &amp; Primary School &middot; Douala</p>
        </div>

        <div class="home-card-body">
            <h2>School Management System</h2>
            <p>Sign in to access student records, attendance, finance &amp; more.</p>

            <a href="{% url 'staff:login' %}" class="btn-login btn-login-staff">
                <i class="fas fa-id-badge"></i> Staff &amp; Admin Login
            </a>
            <a href="{% url 'parents:parent_login' %}" class="btn-login btn-login-parent">
                <i class="fas fa-users"></i> Parent Portal
            </a>

            <div class="home-meta">
                Rapha-Bethel BNPS &middot; &copy; {% now "Y" %} Vi-2s-Dk Foundation
            </div>
        </div>
    </div>
</div>
{% endif %}
{% endblock %}

======================================================================
FILE: templates/academics/assign_class_teacher.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Assign Class Teacher — {{ school_class.name }}{% endblock %}

{% block content %}
<div class="container-fluid">

  <!-- Breadcrumb -->
  <nav aria-label="breadcrumb" class="mb-3">
    <ol class="breadcrumb">
      <li class="breadcrumb-item"><a href="{% url 'academics:class_list' %}">Classes</a></li>
      <li class="breadcrumb-item"><a href="{% url 'academics:class_detail' school_class.pk %}">{{ school_class.name }}</a></li>
      <li class="breadcrumb-item active">Assign Class Teacher</li>
    </ol>
  </nav>

  <div class="row justify-content-center">
    <div class="col-lg-7">

      <!-- Current teacher card -->
      <div class="card shadow mb-4">
        <div class="card-header bg-white border-bottom d-flex align-items-center">
          <i class="fas fa-chalkboard-teacher text-primary me-2"></i>
          <strong>{{ school_class.name }} — Class Teacher Assignment</strong>
        </div>
        <div class="card-body">
          {% if current_teacher %}
          <div class="alert alert-info d-flex align-items-center mb-4" role="alert">
            <i class="fas fa-user-check fa-lg me-3 text-info"></i>
            <div>
              <strong>Current class teacher:</strong>
              {{ current_teacher.user.get_full_name }}
              <span class="badge bg-secondary ms-2">{{ current_teacher.get_role_display }}</span>
            </div>
          </div>
          {% else %}
          <div class="alert alert-warning d-flex align-items-center mb-4" role="alert">
            <i class="fas fa-exclamation-triangle fa-lg me-3"></i>
            <div>No class teacher assigned yet.</div>
          </div>
          {% endif %}

          <!-- Assign form -->
          <form method="post">
            {% csrf_token %}
            <div class="mb-3">
              <label for="teacher_id" class="form-label fw-semibold">
                Select new class teacher
              </label>
              <select name="teacher_id" id="teacher_id" class="form-select form-select-lg">
                <option value="">— Remove class teacher —</option>
                {% for teacher in teachers %}
                <option value="{{ teacher.id }}"
                  {% if current_teacher and teacher.id == current_teacher.id %}selected{% endif %}>
                  {{ teacher.user.get_full_name }}
                  ({{ teacher.get_role_display }}
                  {% if teacher.employee_id %} · {{ teacher.employee_id }}{% endif %})
                </option>
                {% endfor %}
              </select>
              <div class="form-text">
                Only staff with role <em>Teacher</em> or <em>Class Teacher</em> are listed.
                To add more staff, change their role in
                <a href="{% url 'staff:staff_list' %}">Staff Management</a>.
              </div>
            </div>

            <div class="d-flex gap-2 mt-4">
              <button type="submit" class="btn btn-primary px-4">
                <i class="fas fa-save me-1"></i> Save Assignment
              </button>
              <a href="{% url 'academics:class_detail' school_class.pk %}" class="btn btn-outline-secondary px-4">
                Cancel
              </a>
            </div>
          </form>
        </div>
      </div>

      <!-- Info box -->
      <div class="card border-0 bg-light">
        <div class="card-body">
          <h6 class="text-muted mb-2"><i class="fas fa-info-circle me-1"></i> What does "Class Teacher" mean?</h6>
          <p class="small text-muted mb-1">
            The <strong>class teacher</strong> (homeroom teacher) is assigned directly to the class.
            They will see this class in the attendance marking dropdown when they log in.
          </p>
          <p class="small text-muted mb-0">
            <strong>Subject teachers</strong> are assigned separately per subject via the class detail page.
            A teacher can be both the class teacher <em>and</em> a subject teacher for the same class.
          </p>
        </div>
      </div>

    </div>
  </div>
</div>
{% endblock %}


======================================================================
FILE: templates/academics/class_detail-1.html
======================================================================
<!-- templates/academics/class_detail.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ class.name }} - Class Details{% endblock %}

{% block extra_css %}
<style>
    .stat-card {
        transition: transform 0.3s, box-shadow 0.3s;
        border-radius: 10px;
        overflow: hidden;
    }
    .stat-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.15);
    }
    .teacher-card {
        border-left: 4px solid #4CAF50;
        transition: all 0.3s;
        padding: 15px;
        margin-bottom: 15px;
        background-color: #f8f9fc;
        border-radius: 8px;
    }
    .teacher-card:hover {
        background-color: #e8f0fe;
        transform: translateX(5px);
    }
    .student-row:hover {
        background-color: #f8f9fc;
        cursor: pointer;
    }
    .class-header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 30px;
        border-radius: 15px;
        margin-bottom: 25px;
        box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
    }
    .info-label {
        font-weight: 600;
        color: #495057;
        width: 150px;
    }
    .avatar-circle {
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background-color: #4CAF50;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: bold;
        font-size: 1.2rem;
        box-shadow: 0 4px 10px rgba(76, 175, 80, 0.3);
    }
    .small-avatar {
        width: 35px;
        height: 35px;
        font-size: 0.9rem;
    }
    .badge-subject {
        background-color: #e3f2fd;
        color: #1976d2;
        padding: 5px 10px;
        border-radius: 20px;
        font-size: 0.8rem;
        font-weight: 500;
    }
    .progress {
        height: 10px;
        border-radius: 5px;
    }
    .section-title {
        position: relative;
        padding-bottom: 10px;
        margin-bottom: 20px;
    }
    .section-title:after {
        content: '';
        position: absolute;
        bottom: 0;
        left: 0;
        width: 50px;
        height: 3px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 3px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Class Header -->
    <div class="class-header d-flex justify-content-between align-items-center">
        <div>
            <h1 class="mb-2">{{ class.name }}</h1>
            <p class="mb-0">
                <i class="fas fa-code me-2"></i> {{ class.code }} |
                <i class="fas fa-calendar ms-3 me-2"></i> {{ class.academic_year }} |
                <i class="fas fa-users ms-3 me-2"></i> {{ total_students }} Students |
                <i class="fas fa-chalkboard-teacher ms-3 me-2"></i> {{ total_teachers }} Teachers
            </p>
        </div>
        <div>
            <a href="{% url 'academics:class_list' %}" class="btn btn-light me-2">
                <i class="fas fa-arrow-left"></i> Back
            </a>
            <a href="/admin/academics/schoolclass/{{ class.id }}/change/" class="btn btn-warning">
                <i class="fas fa-edit"></i> Edit
            </a>
        </div>
    </div>

    <!-- Quick Stats Cards -->
    <div class="row mb-4">
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-primary shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
                                Total Students
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_students }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-user-plus text-success me-1"></i> Capacity: {{ class.capacity|default:"40" }}
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-users fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-success shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
                                Teachers
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_teachers }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-chalkboard-teacher text-info me-1"></i> {{ total_subjects }} Subjects
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-chalkboard-teacher fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-info shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-info text-uppercase mb-1">
                                Today's Attendance
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ today_attendance|default:"0" }}</div>
                            <div class="progress mt-2">
                                <div class="progress-bar bg-info" role="progressbar" 
                                     style="width: {{ attendance_rate|default:'0' }}%"></div>
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-calendar-check fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-warning shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
                                Section
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ class.get_section_type_display }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-door-open me-1"></i> Room: {{ class.room_number|default:"TBD" }}
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-door-open fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <!-- Left Column - Class Info & Teachers -->
        <div class="col-lg-5">
            <!-- Class Information Card -->
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Class Information</h6>
                    <span class="badge bg-{{ class.section_type }}">{{ class.get_section_type_display }}</span>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td class="info-label">Code:</td>
                            <td><span class="badge bg-secondary">{{ class.code }}</span></td>
                        </tr>
                        <tr>
                            <td class="info-label">Level:</td>
                            <td>{{ class.get_level_display }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Section:</td>
                            <td>{{ class.section|default:"A" }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Academic Year:</td>
                            <td>{{ class.academic_year }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Room Number:</td>
                            <td>{{ class.room_number|default:"<span class='text-muted'>Not assigned</span>" }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Capacity:</td>
                            <td>
                                <div class="d-flex align-items-center">
                                    <span>{{ total_students }}/{{ class.capacity|default:"40" }}</span>
                                    <div class="progress flex-grow-1 ms-3" style="height: 8px;">
                                        {% with percentage=total_students|divisibleby:class.capacity|default:40|floatformat:0 %}
                                        <div class="progress-bar bg-{% if percentage > 90 %}danger{% elif percentage > 75 %}warning{% else %}success{% endif %}" 
                                             style="width: {% widthratio total_students class.capacity|default:40 100 %}%"></div>
                                        {% endwith %}
                                    </div>
                                </div>
                            </td>
                        </tr>
                    </table>
                </div>
            </div>

            <!-- Class Teacher Card -->
            {% if class_teacher %}
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-success">
                        <i class="fas fa-star"></i> Class Teacher
                    </h6>
                </div>
                <div class="card-body">
                    <div class="d-flex align-items-center">
                        <div class="avatar-circle me-3">
                            {{ class_teacher.user.first_name|first|upper }}{{ class_teacher.user.last_name|first|upper }}
                        </div>
                        <div>
                            <h5 class="mb-1">{{ class_teacher.user.get_full_name }}</h5>
                            <p class="text-muted small mb-1">
                                <i class="fas fa-phone"></i> {{ class_teacher.phone_number|default:"No phone" }}
                            </p>
                            <p class="text-muted small mb-0">
                                <i class="fas fa-envelope"></i> {{ class_teacher.user.email }}
                            </p>
                        </div>
                        <div class="ms-auto">
                            <a href="{% url 'staff:staff_detail' class_teacher.pk %}" class="btn btn-sm btn-outline-primary">
                                <i class="fas fa-eye"></i>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
            {% endif %}

            <!-- Subject Teachers Card -->
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-info">
                        <i class="fas fa-chalkboard-teacher"></i> Subject Teachers ({{ total_teachers }})
                    </h6>
                </div>
                <div class="card-body">
                    {% if teachers %}
                        {% for teacher_data in teachers %}
                        <div class="teacher-card">
                            <div class="d-flex justify-content-between align-items-start">
                                <div>
                                    <h6 class="mb-2">{{ teacher_data.teacher.user.get_full_name }}</h6>
                                    <div class="mb-2">
                                        {% for subject in teacher_data.subjects %}
                                        <span class="badge-subject me-1 mb-1">
                                            <i class="fas fa-book me-1"></i>{{ subject.name }}
                                        </span>
                                        {% endfor %}
                                    </div>
                                    <small class="text-muted">
                                        <i class="fas fa-phone"></i> {{ teacher_data.teacher.phone_number|default:"No phone" }}
                                    </small>
                                </div>
                                <a href="{% url 'staff:staff_detail' teacher_data.teacher.pk %}" 
                                   class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </a>
                            </div>
                        </div>
                        {% endfor %}
                    {% else %}
                        <div class="text-center py-4">
                            <i class="fas fa-chalkboard-teacher fa-2x text-muted mb-3"></i>
                            <p class="text-muted">No teachers assigned yet</p>
                            <a href="/admin/academics/classsubject/add/?class={{ class.id }}" 
                               class="btn btn-sm btn-primary">
                                <i class="fas fa-plus"></i> Assign Teacher
                            </a>
                        </div>
                    {% endif %}
                </div>
            </div>
        </div>

        <!-- Right Column - Students List -->
        <div class="col-lg-7">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">
                        <i class="fas fa-users"></i> Students in {{ class.name }} ({{ total_students }})
                    </h6>
                    <div>
                        <a href="{% url 'students:student_add' %}?class={{ class.id }}" class="btn btn-sm btn-success">
                            <i class="fas fa-plus"></i> Add Student
                        </a>
                        <a href="{% url 'students:import_students_csv' %}?class={{ class.id }}" 
                           class="btn btn-sm btn-info">
                            <i class="fas fa-upload"></i> Import
                        </a>
                    </div>
                </div>
                <div class="card-body">
                    {% if students %}
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Student</th>
                                    <th>Gender</th>
                                    <th>Age</th>
                                    <th>Parent Contact</th>
                                    <th>Status</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for student in students %}
                                <tr class="student-row" onclick="window.location='{% url 'students:student_detail' student.pk %}'">
                                    <td><small>{{ student.student_id }}</small></td>
                                    <td>
                                        <div class="d-flex align-items-center">
                                            <div class="avatar-circle small-avatar me-2">
                                                {{ student.first_name|first|upper }}{{ student.last_name|first|upper }}
                                            </div>
                                            <strong>{{ student.first_name }} {{ student.last_name }}</strong>
                                        </div>
                                    </td>
                                    <td>
                                        <span class="badge bg-{% if student.gender == 'M' %}info{% else %}warning{% endif %}">
                                            {{ student.get_gender_display }}
                                        </span>
                                    </td>
                                    <td>{{ student.get_age|default:"-" }}</td>
                                    <td>
                                        {% with parent=student.parents.first %}
                                            {% if parent %}
                                                <small>{{ parent.phone }}</small>
                                            {% else %}
                                                <span class="text-muted">—</span>
                                            {% endif %}
                                        {% endwith %}
                                    </td>
                                    <td>
                                        <span class="badge bg-{% if student.status == 'active' %}success{% else %}secondary{% endif %}">
                                            {{ student.get_status_display }}
                                        </span>
                                    </td>
                                    <td>
                                        <a href="{% url 'students:student_detail' student.pk %}" 
                                           class="btn btn-sm btn-outline-primary" 
                                           onclick="event.stopPropagation();"
                                           title="View">
                                            <i class="fas fa-eye"></i>
                                        </a>
                                        <a href="{% url 'students:student_edit' student.pk %}" 
                                           class="btn btn-sm btn-outline-warning"
                                           onclick="event.stopPropagation();"
                                           title="Edit">
                                            <i class="fas fa-edit"></i>
                                        </a>
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                    {% else %}
                    <div class="text-center py-5">
                        <i class="fas fa-users fa-3x text-muted mb-3"></i>
                        <h5 class="text-muted">No students in this class</h5>
                        <p class="text-muted mb-3">Add students to {{ class.name }} to see them here</p>
                        <a href="{% url 'students:student_add' %}?class={{ class.id }}" class="btn btn-primary">
                            <i class="fas fa-user-plus"></i> Add Student
                        </a>
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>

<!-- Assign Teacher Modal -->
<div class="modal fade" id="assignTeacherModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header bg-success text-white">
                <h5 class="modal-title">Assign Teacher to {{ class.name }}</h5>
                <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
            </div>
            <form method="post" action="{% url 'academics:assign_teacher' class.id %}">
                {% csrf_token %}
                <div class="modal-body">
                    <div class="mb-3">
                        <label class="form-label">Select Teacher</label>
                        <select name="teacher_id" class="form-control" required>
                            <option value="">-- Choose a teacher --</option>
                            {% for teacher in all_teachers %}
                            <option value="{{ teacher.id }}">
                                {{ teacher.user.get_full_name }} ({{ teacher.get_role_display }})
                            </option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Select Subject</label>
                        <select name="subject_id" class="form-control" required>
                            <option value="">-- Choose a subject --</option>
                            {% for subject in all_subjects %}
                            <option value="{{ subject.id }}">{{ subject.name }}</option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Hours per week</label>
                        <input type="number" name="hours_per_week" class="form-control" value="2" min="1" max="10">
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                    <button type="submit" class="btn btn-success">Assign Teacher</button>
                </div>
            </form>
        </div>
    </div>
</div>

{% endblock %}

{% block extra_js %}
<script>
    // Add click handlers or any additional JS here
    document.addEventListener('DOMContentLoaded', function() {
        // Tooltip initialization if needed
        var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
        var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) {
            return new bootstrap.Tooltip(tooltipTriggerEl)
        });
    });
</script>
{% endblock %}

======================================================================
FILE: templates/academics/class_detail.html
======================================================================
<!-- templates/academics/class_detail.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ class.name }} - Class Details{% endblock %}

{% block extra_css %}
<style>
    .stat-card {
        transition: transform 0.3s, box-shadow 0.3s;
        border-radius: 10px;
        overflow: hidden;
    }
    .stat-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.15);
    }
    .teacher-card {
        border-left: 4px solid #4CAF50;
        transition: all 0.3s;
        padding: 15px;
        margin-bottom: 15px;
        background-color: #f8f9fc;
        border-radius: 8px;
    }
    .teacher-card:hover {
        background-color: #e8f0fe;
        transform: translateX(5px);
    }
    .student-row:hover {
        background-color: #f8f9fc;
        cursor: pointer;
    }
    .class-header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 30px;
        border-radius: 15px;
        margin-bottom: 25px;
        box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
    }
    .info-label {
        font-weight: 600;
        color: #495057;
        width: 150px;
    }
    .avatar-circle {
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background-color: #4CAF50;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: bold;
        font-size: 1.2rem;
        box-shadow: 0 4px 10px rgba(76, 175, 80, 0.3);
    }
    .small-avatar {
        width: 35px;
        height: 35px;
        font-size: 0.9rem;
    }
    .badge-subject {
        background-color: #e3f2fd;
        color: #1976d2;
        padding: 5px 10px;
        border-radius: 20px;
        font-size: 0.8rem;
        font-weight: 500;
    }
    .progress {
        height: 10px;
        border-radius: 5px;
    }
    .section-title {
        position: relative;
        padding-bottom: 10px;
        margin-bottom: 20px;
    }
    .section-title:after {
        content: '';
        position: absolute;
        bottom: 0;
        left: 0;
        width: 50px;
        height: 3px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 3px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Class Header -->
    <div class="class-header d-flex justify-content-between align-items-center">
        <div>
            <h1 class="mb-2">{{ class.name }}</h1>
            <p class="mb-0">
                <i class="fas fa-code me-2"></i> {{ class.code }} |
                <i class="fas fa-calendar ms-3 me-2"></i> {{ class.academic_year }} |
                <i class="fas fa-users ms-3 me-2"></i> {{ total_students }} Students |
                <i class="fas fa-chalkboard-teacher ms-3 me-2"></i> {{ total_teachers }} Teachers
            </p>
        </div>
        <div>
            <a href="{% url 'academics:class_list' %}" class="btn btn-light me-2">
                <i class="fas fa-arrow-left"></i> Back
            </a>
            <a href="{% url 'academics:class_edit' class.id %}" class="btn btn-warning">
                <i class="fas fa-edit"></i> Edit
            </a>
        </div>
    </div>

    <!-- Quick Stats Cards -->
    <div class="row mb-4">
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-primary shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
                                Total Students
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_students }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-user-plus text-success me-1"></i> Capacity: {{ class.capacity|default:"40" }}
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-users fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-success shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
                                Teachers
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_teachers }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-chalkboard-teacher text-info me-1"></i> {{ total_subjects }} Subjects
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-chalkboard-teacher fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-info shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-info text-uppercase mb-1">
                                Today's Attendance
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ today_attendance|default:"0" }}</div>
                            <div class="progress mt-2">
                                <div class="progress-bar bg-info" role="progressbar" 
                                     style="width: {{ attendance_rate|default:'0' }}%"></div>
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-calendar-check fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-warning shadow h-100">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
                                Section
                            </div>
                            <div class="h5 mb-0 font-weight-bold text-gray-800">{{ class.get_section_type_display }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-door-open me-1"></i> Room: {{ class.room_number|default:"TBD" }}
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-door-open fa-2x text-gray-300"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <!-- Left Column - Class Info & Teachers -->
        <div class="col-lg-5">
            <!-- Class Information Card -->
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Class Information</h6>
                    <span class="badge bg-{{ class.section_type }}">{{ class.get_section_type_display }}</span>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td class="info-label">Code:</td>
                            <td><span class="badge bg-secondary">{{ class.code }}</span></td>
                        </tr>
                        <tr>
                            <td class="info-label">Level:</td>
                            <td>{{ class.get_level_display }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Section:</td>
                            <td>{{ class.section|default:"A" }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Academic Year:</td>
                            <td>{{ class.academic_year }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Room Number:</td>
                            <td>{{ class.room_number|default:"<span class='text-muted'>Not assigned</span>" }}</td>
                        </tr>
                        <tr>
                            <td class="info-label">Capacity:</td>
                            <td>
                                <div class="d-flex align-items-center">
                                    <span>{{ total_students }}/{{ class.capacity|default:"40" }}</span>
                                    <div class="progress flex-grow-1 ms-3" style="height: 8px;">
                                        {% with percentage=total_students|divisibleby:class.capacity|default:40|floatformat:0 %}
                                        <div class="progress-bar bg-{% if percentage > 90 %}danger{% elif percentage > 75 %}warning{% else %}success{% endif %}" 
                                             style="width: {% widthratio total_students class.capacity|default:40 100 %}%"></div>
                                        {% endwith %}
                                    </div>
                                </div>
                            </td>
                        </tr>
                    </table>
                </div>
            </div>

            <!-- Class Teacher Card -->
            {% if class_teacher %}
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-success">
                        <i class="fas fa-star"></i> Class Teacher
                    </h6>
                    {% if perms_can.staff_edit %}
                    <a href="{% url 'academics:assign_class_teacher' class.id %}" class="btn btn-sm btn-outline-secondary">
                        <i class="fas fa-exchange-alt"></i> Change
                    </a>
                    {% endif %}
                </div>
                <div class="card-body">
                    <div class="d-flex align-items-center">
                        <div class="avatar-circle me-3">
                            {{ class_teacher.user.first_name|first|upper }}{{ class_teacher.user.last_name|first|upper }}
                        </div>
                        <div>
                            <h5 class="mb-1">{{ class_teacher.user.get_full_name }}</h5>
                            <p class="text-muted small mb-1">
                                <i class="fas fa-phone"></i> {{ class_teacher.phone_number|default:"No phone" }}
                            </p>
                            <p class="text-muted small mb-0">
                                <i class="fas fa-envelope"></i> {{ class_teacher.user.email }}
                            </p>
                        </div>
                        <div class="ms-auto">
                            <a href="{% url 'staff:staff_detail' class_teacher.pk %}" class="btn btn-sm btn-outline-primary">
                                <i class="fas fa-eye"></i>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
            {% else %}
            {% if perms_can.staff_edit %}
            <div class="card shadow mb-4 border-warning">
                <div class="card-body text-center py-3">
                    <p class="text-muted small mb-2"><i class="fas fa-exclamation-triangle text-warning me-1"></i> No class teacher assigned</p>
                    <a href="{% url 'academics:assign_class_teacher' class.id %}" class="btn btn-sm btn-warning">
                        <i class="fas fa-user-plus me-1"></i> Assign Class Teacher
                    </a>
                </div>
            </div>
            {% endif %}
            {% endif %}

            <!-- Subject Teachers Card -->
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-info">
                        <i class="fas fa-chalkboard-teacher"></i> Subject Teachers ({{ total_teachers }})
                    </h6>
                </div>
                <div class="card-body">
                    {% if teachers %}
                        {% for teacher_data in teachers %}
                        <div class="teacher-card">
                            <div class="d-flex justify-content-between align-items-start">
                                <div>
                                    <h6 class="mb-2">{{ teacher_data.teacher.user.get_full_name }}</h6>
                                    <div class="mb-2">
                                        {% for subject in teacher_data.subjects %}
                                        <span class="badge-subject me-1 mb-1">
                                            <i class="fas fa-book me-1"></i>{{ subject.name }}
                                        </span>
                                        {% endfor %}
                                    </div>
                                    <small class="text-muted">
                                        <i class="fas fa-phone"></i> {{ teacher_data.teacher.phone_number|default:"No phone" }}
                                    </small>
                                </div>
                                <a href="{% url 'staff:staff_detail' teacher_data.teacher.pk %}" 
                                   class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </a>
                            </div>
                        </div>
                        {% endfor %}
                    {% else %}
                        <div class="text-center py-4">
                            <i class="fas fa-chalkboard-teacher fa-2x text-muted mb-3"></i>
                            <p class="text-muted">No teachers assigned yet</p>
                            <a href="/admin/academics/classsubject/add/?class={{ class.id }}" 
                               class="btn btn-sm btn-primary">
                                <i class="fas fa-plus"></i> Assign Teacher
                            </a>
                        </div>
                    {% endif %}
                </div>
            </div>
        </div>

        <!-- Right Column - Students List -->
        <div class="col-lg-7">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">
                        <i class="fas fa-users"></i> Students in {{ class.name }} ({{ total_students }})
                    </h6>
                    <div>
                        <a href="{% url 'students:student_add' %}?class={{ class.id }}" class="btn btn-sm btn-success">
                            <i class="fas fa-plus"></i> Add Student
                        </a>
                        <a href="{% url 'students:import_students_csv' %}?class={{ class.id }}" 
                           class="btn btn-sm btn-info">
                            <i class="fas fa-upload"></i> Import
                        </a>
                    </div>
                </div>
                <div class="card-body">
                    {% if students %}
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>ID</th>
                                    <th>Student</th>
                                    <th>Gender</th>
                                    <th>Age</th>
                                    <th>Parent Contact</th>
                                    <th>Status</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for student in students %}
                                <tr class="student-row" onclick="window.location='{% url 'students:student_detail' student.pk %}'">
                                    <td><small>{{ student.student_id }}</small></td>
                                    <td>
                                        <div class="d-flex align-items-center">
                                            <div class="avatar-circle small-avatar me-2">
                                                {{ student.first_name|first|upper }}{{ student.last_name|first|upper }}
                                            </div>
                                            <strong>{{ student.first_name }} {{ student.last_name }}</strong>
                                        </div>
                                    </td>
                                    <td>
                                        <span class="badge bg-{% if student.gender == 'M' %}info{% else %}warning{% endif %}">
                                            {{ student.get_gender_display }}
                                        </span>
                                    </td>
                                    <td>{{ student.get_age|default:"-" }}</td>
                                    <td>
                                        {% with parent=student.parents.first %}
                                            {% if parent %}
                                                <small>{{ parent.phone }}</small>
                                            {% else %}
                                                <span class="text-muted">—</span>
                                            {% endif %}
                                        {% endwith %}
                                    </td>
                                    <td>
                                        <span class="badge bg-{% if student.status == 'active' %}success{% else %}secondary{% endif %}">
                                            {{ student.get_status_display }}
                                        </span>
                                    </td>
                                    <td>
                                        <a href="{% url 'students:student_detail' student.pk %}" 
                                           class="btn btn-sm btn-outline-primary" 
                                           onclick="event.stopPropagation();"
                                           title="View">
                                            <i class="fas fa-eye"></i>
                                        </a>
                                        <a href="{% url 'students:student_edit' student.pk %}" 
                                           class="btn btn-sm btn-outline-warning"
                                           onclick="event.stopPropagation();"
                                           title="Edit">
                                            <i class="fas fa-edit"></i>
                                        </a>
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                    {% else %}
                    <div class="text-center py-5">
                        <i class="fas fa-users fa-3x text-muted mb-3"></i>
                        <h5 class="text-muted">No students in this class</h5>
                        <p class="text-muted mb-3">Add students to {{ class.name }} to see them here</p>
                        <a href="{% url 'students:student_add' %}?class={{ class.id }}" class="btn btn-primary">
                            <i class="fas fa-user-plus"></i> Add Student
                        </a>
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>

<!-- Assign Teacher Modal -->
<div class="modal fade" id="assignTeacherModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header bg-success text-white">
                <h5 class="modal-title">Assign Teacher to {{ class.name }}</h5>
                <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
            </div>
            <form method="post" action="{% url 'academics:assign_teacher' class.id %}">
                {% csrf_token %}
                <div class="modal-body">
                    <div class="mb-3">
                        <label class="form-label">Select Teacher</label>
                        <select name="teacher_id" class="form-control" required>
                            <option value="">-- Choose a teacher --</option>
                            {% for teacher in all_teachers %}
                            <option value="{{ teacher.id }}">
                                {{ teacher.user.get_full_name }} ({{ teacher.get_role_display }})
                            </option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Select Subject</label>
                        <select name="subject_id" class="form-control" required>
                            <option value="">-- Choose a subject --</option>
                            {% for subject in all_subjects %}
                            <option value="{{ subject.id }}">{{ subject.name }}</option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Hours per week</label>
                        <input type="number" name="hours_per_week" class="form-control" value="2" min="1" max="10">
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                    <button type="submit" class="btn btn-success">Assign Teacher</button>
                </div>
            </form>
        </div>
    </div>
</div>

{% endblock %}

{% block extra_js %}
<script>
    // Add click handlers or any additional JS here
    document.addEventListener('DOMContentLoaded', function() {
        // Tooltip initialization if needed
        var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
        var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) {
            return new bootstrap.Tooltip(tooltipTriggerEl)
        });
    });
</script>
{% endblock %}

======================================================================
FILE: templates/academics/class_form.html
======================================================================
{% extends 'base.html' %}

{% block title %}{% if object %}Edit Class{% else %}Add Class{% endif %} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">{% if object %}Edit Class: {{ object.name }}{% else %}Add New Class{% endif %}</h1>
        <p class="rb-page-subtitle">{% if object %}Update class details{% else %}Create a new class for {{ form.academic_year.value|default:"2025-2026" }}{% endif %}</p>
    </div>
    <a href="{% url 'academics:class_list' %}" class="btn btn-outline-secondary btn-sm">
        <i class="fas fa-arrow-left me-1"></i> Back to Classes
    </a>
</div>

<div class="row">
<div class="col-lg-7">
<form method="post">
{% csrf_token %}

<div class="card mb-3">
    <div class="card-header"><span style="font-weight:600;font-size:.875rem"><i class="fas fa-chalkboard me-2" style="color:var(--rb-red)"></i>Class Details</span></div>
    <div class="card-body">
        <div class="row g-3">
            <div class="col-sm-8">
                <label class="form-label">Class Name <span class="text-danger">*</span></label>
                {{ form.name }}
                <div style="font-size:.75rem;color:#aaa;margin-top:.2rem">e.g. Nursery 1A, Grade 3B</div>
                {% if form.name.errors %}<div class="text-danger" style="font-size:.8rem">{{ form.name.errors }}</div>{% endif %}
            </div>
            <div class="col-sm-4">
                <label class="form-label">Code</label>
                {{ form.code }}
                <div style="font-size:.75rem;color:#aaa;margin-top:.2rem">Short code e.g. N1A</div>
            </div>
            <div class="col-sm-6">
                <label class="form-label">Level <span class="text-danger">*</span></label>
                {{ form.level }}
                {% if form.level.errors %}<div class="text-danger" style="font-size:.8rem">{{ form.level.errors }}</div>{% endif %}
            </div>
            <div class="col-sm-3">
                <label class="form-label">Section</label>
                {{ form.section }}
                <div style="font-size:.75rem;color:#aaa;margin-top:.2rem">A, B, C…</div>
            </div>
            <div class="col-sm-3">
                <label class="form-label">Section Type</label>
                {{ form.section_type }}
            </div>
            <div class="col-sm-4">
                <label class="form-label">Capacity</label>
                {{ form.capacity }}
            </div>
            <div class="col-sm-4">
                <label class="form-label">Room Number</label>
                {{ form.room_number }}
            </div>
            <div class="col-sm-4">
                <label class="form-label">Academic Year</label>
                {{ form.academic_year }}
            </div>
            <div class="col-12">
                <label class="form-label">Class Teacher</label>
                {{ form.class_teacher }}
                <div style="font-size:.75rem;color:#aaa;margin-top:.2rem">The teacher primarily responsible for this class</div>
            </div>
        </div>
    </div>
</div>

<div class="d-flex justify-content-end gap-2 mb-4">
    <a href="{% url 'academics:class_list' %}" class="btn btn-outline-secondary">Cancel</a>
    <button type="submit" class="btn btn-rb-primary px-4">
        <i class="fas fa-save me-2"></i> {% if object %}Save Changes{% else %}Create Class{% endif %}
    </button>
</div>

</form>
</div>

<div class="col-lg-5">
    <div class="card">
        <div class="card-header"><span style="font-weight:600;font-size:.875rem">Rapha-Bethel Class Structure</span></div>
        <div class="card-body" style="font-size:.82rem;color:#666">
            <div style="display:grid;grid-template-columns:1fr 1fr;gap:.4rem .75rem">
                <span style="font-weight:600;color:#444">Pre-Nursery</span><span>Ages 2–3</span>
                <span style="font-weight:600;color:#444">Nursery 1–2</span><span>Ages 3–5</span>
                <span style="font-weight:600;color:#444">Moyenne Section</span><span>Ages 4–5</span>
                <span style="font-weight:600;color:#444">Grande Section</span><span>Ages 5–6</span>
                <span style="font-weight:600;color:#444">Class 1–6</span><span>Primary school</span>
            </div>
            <hr style="margin:.85rem 0;border-color:#f0ebe5">
            <p class="mb-0"><i class="fas fa-language" style="color:var(--rb-gold)"></i> Set <strong>Section Type</strong> to English or French to reflect the bilingual stream.</p>
        </div>
    </div>
</div>
</div>
{% endblock %}


======================================================================
FILE: templates/academics/class_list-1.html
======================================================================
<!-- templates/academics/class_list.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Classes - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .class-card {
        transition: transform 0.3s, box-shadow 0.3s;
        border-radius: 10px;
        overflow: hidden;
        border-left: 4px solid transparent;
    }
    .class-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.15);
    }
    .class-card.english { border-left-color: #2196F3; }
    .class-card.bilingual { border-left-color: #4CAF50; }
    .class-card.french { border-left-color: #FF9800; }
    
    .stats-badge {
        position: absolute;
        top: 15px;
        right: 15px;
    }
    .section-header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 20px;
        border-radius: 10px;
        margin-bottom: 25px;
    }
    .filter-section {
        background: #f8f9fc;
        padding: 20px;
        border-radius: 10px;
        margin-bottom: 25px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0 text-gray-800">Classes</h1>
            <p class="text-muted">Manage all classes and sections</p>
        </div>
        <div>
            <a href="/admin/academics/schoolclass/add/" class="btn btn-primary">
                <i class="fas fa-plus"></i> Add New Class
            </a>
        </div>
    </div>

    <!-- Summary Stats -->
    <div class="row mb-4">
        <div class="col-md-4">
            <div class="card bg-primary text-white shadow">
                <div class="card-body">
                    <div class="row align-items-center">
                        <div class="col">
                            <div class="small">Total Classes</div>
                            <div class="h3 mb-0">{{ classes|length }}</div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-school fa-2x"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card bg-success text-white shadow">
                <div class="card-body">
                    <div class="row align-items-center">
                        <div class="col">
                            <div class="small">Total Students</div>
                            <div class="h3 mb-0">{{ total_students|default:"0" }}</div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-users fa-2x"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card bg-info text-white shadow">
                <div class="card-body">
                    <div class="row align-items-center">
                        <div class="col">
                            <div class="small">English Section</div>
                            <div class="h3 mb-0">{{ english_count|default:"0" }}</div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-language fa-2x"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Class Grid -->
    <div class="row">
        {% for class in classes %}
        <div class="col-xl-4 col-md-6 mb-4">
            <div class="card class-card {{ class.section_type }} h-100 shadow">
                <div class="card-body">
                    <div class="stats-badge">
                        <span class="badge bg-{% if class.section_type == 'english' %}primary{% elif class.section_type == 'bilingual' %}success{% else %}warning{% endif %}">
                            {{ class.get_section_type_display }}
                        </span>
                    </div>
                    
                    <h5 class="card-title mb-1">{{ class.name }}</h5>
                    <p class="text-muted small mb-3">Code: {{ class.code }}</p>
                    
                    <div class="row mb-3">
                        <div class="col-6">
                            <div class="text-center p-2 bg-light rounded">
                                <h6 class="mb-0">{{ class.student_count }}</h6>
                                <small class="text-muted">Students</small>
                            </div>
                        </div>
                        <div class="col-6">
                            <div class="text-center p-2 bg-light rounded">
                                <h6 class="mb-0">{{ class.teacher_count|default:"0" }}</h6>
                                <small class="text-muted">Teachers</small>
                            </div>
                        </div>
                    </div>
                    
                    <div class="mb-3">
                        <strong>Class Teacher:</strong><br>
                        {% if class.class_teacher %}
                            <small>{{ class.class_teacher.user.get_full_name }}</small>
                        {% else %}
                            <small class="text-muted">Not assigned</small>
                        {% endif %}
                    </div>
                    
                    <div class="d-flex justify-content-between align-items-center">
                        <span class="text-muted small">
                            <i class="fas fa-door-open"></i> {{ class.room_number|default:"No room" }}
                        </span>
                        <a href="{% url 'academics:class_detail' class.pk %}" class="btn btn-sm btn-outline-primary">
                            <i class="fas fa-eye"></i> View Details
                        </a>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <div class="text-center py-5">
                <i class="fas fa-school fa-3x text-muted mb-3"></i>
                <h4 class="text-muted">No classes found</h4>
                <p class="text-muted">Click the "Add New Class" button to create your first class</p>
            </div>
        </div>
        {% endfor %}
    </div>

    <!-- Pagination if needed -->
    {% if is_paginated %}
    <nav aria-label="Page navigation" class="mt-4">
        <ul class="pagination justify-content-center">
            {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.previous_page_number }}">
                    <i class="fas fa-chevron-left"></i> Previous
                </a>
            </li>
            {% endif %}
            
            {% for num in page_obj.paginator.page_range %}
                {% if page_obj.number == num %}
                <li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
                {% else %}
                <li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
                {% endif %}
            {% endfor %}
            
            {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.next_page_number }}">
                    Next <i class="fas fa-chevron-right"></i>
                </a>
            </li>
            {% endif %}
        </ul>
    </nav>
    {% endif %}
</div>
{% endblock %}

======================================================================
FILE: templates/academics/class_list.html
======================================================================
<!-- templates/academics/class_list.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Classes - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
/* ── Section headers ── */
.section-group { margin-bottom: 2.5rem; }
.section-header {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 18px; border-radius: 10px;
    margin-bottom: 1rem; font-weight: 700; letter-spacing: .3px;
}
.section-header.english   { background: linear-gradient(135deg,#1d4ed8,#3b82f6); color:#fff; }
.section-header.bilingual { background: linear-gradient(135deg,#065f46,#10b981); color:#fff; }
.section-header.french    { background: linear-gradient(135deg,#78350f,#f59e0b); color:#1c1c1c; }
.section-header .icon { font-size:1.5rem; line-height:1; }
.section-header .meta { font-size:.76rem; font-weight:400; opacity:.85; margin-top:1px; }
.section-badge {
    margin-left:auto; background:rgba(255,255,255,.22);
    border-radius:99px; padding:3px 12px; font-size:.75rem; white-space:nowrap;
}
.section-header.french .section-badge { background:rgba(0,0,0,.1); }

/* ── Class cards ── */
.class-card {
    border-radius:10px; border:1px solid #e5e7eb;
    border-left:5px solid transparent;
    transition: transform .2s, box-shadow .2s; background:#fff;
}
.class-card:hover { transform:translateY(-4px); box-shadow:0 8px 24px rgba(0,0,0,.1); }
.class-card.english   { border-left-color:#3b82f6; }
.class-card.bilingual { border-left-color:#10b981; }
.class-card.french    { border-left-color:#f59e0b; }

.order-num {
    width:24px; height:24px; border-radius:50%; flex-shrink:0;
    display:inline-flex; align-items:center; justify-content:center;
    font-size:.68rem; font-weight:800;
}
.english   .order-num { background:#dbeafe; color:#1d4ed8; }
.bilingual .order-num { background:#d1fae5; color:#065f46; }
.french    .order-num { background:#fef3c7; color:#92400e; }

.class-name-main { font-size:.92rem; font-weight:700; line-height:1.2; color:#111; }
.class-name-alt  { font-size:.75rem; color:#888; margin-top:1px; }
.class-code      { font-size:.7rem; font-family:monospace; color:#aaa; }

.stat-box { text-align:center; padding:7px 4px; background:#f8fafc; border-radius:7px; }
.stat-box .n { font-size:1.2rem; font-weight:700; }
.stat-box .l { font-size:.65rem; color:#888; }
.english   .stat-box .n { color:#3b82f6; }
.bilingual .stat-box .n { color:#10b981; }
.french    .stat-box .n { color:#f59e0b; }

.teacher-line { font-size:.75rem; border-top:1px solid #f1f5f9; padding-top:7px; margin-top:8px; color:#555; }
.no-teacher-txt { color:#dc2626; font-style:italic; }

/* ── Summary stat cards ── */
.stat-card { border-radius:10px; padding:14px 18px; color:#fff; }
.stat-card .l { font-size:.75rem; opacity:.85; }
.stat-card .n { font-size:2rem; font-weight:800; line-height:1; }

/* ── Table ── */
.tbl-section-row td { font-weight:700; font-size:.78rem; letter-spacing:.3px; padding:7px 12px !important; background:#f8fafc; }
.tbl-section-row td.english   { border-left:4px solid #3b82f6; color:#1d4ed8; }
.tbl-section-row td.bilingual { border-left:4px solid #10b981; color:#065f46; }
.tbl-section-row td.french    { border-left:4px solid #f59e0b; color:#92400e; }
.no-teacher-td { color:#dc2626; font-style:italic; font-size:.8rem; }

/* ── Misc ── */
.result-bar { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:.5rem; margin-bottom:12px; font-size:.84rem; color:#555; }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">

    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-3">
        <div>
            <h1 class="h3 mb-0">Classes</h1>
            <p class="text-muted mb-0" style="font-size:.85rem">Manage all classes and sections</p>
        </div>
        <a href="{% url 'academics:class_add' %}" class="btn btn-primary btn-sm">
            <i class="fas fa-plus me-1"></i> Add New Class
        </a>
    </div>

    <!-- Summary Stats -->
    <div class="row g-2 mb-3">
        <div class="col-6 col-md-3">
            <div class="stat-card" style="background:linear-gradient(135deg,#374151,#6b7280)">
                <div class="l">Total Classes</div>
                <div class="n">{{ classes|length }}</div>
            </div>
        </div>
        <div class="col-6 col-md-3">
            <div class="stat-card" style="background:linear-gradient(135deg,#065f46,#10b981)">
                <div class="l">Total Students</div>
                <div class="n">{{ total_students|default:"0" }}</div>
            </div>
        </div>
        <div class="col-6 col-md-3">
            <div class="stat-card" style="background:linear-gradient(135deg,#1d4ed8,#3b82f6)">
                <div class="l">English Section</div>
                <div class="n">{{ english_count|default:"0" }}</div>
            </div>
        </div>
        <div class="col-6 col-md-3">
            <div class="stat-card" style="background:linear-gradient(135deg,#78350f,#f59e0b)">
                <div class="l">No Class Teacher</div>
                <div class="n">{{ unassigned_teachers|default:"0" }}</div>
            </div>
        </div>
    </div>

    <!-- Result bar + View toggle -->
    <div class="result-bar">
        <span>
            <strong>{{ classes|length }}</strong> class{{ classes|length|pluralize:"es" }} &nbsp;·&nbsp;
            <span style="color:#3b82f6">{{ english_classes|length }} English</span> &nbsp;·&nbsp;
            <span style="color:#10b981">{{ bilingual_classes|length }} Bilingual</span> &nbsp;·&nbsp;
            <span style="color:#92400e">{{ french_classes|length }} French</span>
        </span>
        <div class="btn-group btn-group-sm">
            <button class="btn btn-outline-primary active" id="gridViewBtn">
                <i class="fas fa-th-large me-1"></i> Grid
            </button>
            <button class="btn btn-outline-primary" id="tableViewBtn">
                <i class="fas fa-table me-1"></i> Table
            </button>
        </div>
    </div>

    <!-- ══════════════════════════ GRID VIEW ══════════════════════════ -->
    <div id="gridView">

        <!-- ENGLISH SUB-SECTION -->
        {% if english_classes %}
        <div class="section-group">
            <div class="section-header english">
                <span class="icon">🇬🇧</span>
                <div>
                    <div>English Sub-section</div>
                    <div class="meta">Nursery 1 &nbsp;·&nbsp; Nursery 2 &nbsp;·&nbsp; Class 1 → Class 6</div>
                </div>
                <span class="section-badge">{{ english_classes|length }} class{{ english_classes|length|pluralize:"es" }}</span>
            </div>
            <div class="row g-3">
                {% for cls in english_classes %}
                <div class="col-xl-3 col-lg-4 col-md-6">
                    <div class="card class-card english h-100">
                        <div class="card-body">
                            <div class="d-flex align-items-start gap-2 mb-3">
                                <span class="order-num">{{ forloop.counter }}</span>
                                <div class="flex-grow-1">
                                    <div class="class-name-main">{{ cls.name }}</div>
                                    <div class="class-code">{{ cls.code }}</div>
                                </div>
                                <span class="badge bg-primary" style="font-size:.68rem">English</span>
                            </div>
                            <div class="row g-2 mb-2">
                                <div class="col-6">
                                    <div class="stat-box english">
                                        <div class="n">{{ cls.student_count }}</div>
                                        <div class="l">Students</div>
                                    </div>
                                </div>
                                <div class="col-6">
                                    <div class="stat-box english">
                                        <div class="n">{{ cls.teacher_count|default:"0" }}</div>
                                        <div class="l">Teachers</div>
                                    </div>
                                </div>
                            </div>
                            <div class="teacher-line">
                                <i class="fas fa-chalkboard-teacher me-1"></i>
                                {% if cls.class_teacher %}
                                    {{ cls.class_teacher.user.get_full_name }}
                                {% else %}
                                    <span class="no-teacher-txt">No class teacher</span>
                                {% endif %}
                            </div>
                            <div class="d-flex justify-content-between align-items-center mt-2">
                                <span style="font-size:.72rem;color:#aaa">
                                    <i class="fas fa-door-open me-1"></i>{{ cls.room_number|default:"No room" }}
                                </span>
                                <a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye me-1"></i>View
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
        </div>
        {% endif %}

        <!-- BILINGUAL SUB-SECTION -->
        {% if bilingual_classes %}
        <div class="section-group">
            <div class="section-header bilingual">
                <span class="icon">🌍</span>
                <div>
                    <div>Bilingual Sub-section <span style="font-weight:400;font-size:.82rem">(English &amp; French)</span></div>
                    <div class="meta">Petite Section &nbsp;·&nbsp; Moyenne Section &nbsp;·&nbsp; Grande Section &nbsp;·&nbsp; SIL &nbsp;·&nbsp; CP &nbsp;·&nbsp; CE1 &nbsp;·&nbsp; CE2</div>
                </div>
                <span class="section-badge">{{ bilingual_classes|length }} class{{ bilingual_classes|length|pluralize:"es" }}</span>
            </div>
            <div class="row g-3">
                {% for cls in bilingual_classes %}
                <div class="col-xl-3 col-lg-4 col-md-6">
                    <div class="card class-card bilingual h-100">
                        <div class="card-body">
                            <div class="d-flex align-items-start gap-2 mb-3">
                                <span class="order-num">{{ forloop.counter }}</span>
                                <div class="flex-grow-1">
                                    <div class="class-name-main">{{ cls.name }}</div>
                                    {% if cls.french_name %}
                                    <div class="class-name-alt">{{ cls.french_name }}</div>
                                    {% endif %}
                                    <div class="class-code">{{ cls.code }}</div>
                                </div>
                                <span class="badge bg-success" style="font-size:.68rem">Bilingual</span>
                            </div>
                            <div class="row g-2 mb-2">
                                <div class="col-6">
                                    <div class="stat-box bilingual">
                                        <div class="n">{{ cls.student_count }}</div>
                                        <div class="l">Students</div>
                                    </div>
                                </div>
                                <div class="col-6">
                                    <div class="stat-box bilingual">
                                        <div class="n">{{ cls.teacher_count|default:"0" }}</div>
                                        <div class="l">Teachers</div>
                                    </div>
                                </div>
                            </div>
                            <div class="teacher-line">
                                <i class="fas fa-chalkboard-teacher me-1"></i>
                                {% if cls.class_teacher %}
                                    {{ cls.class_teacher.user.get_full_name }}
                                {% else %}
                                    <span class="no-teacher-txt">No class teacher</span>
                                {% endif %}
                            </div>
                            <div class="d-flex justify-content-between align-items-center mt-2">
                                <span style="font-size:.72rem;color:#aaa">
                                    <i class="fas fa-door-open me-1"></i>{{ cls.room_number|default:"No room" }}
                                </span>
                                <a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm btn-outline-success">
                                    <i class="fas fa-eye me-1"></i>View
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
        </div>
        {% endif %}

        <!-- FRENCH SUB-SECTION -->
        {% if french_classes %}
        <div class="section-group">
            <div class="section-header french">
                <span class="icon">🇫🇷</span>
                <div>
                    <div>French Sub-section</div>
                    <div class="meta">CM1 &nbsp;·&nbsp; CM2</div>
                </div>
                <span class="section-badge">{{ french_classes|length }} class{{ french_classes|length|pluralize:"es" }}</span>
            </div>
            <div class="row g-3">
                {% for cls in french_classes %}
                <div class="col-xl-3 col-lg-4 col-md-6">
                    <div class="card class-card french h-100">
                        <div class="card-body">
                            <div class="d-flex align-items-start gap-2 mb-3">
                                <span class="order-num">{{ forloop.counter }}</span>
                                <div class="flex-grow-1">
                                    <div class="class-name-main">{{ cls.name }}</div>
                                    <div class="class-code">{{ cls.code }}</div>
                                </div>
                                <span class="badge bg-warning text-dark" style="font-size:.68rem">French</span>
                            </div>
                            <div class="row g-2 mb-2">
                                <div class="col-6">
                                    <div class="stat-box french">
                                        <div class="n">{{ cls.student_count }}</div>
                                        <div class="l">Students</div>
                                    </div>
                                </div>
                                <div class="col-6">
                                    <div class="stat-box french">
                                        <div class="n">{{ cls.teacher_count|default:"0" }}</div>
                                        <div class="l">Teachers</div>
                                    </div>
                                </div>
                            </div>
                            <div class="teacher-line">
                                <i class="fas fa-chalkboard-teacher me-1"></i>
                                {% if cls.class_teacher %}
                                    {{ cls.class_teacher.user.get_full_name }}
                                {% else %}
                                    <span class="no-teacher-txt">No class teacher</span>
                                {% endif %}
                            </div>
                            <div class="d-flex justify-content-between align-items-center mt-2">
                                <span style="font-size:.72rem;color:#aaa">
                                    <i class="fas fa-door-open me-1"></i>{{ cls.room_number|default:"No room" }}
                                </span>
                                <a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm btn-outline-warning">
                                    <i class="fas fa-eye me-1"></i>View
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
        </div>
        {% endif %}

        {% if not classes %}
        <div class="text-center py-5 text-muted">
            <i class="fas fa-school fa-3x mb-3 d-block"></i>
            <h5>No classes yet</h5>
            <p>Click <strong>Add New Class</strong> to get started.</p>
        </div>
        {% endif %}

    </div>{# /gridView #}

    <!-- ══════════════════════════ TABLE VIEW ══════════════════════════ -->
    <div id="tableView" style="display:none">
        <div class="card">
            <div class="table-responsive">
                <table class="table table-hover mb-0" style="font-size:.84rem">
                    <thead style="background:#f8fafc">
                        <tr>
                            <th style="width:32px;font-size:.7rem;color:#888">#</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px">Class Name</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px">Code</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px">Section</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px" class="text-center">Students</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px" class="text-center">Teachers</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px">Class Teacher</th>
                            <th style="font-size:.7rem;color:#888;text-transform:uppercase;letter-spacing:.4px">Room</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>

                        {% if english_classes %}
                        <tr class="tbl-section-row">
                            <td colspan="9" class="english">🇬🇧 &nbsp;English Sub-section</td>
                        </tr>
                        {% for cls in english_classes %}
                        <tr>
                            <td class="text-muted" style="font-size:.72rem">{{ forloop.counter }}</td>
                            <td><strong>{{ cls.name }}</strong></td>
                            <td><code style="font-size:.76rem">{{ cls.code }}</code></td>
                            <td><span class="badge bg-primary" style="font-size:.68rem">English</span></td>
                            <td class="text-center">{{ cls.student_count }}</td>
                            <td class="text-center">{{ cls.teacher_count|default:"0" }}</td>
                            <td>{% if cls.class_teacher %}{{ cls.class_teacher.user.get_full_name }}{% else %}<span class="no-teacher-td">Not assigned</span>{% endif %}</td>
                            <td>{{ cls.room_number|default:"—" }}</td>
                            <td><a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm btn-outline-primary"><i class="fas fa-eye"></i></a></td>
                        </tr>
                        {% endfor %}
                        {% endif %}

                        {% if bilingual_classes %}
                        <tr class="tbl-section-row">
                            <td colspan="9" class="bilingual">🌍 &nbsp;Bilingual Sub-section (English &amp; French)</td>
                        </tr>
                        {% for cls in bilingual_classes %}
                        <tr>
                            <td class="text-muted" style="font-size:.72rem">{{ forloop.counter }}</td>
                            <td>
                                <strong>{{ cls.name }}</strong>
                                {% if cls.french_name %}<br><span class="text-muted" style="font-size:.74rem">{{ cls.french_name }}</span>{% endif %}
                            </td>
                            <td><code style="font-size:.76rem">{{ cls.code }}</code></td>
                            <td><span class="badge bg-success" style="font-size:.68rem">Bilingual</span></td>
                            <td class="text-center">{{ cls.student_count }}</td>
                            <td class="text-center">{{ cls.teacher_count|default:"0" }}</td>
                            <td>{% if cls.class_teacher %}{{ cls.class_teacher.user.get_full_name }}{% else %}<span class="no-teacher-td">Not assigned</span>{% endif %}</td>
                            <td>{{ cls.room_number|default:"—" }}</td>
                            <td><a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm btn-outline-success"><i class="fas fa-eye"></i></a></td>
                        </tr>
                        {% endfor %}
                        {% endif %}

                        {% if french_classes %}
                        <tr class="tbl-section-row">
                            <td colspan="9" class="french">🇫🇷 &nbsp;French Sub-section</td>
                        </tr>
                        {% for cls in french_classes %}
                        <tr>
                            <td class="text-muted" style="font-size:.72rem">{{ forloop.counter }}</td>
                            <td><strong>{{ cls.name }}</strong></td>
                            <td><code style="font-size:.76rem">{{ cls.code }}</code></td>
                            <td><span class="badge bg-warning text-dark" style="font-size:.68rem">French</span></td>
                            <td class="text-center">{{ cls.student_count }}</td>
                            <td class="text-center">{{ cls.teacher_count|default:"0" }}</td>
                            <td>{% if cls.class_teacher %}{{ cls.class_teacher.user.get_full_name }}{% else %}<span class="no-teacher-td">Not assigned</span>{% endif %}</td>
                            <td>{{ cls.room_number|default:"—" }}</td>
                            <td><a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm btn-outline-warning"><i class="fas fa-eye"></i></a></td>
                        </tr>
                        {% endfor %}
                        {% endif %}

                    </tbody>
                </table>
            </div>
        </div>
    </div>{# /tableView #}

</div>
{% endblock %}

{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function () {
    const gridView = document.getElementById('gridView');
    const tableView = document.getElementById('tableView');
    const gridBtn  = document.getElementById('gridViewBtn');
    const tableBtn = document.getElementById('tableViewBtn');

    function showGrid() {
        gridView.style.display = ''; tableView.style.display = 'none';
        gridBtn.classList.add('active'); tableBtn.classList.remove('active');
        localStorage.setItem('classView', 'grid');
    }
    function showTable() {
        gridView.style.display = 'none'; tableView.style.display = 'block';
        tableBtn.classList.add('active'); gridBtn.classList.remove('active');
        localStorage.setItem('classView', 'table');
    }
    gridBtn.addEventListener('click', showGrid);
    tableBtn.addEventListener('click', showTable);
    if (localStorage.getItem('classView') === 'table') showTable();
});
</script>
{% endblock %}

======================================================================
FILE: templates/academics/class_students.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ school_class }} — Students{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{{ school_class }}</h1>
            <p class="text-muted">
                {{ students.count }} student{{ students.count|pluralize }} &bull;
                {{ school_class.get_section_type_display }} &bull;
                {{ school_class.academic_year }}
            </p>
        </div>
        <div class="btn-group">
            <a href="{% url 'academics:class_detail' school_class.pk %}" class="btn btn-outline-secondary">
                <i class="fas fa-arrow-left me-2"></i>Back to Class
            </a>
            <a href="{% url 'academics:assign_teacher' school_class.pk %}" class="btn btn-outline-primary">
                <i class="fas fa-chalkboard-teacher me-2"></i>Manage Teachers
            </a>
        </div>
    </div>

    <!-- Class Teacher Banner -->
    {% if school_class.class_teacher %}
    <div class="alert alert-info d-flex align-items-center mb-4">
        <i class="fas fa-user-tie fa-lg me-3"></i>
        <div>
            <strong>Class Teacher:</strong> {{ school_class.class_teacher.user.get_full_name }}
            &bull; {{ school_class.class_teacher.phone_number|default:"No phone" }}
        </div>
    </div>
    {% endif %}

    <!-- Stats Row -->
    <div class="row mb-4">
        <div class="col-md-3">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Total Students</div>
                    <div class="h4 mb-0 font-weight-bold">{{ students.count }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Male</div>
                    <div class="h4 mb-0 font-weight-bold">{{ male_count|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Female</div>
                    <div class="h4 mb-0 font-weight-bold">{{ female_count|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-info text-uppercase mb-1">Capacity</div>
                    <div class="h4 mb-0 font-weight-bold">{{ students.count }}/{{ school_class.capacity }}</div>
                </div>
            </div>
        </div>
    </div>

    <!-- Student Table -->
    <div class="card shadow">
        <div class="card-header py-3 d-flex justify-content-between align-items-center">
            <h6 class="m-0 font-weight-bold text-primary">Student Roster</h6>
            <div class="input-group" style="max-width:250px;">
                <input type="text" id="studentSearch" class="form-control form-control-sm" placeholder="Filter students...">
                <span class="input-group-text"><i class="fas fa-search"></i></span>
            </div>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-hover mb-0" id="studentsTable">
                    <thead class="table-dark">
                        <tr>
                            <th>#</th>
                            <th>Student ID</th>
                            <th>Name</th>
                            <th>Gender</th>
                            <th>Date of Birth</th>
                            <th>Parent Contact</th>
                            <th>Status</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for student in students %}
                        <tr>
                            <td class="text-muted">{{ forloop.counter }}</td>
                            <td><span class="badge bg-light text-dark">{{ student.student_id }}</span></td>
                            <td>
                                <div class="fw-bold">{{ student.get_full_name }}</div>
                            </td>
                            <td>
                                <i class="fas fa-{% if student.gender == 'M' %}mars text-primary{% elif student.gender == 'F' %}venus text-danger{% else %}genderless text-secondary{% endif %}"></i>
                                {{ student.get_gender_display }}
                            </td>
                            <td>{{ student.date_of_birth|date:"d M Y"|default:"—" }}</td>
                            <td>
                                {% with student.parents.filter(is_primary_contact=True).first as primary %}
                                {% if primary %}
                                <div class="small">{{ primary.get_full_name }}</div>
                                <div class="text-muted small"><i class="fas fa-phone me-1"></i>{{ primary.phone }}</div>
                                {% else %}
                                {% with student.parents.first as any_parent %}
                                {% if any_parent %}
                                <div class="small">{{ any_parent.get_full_name }}</div>
                                <div class="text-muted small"><i class="fas fa-phone me-1"></i>{{ any_parent.phone }}</div>
                                {% else %}
                                <span class="text-muted">—</span>
                                {% endif %}
                                {% endwith %}
                                {% endif %}
                                {% endwith %}
                            </td>
                            <td>
                                <span class="badge bg-{% if student.status == 'active' %}success{% else %}secondary{% endif %}">
                                    {{ student.get_status_display }}
                                </span>
                            </td>
                            <td>
                                <a href="{% url 'students:student_detail' student.pk %}" class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </a>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="8" class="text-center py-4 text-muted">
                                <i class="fas fa-user-graduate fa-2x mb-2 d-block"></i>
                                No students enrolled in this class yet.
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>

{% block extra_js %}
<script>
document.getElementById('studentSearch').addEventListener('keyup', function() {
    const query = this.value.toLowerCase();
    document.querySelectorAll('#studentsTable tbody tr').forEach(row => {
        row.style.display = row.textContent.toLowerCase().includes(query) ? '' : 'none';
    });
});
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/academics/subject_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ subject.name }} - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{{ subject.name }}</h1>
            <p class="text-muted">{{ subject.code }} &bull; {{ subject.get_category_display }}</p>
        </div>
        <a href="{% url 'academics:subject_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back to Subjects
        </a>
    </div>

    <div class="row">
        <div class="col-md-6">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Subject Details</h6>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr><td class="text-muted fw-bold" width="40%">Subject Code</td><td>{{ subject.code }}</td></tr>
                        <tr><td class="text-muted fw-bold">Name (English)</td><td class="fw-bold">{{ subject.name }}</td></tr>
                        <tr><td class="text-muted fw-bold">Name (French)</td><td>{{ subject.name_fr|default:"—" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Category</td><td><span class="badge bg-primary">{{ subject.get_category_display }}</span></td></tr>
                        <tr><td class="text-muted fw-bold">Description</td><td>{{ subject.description|default:"—" }}</td></tr>
                    </table>
                </div>
            </div>
        </div>

        <div class="col-md-6">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Assigned Teachers</h6>
                </div>
                <div class="card-body p-0">
                    <table class="table table-hover mb-0">
                        <thead class="table-light">
                            <tr><th>Teacher</th><th>Class</th><th>Hrs/Week</th></tr>
                        </thead>
                        <tbody>
                            {% for ts in subject.class_subjects.select_related('teacher','school_class') %}
                            <tr>
                                <td>{{ ts.teacher.user.get_full_name|default:"Unassigned" }}</td>
                                <td>{{ ts.school_class }}</td>
                                <td>{{ ts.hours_per_week }}</td>
                            </tr>
                            {% empty %}
                            <tr><td colspan="3" class="text-center text-muted py-3">No teachers assigned</td></tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/academics/subject_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{% if object %}Edit Subject{% else %}Add Subject{% endif %} - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{% if object %}Edit Subject{% else %}Add New Subject{% endif %}</h1>
            <p class="text-muted">{% if object %}Update subject details{% else %}Add a subject to the curriculum{% endif %}</p>
        </div>
        <a href="{% url 'academics:subject_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back to Subjects
        </a>
    </div>

    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white">
                    <h6 class="m-0"><i class="fas fa-book me-2"></i>Subject Details</h6>
                </div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}
                        <div class="alert alert-danger"><i class="fas fa-exclamation-circle me-2"></i>Please correct the errors below.</div>
                        {% endif %}

                        <div class="row mb-3">
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Subject Code <span class="text-danger">*</span></label>
                                {{ form.code }}
                                {% if form.code.errors %}<div class="text-danger small">{{ form.code.errors }}</div>{% endif %}
                                <div class="text-muted small">e.g. MATH, ENG, SCI</div>
                            </div>
                            <div class="col-md-8">
                                <label class="form-label fw-bold">Category <span class="text-danger">*</span></label>
                                {{ form.category }}
                            </div>
                        </div>

                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Name (English) <span class="text-danger">*</span></label>
                                {{ form.name }}
                                {% if form.name.errors %}<div class="text-danger small">{{ form.name.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Name (French)</label>
                                {{ form.name_fr }}
                            </div>
                        </div>

                        <div class="mb-3">
                            <label class="form-label fw-bold">Description</label>
                            {{ form.description }}
                        </div>

                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'academics:subject_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary">
                                <i class="fas fa-save me-2"></i>{% if object %}Update{% else %}Add{% endif %} Subject
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

{% block extra_js %}
<script>
document.querySelectorAll('input:not(.form-check-input), select, textarea').forEach(el => {
    el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
});
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/academics/subject_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Subjects - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Subjects</h1>
            <p class="text-muted">{{ subjects.count }} subject{{ subjects.count|pluralize }} in the curriculum</p>
        </div>
        <a href="{% url 'academics:subject_add' %}" class="btn btn-primary">
            <i class="fas fa-plus me-2"></i>Add Subject
        </a>
    </div>

    <!-- Group by category -->
    {% regroup subjects by get_category_display as category_list %}
    {% for category in category_list %}
    <div class="card shadow mb-4">
        <div class="card-header py-3 bg-light">
            <h6 class="m-0 font-weight-bold text-primary">
                <i class="fas fa-book-open me-2"></i>{{ category.grouper }}
            </h6>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-hover mb-0">
                    <thead class="table-light">
                        <tr>
                            <th>Code</th>
                            <th>Subject Name (EN)</th>
                            <th>Subject Name (FR)</th>
                            <th>Teachers Assigned</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for subject in category.list %}
                        <tr>
                            <td><span class="badge bg-secondary">{{ subject.code }}</span></td>
                            <td class="fw-bold">{{ subject.name }}</td>
                            <td class="text-muted">{{ subject.name_fr|default:"—" }}</td>
                            <td>
                                <span class="badge bg-info">{{ subject.teachers.count }} teacher{{ subject.teachers.count|pluralize }}</span>
                            </td>
                            <td>
                                <a href="{% url 'academics:subject_detail' subject.pk %}" class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </a>
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
    {% empty %}
    <div class="text-center py-5">
        <i class="fas fa-book fa-3x text-muted mb-3"></i>
        <h4 class="text-muted">No subjects found</h4>
        <a href="{% url 'academics:subject_add' %}" class="btn btn-primary mt-2">Add First Subject</a>
    </div>
    {% endfor %}
</div>
{% endblock %}


======================================================================
FILE: templates/academics/attendance/list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Attendance Records - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Attendance Records</h1>
        <a href="{% url 'attendance:mark_attendance' %}" class="btn btn-primary">
            <i class="fas fa-plus"></i> Mark Attendance
        </a>
    </div>

    <div class="card shadow">
        <div class="card-body">
            <div class="table-responsive">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>Date</th>
                            <th>Student</th>
                            <th>Class</th>
                            <th>Status</th>
                            <th>Marked By</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for attendance in attendances %}
                        <tr>
                            <td>{{ attendance.date }}</td>
                            <td>{{ attendance.student }}</td>
                            <td>{{ attendance.school_class }}</td>
                            <td>
                                <span class="badge bg-{% if attendance.status == 'present' %}success{% elif attendance.status == 'absent' %}danger{% else %}warning{% endif %}">
                                    {{ attendance.get_status_display }}
                                </span>
                            </td>
                            <td>{{ attendance.marked_by.user.get_full_name|default:"System" }}</td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="5" class="text-center">No attendance records found</td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/academics/attendance/mark.html
======================================================================
{% extends 'base.html' %}
{% load static academics_tags %}

{% block title %}Mark Attendance{% endblock %}

{% block extra_css %}
<style>
    .status-btn-group {
        display: flex;
        gap: 5px;
        flex-wrap: wrap;
    }
    .status-btn {
        min-width: 80px;
    }
    .student-row {
        transition: background-color 0.2s;
    }
    .student-row:hover {
        background-color: #f8f9fc;
    }
    .quick-actions {
        position: sticky;
        top: 70px;
        z-index: 100;
    }
    .all-present-btn {
        cursor: pointer;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Header with Quick Actions -->
    <div class="quick-actions mb-4">
        <div class="card shadow">
            <div class="card-body">
                <div class="d-flex justify-content-between align-items-center">
                    <h5 class="mb-0">
                        <i class="fas fa-clipboard-check text-primary"></i> 
                        Mark Attendance - {{ today|date:"l, F d, Y" }}
                    </h5>
                    <div>
                        <button class="btn btn-sm btn-success" onclick="setAllPresent()">
                            <i class="fas fa-check-circle"></i> All Present
                        </button>
                        <button class="btn btn-sm btn-warning" onclick="setAllAbsent()">
                            <i class="fas fa-times-circle"></i> All Absent
                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Class Selection -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row">
                <div class="col-md-6">
                    <label class="form-label">Select Class</label>
                    <select name="class" class="form-control" onchange="this.form.submit()">
                        <option value="">-- Choose a class --</option>
                        {% for class in classes %}
                        <option value="{{ class.id }}" {% if selected_class.id == class.id %}selected{% endif %}>
                            {{ class.name }} ({{ class.code }})
                        </option>
                        {% endfor %}
                    </select>
                </div>
            </form>
        </div>
    </div>

    {% if selected_class %}
    <!-- Attendance Form -->
    <div class="card shadow">
        <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
            <h5 class="mb-0">{{ selected_class.name }} - {{ students|length }} Students</h5>
            <span class="badge bg-light text-dark" id="markedCount">0 marked</span>
        </div>
        
        <div class="card-body">
            <form method="post" id="attendanceForm">
                {% csrf_token %}
                <input type="hidden" name="class_id" value="{{ selected_class.id }}">
                
                <div class="table-responsive">
                    <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Student</th>
                                <th>ID</th>
                                <th>Status</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for student in students %}
                            <tr class="student-row" data-student-id="{{ student.id }}">
                                <td>{{ forloop.counter }}</td>
                                <td>
                                    <strong>{{ student.first_name }} {{ student.last_name }}</strong>
                                </td>
                                <td><small class="text-muted">{{ student.student_id }}</small></td>
                                <td>
                                    <div class="status-btn-group">
                                        <input type="radio" class="btn-check" 
                                               name="status_{{ student.id }}" 
                                               id="present_{{ student.id }}" 
                                               value="present" 
                                               {% if attendance_dict|get_item:student.id == 'present' %}checked{% endif %}
                                               autocomplete="off">
                                        <label class="btn btn-outline-success btn-sm status-btn" 
                                               for="present_{{ student.id }}">✅ Present</label>
                                        
                                        <input type="radio" class="btn-check" 
                                               name="status_{{ student.id }}" 
                                               id="absent_{{ student.id }}" 
                                               value="absent"
                                               {% if attendance_dict|get_item:student.id == 'absent' %}checked{% endif %}
                                               autocomplete="off">
                                        <label class="btn btn-outline-danger btn-sm status-btn" 
                                               for="absent_{{ student.id }}">❌ Absent</label>
                                        
                                        <input type="radio" class="btn-check" 
                                               name="status_{{ student.id }}" 
                                               id="late_{{ student.id }}" 
                                               value="late"
                                               {% if attendance_dict|get_item:student.id == 'late' %}checked{% endif %}
                                               autocomplete="off">
                                        <label class="btn btn-outline-warning btn-sm status-btn" 
                                               for="late_{{ student.id }}">⏰ Late</label>
                                    </div>
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                
                <div class="mt-4 text-center">
                    <button type="submit" class="btn btn-primary btn-lg px-5">
                        <i class="fas fa-save"></i> Save Attendance
                    </button>
                    <a href="{% url 'staff:teacher_dashboard' %}" class="btn btn-secondary btn-lg px-5">
                        <i class="fas fa-times"></i> Cancel
                    </a>
                </div>
            </form>
        </div>
    </div>
    {% endif %}
</div>
{% endblock %}

{% block extra_js %}
<script>
// Count marked students
function updateMarkedCount() {
    let marked = document.querySelectorAll('input[type="radio"]:checked').length;
    document.getElementById('markedCount').textContent = marked + ' marked';
}

// Set all students to present
function setAllPresent() {
    document.querySelectorAll('input[value="present"]').forEach(radio => {
        radio.checked = true;
    });
    updateMarkedCount();
}

// Set all students to absent
function setAllAbsent() {
    document.querySelectorAll('input[value="absent"]').forEach(radio => {
        radio.checked = true;
    });
    updateMarkedCount();
}

// Update count when any radio changes
document.querySelectorAll('input[type="radio"]').forEach(radio => {
    radio.addEventListener('change', updateMarkedCount);
});

// Initialize count
document.addEventListener('DOMContentLoaded', updateMarkedCount);
</script>
{% endblock %}

======================================================================
FILE: templates/academics/attendance/report.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Attendance Report - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <h1 class="h3 mb-4 text-gray-800">Attendance Report</h1>

    <div class="card shadow">
        <div class="card-body">
            <form method="get" class="row g-3 mb-4">
                <div class="col-md-3">
                    <label>From Date</label>
                    <input type="date" name="from_date" class="form-control">
                </div>
                <div class="col-md-3">
                    <label>To Date</label>
                    <input type="date" name="to_date" class="form-control">
                </div>
                <div class="col-md-3">
                    <label>Class</label>
                    <select name="class" class="form-control">
                        <option value="">All Classes</option>
                        {% for class in classes %}
                        <option value="{{ class.id }}">{{ class.name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3 align-self-end">
                    <button type="submit" class="btn btn-primary">
                        <i class="fas fa-search"></i> Generate Report
                    </button>
                </div>
            </form>

            <div class="table-responsive">
                <table class="table table-bordered">
                    <thead>
                        <tr>
                            <th>Class</th>
                            <th>Total Students</th>
                            <th>Present</th>
                            <th>Absent</th>
                            <th>Late</th>
                            <th>Attendance Rate</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for stat in stats %}
                        <tr>
                            <td>{{ stat.class }}</td>
                            <td>{{ stat.total }}</td>
                            <td class="text-success">{{ stat.present }}</td>
                            <td class="text-danger">{{ stat.absent }}</td>
                            <td class="text-warning">{{ stat.late }}</td>
                            <td>
                                <div class="progress">
                                    <div class="progress-bar bg-success" style="width: {{ stat.rate }}%">
                                        {{ stat.rate }}%
                                    </div>
                                </div>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="6" class="text-center">No data available</td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/academics/attendance/student.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Attendance — {{ student.get_full_name }}{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{{ student.get_full_name }}</h1>
            <p class="text-muted">Attendance Record &bull; {{ student.current_class|default:"No class" }}</p>
        </div>
        <a href="{% url 'students:student_detail' student.pk %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back to Student
        </a>
    </div>

    <!-- Summary Stats -->
    <div class="row mb-4">
        <div class="col-md-3">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Present</div>
                    <div class="h4 mb-0 font-weight-bold">{{ present_count|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-danger shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-danger text-uppercase mb-1">Absent</div>
                    <div class="h4 mb-0 font-weight-bold">{{ absent_count|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Late</div>
                    <div class="h4 mb-0 font-weight-bold">{{ late_count|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Attendance Rate</div>
                    <div class="h4 mb-0 font-weight-bold">{{ attendance_rate|default:"0" }}%</div>
                </div>
            </div>
        </div>
    </div>

    <!-- Filter -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-3">
                    <label class="form-label">Month</label>
                    <select name="month" class="form-control">
                        {% for num, name in months %}
                        <option value="{{ num }}" {% if selected_month|stringformat:"s" == num|stringformat:"s" %}selected{% endif %}>{{ name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3">
                    <label class="form-label">Year</label>
                    <select name="year" class="form-control">
                        {% for yr in years %}
                        <option value="{{ yr }}" {% if selected_year|stringformat:"s" == yr|stringformat:"s" %}selected{% endif %}>{{ yr }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-2">
                    <button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-1"></i>Filter</button>
                </div>
            </form>
        </div>
    </div>

    <!-- Attendance Records -->
    <div class="card shadow">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Attendance Records</h6>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-hover mb-0">
                    <thead class="table-dark">
                        <tr>
                            <th>Date</th>
                            <th>Day</th>
                            <th>Status</th>
                            <th>Period</th>
                            <th>Marked By</th>
                            <th>Remarks</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for att in attendances %}
                        <tr>
                            <td class="fw-bold">{{ att.date|date:"d M Y" }}</td>
                            <td class="text-muted">{{ att.date|date:"l" }}</td>
                            <td>
                                <span class="badge bg-{% if att.status == 'present' %}success{% elif att.status == 'absent' %}danger{% elif att.status == 'late' %}warning{% elif att.status == 'excused' %}info{% else %}secondary{% endif %}">
                                    {{ att.get_status_display }}
                                </span>
                            </td>
                            <td>{{ att.get_period_display }}</td>
                            <td>{{ att.marked_by.user.get_full_name|default:"—" }}</td>
                            <td class="text-muted small">{{ att.remarks|default:"—" }}</td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="6" class="text-center py-4 text-muted">
                                <i class="fas fa-calendar-times fa-2x mb-2 d-block"></i>
                                No attendance records for this period.
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/communication/announcement_confirm_delete.html
======================================================================
{% extends 'base.html' %}
{% block title %}Delete Announcement{% endblock %}
{% block content %}
<div class="container-fluid"><div class="row justify-content-center mt-5"><div class="col-md-5">
    <div class="card shadow border-danger">
        <div class="card-header bg-danger text-white"><h5 class="mb-0"><i class="fas fa-exclamation-triangle me-2"></i>Confirm Delete</h5></div>
        <div class="card-body text-center py-4">
            <div class="rounded-circle bg-danger bg-opacity-10 d-inline-flex align-items-center justify-content-center mb-4" style="width:80px;height:80px;"><i class="fas fa-bullhorn fa-2x text-danger"></i></div>
            <h4>Delete <strong>{{ announcement.title }}</strong>?</h4>
            <p class="text-muted">{{ announcement.publish_date|date:"d M Y" }} &bull; {{ announcement.get_audience_display }}</p>
            <div class="alert alert-warning text-start"><i class="fas fa-exclamation-circle me-2"></i>This action cannot be undone.</div>
            <div class="d-flex justify-content-center gap-3 mt-4">
                <a href="{% url 'communication:announcement_detail' announcement.pk %}" class="btn btn-secondary btn-lg">Cancel</a>
                <form method="post">{% csrf_token %}<button type="submit" class="btn btn-danger btn-lg"><i class="fas fa-trash me-2"></i>Delete</button></form>
            </div>
        </div>
    </div>
</div></div></div>
{% endblock %}


======================================================================
FILE: templates/communication/announcement_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ announcement.title }}{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">{{ announcement.title }}</h1><p class="text-muted">{{ announcement.publish_date|date:"d M Y" }} &bull; {{ announcement.get_audience_display }} &bull; <span class="badge bg-{% if announcement.priority == 'urgent' %}danger{% elif announcement.priority == 'high' %}warning{% else %}secondary{% endif %}">{{ announcement.get_priority_display }}</span></p></div>
        <div class="btn-group">
            <a href="{% url 'communication:announcement_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
            <a href="{% url 'communication:announcement_edit' announcement.pk %}" class="btn btn-warning"><i class="fas fa-edit me-2"></i>Edit</a>
            <a href="{% url 'communication:announcement_delete' announcement.pk %}" class="btn btn-danger"><i class="fas fa-trash me-2"></i>Delete</a>
        </div>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-9">
            <div class="card shadow">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Announcement</h6>
                    {% if announcement.is_published %}<span class="badge bg-success">Published</span>{% else %}<span class="badge bg-secondary">Draft</span>{% endif %}
                </div>
                <div class="card-body">
                    <div class="mb-3 pb-3 border-bottom">
                        <div class="row">
                            <div class="col-md-4"><small class="text-muted">Audience</small><p class="fw-bold mb-0">{{ announcement.get_audience_display }}</p></div>
                            <div class="col-md-4"><small class="text-muted">Priority</small><p class="fw-bold mb-0">{{ announcement.get_priority_display }}</p></div>
                            <div class="col-md-4"><small class="text-muted">Date</small><p class="fw-bold mb-0">{{ announcement.publish_date|date:"d F Y" }}</p></div>
                        </div>
                    </div>
                    <div class="announcement-content" style="white-space:pre-line;">{{ announcement.content }}</div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/communication/announcement_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">{{ title }}</h1>
        <a href="{% url 'communication:announcement_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white"><h6 class="m-0"><i class="fas fa-bullhorn me-2"></i>Announcement Details</h6></div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}<div class="alert alert-danger">Please correct the errors below.</div>{% endif %}
                        <div class="mb-3"><label class="form-label fw-bold">Title <span class="text-danger">*</span></label>{{ form.title }}{% if form.title.errors %}<div class="text-danger small">{{ form.title.errors }}</div>{% endif %}</div>
                        <div class="mb-3"><label class="form-label fw-bold">Content <span class="text-danger">*</span></label>{{ form.content }}{% if form.content.errors %}<div class="text-danger small">{{ form.content.errors }}</div>{% endif %}</div>
                        <div class="row mb-3">
                            <div class="col-md-4"><label class="form-label fw-bold">Audience</label>{{ form.audience }}</div>
                            <div class="col-md-4"><label class="form-label fw-bold">Priority</label>{{ form.priority }}</div>
                            <div class="col-md-4"><label class="form-label fw-bold">Publish Date</label>{{ form.publish_date }}</div>
                        </div>
                        <div class="form-check mb-3">{{ form.is_published }}<label class="form-check-label fw-bold ms-2">Publish immediately</label></div>
                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'communication:announcement_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary"><i class="fas fa-save me-2"></i>Save Announcement</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => { el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control'); });</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/communication/announcements.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Announcements - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Announcements</h1>
        <a href="/admin/communication/announcement/add/" class="btn btn-primary">
            <i class="fas fa-plus"></i> New Announcement
        </a>
    </div>

    <div class="row">
        {% for announcement in announcements %}
        <div class="col-md-6 mb-4">
            <div class="card shadow h-100 {% if announcement.priority == 'urgent' %}border-danger{% endif %}">
                <div class="card-header d-flex justify-content-between align-items-center">
                    <h5 class="mb-0">{{ announcement.title }}</h5>
                    <span class="badge bg-{% if announcement.priority == 'urgent' %}danger{% elif announcement.priority == 'high' %}warning{% else %}info{% endif %}">
                        {{ announcement.get_priority_display }}
                    </span>
                </div>
                <div class="card-body">
                    <p>{{ announcement.content }}</p>
                    <p class="text-muted small">
                        <i class="far fa-clock"></i> Published: {{ announcement.publish_date }}
                    </p>
                    <p class="text-muted small">
                        <i class="fas fa-users"></i> Audience: {{ announcement.get_audience_display }}
                    </p>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <p class="text-center">No announcements yet</p>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/communication/parent_communication.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Parent Communication - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Parent Communication</h1><p class="text-muted">{{ total_parents }} parent contact{{ total_parents|pluralize }}</p></div>
        <a href="{% url 'communication:sms_compose' %}?recipient_type=parents" class="btn btn-primary"><i class="fas fa-sms me-2"></i>Bulk SMS to Parents</a>
    </div>
    <div class="card shadow">
        <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Parent Contact Directory</h6></div>
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark"><tr><th>Parent</th><th>Student</th><th>Phone</th><th>Language</th><th>SMS</th><th>Action</th></tr></thead>
                <tbody>
                    {% for entry in parents %}
                    <tr>
                        <td>
                            <div class="fw-bold">{{ entry.parent.get_full_name }}</div>
                            <small class="text-muted">{{ entry.parent.get_relationship_display }}</small>
                        </td>
                        <td><a href="{% url 'students:student_detail' entry.student.pk %}">{{ entry.student.get_full_name }}</a><br><small class="text-muted">{{ entry.student.current_class|default:"No class" }}</small></td>
                        <td><i class="fas fa-phone text-success me-1"></i>{{ entry.phone }}</td>
                        <td><span class="badge bg-secondary">{{ entry.preferred_language|upper }}</span></td>
                        <td>{% if entry.receive_sms %}<span class="badge bg-success"><i class="fas fa-check"></i></span>{% else %}<span class="badge bg-secondary"><i class="fas fa-times"></i></span>{% endif %}</td>
                        <td>
                            <a href="{% url 'communication:send_parent_message' entry.parent.pk %}" class="btn btn-sm btn-outline-primary" title="Send message">
                                <i class="fas fa-paper-plane"></i>
                            </a>
                        </td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="6" class="text-center py-4 text-muted"><i class="fas fa-users fa-2x mb-2 d-block"></i>No parent contacts found.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/communication/parent_message_form.html
======================================================================
{% extends 'base.html' %}

{% block title %}Message Parent — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">Send Message to Parent</h1>
        <p class="rb-page-subtitle">{{ parent.first_name }} {{ parent.last_name }} — {{ parent.phone }}</p>
    </div>
    <a href="{% url 'communication:parent_communication' %}" class="btn btn-outline-secondary btn-sm">
        <i class="fas fa-arrow-left me-1"></i> Back
    </a>
</div>

<div class="row justify-content-center">
    <div class="col-md-7">
        <div class="card">
            <div class="card-header">
                <span style="font-weight:600;font-size:.9rem">
                    <i class="fas fa-comment-sms me-2" style="color:var(--rb-red)"></i>
                    SMS to {{ parent.first_name }} {{ parent.last_name }}
                </span>
            </div>
            <div class="card-body">
                <!-- Parent info -->
                <div style="background:#fdfaf7;border-radius:8px;padding:.85rem 1rem;margin-bottom:1.25rem;display:flex;align-items:center;gap:.75rem">
                    <div style="width:40px;height:40px;border-radius:50%;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-gold));color:#fff;font-weight:700;font-size:.9rem;display:flex;align-items:center;justify-content:center;flex-shrink:0">
                        {{ parent.first_name|first }}{{ parent.last_name|first }}
                    </div>
                    <div>
                        <div style="font-weight:600;font-size:.875rem">{{ parent.first_name }} {{ parent.last_name }}</div>
                        <div style="font-size:.78rem;color:#888">
                            {{ parent.get_relationship_display }} of
                            {% if parent.student %}{{ parent.student.first_name }} {{ parent.student.last_name }}{% endif %}
                            &middot; <a href="tel:{{ parent.phone }}">{{ parent.phone }}</a>
                        </div>
                    </div>
                </div>

                <form method="post">
                    {% csrf_token %}
                    <div class="mb-3">
                        <label class="form-label">Message Type</label>
                        <select name="message_type" class="form-select">
                            <option value="general">General</option>
                            <option value="attendance">Attendance</option>
                            <option value="fees">Fees / Payment</option>
                            <option value="academic">Academic</option>
                            <option value="emergency">Emergency</option>
                        </select>
                    </div>
                    <div class="mb-3">
                        <label class="form-label">Message <span class="text-danger">*</span></label>
                        <textarea name="message" class="form-control" rows="5" maxlength="160" placeholder="Type your message here…" required style="resize:vertical"></textarea>
                        <div style="text-align:right;font-size:.75rem;color:#aaa;margin-top:.25rem">
                            <span id="charCount">0</span>/160 characters
                        </div>
                    </div>
                    <div class="d-flex justify-content-end gap-2 mt-4">
                        <a href="{% url 'communication:parent_communication' %}" class="btn btn-outline-secondary">Cancel</a>
                        <button type="submit" class="btn btn-rb-primary">
                            <i class="fas fa-paper-plane me-2"></i> Send SMS
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
const ta = document.querySelector('textarea[name=message]');
const counter = document.getElementById('charCount');
if (ta && counter) {
    ta.addEventListener('input', () => {
        counter.textContent = ta.value.length;
        counter.style.color = ta.value.length > 140 ? 'var(--rb-red)' : '#aaa';
    });
}
</script>
{% endblock %}


======================================================================
FILE: templates/communication/sms.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}SMS Messages - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">SMS Messages</h1>
        <a href="/admin/communication/smsmessage/add/" class="btn btn-primary">
            <i class="fas fa-plus"></i> Compose SMS
        </a>
    </div>

    <div class="card shadow">
        <div class="card-body">
            <div class="table-responsive">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>Type</th>
                            <th>Message</th>
                            <th>Recipients</th>
                            <th>Status</th>
                            <th>Sent Time</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for sms in messages %}
                        <tr>
                            <td>{{ sms.get_message_type_display }}</td>
                            <td>{{ sms.message|truncatechars:50 }}</td>
                            <td>{{ sms.phone_numbers|length }}</td>
                            <td>
                                <span class="badge bg-{% if sms.status == 'sent' %}success{% elif sms.status == 'failed' %}danger{% else %}secondary{% endif %}">
                                    {{ sms.get_status_display }}
                                </span>
                            </td>
                            <td>{{ sms.sent_time|default:"Not sent" }}</td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="5" class="text-center">No SMS messages</td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/communication/sms_compose.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Compose SMS - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Compose SMS</h1><p class="text-muted">{{ recipient_count }} recipient{{ recipient_count|pluralize }} selected</p></div>
        <a href="{% url 'communication:sms_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row">
        <div class="col-md-8">
            <div class="card shadow mb-4">
                <div class="card-header py-3 bg-primary text-white"><h6 class="m-0"><i class="fas fa-sms me-2"></i>Message</h6></div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        <div class="mb-3">
                            <label class="form-label fw-bold">Recipient Type</label>
                            <div class="btn-group w-100" role="group">
                                <a href="?recipient_type=all" class="btn btn-{% if recipient_type == 'all' or not recipient_type %}primary{% else %}outline-primary{% endif %}">All Parents</a>
                                <a href="?recipient_type=staff" class="btn btn-{% if recipient_type == 'staff' %}primary{% else %}outline-primary{% endif %}">Staff</a>
                                <a href="?recipient_type=parents" class="btn btn-{% if recipient_type == 'parents' %}primary{% else %}outline-primary{% endif %}">SMS-Opted Parents</a>
                            </div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Message Type <span class="text-danger">*</span></label>
                            <select name="message_type" class="form-select" required>
                                {% for val, label in message_types %}<option value="{{ val }}">{{ label }}</option>{% endfor %}
                            </select>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Message <span class="text-danger">*</span></label>
                            <textarea name="message" class="form-control" rows="5" maxlength="160" required placeholder="Type your message (max 160 characters)..."></textarea>
                            <div class="text-end text-muted small mt-1"><span id="charCount">0</span>/160 characters</div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Select Recipients</label>
                            <div style="max-height:300px;overflow-y:auto;border:1px solid #dee2e6;border-radius:4px;padding:10px;">
                                <div class="mb-2">
                                    <button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectAll(true)">Select All</button>
                                    <button type="button" class="btn btn-sm btn-outline-secondary ms-2" onclick="selectAll(false)">Deselect All</button>
                                </div>
                                {% for recipient in recipients %}
                                <div class="form-check">
                                    <input class="form-check-input recipient-check" type="checkbox" name="recipients" value="{{ recipient.pk }}" id="r{{ recipient.pk }}" checked>
                                    <label class="form-check-label" for="r{{ recipient.pk }}">
                                        {{ recipient.get_full_name }} — {{ recipient.phone }}
                                        {% if recipient.student %}<small class="text-muted">({{ recipient.student.get_full_name }})</small>{% endif %}
                                    </label>
                                </div>
                                {% empty %}
                                <p class="text-muted mb-0">No recipients available for this type.</p>
                                {% endfor %}
                            </div>
                        </div>
                        <div class="alert alert-info"><i class="fas fa-info-circle me-2"></i>In development mode, SMS messages are logged but not actually sent. Integration with an SMS gateway (e.g. Orange/MTN API) is required for production.</div>
                        <div class="d-flex justify-content-end gap-2">
                            <a href="{% url 'communication:sms_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane me-2"></i>Send SMS</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card shadow"><div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">SMS Tips</h6></div>
            <div class="card-body">
                <ul class="list-unstyled small">
                    <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Keep messages under 160 characters</li>
                    <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Use French for parent messages where possible</li>
                    <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Avoid sending after 8PM</li>
                    <li class="mb-2"><i class="fas fa-check text-success me-2"></i>Always include school name in message</li>
                </ul>
            </div></div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>
const msg = document.querySelector('[name="message"]');
const count = document.getElementById('charCount');
if (msg) msg.addEventListener('input', () => count.textContent = msg.value.length);
function selectAll(v) { document.querySelectorAll('.recipient-check').forEach(c => c.checked = v); }
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/communication/sms_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}SMS Message Detail{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">SMS Message Detail</h1>
        <a href="{% url 'communication:sms_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-sms me-2"></i>{{ sms.get_message_type_display }}</h6>
                    <span class="badge bg-{% if sms.status == 'sent' %}success{% elif sms.status == 'failed' %}danger{% else %}secondary{% endif %} fs-6">{{ sms.get_status_display }}</span>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr><td class="text-muted fw-bold" width="35%">Type</td><td>{{ sms.get_message_type_display }}</td></tr>
                        <tr><td class="text-muted fw-bold">Sent Time</td><td>{{ sms.sent_time|date:"l, d F Y H:i"|default:"Draft — not sent" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Recipients</td><td>{{ sms.phone_numbers|length }} number{{ sms.phone_numbers|length|pluralize }}</td></tr>
                    </table>
                    <hr>
                    <h6 class="text-muted text-uppercase small">Message Content</h6>
                    <div class="alert alert-light" style="white-space:pre-line;">{{ sms.message }}</div>
                    <h6 class="text-muted text-uppercase small mt-3">Phone Numbers</h6>
                    <div class="d-flex flex-wrap gap-2">
                        {% for phone in sms.phone_numbers %}<span class="badge bg-secondary">{{ phone }}</span>{% endfor %}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/communication/sms_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}SMS Messages - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">SMS Messages</h1><p class="text-muted">All outgoing SMS records</p></div>
        <a href="{% url 'communication:sms_compose' %}" class="btn btn-primary"><i class="fas fa-sms me-2"></i>Compose SMS</a>
    </div>
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-4"><label class="form-label">Type</label>
                    <select name="type" class="form-select">
                        <option value="">All Types</option>
                        {% for val, label in message_types %}<option value="{{ val }}" {% if request.GET.type == val %}selected{% endif %}>{{ label }}</option>{% endfor %}
                    </select>
                </div>
                <div class="col-md-4"><label class="form-label">Status</label>
                    <select name="status" class="form-select">
                        <option value="">All Statuses</option>
                        {% for val, label in status_choices %}<option value="{{ val }}" {% if request.GET.status == val %}selected{% endif %}>{{ label }}</option>{% endfor %}
                    </select>
                </div>
                <div class="col-md-4"><button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-1"></i>Filter</button></div>
            </form>
        </div>
    </div>
    <div class="card shadow">
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark"><tr><th>Type</th><th>Message Preview</th><th>Recipients</th><th>Sent</th><th>Status</th><th>Action</th></tr></thead>
                <tbody>
                    {% for sms in messages %}
                    <tr>
                        <td><span class="badge bg-info">{{ sms.get_message_type_display }}</span></td>
                        <td>{{ sms.message|truncatechars:60 }}</td>
                        <td>{{ sms.phone_numbers|length }} number{{ sms.phone_numbers|length|pluralize }}</td>
                        <td>{{ sms.sent_time|date:"d M Y H:i"|default:"Draft" }}</td>
                        <td><span class="badge bg-{% if sms.status == 'sent' %}success{% elif sms.status == 'failed' %}danger{% else %}secondary{% endif %}">{{ sms.get_status_display }}</span></td>
                        <td><a href="{% url 'communication:sms_detail' sms.pk %}" class="btn btn-sm btn-outline-primary"><i class="fas fa-eye"></i></a></td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="6" class="text-center py-4 text-muted"><i class="fas fa-sms fa-2x mb-2 d-block"></i>No SMS messages yet.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/finance/bulk_invoice.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Bulk Invoice Generation — Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
  .scope-card {
    border: 2px solid #dee2e6; border-radius: 8px; cursor: pointer;
    transition: border-color .15s, background .15s;
    padding: 10px 14px; display: flex; align-items: center; gap: 8px; user-select: none;
  }
  .scope-card:hover { border-color: #0d6efd; background: #f0f5ff; }
  .scope-card.active { border-color: #0d6efd; background: #e7f0ff; font-weight: 600; }
  .scope-card input[type=radio] { accent-color: #0d6efd; }
  #class-picker { display: none; }
  .class-chip {
    display: inline-flex; align-items: center; gap: 4px;
    border: 1.5px solid #ced4da; border-radius: 20px; padding: 3px 10px;
    cursor: pointer; font-size: .82rem; transition: border-color .12s, background .12s; user-select: none;
  }
  .class-chip:hover { border-color: #0d6efd; }
  .class-chip input { accent-color: #0d6efd; width: 14px; height: 14px; }
  .class-chip.checked { background: #e7f0ff; border-color: #0d6efd; font-weight: 600; }
  .stat-card { border-left: 4px solid; border-radius: 6px; }
  .stat-card.blue  { border-left-color: #0d6efd; }
  .stat-card.amber { border-left-color: #fd7e14; }
  .stat-card.green { border-left-color: #198754; }
  .stat-card.teal  { border-left-color: #0dcaf0; }
  .preview-table { max-height: 430px; overflow-y: auto; }
  .preview-table thead th { position: sticky; top: 0; background: #f8f9fa; z-index: 1; }
  .amount { font-variant-numeric: tabular-nums; }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">

  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">Bulk Invoice Generation</h1>
      <p class="text-muted mb-0">Create invoices for all active students at once</p>
    </div>
    <a href="{% url 'finance:invoice_list' %}" class="btn btn-outline-secondary">
      <i class="fas fa-arrow-left me-2"></i>Back to Invoices
    </a>
  </div>

  {% if messages %}
    {% for msg in messages %}
    <div class="alert alert-{{ msg.tags|default:'info' }} alert-dismissible fade show">
      {{ msg }}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
    {% endfor %}
  {% endif %}

  {% if not preview %}
  <!-- STEP 1: FORM -->
  <div class="row justify-content-center">
    <div class="col-lg-7">
      <div class="card shadow">
        <div class="card-header py-3 bg-primary text-white">
          <h6 class="m-0 fw-bold">
            <i class="fas fa-magic me-2"></i>Step 1 — Choose Invoice Type, Scope &amp; Due Date
          </h6>
        </div>
        <div class="card-body">
          <div class="alert alert-info mb-4">
            <i class="fas fa-info-circle me-2"></i>
            Creates one invoice per active student using the correct fee structure for their class.
            Students who already have an invoice of the same type for the selected year are skipped.
            <strong>Fee structures must be set up first</strong>
            (<a href="{% url 'finance:fee_list' %}">Finance → Fee Structures</a>).
          </div>

          <form method="post" id="bulkForm">
            {% csrf_token %}

            <!-- Academic Year -->
            <div class="mb-3">
              <label class="form-label fw-bold">Academic Year <span class="text-danger">*</span></label>
              <select class="form-select" name="academic_year" required>
                {% for yr in year_choices %}
                <option value="{{ yr }}" {% if yr == default_year %}selected{% endif %}>{{ yr }}</option>
                {% endfor %}
              </select>
            </div>

            <!-- Invoice Type (replaces Term) -->
            <div class="mb-3">
              <label class="form-label fw-bold">Invoice Type <span class="text-danger">*</span></label>
              <select class="form-select" name="invoice_type" required>
                <option value="">Select type…</option>
                {% for val, label in invoice_type_choices %}
                <option value="{{ val }}">{{ label }}</option>
                {% endfor %}
              </select>
              <div class="form-text">
                Select <em>Registration</em> for enrollment fees,
                <em>1st/2nd Installment</em> for tuition payments.
              </div>
            </div>

            <!-- Due Date -->
            <div class="mb-4">
              <label class="form-label fw-bold">Due Date <span class="text-danger">*</span></label>
              <input type="date" class="form-control" name="due_date" required>
            </div>

            <!-- Scope -->
            <div class="mb-4">
              <label class="form-label fw-bold">Generate For</label>
              <div class="d-flex flex-wrap gap-2 mb-3">
                <label class="scope-card active" data-scope="all">
                  <input type="radio" name="scope" value="all" checked>
                  <i class="fas fa-users text-primary"></i> All Students
                </label>
                <label class="scope-card" data-scope="nursery">
                  <input type="radio" name="scope" value="nursery">
                  <i class="fas fa-child text-warning"></i> Nursery Section
                </label>
                <label class="scope-card" data-scope="primary">
                  <input type="radio" name="scope" value="primary">
                  <i class="fas fa-book text-success"></i> Primary (Class&nbsp;1–5)
                </label>
                <label class="scope-card" data-scope="class6">
                  <input type="radio" name="scope" value="class6">
                  <i class="fas fa-graduation-cap text-danger"></i> Class&nbsp;6 Only
                </label>
                <label class="scope-card" data-scope="english">
                  <input type="radio" name="scope" value="english">
                  <i class="fas fa-flag text-info"></i> English Section
                </label>
                <label class="scope-card" data-scope="bilingual">
                  <input type="radio" name="scope" value="bilingual">
                  <i class="fas fa-language" style="color:#6f42c1"></i> Bilingual Section
                </label>
                <label class="scope-card" data-scope="specific">
                  <input type="radio" name="scope" value="specific">
                  <i class="fas fa-filter text-secondary"></i> Specific Classes…
                </label>
              </div>

              <div id="class-picker" class="border rounded p-3 bg-light">
                <p class="small text-muted mb-2 fw-bold">Select the classes to include:</p>
                <div class="d-flex flex-wrap gap-2">
                  {% for cls in all_classes %}
                  <label class="class-chip" id="chip-{{ cls.pk }}">
                    <input type="checkbox" name="class_ids" value="{{ cls.pk }}">
                    {{ cls }}
                    <span class="badge bg-secondary ms-1" style="font-size:.7rem">
                      {{ cls.get_section_type_display }}
                    </span>
                  </label>
                  {% endfor %}
                </div>
              </div>
            </div>

            <div class="d-grid">
              <button type="submit" class="btn btn-primary btn-lg">
                <i class="fas fa-eye me-2"></i>Preview Invoices
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>

  {% else %}
  <!-- STEP 2: PREVIEW -->

  <div class="row g-3 mb-4">
    <div class="col-6 col-md-3">
      <div class="card stat-card blue shadow-sm h-100 py-2 px-3">
        <div class="text-uppercase fw-bold mb-1 text-primary" style="font-size:.72rem">
          Invoices to Create
        </div>
        <div class="h3 mb-0 fw-bold text-success">{{ total_to_create }}</div>
      </div>
    </div>
    <div class="col-6 col-md-3">
      <div class="card stat-card amber shadow-sm h-100 py-2 px-3">
        <div class="text-uppercase fw-bold mb-1" style="font-size:.72rem;color:#fd7e14">
          Already Invoiced
        </div>
        <div class="h3 mb-0 fw-bold text-warning">{{ skip_count }} skipped</div>
      </div>
    </div>
    <div class="col-6 col-md-3">
      <div class="card stat-card green shadow-sm h-100 py-2 px-3">
        <div class="text-uppercase fw-bold mb-1 text-success" style="font-size:.72rem">Total Value</div>
        <div class="h3 mb-0 fw-bold amount" data-raw="{{ total_amount }}">
          {{ total_amount|floatformat:0 }} XAF
        </div>
      </div>
    </div>
    <div class="col-6 col-md-3">
      <div class="card stat-card teal shadow-sm h-100 py-2 px-3">
        <div class="text-uppercase fw-bold mb-1" style="font-size:.72rem;color:#0dcaf0">Type</div>
        <div class="h6 mb-0 fw-bold">{{ academic_year }}</div>
        <small class="text-muted">{{ invoice_type|title }} — Due: {{ due_date }}</small>
      </div>
    </div>
  </div>

  {% if total_to_create == 0 %}
  <div class="alert alert-warning">
    <i class="fas fa-exclamation-triangle me-2"></i>
    <strong>No invoices to create.</strong>
    Either all matching students already have this invoice type for {{ academic_year }},
    or no fee structures are set up for this year/section combination.
    <a href="{% url 'finance:fee_list' %}">Check fee structures →</a>
  </div>
  <a href="{% url 'finance:bulk_invoice' %}" class="btn btn-outline-secondary">
    <i class="fas fa-arrow-left me-2"></i>Start Over
  </a>

  {% else %}

  <div class="card shadow mb-4">
    <div class="card-header py-3 d-flex justify-content-between align-items-center">
      <h6 class="m-0 fw-bold text-primary">
        Preview — {{ total_to_create }} invoice{{ total_to_create|pluralize }} will be created
      </h6>
      <span class="badge bg-info">{{ academic_year }} — {{ invoice_type|title }}</span>
    </div>
    <div class="card-body p-0">
      <div class="preview-table">
        <table class="table table-hover table-sm mb-0">
          <thead class="table-light">
            <tr>
              <th class="ps-3" style="width:42px">#</th>
              <th>Student</th>
              <th>Class</th>
              <th>Fee Tier</th>
              <th class="text-end pe-3">Amount (XAF)</th>
            </tr>
          </thead>
          <tbody>
            {% for item in preview %}
            <tr>
              <td class="ps-3 text-muted">{{ forloop.counter }}</td>
              <td>
                <strong>{{ item.student.get_full_name }}</strong>
                {% if item.is_new_pupil %}
                <span class="badge bg-warning text-dark ms-1" style="font-size:.7rem">New</span>
                {% endif %}
              </td>
              <td>
                <span class="badge bg-light text-dark border">
                  {{ item.student.current_class }}
                </span>
              </td>
              <td class="small text-muted">
                {{ item.fee.get_section_display }} — {{ item.fee.get_class_group_display }}
              </td>
              <td class="text-end pe-3 fw-bold text-success amount" data-raw="{{ item.amount }}">
                {{ item.amount|floatformat:0 }}
              </td>
            </tr>
            {% endfor %}
          </tbody>
          <tfoot class="table-light fw-bold border-top">
            <tr>
              <td colspan="4" class="ps-3 text-end py-2">Grand Total:</td>
              <td class="text-end pe-3 text-success amount" data-raw="{{ total_amount }}">
                {{ total_amount|floatformat:0 }} XAF
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
    </div>
  </div>

  <div class="row justify-content-center">
    <div class="col-lg-6">
      <div class="card border-success shadow">
        <div class="card-header bg-success text-white py-3">
          <h6 class="m-0 fw-bold">
            <i class="fas fa-check-circle me-2"></i>Step 2 — Confirm &amp; Create
          </h6>
        </div>
        <div class="card-body">
          <p class="mb-3">
            You are about to create
            <strong>{{ total_to_create }} invoice{{ total_to_create|pluralize }}</strong>
            totalling
            <strong class="amount" data-raw="{{ total_amount }}">
              {{ total_amount|floatformat:0 }} XAF
            </strong>
            for <strong>{{ academic_year }} — {{ invoice_type|title }}</strong>.
            All invoices will be created with status
            <span class="badge bg-secondary">Draft</span>.
          </p>
          <form method="post" class="d-flex gap-3">
            {% csrf_token %}
            <input type="hidden" name="academic_year"  value="{{ academic_year }}">
            <input type="hidden" name="invoice_type"   value="{{ invoice_type }}">
            <input type="hidden" name="due_date"       value="{{ due_date }}">
            <input type="hidden" name="scope"          value="{{ scope }}">
            {% for cid in class_ids %}
            <input type="hidden" name="class_ids" value="{{ cid }}">
            {% endfor %}
            <input type="hidden" name="confirmed" value="yes">

            <a href="{% url 'finance:bulk_invoice' %}" class="btn btn-outline-secondary flex-fill">
              <i class="fas fa-arrow-left me-2"></i>Start Over
            </a>
            <button type="submit" class="btn btn-success flex-fill">
              <i class="fas fa-bolt me-2"></i>
              Create {{ total_to_create }} Invoice{{ total_to_create|pluralize }}
            </button>
          </form>
        </div>
      </div>
    </div>
  </div>

  {% endif %}
  {% endif %}

</div>
{% endblock %}

{% block extra_js %}
<script>
document.querySelectorAll('.scope-card').forEach(card => {
  card.addEventListener('click', () => {
    document.querySelectorAll('.scope-card').forEach(c => c.classList.remove('active'));
    card.classList.add('active');
    document.getElementById('class-picker').style.display =
      card.dataset.scope === 'specific' ? 'block' : 'none';
  });
});

document.querySelectorAll('.class-chip input[type=checkbox]').forEach(cb => {
  cb.addEventListener('change', () => {
    cb.closest('.class-chip').classList.toggle('checked', cb.checked);
  });
});

function fmtXAF(raw) {
  const n = parseInt(String(raw).replace(/[^\d]/g, ''));
  if (isNaN(n)) return raw;
  return n.toLocaleString('fr-CM');
}
document.querySelectorAll('.amount').forEach(el => {
  const raw    = el.dataset.raw || el.textContent.replace(/[^\d]/g, '');
  const hasXAF = el.textContent.includes('XAF');
  el.textContent = fmtXAF(raw) + (hasXAF ? ' XAF' : '');
});
</script>
{% endblock %}

======================================================================
FILE: templates/finance/bursar_dashboard.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Bursar Dashboard - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Bursar Dashboard</h1>
            <p class="text-muted">Financial overview — {{ "now"|date:"F Y" }}</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'finance:invoice_create' %}" class="btn btn-primary"><i class="fas fa-plus me-2"></i>New Invoice</a>
            <a href="{% url 'finance:payment_add' %}" class="btn btn-success"><i class="fas fa-money-bill me-2"></i>Record Payment</a>
            <a href="{% url 'finance:financial_reports' %}" class="btn btn-outline-secondary"><i class="fas fa-chart-bar me-2"></i>Reports</a>
        </div>
    </div>

    <!-- KPI Cards -->
    <div class="row mb-4">
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Total Revenue</div>
                    <div class="h4 mb-0 font-weight-bold">{{ total_revenue|floatformat:0 }} XAF</div>
                    <small class="text-muted">All time</small>
                </div>
            </div>
        </div>
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">This Month</div>
                    <div class="h4 mb-0 font-weight-bold">{{ monthly_revenue|floatformat:0 }} XAF</div>
                    <small class="text-muted">Net: {{ net_income|floatformat:0 }} XAF</small>
                </div>
            </div>
        </div>
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Pending Invoices</div>
                    <div class="h4 mb-0 font-weight-bold">{{ pending_invoices }}</div>
                    <a href="{% url 'finance:invoice_list' %}?status=sent" class="small text-warning">View all</a>
                </div>
            </div>
        </div>
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card border-left-danger shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-danger text-uppercase mb-1">Overdue</div>
                    <div class="h4 mb-0 font-weight-bold">{{ overdue_invoices }}</div>
                    <a href="{% url 'finance:invoice_list' %}?status=overdue" class="small text-danger">View all</a>
                </div>
            </div>
        </div>
    </div>

    <div class="row mb-4">
        <!-- Revenue Chart -->
        <div class="col-lg-8">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Revenue — Last 6 Months (XAF)</h6>
                </div>
                <div class="card-body">
                    <canvas id="revenueChart" height="100"></canvas>
                </div>
            </div>
        </div>
        <!-- Expenses Summary -->
        <div class="col-lg-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between">
                    <h6 class="m-0 font-weight-bold text-primary">This Month</h6>
                </div>
                <div class="card-body">
                    <div class="d-flex justify-content-between mb-3 pb-3 border-bottom">
                        <span class="text-success fw-bold"><i class="fas fa-arrow-up me-2"></i>Revenue</span>
                        <span class="fw-bold">{{ monthly_revenue|floatformat:0 }} XAF</span>
                    </div>
                    <div class="d-flex justify-content-between mb-3 pb-3 border-bottom">
                        <span class="text-danger fw-bold"><i class="fas fa-arrow-down me-2"></i>Expenses</span>
                        <span class="fw-bold">{{ monthly_expenses|floatformat:0 }} XAF</span>
                    </div>
                    <div class="d-flex justify-content-between">
                        <span class="fw-bold">Net Income</span>
                        <span class="fw-bold {% if net_income >= 0 %}text-success{% else %}text-danger{% endif %}">
                            {{ net_income|floatformat:0 }} XAF
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <!-- Recent Payments -->
        <div class="col-lg-7">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Recent Payments</h6>
                    <a href="{% url 'finance:payment_list' %}" class="btn btn-sm btn-outline-primary">View All</a>
                </div>
                <div class="card-body p-0">
                    <table class="table table-hover mb-0">
                        <thead class="table-light"><tr><th>Student</th><th>Amount</th><th>Date</th><th>Method</th></tr></thead>
                        <tbody>
                            {% for payment in recent_payments %}
                            <tr>
                                <td><a href="{% url 'students:student_detail' payment.student.pk %}">{{ payment.student.get_full_name }}</a></td>
                                <td class="text-success fw-bold">{{ payment.amount|floatformat:0 }} XAF</td>
                                <td>{{ payment.payment_date|date:"d M Y" }}</td>
                                <td><span class="badge bg-info">{{ payment.get_payment_method_display }}</span></td>
                            </tr>
                            {% empty %}
                            <tr><td colspan="4" class="text-center text-muted py-3">No recent payments</td></tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!-- Due Soon -->
        <div class="col-lg-5">
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-warning">Due This Week</h6>
                    <a href="{% url 'finance:invoice_list' %}" class="btn btn-sm btn-outline-warning">All Invoices</a>
                </div>
                <div class="card-body p-0">
                    <table class="table table-hover mb-0">
                        <thead class="table-light"><tr><th>Student</th><th>Due</th><th>Balance</th></tr></thead>
                        <tbody>
                            {% for inv in upcoming_due %}
                            <tr>
                                <td>{{ inv.student.get_full_name }}</td>
                                <td class="text-danger">{{ inv.due_date|date:"d M" }}</td>
                                <td class="fw-bold">{{ inv.balance|floatformat:0 }} XAF</td>
                            </tr>
                            {% empty %}
                            <tr><td colspan="3" class="text-center text-muted py-3">Nothing due this week</td></tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
const ctx = document.getElementById('revenueChart').getContext('2d');
new Chart(ctx, {
    type: 'bar',
    data: {
        labels: {{ chart_labels|safe }},
        datasets: [{
            label: 'Revenue (XAF)',
            data: {{ chart_data|safe }},
            backgroundColor: 'rgba(40, 167, 69, 0.7)',
            borderColor: 'rgba(40, 167, 69, 1)',
            borderWidth: 1
        }]
    },
    options: { responsive: true, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true } } }
});
</script>
{% endblock %}


======================================================================
FILE: templates/finance/discount_form.html
======================================================================
{% extends 'base.html' %}
{% block title %}Add Discount - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">{% if object %}Edit{% else %}Add{% endif %} Discount</h1>
        <a href="{% url 'finance:discount_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white"><h6 class="m-0"><i class="fas fa-tags me-2"></i>Discount Details</h6></div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}<div class="alert alert-danger">Please correct the errors below.</div>{% endif %}
                        <div class="row mb-3">
                            <div class="col-md-6"><label class="form-label fw-bold">Name (EN) <span class="text-danger">*</span></label>{{ form.name }}</div>
                            <div class="col-md-6"><label class="form-label fw-bold">Name (FR)</label>{{ form.name_fr }}</div>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-6"><label class="form-label fw-bold">Discount Type</label>{{ form.discount_type }}</div>
                            <div class="col-md-6"><label class="form-label fw-bold">Value <span class="text-danger">*</span></label>{{ form.value }}</div>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-6"><label class="form-label fw-bold">Applies To</label>{{ form.applies_to }}</div>
                        </div>
                        <div class="mb-3"><label class="form-label fw-bold">Specific Fees</label>{{ form.specific_fees }}</div>
                        <div class="mb-3"><label class="form-label fw-bold">Description</label>{{ form.description }}</div>
                        <div class="form-check mb-3">{{ form.is_active }}<label class="form-check-label fw-bold ms-2">Active</label></div>
                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'finance:discount_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary"><i class="fas fa-save me-2"></i>Save Discount</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => { el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control'); });</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/finance/discount_list.html
======================================================================
{% extends 'base.html' %}
{% block title %}Discounts - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Discounts</h1><p class="text-muted">Manage fee discounts and waivers</p></div>
        <div class="btn-group">
            <a href="{% url 'finance:discount_add' %}" class="btn btn-primary"><i class="fas fa-plus me-2"></i>Add Discount</a>
            <a href="{% url 'finance:student_discount_add' %}" class="btn btn-outline-primary"><i class="fas fa-user-tag me-2"></i>Apply to Student</a>
        </div>
    </div>
    <div class="card shadow">
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark"><tr><th>Name</th><th>Type</th><th>Value</th><th>Applies To</th><th>Active</th></tr></thead>
                <tbody>
                    {% for discount in discounts %}
                    <tr>
                        <td><div class="fw-bold">{{ discount.name }}</div><small class="text-muted">{{ discount.name_fr }}</small></td>
                        <td><span class="badge bg-info">{{ discount.get_discount_type_display }}</span></td>
                        <td class="fw-bold">{% if discount.discount_type == 'percentage' %}{{ discount.value }}%{% else %}{{ discount.value|floatformat:0 }} XAF{% endif %}</td>
                        <td>{{ discount.get_applies_to_display }}</td>
                        <td>{% if discount.is_active %}<span class="badge bg-success">Active</span>{% else %}<span class="badge bg-secondary">Inactive</span>{% endif %}</td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="5" class="text-center py-4 text-muted"><i class="fas fa-tags fa-2x mb-2 d-block"></i>No discounts defined yet.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/finance/enrollment_fee_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">{{ title }}</h1>
      <p class="text-muted mb-0">Assign a fee structure to a student for the academic year</p>
    </div>
    <a href="{% url 'finance:enrollment_fee_list' %}" class="btn btn-outline-secondary">
      <i class="fas fa-arrow-left me-1"></i>Back
    </a>
  </div>

  <div class="row justify-content-center">
    <div class="col-md-8">
      <div class="card shadow">
        <div class="card-header py-3 bg-primary text-white">
          <h6 class="m-0"><i class="fas fa-user-graduate me-2"></i>Enrollment Fee Details</h6>
        </div>
        <div class="card-body">
          <form method="post">
            {% csrf_token %}
            {% if form.errors %}
            <div class="alert alert-danger">
              Please correct the errors below. {{ form.non_field_errors }}
            </div>
            {% endif %}

            <div class="row mb-3">
              <div class="col-md-6">
                <label class="form-label fw-bold">Student <span class="text-danger">*</span></label>
                {{ form.student }}
                {% if form.student.errors %}<div class="text-danger small">{{ form.student.errors }}</div>{% endif %}
              </div>
              <div class="col-md-6">
                <label class="form-label fw-bold">Academic Year <span class="text-danger">*</span></label>
                {{ form.academic_year }}
              </div>
            </div>

            <div class="mb-3">
              <label class="form-label fw-bold">Fee Structure (Class Tier) <span class="text-danger">*</span></label>
              {{ form.fee_structure }}
              <div class="form-text">
                Select the row matching this student's class level and section.
              </div>
              {% if form.fee_structure.errors %}
              <div class="text-danger small">{{ form.fee_structure.errors }}</div>
              {% endif %}
            </div>

            <!-- Fee preview table (populated by JS) -->
            <div id="fee-preview" class="alert alert-light border mb-3" style="display:none;">
              <table class="table table-sm table-borderless mb-0">
                <tr>
                  <td class="text-muted">Registration (New)</td>
                  <td class="fw-bold text-end" id="prev-reg-new">—</td>
                </tr>
                <tr>
                  <td class="text-muted">Registration (Returning)</td>
                  <td class="fw-bold text-end" id="prev-reg-old">—</td>
                </tr>
                <tr><td colspan="2"><hr class="my-1"></td></tr>
                <tr>
                  <td class="text-muted">Total Annual Fees</td>
                  <td class="fw-bold text-primary text-end" id="prev-total">—</td>
                </tr>
                <tr>
                  <td class="text-muted">1st Installment</td>
                  <td class="text-success fw-bold text-end" id="prev-inst1">—</td>
                </tr>
                <tr>
                  <td class="text-muted">2nd Installment</td>
                  <td class="text-success fw-bold text-end" id="prev-inst2">—</td>
                </tr>
              </table>
            </div>

            <div class="mb-3">
              <div class="form-check">
                {{ form.is_new_pupil }}
                <label class="form-check-label fw-bold">New Pupil (first-time admission)</label>
              </div>
              <div class="form-text">
                Tick for new admissions — registration fee = 15,000 XAF.
                Leave unticked for returning pupils — registration fee = 10,000 XAF.
              </div>
            </div>

            <div class="row mb-3">
              <div class="col-md-6">
                <label class="form-label fw-bold">1st Installment Due Date</label>
                {{ form.installment_1_due }}
              </div>
              <div class="col-md-6">
                <label class="form-label fw-bold">2nd Installment Due Date</label>
                {{ form.installment_2_due }}
              </div>
            </div>

            <div class="mb-3">
              <label class="form-label fw-bold">Notes</label>
              {{ form.notes }}
            </div>

            <div class="d-flex justify-content-end gap-2 mt-4">
              <a href="{% url 'finance:enrollment_fee_list' %}" class="btn btn-secondary">Cancel</a>
              <button type="submit" class="btn btn-primary">
                <i class="fas fa-save me-1"></i>Save Enrollment Record
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>

    <!-- Fee structure quick-reference -->
    <div class="col-md-4">
      <div class="card shadow">
        <div class="card-header py-3">
          <h6 class="m-0 fw-bold text-primary">Available Fee Structures</h6>
        </div>
        <div class="card-body p-0">
          <table class="table table-sm table-hover mb-0">
            <thead class="table-light">
              <tr>
                <th>Section / Tier</th>
                <th class="text-end">Total</th>
              </tr>
            </thead>
            <tbody>
              {% for fs in fee_structures %}
              <tr data-pk="{{ fs.pk }}"
                  data-reg-new="{{ fs.registration_new }}"
                  data-reg-old="{{ fs.registration_old }}"
                  data-total="{{ fs.total_fees }}"
                  data-inst1="{{ fs.installment_1 }}"
                  data-inst2="{{ fs.installment_2 }}">
                <td>
                  <span class="badge {% if fs.section == 'anglo' %}bg-primary{% else %}bg-success{% endif %} me-1">
                    {{ fs.get_section_display }}
                  </span>
                  {{ fs.get_class_group_display }}
                </td>
                <td class="text-end fw-bold">{{ fs.total_fees|floatformat:0 }}</td>
              </tr>
              {% endfor %}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
// Apply Bootstrap classes
document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => {
  el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
});

// Fee preview on structure select
const feeSelect = document.querySelector('[name="fee_structure"]');
const preview   = document.getElementById('fee-preview');
const rows      = document.querySelectorAll('table tbody tr[data-pk]');

function fmt(n) { return parseInt(n).toLocaleString('fr-CM') + ' XAF'; }

feeSelect?.addEventListener('change', () => {
  const pk  = feeSelect.value;
  const row = [...rows].find(r => r.dataset.pk === pk);
  if (!row) { preview.style.display = 'none'; return; }
  document.getElementById('prev-reg-new').textContent  = fmt(row.dataset.regNew);
  document.getElementById('prev-reg-old').textContent  = fmt(row.dataset.regOld);
  document.getElementById('prev-total').textContent    = fmt(row.dataset.total);
  document.getElementById('prev-inst1').textContent    = fmt(row.dataset.inst1);
  document.getElementById('prev-inst2').textContent    = fmt(row.dataset.inst2);
  preview.style.display = 'block';
});
</script>
{% endblock %}

======================================================================
FILE: templates/finance/enrollment_fee_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Enrollment Fees — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">Student Enrollment Fees</h1>
      <p class="text-muted mb-0">Links each student to their fee tier and records new/returning status</p>
    </div>
    <a href="{% url 'finance:enrollment_fee_add' %}" class="btn btn-primary">
      <i class="fas fa-plus me-1"></i>Enroll Student
    </a>
  </div>

  {% if messages %}
    {% for msg in messages %}
    <div class="alert alert-{{ msg.tags|default:'info' }} alert-dismissible fade show">
      {{ msg }}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
    {% endfor %}
  {% endif %}

  <!-- Filter -->
  <div class="card shadow-sm mb-4">
    <div class="card-body py-2">
      <form method="get" class="row g-2 align-items-center">
        <div class="col-md-3">
          <input type="text" class="form-control form-control-sm" name="q"
                 placeholder="Search student…" value="{{ request.GET.q }}">
        </div>
        <div class="col-md-3">
          <select class="form-select form-select-sm" name="academic_year">
            <option value="">All Years</option>
            {% for yr in academic_years %}
            <option value="{{ yr }}" {% if request.GET.academic_year == yr %}selected{% endif %}>{{ yr }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="col-auto">
          <button type="submit" class="btn btn-sm btn-primary">Filter</button>
          <a href="{% url 'finance:enrollment_fee_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
        </div>
      </form>
    </div>
  </div>

  <div class="card shadow">
    <div class="card-body p-0">
      <div class="table-responsive">
        <table class="table table-hover mb-0">
          <thead class="table-light">
            <tr>
              <th>Student</th>
              <th>Year</th>
              <th>Section / Tier</th>
              <th>New/Returning</th>
              <th class="text-end">Reg. Fee</th>
              <th class="text-end">Total Fees</th>
              <th>1st Due</th>
              <th>2nd Due</th>
            </tr>
          </thead>
          <tbody>
            {% for ef in enrollment_fees %}
            <tr>
              <td>
                <a href="{% url 'students:student_detail' ef.student.pk %}">
                  {{ ef.student.get_full_name }}
                </a>
                <small class="text-muted d-block">{{ ef.student.student_id }}</small>
              </td>
              <td>{{ ef.academic_year }}</td>
              <td>
                <span class="badge {% if ef.fee_structure.section == 'anglo' %}bg-primary{% else %}bg-success{% endif %}">
                  {{ ef.fee_structure.get_section_display }}
                </span>
                <small class="d-block text-muted">{{ ef.fee_structure.get_class_group_display }}</small>
              </td>
              <td>
                {% if ef.is_new_pupil %}
                  <span class="badge bg-warning text-dark">New Pupil</span>
                {% else %}
                  <span class="badge bg-light text-dark border">Returning</span>
                {% endif %}
              </td>
              <td class="text-end">{{ ef.registration_fee|floatformat:0 }}</td>
              <td class="text-end fw-bold text-primary">{{ ef.total_fees|floatformat:0 }}</td>
              <td>{{ ef.installment_1_due|date:"d M Y"|default:"—" }}</td>
              <td>{{ ef.installment_2_due|date:"d M Y"|default:"—" }}</td>
            </tr>
            {% empty %}
            <tr>
              <td colspan="8" class="text-center py-5 text-muted">
                <i class="fas fa-user-graduate fa-3x d-block mb-3"></i>
                No enrollment records yet.
                <a href="{% url 'finance:enrollment_fee_add' %}">Add the first one</a>
              </td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>
  </div>

  {% if is_paginated %}
  <nav class="mt-3">
    <ul class="pagination justify-content-center">
      {% if page_obj.has_previous %}
      <li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}">«</a></li>
      {% endif %}
      {% for num in page_obj.paginator.page_range %}
        {% if page_obj.number == num %}
        <li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
        {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
        <li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
        {% endif %}
      {% endfor %}
      {% if page_obj.has_next %}
      <li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}">»</a></li>
      {% endif %}
    </ul>
  </nav>
  {% endif %}
</div>
{% endblock %}

======================================================================
FILE: templates/finance/expense_categories.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Expense Categories — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">

  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">Expense Categories</h1>
      <p class="text-muted mb-0">Manage categories used when recording expenses</p>
    </div>
    <a href="{% url 'finance:expense_list' %}" class="btn btn-outline-secondary">
      <i class="fas fa-arrow-left me-2"></i>Back to Expenses
    </a>
  </div>

  {% if messages %}
    {% for msg in messages %}
    <div class="alert alert-{{ msg.tags|default:'info' }} alert-dismissible fade show">
      {{ msg }}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
    {% endfor %}
  {% endif %}

  <div class="row g-4">

    <!-- ── Left: Category List ── -->
    <div class="col-lg-8">
      <div class="card shadow">
        <div class="card-header py-3 d-flex justify-content-between align-items-center">
          <h6 class="m-0 fw-bold text-primary">
            <i class="fas fa-list me-2"></i>All Categories
            <span class="badge bg-secondary ms-2">{{ categories|length }}</span>
          </h6>
          {% if not categories %}
          <form method="post">
            {% csrf_token %}
            <input type="hidden" name="action" value="seed">
            <button type="submit" class="btn btn-success btn-sm">
              <i class="fas fa-magic me-1"></i> Load Default Categories
            </button>
          </form>
          {% else %}
          <form method="post" onsubmit="return confirm('This will add any missing default categories without touching existing ones. Continue?')">
            {% csrf_token %}
            <input type="hidden" name="action" value="seed">
            <button type="submit" class="btn btn-outline-secondary btn-sm">
              <i class="fas fa-magic me-1"></i> Add Missing Defaults
            </button>
          </form>
          {% endif %}
        </div>

        {% if not categories %}
        <div class="card-body text-center py-5">
          <i class="fas fa-tags fa-3x text-muted mb-3"></i>
          <h5 class="text-muted">No categories yet</h5>
          <p class="text-muted mb-4">Click <strong>"Load Default Categories"</strong> to add 15 standard school expense categories instantly, or add your own using the form on the right.</p>
          <form method="post">
            {% csrf_token %}
            <input type="hidden" name="action" value="seed">
            <button type="submit" class="btn btn-success btn-lg">
              <i class="fas fa-magic me-2"></i>Load Default Categories
            </button>
          </form>
        </div>
        {% else %}
        <div class="card-body p-0">
          <table class="table table-hover mb-0">
            <thead class="table-light">
              <tr>
                <th class="ps-3">Category Name</th>
                <th>French Name</th>
                <th>Description</th>
                <th class="text-center">Status</th>
                <th class="text-end pe-3">Actions</th>
              </tr>
            </thead>
            <tbody>
              {% for cat in categories %}
              <tr class="{% if not cat.is_active %}text-muted{% endif %}">
                <td class="ps-3 fw-bold">
                  <i class="fas fa-tag me-2 text-primary opacity-75"></i>
                  {{ cat.name }}
                </td>
                <td class="text-muted fst-italic">{{ cat.name_fr|default:"—" }}</td>
                <td class="small text-muted">{{ cat.description|truncatechars:60|default:"—" }}</td>
                <td class="text-center">
                  {% if cat.is_active %}
                    <span class="badge bg-success">Active</span>
                  {% else %}
                    <span class="badge bg-secondary">Inactive</span>
                  {% endif %}
                </td>
                <td class="text-end pe-3">
                  <div class="btn-group btn-group-sm">
                    <!-- Toggle active/inactive -->
                    <form method="post" class="d-inline">
                      {% csrf_token %}
                      <input type="hidden" name="action" value="toggle">
                      <input type="hidden" name="pk" value="{{ cat.pk }}">
                      <button type="submit" class="btn {% if cat.is_active %}btn-outline-warning{% else %}btn-outline-success{% endif %}"
                              title="{% if cat.is_active %}Deactivate{% else %}Activate{% endif %}">
                        <i class="fas {% if cat.is_active %}fa-eye-slash{% else %}fa-eye{% endif %}"></i>
                      </button>
                    </form>
                    <!-- Delete -->
                    <form method="post" class="d-inline"
                          onsubmit="return confirm('Delete category \'{{ cat.name }}\'? This cannot be undone.')">
                      {% csrf_token %}
                      <input type="hidden" name="action" value="delete">
                      <input type="hidden" name="pk" value="{{ cat.pk }}">
                      <button type="submit" class="btn btn-outline-danger" title="Delete">
                        <i class="fas fa-trash"></i>
                      </button>
                    </form>
                  </div>
                </td>
              </tr>
              {% endfor %}
            </tbody>
          </table>
        </div>
        {% endif %}
      </div>
    </div>

    <!-- ── Right: Add New ── -->
    <div class="col-lg-4">
      <div class="card shadow">
        <div class="card-header py-3">
          <h6 class="m-0 fw-bold text-success"><i class="fas fa-plus me-2"></i>Add New Category</h6>
        </div>
        <div class="card-body">
          <form method="post">
            {% csrf_token %}
            <input type="hidden" name="action" value="add">
            <div class="mb-3">
              <label class="form-label fw-bold">Name (English) <span class="text-danger">*</span></label>
              <input type="text" class="form-control" name="name" placeholder="e.g. Maintenance & Repairs" required>
            </div>
            <div class="mb-3">
              <label class="form-label fw-bold">Name (French)</label>
              <input type="text" class="form-control" name="name_fr" placeholder="e.g. Entretien et réparations">
            </div>
            <div class="mb-4">
              <label class="form-label fw-bold">Description</label>
              <textarea class="form-control" name="description" rows="3"
                        placeholder="What kinds of expenses belong in this category?"></textarea>
            </div>
            <div class="d-grid">
              <button type="submit" class="btn btn-success">
                <i class="fas fa-plus me-2"></i>Add Category
              </button>
            </div>
          </form>
        </div>
      </div>

      <!-- Default categories reference card -->
      <div class="card shadow mt-3 border-info">
        <div class="card-header py-2 bg-info bg-opacity-10">
          <h6 class="m-0 fw-bold text-info"><i class="fas fa-info-circle me-2"></i>Default Categories</h6>
        </div>
        <div class="card-body p-2">
          <small class="text-muted">
            Clicking <em>"Load Default Categories"</em> will add these 15 standard school expense categories:
          </small>
          <ul class="list-unstyled mt-2 mb-0" style="font-size:.8rem;">
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Salaries &amp; Wages</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Teaching Materials</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Stationery &amp; Supplies</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Utilities</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Maintenance &amp; Repairs</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Transport</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Canteen &amp; Catering</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Uniforms &amp; Sportswear</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Exams &amp; Certificates</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Events &amp; Activities</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> IT &amp; Technology</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Cleaning &amp; Sanitation</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Security</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Bank &amp; Admin Charges</li>
            <li><i class="fas fa-circle text-primary me-1" style="font-size:.4rem;vertical-align:middle"></i> Miscellaneous</li>
          </ul>
        </div>
      </div>
    </div>

  </div>
</div>
{% endblock %}

======================================================================
FILE: templates/finance/expense_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{% if object %}Edit{% else %}Add{% endif %} Expense{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">{% if object %}Edit{% else %}Add{% endif %} Expense</h1>
        <a href="{% url 'finance:expense_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 bg-danger text-white"><h6 class="m-0"><i class="fas fa-receipt me-2"></i>Expense Details</h6></div>
                <div class="card-body">
                    <form method="post" enctype="multipart/form-data">
                        {% csrf_token %}
                        {% if form.errors %}<div class="alert alert-danger">Please correct the errors below.</div>{% endif %}
                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Category <span class="text-danger">*</span></label>
                                {{ form.category }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Expense Date <span class="text-danger">*</span></label>
                                {{ form.expense_date }}
                            </div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Description <span class="text-danger">*</span></label>
                            {{ form.description }}
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Amount (XAF) <span class="text-danger">*</span></label>
                                {{ form.amount }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Payment Method</label>
                                {{ form.payment_method }}
                            </div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Vendor / Supplier</label>
                            {{ form.vendor }}
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Notes</label>
                            {{ form.notes }}
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Receipt File</label>
                            {{ form.receipt_file }}
                        </div>
                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'finance:expense_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-danger"><i class="fas fa-save me-2"></i>Save Expense</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>
document.querySelectorAll('input:not(.form-check-input):not([type="submit"]):not([type="file"]), select, textarea').forEach(el => {
    el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
});
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/finance/expense_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Expenses - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Expenses</h1>
            <p class="text-muted">Total: {{ total_expenses|floatformat:0 }} XAF</p>
        </div>
        <a href="{% url 'finance:expense_add' %}" class="btn btn-primary"><i class="fas fa-plus me-2"></i>Add Expense</a>
    </div>

    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-3">
                    <label class="form-label">Category</label>
                    <select name="category" class="form-select">
                        <option value="">All Categories</option>
                        {% for cat in categories %}
                        <option value="{{ cat.pk }}" {% if request.GET.category == cat.pk|stringformat:"s" %}selected{% endif %}>{{ cat.name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3"><label class="form-label">From</label><input type="date" name="from_date" class="form-control" value="{{ request.GET.from_date }}"></div>
                <div class="col-md-3"><label class="form-label">To</label><input type="date" name="to_date" class="form-control" value="{{ request.GET.to_date }}"></div>
                <div class="col-md-3 d-flex gap-2">
                    <button type="submit" class="btn btn-primary flex-fill"><i class="fas fa-filter me-1"></i>Filter</button>
                    <a href="{% url 'finance:expense_list' %}" class="btn btn-outline-secondary">Clear</a>
                </div>
            </form>
        </div>
    </div>

    <div class="card shadow">
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark">
                    <tr><th>Date</th><th>Category</th><th>Description</th><th>Vendor</th><th>Amount</th><th>Method</th><th>Approved By</th><th>Actions</th></tr>
                </thead>
                <tbody>
                    {% for expense in expenses %}
                    <tr>
                        <td>{{ expense.expense_date|date:"d M Y" }}</td>
                        <td><span class="badge bg-secondary">{{ expense.category.name }}</span></td>
                        <td>{{ expense.description }}</td>
                        <td>{{ expense.vendor|default:"—" }}</td>
                        <td class="text-danger fw-bold">{{ expense.amount|floatformat:0 }} XAF</td>
                        <td>{{ expense.get_payment_method_display }}</td>
                        <td>{% if expense.approved_by %}<span class="badge bg-success">{{ expense.approved_by.get_full_name }}</span>{% else %}<span class="badge bg-warning text-dark">Pending</span>{% endif %}</td>
                        <td>
                            <a href="{% url 'finance:expense_edit' expense.pk %}" class="btn btn-sm btn-outline-warning"><i class="fas fa-edit"></i></a>
                        </td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="8" class="text-center py-4 text-muted"><i class="fas fa-receipt fa-2x mb-2 d-block"></i>No expenses found.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
    {% if is_paginated %}
    <nav class="mt-4"><ul class="pagination justify-content-center">
        {% if page_obj.has_previous %}<li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a></li>{% endif %}
        <li class="page-item active"><a class="page-link" href="#">{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</a></li>
        {% if page_obj.has_next %}<li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a></li>{% endif %}
    </ul></nav>
    {% endif %}
</div>
{% endblock %}


======================================================================
FILE: templates/finance/fee_confirm_delete.html
======================================================================
{% extends 'base.html' %}
{% block title %}Delete Fee Structure{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="row justify-content-center mt-5">
        <div class="col-md-5">
            <div class="card shadow border-danger">
                <div class="card-header bg-danger text-white"><h5 class="mb-0"><i class="fas fa-exclamation-triangle me-2"></i>Confirm Delete</h5></div>
                <div class="card-body text-center py-4">
                    <div class="rounded-circle bg-danger bg-opacity-10 d-inline-flex align-items-center justify-content-center mb-4" style="width:80px;height:80px;">
                        <i class="fas fa-money-check fa-2x text-danger"></i>
                    </div>
                    <h4>Delete <strong>{{ fee.name }}</strong>?</h4>
                    <p class="text-muted">Amount: {{ fee.amount|floatformat:0 }} XAF &bull; {{ fee.get_fee_type_display }}</p>
                    <div class="alert alert-warning text-start"><i class="fas fa-exclamation-circle me-2"></i><strong>This cannot be undone.</strong> Any invoices already generated from this fee will remain.</div>
                    <div class="d-flex justify-content-center gap-3 mt-4">
                        <a href="{% url 'finance:fee_detail' fee.pk %}" class="btn btn-secondary btn-lg"><i class="fas fa-arrow-left me-2"></i>Cancel</a>
                        <form method="post">{% csrf_token %}
                            <button type="submit" class="btn btn-danger btn-lg"><i class="fas fa-trash me-2"></i>Delete</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/finance/fee_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ fee.name }} — Fee Detail{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">{{ fee.name }}</h1>
      <p class="text-muted mb-0">
        {{ fee.get_section_display }} &bull; {{ fee.get_class_group_display }} &bull; {{ fee.academic_year }}
      </p>
    </div>
    <div class="btn-group">
      <a href="{% url 'finance:fee_list' %}" class="btn btn-outline-secondary">
        <i class="fas fa-arrow-left me-1"></i>Back
      </a>
      <a href="{% url 'finance:fee_edit' fee.pk %}" class="btn btn-warning">
        <i class="fas fa-edit me-1"></i>Edit
      </a>
      <a href="{% url 'finance:fee_delete' fee.pk %}" class="btn btn-danger">
        <i class="fas fa-trash me-1"></i>Delete
      </a>
    </div>
  </div>

  <div class="row">
    <!-- Main details -->
    <div class="col-md-7">
      <div class="card shadow mb-4">
        <div class="card-header py-3">
          <h6 class="m-0 fw-bold text-primary">Fee Details</h6>
        </div>
        <div class="card-body">
          <table class="table table-borderless mb-0">
            <tr>
              <td class="text-muted fw-bold" width="35%">Section</td>
              <td>
                <span class="badge {% if fee.section == 'anglo' %}bg-primary{% else %}bg-success{% endif %}">
                  {{ fee.get_section_display }}
                </span>
              </td>
            </tr>
            <tr>
              <td class="text-muted fw-bold">Class Group</td>
              <td><strong>{{ fee.get_class_group_display }}</strong></td>
            </tr>
            <tr>
              <td class="text-muted fw-bold">Academic Year</td>
              <td>{{ fee.academic_year }}</td>
            </tr>
            <tr><td colspan="2"><hr class="my-1"></td></tr>
            <tr>
              <td class="text-muted fw-bold">Registration — New Pupil</td>
              <td class="fw-bold text-warning">{{ fee.registration_new|floatformat:0 }} XAF</td>
            </tr>
            <tr>
              <td class="text-muted fw-bold">Registration — Returning Pupil</td>
              <td class="fw-bold text-warning">{{ fee.registration_old|floatformat:0 }} XAF</td>
            </tr>
            <tr><td colspan="2"><hr class="my-1"></td></tr>
            <tr>
              <td class="text-muted fw-bold">Total Annual Fees</td>
              <td class="fw-bold text-primary fs-5">{{ fee.total_fees|floatformat:0 }} XAF</td>
            </tr>
            <tr>
              <td class="text-muted fw-bold">1st Installment</td>
              <td class="text-success fw-bold">{{ fee.installment_1|floatformat:0 }} XAF</td>
            </tr>
            <tr>
              <td class="text-muted fw-bold">2nd Installment</td>
              <td class="text-success fw-bold">{{ fee.installment_2|floatformat:0 }} XAF</td>
            </tr>
            <tr><td colspan="2"><hr class="my-1"></td></tr>
            <tr>
              <td class="text-muted fw-bold">Status</td>
              <td>
                {% if fee.is_active %}
                  <span class="badge bg-success">Active</span>
                {% else %}
                  <span class="badge bg-secondary">Inactive</span>
                {% endif %}
              </td>
            </tr>
            {% if fee.description %}
            <tr>
              <td class="text-muted fw-bold">Notes</td>
              <td>{{ fee.description }}</td>
            </tr>
            {% endif %}
          </table>
        </div>
      </div>
    </div>

    <!-- Applicable classes -->
    <div class="col-md-5">
      {% if applicable_classes %}
      <div class="card shadow">
        <div class="card-header py-3">
          <h6 class="m-0 fw-bold text-primary">Pinned to Specific Classes</h6>
        </div>
        <div class="card-body p-0">
          <ul class="list-group list-group-flush">
            {% for cls in applicable_classes %}
            <li class="list-group-item">
              <i class="fas fa-chalkboard text-primary me-2"></i>{{ cls }}
            </li>
            {% endfor %}
          </ul>
        </div>
      </div>
      {% else %}
      <div class="alert alert-light border">
        <i class="fas fa-info-circle me-2 text-muted"></i>
        This fee row applies to <strong>all classes</strong> in its group — no specific class pins.
      </div>
      {% endif %}
    </div>
  </div>
</div>
{% endblock %}

======================================================================
FILE: templates/finance/fee_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">{{ title }}</h1>
      <p class="text-muted mb-0">All amounts in XAF (Central African CFA Franc)</p>
    </div>
    <a href="{% url 'finance:fee_list' %}" class="btn btn-outline-secondary">
      <i class="fas fa-arrow-left me-1"></i>Back
    </a>
  </div>

  <div class="row justify-content-center">
    <div class="col-md-9">
      <div class="card shadow">
        <div class="card-header py-3 bg-primary text-white">
          <h6 class="m-0"><i class="fas fa-money-check-alt me-2"></i>Fee Structure Details</h6>
        </div>
        <div class="card-body">
          <form method="post">
            {% csrf_token %}
            {% if form.errors %}
            <div class="alert alert-danger">
              <i class="fas fa-exclamation-circle me-2"></i>Please correct the errors below.
              {{ form.non_field_errors }}
            </div>
            {% endif %}

            <!-- Section & Class Group -->
            <h6 class="text-primary border-bottom pb-2 mb-3">Classification</h6>
            <div class="row mb-3">
              <div class="col-md-4">
                <label class="form-label fw-bold">Section <span class="text-danger">*</span></label>
                {{ form.section }}
                {% if form.section.errors %}<div class="text-danger small">{{ form.section.errors }}</div>{% endif %}
              </div>
              <div class="col-md-4">
                <label class="form-label fw-bold">Class Group <span class="text-danger">*</span></label>
                {{ form.class_group }}
                {% if form.class_group.errors %}<div class="text-danger small">{{ form.class_group.errors }}</div>{% endif %}
              </div>
              <div class="col-md-4">
                <label class="form-label fw-bold">Academic Year <span class="text-danger">*</span></label>
                {{ form.academic_year }}
              </div>
            </div>

            <!-- Registration Fees -->
            <h6 class="text-primary border-bottom pb-2 mb-3 mt-4">Registration Fees</h6>
            <div class="alert alert-light border mb-3 small">
              <i class="fas fa-info-circle me-1 text-info"></i>
              Registration fees differ for <strong>new admissions</strong> vs <strong>returning pupils</strong>.
              From your fee table: New = 15,000 XAF / Returning = 10,000 XAF.
            </div>
            <div class="row mb-3">
              <div class="col-md-6">
                <label class="form-label fw-bold">New Pupil Registration (XAF) <span class="text-danger">*</span></label>
                {{ form.registration_new }}
                {% if form.registration_new.errors %}<div class="text-danger small">{{ form.registration_new.errors }}</div>{% endif %}
              </div>
              <div class="col-md-6">
                <label class="form-label fw-bold">Returning Pupil Registration (XAF) <span class="text-danger">*</span></label>
                {{ form.registration_old }}
                {% if form.registration_old.errors %}<div class="text-danger small">{{ form.registration_old.errors }}</div>{% endif %}
              </div>
            </div>

            <!-- Tuition & Installments -->
            <h6 class="text-primary border-bottom pb-2 mb-3 mt-4">Annual Tuition &amp; Installments</h6>
            <div class="alert alert-light border mb-3 small">
              <i class="fas fa-info-circle me-1 text-info"></i>
              <strong>Total Fees must equal 1st Installment + 2nd Installment.</strong>
              The system will validate this before saving.
            </div>
            <div class="row mb-3">
              <div class="col-md-4">
                <label class="form-label fw-bold">Total Annual Fees (XAF) <span class="text-danger">*</span></label>
                {{ form.total_fees }}
                {% if form.total_fees.errors %}<div class="text-danger small">{{ form.total_fees.errors }}</div>{% endif %}
              </div>
              <div class="col-md-4">
                <label class="form-label fw-bold">1st Installment (XAF) <span class="text-danger">*</span></label>
                {{ form.installment_1 }}
                {% if form.installment_1.errors %}<div class="text-danger small">{{ form.installment_1.errors }}</div>{% endif %}
              </div>
              <div class="col-md-4">
                <label class="form-label fw-bold">2nd Installment (XAF) <span class="text-danger">*</span></label>
                {{ form.installment_2 }}
                {% if form.installment_2.errors %}<div class="text-danger small">{{ form.installment_2.errors }}</div>{% endif %}
              </div>
            </div>

            <!-- Live validation hint -->
            <div class="alert alert-info small mb-4" id="installment-check" style="display:none;">
              <span id="installment-msg"></span>
            </div>

            <!-- Optional class pins -->
            <h6 class="text-primary border-bottom pb-2 mb-3 mt-2">Optional — Pin to Specific Classes</h6>
            <div class="mb-3">
              <label class="form-label fw-bold">Specific Classes</label>
              {{ form.specific_classes }}
              <div class="form-text">Leave blank to apply to the whole class group.</div>
            </div>

            <!-- Settings -->
            <h6 class="text-primary border-bottom pb-2 mb-3 mt-4">Settings</h6>
            <div class="row mb-3">
              <div class="col-md-8">
                <label class="form-label fw-bold">Notes</label>
                {{ form.description }}
              </div>
              <div class="col-md-4 d-flex align-items-center mt-4">
                <div class="form-check">
                  {{ form.is_active }}
                  <label class="form-check-label fw-bold">Active</label>
                </div>
              </div>
            </div>

            <div class="d-flex justify-content-end gap-2 mt-4">
              <a href="{% url 'finance:fee_list' %}" class="btn btn-secondary">Cancel</a>
              <button type="submit" class="btn btn-primary">
                <i class="fas fa-save me-1"></i>Save Fee Structure
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
// Apply Bootstrap classes to all form inputs
document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => {
  if (!el.classList.contains('form-control') && !el.classList.contains('form-select')) {
    el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
  }
});

// Live installment validation
const fTotal = document.querySelector('[name="total_fees"]');
const fInst1 = document.querySelector('[name="installment_1"]');
const fInst2 = document.querySelector('[name="installment_2"]');
const checkDiv = document.getElementById('installment-check');
const checkMsg = document.getElementById('installment-msg');

function validateInstallments() {
  const t = parseFloat(fTotal?.value) || 0;
  const i1 = parseFloat(fInst1?.value) || 0;
  const i2 = parseFloat(fInst2?.value) || 0;
  if (!t && !i1 && !i2) { checkDiv.style.display = 'none'; return; }
  checkDiv.style.display = 'block';
  const sum = i1 + i2;
  if (sum === t) {
    checkDiv.className = 'alert alert-success small mb-4';
    checkMsg.textContent = `✓ ${i1.toLocaleString()} + ${i2.toLocaleString()} = ${t.toLocaleString()} XAF — correct!`;
  } else {
    checkDiv.className = 'alert alert-danger small mb-4';
    checkMsg.textContent = `✗ ${i1.toLocaleString()} + ${i2.toLocaleString()} = ${sum.toLocaleString()}, but Total is ${t.toLocaleString()} XAF — must be equal.`;
  }
}

[fTotal, fInst1, fInst2].forEach(el => el?.addEventListener('input', validateInstallments));
</script>
{% endblock %}

======================================================================
FILE: templates/finance/fee_structure.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Fee Structure — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">

  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">Fee Structure</h1>
      <p class="text-muted mb-0">Anglo &amp; Bilingual sections — tuition installments</p>
    </div>
    <div class="btn-group">
      <a href="{% url 'finance:fee_add' %}" class="btn btn-primary">
        <i class="fas fa-plus me-1"></i> Add Fee Row
      </a>
      <a href="{% url 'finance:school_item_list' %}" class="btn btn-outline-secondary">
        <i class="fas fa-tshirt me-1"></i> Item Prices
      </a>
    </div>
  </div>

  {% if messages %}
    {% for msg in messages %}
    <div class="alert alert-{{ msg.tags|default:'info' }} alert-dismissible fade show">
      {{ msg }}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
    {% endfor %}
  {% endif %}

  <!-- Filter bar -->
  <div class="card shadow-sm mb-4">
    <div class="card-body py-2">
      <form method="get" class="row g-2 align-items-center">
        <div class="col-md-3">
          <select class="form-select form-select-sm" name="academic_year">
            <option value="">All Academic Years</option>
            {% for yr in academic_years %}
            <option value="{{ yr }}" {% if request.GET.academic_year == yr %}selected{% endif %}>{{ yr }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="col-md-3">
          <select class="form-select form-select-sm" name="section">
            <option value="">All Sections</option>
            {% for val, label in section_choices %}
            <option value="{{ val }}" {% if request.GET.section == val %}selected{% endif %}>{{ label }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="col-md-2">
          <select class="form-select form-select-sm" name="active">
            <option value="">All</option>
            <option value="active"   {% if request.GET.active == 'active'   %}selected{% endif %}>Active</option>
            <option value="inactive" {% if request.GET.active == 'inactive' %}selected{% endif %}>Inactive</option>
          </select>
        </div>
        <div class="col-auto">
          <button type="submit" class="btn btn-sm btn-primary">Filter</button>
          <a href="{% url 'finance:fee_list' %}" class="btn btn-sm btn-outline-secondary">Clear</a>
        </div>
      </form>
    </div>
  </div>

  <!-- Fee table -->
  <div class="card shadow">
    <div class="card-body p-0">
      <div class="table-responsive">
        <table class="table table-hover mb-0">
          <thead class="table-dark">
            <tr>
              <th>Section</th>
              <th>Class Group</th>
              <th>Year</th>
              <th class="text-end">Reg. (New)</th>
              <th class="text-end">Reg. (Old)</th>
              <th class="text-end">Total Fees</th>
              <th class="text-end">1st Inst.</th>
              <th class="text-end">2nd Inst.</th>
              <th>Status</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {% for fee in fees %}
            <tr>
              <td>
                <span class="badge {% if fee.section == 'anglo' %}bg-primary{% else %}bg-success{% endif %}">
                  {{ fee.get_section_display }}
                </span>
              </td>
              <td class="fw-bold">{{ fee.get_class_group_display }}</td>
              <td>{{ fee.academic_year }}</td>
              <td class="text-end">{{ fee.registration_new|floatformat:0 }}</td>
              <td class="text-end">{{ fee.registration_old|floatformat:0 }}</td>
              <td class="text-end fw-bold text-primary">{{ fee.total_fees|floatformat:0 }}</td>
              <td class="text-end text-success">{{ fee.installment_1|floatformat:0 }}</td>
              <td class="text-end text-success">{{ fee.installment_2|floatformat:0 }}</td>
              <td>
                {% if fee.is_active %}
                  <span class="badge bg-success">Active</span>
                {% else %}
                  <span class="badge bg-secondary">Inactive</span>
                {% endif %}
              </td>
              <td>
                <a href="{% url 'finance:fee_detail' fee.pk %}" class="btn btn-sm btn-outline-primary" title="View">
                  <i class="fas fa-eye"></i>
                </a>
                <a href="{% url 'finance:fee_edit' fee.pk %}" class="btn btn-sm btn-outline-warning" title="Edit">
                  <i class="fas fa-edit"></i>
                </a>
                <a href="{% url 'finance:fee_delete' fee.pk %}" class="btn btn-sm btn-outline-danger" title="Delete">
                  <i class="fas fa-trash"></i>
                </a>
              </td>
            </tr>
            {% empty %}
            <tr>
              <td colspan="10" class="text-center py-5 text-muted">
                <i class="fas fa-table fa-3x d-block mb-3"></i>
                No fee structures defined yet.
                <a href="{% url 'finance:fee_add' %}">Add the first one</a>
              </td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>
  </div>

  {% if is_paginated %}
  <nav class="mt-3">
    <ul class="pagination justify-content-center">
      {% if page_obj.has_previous %}
      <li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}">«</a></li>
      {% endif %}
      {% for num in page_obj.paginator.page_range %}
        {% if page_obj.number == num %}
        <li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
        {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
        <li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
        {% endif %}
      {% endfor %}
      {% if page_obj.has_next %}
      <li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}">»</a></li>
      {% endif %}
    </ul>
  </nav>
  {% endif %}

</div>
{% endblock %}

======================================================================
FILE: templates/finance/invoice_confirm_delete.html
======================================================================
{% extends 'base.html' %}
{% block title %}Delete Invoice{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="row justify-content-center mt-5">
        <div class="col-md-5">
            <div class="card shadow border-danger">
                <div class="card-header bg-danger text-white"><h5 class="mb-0"><i class="fas fa-exclamation-triangle me-2"></i>Confirm Delete</h5></div>
                <div class="card-body text-center py-4">
                    <div class="rounded-circle bg-danger bg-opacity-10 d-inline-flex align-items-center justify-content-center mb-4" style="width:80px;height:80px;">
                        <i class="fas fa-file-invoice fa-2x text-danger"></i>
                    </div>
                    <h4>Delete Invoice <strong>{{ invoice.invoice_number }}</strong>?</h4>
                    <p class="text-muted">{{ invoice.student.get_full_name }} &bull; {{ invoice.total_amount|floatformat:0 }} XAF</p>
                    <div class="alert alert-warning text-start"><i class="fas fa-exclamation-circle me-2"></i><strong>This cannot be undone.</strong> Associated payments will also be affected.</div>
                    <div class="d-flex justify-content-center gap-3 mt-4">
                        <a href="{% url 'finance:invoice_detail' invoice.pk %}" class="btn btn-secondary btn-lg">Cancel</a>
                        <form method="post">{% csrf_token %}
                            <button type="submit" class="btn btn-danger btn-lg"><i class="fas fa-trash me-2"></i>Delete Invoice</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/finance/invoice_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Invoice {{ invoice.invoice_number }}{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">Invoice {{ invoice.invoice_number }}</h1>
      <p class="text-muted mb-0">
        {{ invoice.student.get_full_name }} &bull;
        {{ invoice.academic_year }} &bull;
        {{ invoice.get_invoice_type_display }}
      </p>
    </div>
    <div class="btn-group">
      <a href="{% url 'finance:invoice_list' %}" class="btn btn-outline-secondary">
        <i class="fas fa-arrow-left me-1"></i>Back
      </a>
      <a href="{% url 'finance:invoice_edit' invoice.pk %}" class="btn btn-warning">
        <i class="fas fa-edit me-1"></i>Edit
      </a>
      <a href="{% url 'finance:payment_add' %}?invoice={{ invoice.pk }}" class="btn btn-success">
        <i class="fas fa-money-bill me-1"></i>Record Payment
      </a>
      <a href="{% url 'finance:invoice_delete' invoice.pk %}" class="btn btn-danger">
        <i class="fas fa-trash me-1"></i>Delete
      </a>
    </div>
  </div>

  <div class="row">
    <!-- Invoice body -->
    <div class="col-lg-8">
      <div class="card shadow mb-4">
        <div class="card-body">
          <!-- Header -->
          <div class="row mb-4">
            <div class="col-6">
              <h5 class="text-primary">Rapha-Bethel BNPS</h5>
              <p class="text-muted mb-0">Bilingual Nursery &amp; Primary School</p>
              <p class="text-muted mb-0">Douala, Cameroon</p>
              <p class="text-muted">+237 6 70 17 79 79</p>
            </div>
            <div class="col-6 text-end">
              <h4 class="text-uppercase text-muted">Invoice</h4>
              <p class="mb-1"><strong>#{{ invoice.invoice_number }}</strong></p>
              <p class="mb-1">Issued: {{ invoice.issue_date|date:"d M Y" }}</p>
              <p class="mb-0 {% if invoice.is_overdue %}text-danger fw-bold{% endif %}">
                Due: {{ invoice.due_date|date:"d M Y" }}
              </p>
            </div>
          </div>
          <hr>

          <!-- Bill To -->
          <div class="row mb-4">
            <div class="col-6">
              <h6 class="text-muted text-uppercase small">Bill To</h6>
              <p class="fw-bold mb-0">{{ invoice.student.get_full_name }}</p>
              <p class="text-muted mb-0">ID: {{ invoice.student.student_id }}</p>
              <p class="text-muted mb-0">Class: {{ invoice.student.current_class|default:"—" }}</p>
              {% if invoice.enrollment_fee %}
              <p class="text-muted mb-0 small">
                {{ invoice.enrollment_fee.fee_structure.get_section_display }} —
                {{ invoice.enrollment_fee.fee_structure.get_class_group_display }}
              </p>
              {% endif %}
            </div>
            <div class="col-6 text-end">
              <span class="badge fs-6
                {% if invoice.status == 'paid' %}bg-success
                {% elif invoice.status == 'overdue' %}bg-danger
                {% elif invoice.status == 'partial' %}bg-warning text-dark
                {% elif invoice.status == 'draft' %}bg-secondary
                {% else %}bg-info{% endif %}">
                {{ invoice.get_status_display }}
              </span>
              <p class="mt-2 text-muted small">{{ invoice.get_invoice_type_display }}</p>
            </div>
          </div>

          <!-- Line Items -->
          <table class="table">
            <thead class="table-dark">
              <tr>
                <th>Description</th>
                <th class="text-end">Amount (XAF)</th>
              </tr>
            </thead>
            <tbody>
              {% for item in items %}
              <tr>
                <td>
                  {{ item.description }}
                  {% if item.fee_structure %}
                  <small class="text-muted">
                    ({{ item.fee_structure.get_section_display }} —
                    {{ item.fee_structure.get_class_group_display }})
                  </small>
                  {% elif item.school_item %}
                  <small class="text-muted">({{ item.school_item.get_item_type_display }})</small>
                  {% endif %}
                </td>
                <td class="text-end">{{ item.total|floatformat:0 }}</td>
              </tr>
              {% empty %}
              <tr><td colspan="2" class="text-center text-muted">No line items</td></tr>
              {% endfor %}
            </tbody>
            <tfoot>
              <tr class="table-dark">
                <td class="text-end fw-bold">Total</td>
                <td class="text-end fw-bold">{{ invoice.total_amount|floatformat:0 }}</td>
              </tr>
              <tr class="text-success">
                <td class="text-end">Amount Paid</td>
                <td class="text-end">{{ invoice.amount_paid|floatformat:0 }}</td>
              </tr>
              <tr class="{% if invoice.balance > 0 %}table-warning{% else %}table-success{% endif %}">
                <td class="text-end fw-bold">Balance Due</td>
                <td class="text-end fw-bold">{{ invoice.balance|floatformat:0 }}</td>
              </tr>
            </tfoot>
          </table>

          {% if invoice.notes %}
          <div class="alert alert-light mt-3">
            <strong>Notes:</strong> {{ invoice.notes }}
          </div>
          {% endif %}
        </div>
      </div>

      <!-- Payment History -->
      <div class="card shadow mb-4">
        <div class="card-header py-3 d-flex justify-content-between align-items-center">
          <h6 class="m-0 fw-bold text-primary">Payment History</h6>
          <a href="{% url 'finance:payment_add' %}?invoice={{ invoice.pk }}" class="btn btn-sm btn-success">
            + Record Payment
          </a>
        </div>
        <div class="card-body p-0">
          <table class="table table-hover mb-0">
            <thead class="table-light">
              <tr>
                <th>Payment #</th><th>Date</th><th>Method</th>
                <th>Amount</th><th>Status</th><th></th>
              </tr>
            </thead>
            <tbody>
              {% for p in payments %}
              <tr>
                <td><a href="{% url 'finance:payment_detail' p.pk %}">{{ p.payment_number }}</a></td>
                <td>{{ p.payment_date|date:"d M Y" }}</td>
                <td>{{ p.get_payment_method_display }}</td>
                <td class="text-success fw-bold">{{ p.amount|floatformat:0 }} XAF</td>
                <td>
                  <span class="badge bg-{% if p.status == 'completed' %}success{% else %}warning text-dark{% endif %}">
                    {{ p.get_status_display }}
                  </span>
                </td>
                <td>
                  <a href="{% url 'finance:generate_receipt' p.pk %}" class="btn btn-sm btn-outline-secondary">
                    <i class="fas fa-receipt"></i>
                  </a>
                </td>
              </tr>
              {% empty %}
              <tr><td colspan="6" class="text-center text-muted py-3">No payments recorded yet.</td></tr>
              {% endfor %}
            </tbody>
          </table>
        </div>
      </div>
    </div>

    <!-- Sidebar -->
    <div class="col-lg-4">
      <div class="card shadow mb-4">
        <div class="card-header py-3">
          <h6 class="m-0 fw-bold text-primary">Payment Progress</h6>
        </div>
        <div class="card-body">
          <div class="d-flex justify-content-between mb-1">
            <span>{{ invoice.payment_percentage|floatformat:1 }}% paid</span>
            <span class="text-muted">
              {{ invoice.amount_paid|floatformat:0 }} / {{ invoice.total_amount|floatformat:0 }}
            </span>
          </div>
          <div class="progress mb-3" style="height:12px">
            <div class="progress-bar bg-success" style="width:{{ invoice.payment_percentage }}%"></div>
          </div>
          <p class="text-center fw-bold {% if invoice.balance > 0 %}text-danger{% else %}text-success{% endif %}">
            Balance: {{ invoice.balance|floatformat:0 }} XAF
          </p>
        </div>
      </div>

      {% if reminders %}
      <div class="card shadow">
        <div class="card-header py-3">
          <h6 class="m-0 fw-bold text-primary">Reminders Sent</h6>
        </div>
        <ul class="list-group list-group-flush">
          {% for r in reminders %}
          <li class="list-group-item small">
            <i class="fas fa-bell text-warning me-2"></i>
            {{ r.sent_date|date:"d M Y" }} — {{ r.get_reminder_type_display }} to {{ r.sent_to }}
          </li>
          {% endfor %}
        </ul>
      </div>
      {% endif %}
    </div>
  </div>
</div>
{% endblock %}

======================================================================
FILE: templates/finance/invoice_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div><h1 class="h3 mb-0">{{ title }}</h1></div>
    <a href="{% url 'finance:invoice_list' %}" class="btn btn-outline-secondary">
      <i class="fas fa-arrow-left me-1"></i>Back
    </a>
  </div>

  <div class="row justify-content-center">
    <div class="col-md-8">
      <div class="card shadow">
        <div class="card-header py-3 bg-primary text-white">
          <h6 class="m-0"><i class="fas fa-file-invoice me-2"></i>Invoice Details</h6>
        </div>
        <div class="card-body">
          <form method="post">
            {% csrf_token %}
            {% if form.errors %}
            <div class="alert alert-danger">
              Please correct the errors below. {{ form.non_field_errors }}
            </div>
            {% endif %}

            {% if not object %}
            <!-- Student -->
            <div class="mb-3">
              <label class="form-label fw-bold">Student <span class="text-danger">*</span></label>
              {{ form.student }}
              {% if form.student.errors %}<div class="text-danger small">{{ form.student.errors }}</div>{% endif %}
            </div>
            {% else %}
            <div class="alert alert-info">
              Editing invoice for: <strong>{{ object.student.get_full_name }}</strong>
            </div>
            {% endif %}

            <div class="row mb-3">
              <div class="col-md-6">
                <label class="form-label fw-bold">Academic Year <span class="text-danger">*</span></label>
                {{ form.academic_year }}
              </div>
              <div class="col-md-6">
                <label class="form-label fw-bold">Invoice Type <span class="text-danger">*</span></label>
                {{ form.invoice_type }}
                <div class="form-text">
                  Registration / 1st Installment / 2nd Installment / Item Sale
                </div>
              </div>
            </div>

            {% if not object %}
            <div class="mb-3">
              <label class="form-label fw-bold">Enrollment Fee Record</label>
              {{ form.enrollment_fee }}
              <div class="form-text">
                Link to the student's enrollment fee for this year (optional but recommended).
              </div>
            </div>
            {% endif %}

            <div class="row mb-3">
              {% if not object %}
              <div class="col-md-6">
                <label class="form-label fw-bold">Total Amount (XAF) <span class="text-danger">*</span></label>
                <input type="number" name="total_amount" class="form-control"
                       value="{{ form.total_amount.value|default:'' }}" min="0">
              </div>
              {% endif %}
              <div class="col-md-{% if not object %}6{% else %}12{% endif %}">
                <label class="form-label fw-bold">Due Date <span class="text-danger">*</span></label>
                {{ form.due_date }}
                {% if form.due_date.errors %}<div class="text-danger small">{{ form.due_date.errors }}</div>{% endif %}
              </div>
            </div>

            {% if object %}
            <div class="mb-3">
              <label class="form-label fw-bold">Status</label>
              {{ form.status }}
            </div>
            {% endif %}

            <div class="mb-3">
              <label class="form-label fw-bold">Notes</label>
              {{ form.notes }}
            </div>

            <div class="d-flex justify-content-end gap-2 mt-4">
              <a href="{% url 'finance:invoice_list' %}" class="btn btn-secondary">Cancel</a>
              <button type="submit" class="btn btn-primary">
                <i class="fas fa-save me-1"></i>
                {{ object|yesno:"Update Invoice,Create Invoice" }}
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => {
  el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
});
</script>
{% endblock %}

======================================================================
FILE: templates/finance/invoices.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Invoices — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">

  <div class="d-flex justify-content-between align-items-center mb-4">
    <h1 class="h3 mb-0">Fee Invoices</h1>
    <div class="btn-group">
      <a href="{% url 'finance:bulk_invoice' %}" class="btn btn-success">
        <i class="fas fa-bolt me-1"></i>Bulk Generate
      </a>
      <a href="{% url 'finance:invoice_create' %}" class="btn btn-primary">
        <i class="fas fa-plus me-1"></i>Create Invoice
      </a>
      <a href="{% url 'finance:export_invoices' %}" class="btn btn-outline-secondary">
        <i class="fas fa-download me-1"></i>Export CSV
      </a>
    </div>
  </div>

  <!-- Stats -->
  <div class="row mb-4">
    <div class="col-md-3">
      <div class="card border-left-primary shadow h-100 py-2">
        <div class="card-body">
          <div class="text-xs fw-bold text-primary text-uppercase mb-1">Total Invoiced</div>
          <div class="h5 mb-0 fw-bold">{{ total_amount|floatformat:0 }} XAF</div>
          <small class="text-muted">{{ total_invoices }} invoice{{ total_invoices|pluralize }}</small>
        </div>
      </div>
    </div>
    <div class="col-md-3">
      <div class="card border-left-success shadow h-100 py-2">
        <div class="card-body">
          <div class="text-xs fw-bold text-success text-uppercase mb-1">Total Paid</div>
          <div class="h5 mb-0 fw-bold">{{ total_paid|floatformat:0 }} XAF</div>
        </div>
      </div>
    </div>
    <div class="col-md-3">
      <div class="card border-left-warning shadow h-100 py-2">
        <div class="card-body">
          <div class="text-xs fw-bold text-warning text-uppercase mb-1">Outstanding</div>
          <div class="h5 mb-0 fw-bold">{{ total_balance|floatformat:0 }} XAF</div>
        </div>
      </div>
    </div>
    <div class="col-md-3">
      <div class="card border-left-danger shadow h-100 py-2">
        <div class="card-body">
          <div class="text-xs fw-bold text-danger text-uppercase mb-1">Overdue</div>
          <div class="h5 mb-0 fw-bold">
            <a href="?status=overdue" class="text-danger text-decoration-none">View overdue →</a>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- Search & Filter -->
  <div class="card shadow mb-4">
    <div class="card-header py-3">
      <h6 class="m-0 fw-bold text-primary">Search &amp; Filter</h6>
    </div>
    <div class="card-body">
      <form method="get" class="row g-2">
        <div class="col-md-4">
          <div class="input-group">
            <input type="text" class="form-control" name="q"
                   placeholder="Invoice #, student name…"
                   value="{{ request.GET.q }}">
            <button class="btn btn-primary" type="submit"><i class="fas fa-search"></i></button>
          </div>
        </div>
        <div class="col-md-2">
          <select class="form-select" name="status">
            <option value="">All Statuses</option>
            {% for val, label in status_choices %}
            <option value="{{ val }}" {% if request.GET.status == val %}selected{% endif %}>{{ label }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="col-md-2">
          <select class="form-select" name="academic_year">
            <option value="">All Years</option>
            {% for yr in academic_years %}
            <option value="{{ yr }}" {% if request.GET.academic_year == yr %}selected{% endif %}>{{ yr }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="col-md-2">
          <select class="form-select" name="invoice_type">
            <option value="">All Types</option>
            {% for val, label in invoice_type_choices %}
            <option value="{{ val }}" {% if request.GET.invoice_type == val %}selected{% endif %}>{{ label }}</option>
            {% endfor %}
          </select>
        </div>
        <div class="col-md-2 d-flex gap-2">
          <button type="submit" class="btn btn-primary flex-fill">
            <i class="fas fa-filter me-1"></i>Filter
          </button>
          <a href="{% url 'finance:invoice_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-times"></i>
          </a>
        </div>
      </form>
    </div>
  </div>

  <!-- Table -->
  <div class="card shadow">
    <div class="card-header py-3">
      <h6 class="m-0 fw-bold text-primary">
        All Invoices
        {% if request.GET.q or request.GET.status or request.GET.academic_year or request.GET.invoice_type %}
        <span class="badge bg-info ms-2">Filtered</span>
        {% endif %}
      </h6>
    </div>
    <div class="card-body p-0">
      <div class="table-responsive">
        <table class="table table-hover mb-0">
          <thead class="table-light">
            <tr>
              <th>Invoice #</th>
              <th>Student</th>
              <th>Year</th>
              <th>Type</th>
              <th class="text-end">Total</th>
              <th class="text-end">Paid</th>
              <th class="text-end">Balance</th>
              <th>Due</th>
              <th>Status</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {% for invoice in invoices %}
            <tr>
              <td>
                <a href="{% url 'finance:invoice_detail' invoice.pk %}">
                  {{ invoice.invoice_number }}
                </a>
              </td>
              <td>
                <a href="{% url 'students:student_detail' invoice.student.pk %}">
                  {{ invoice.student.get_full_name }}
                </a>
              </td>
              <td>{{ invoice.academic_year }}</td>
              <td>
                <span class="badge bg-light text-dark border" style="font-size:.75rem">
                  {{ invoice.get_invoice_type_display }}
                </span>
              </td>
              <td class="text-end">{{ invoice.total_amount|floatformat:0 }}</td>
              <td class="text-end text-success">{{ invoice.amount_paid|floatformat:0 }}</td>
              <td class="text-end {% if invoice.balance > 0 %}text-danger fw-bold{% else %}text-success{% endif %}">
                {{ invoice.balance|floatformat:0 }}
              </td>
              <td>
                <span class="{% if invoice.due_date < today and invoice.status != 'paid' %}text-danger fw-bold{% endif %}">
                  {{ invoice.due_date|date:"d M Y" }}
                </span>
              </td>
              <td>
                <span class="badge
                  {% if invoice.status == 'paid' %}bg-success
                  {% elif invoice.status == 'overdue' %}bg-danger
                  {% elif invoice.status == 'partial' %}bg-warning text-dark
                  {% elif invoice.status == 'sent' %}bg-info
                  {% else %}bg-secondary{% endif %}">
                  {{ invoice.get_status_display }}
                </span>
              </td>
              <td>
                <a href="{% url 'finance:invoice_detail' invoice.pk %}"
                   class="btn btn-sm btn-outline-primary" title="View">
                  <i class="fas fa-eye"></i>
                </a>
                <a href="{% url 'finance:invoice_edit' invoice.pk %}"
                   class="btn btn-sm btn-outline-warning" title="Edit">
                  <i class="fas fa-edit"></i>
                </a>
                <a href="{% url 'finance:payment_add' %}?invoice={{ invoice.pk }}"
                   class="btn btn-sm btn-outline-success" title="Record Payment">
                  <i class="fas fa-money-bill"></i>
                </a>
              </td>
            </tr>
            {% empty %}
            <tr>
              <td colspan="10" class="text-center py-5 text-muted">
                <i class="fas fa-file-invoice fa-3x mb-3 d-block"></i>
                No invoices found.
                {% if not request.GET.q and not request.GET.status %}
                <a href="{% url 'finance:invoice_create' %}">Create the first invoice</a>
                {% endif %}
              </td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>
  </div>

  <!-- Pagination -->
  {% if is_paginated %}
  <nav class="mt-4">
    <ul class="pagination justify-content-center">
      {% if page_obj.has_previous %}
      <li class="page-item">
        <a class="page-link"
           href="?page={{ page_obj.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}{% if request.GET.status %}&status={{ request.GET.status }}{% endif %}">
          &laquo; Previous
        </a>
      </li>
      {% endif %}
      {% for num in page_obj.paginator.page_range %}
        {% if page_obj.number == num %}
        <li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
        {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
        <li class="page-item">
          <a class="page-link"
             href="?page={{ num }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}{% if request.GET.status %}&status={{ request.GET.status }}{% endif %}">
            {{ num }}
          </a>
        </li>
        {% endif %}
      {% endfor %}
      {% if page_obj.has_next %}
      <li class="page-item">
        <a class="page-link"
           href="?page={{ page_obj.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}{% if request.GET.status %}&status={{ request.GET.status }}{% endif %}">
          Next &raquo;
        </a>
      </li>
      {% endif %}
    </ul>
  </nav>
  {% endif %}

</div>
{% endblock %}

======================================================================
FILE: templates/finance/payment_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Payment {{ payment.payment_number }}{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Payment {{ payment.payment_number }}</h1>
            <p class="text-muted">{{ payment.student.get_full_name }} &bull; {{ payment.payment_date|date:"d M Y" }}</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'finance:payment_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
            <a href="{% url 'finance:invoice_detail' payment.invoice.pk %}" class="btn btn-outline-primary"><i class="fas fa-file-invoice me-2"></i>View Invoice</a>
            <a href="{% url 'finance:generate_receipt' payment.pk %}" class="btn btn-success"><i class="fas fa-receipt me-2"></i>Print Receipt</a>
        </div>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Payment Receipt</h6>
                    <span class="badge bg-{% if payment.status == 'completed' %}success{% elif payment.status == 'pending' %}warning{% else %}danger{% endif %} fs-6">{{ payment.get_status_display }}</span>
                </div>
                <div class="card-body">
                    <div class="row mb-4">
                        <div class="col-6">
                            <p class="text-muted small mb-0">From</p>
                            <p class="fw-bold">{{ payment.student.get_full_name }}</p>
                            <p class="text-muted small">{{ payment.student.student_id }}</p>
                        </div>
                        <div class="col-6 text-end">
                            <p class="text-muted small mb-0">Payment #</p>
                            <p class="fw-bold">{{ payment.payment_number }}</p>
                            {% if payment.receipt_number %}<p class="text-muted small">Receipt: {{ payment.receipt_number }}</p>{% endif %}
                        </div>
                    </div>
                    <hr>
                    <table class="table table-borderless">
                        <tr><td class="text-muted fw-bold" width="40%">Invoice</td><td>{{ payment.invoice.invoice_number }}</td></tr>
                        <tr><td class="text-muted fw-bold">Amount</td><td class="text-success fw-bold fs-5">{{ payment.amount|floatformat:0 }} XAF</td></tr>
                        <tr><td class="text-muted fw-bold">Payment Method</td><td>{{ payment.get_payment_method_display }}</td></tr>
                        <tr><td class="text-muted fw-bold">Payment Date</td><td>{{ payment.payment_date|date:"l, d F Y" }}</td></tr>
                        {% if payment.transaction_id %}<tr><td class="text-muted fw-bold">Transaction ID</td><td>{{ payment.transaction_id }}</td></tr>{% endif %}
                        {% if payment.mobile_money_number %}<tr><td class="text-muted fw-bold">Mobile Money</td><td>{{ payment.get_mobile_money_provider_display }} — {{ payment.mobile_money_number }}</td></tr>{% endif %}
                        {% if payment.bank_name %}<tr><td class="text-muted fw-bold">Bank</td><td>{{ payment.bank_name }}{% if payment.cheque_number %} (Cheque: {{ payment.cheque_number }}){% endif %}</td></tr>{% endif %}
                        <tr><td class="text-muted fw-bold">Received By</td><td>{{ payment.received_by.get_full_name|default:"—" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Receipt Issued</td><td>{% if payment.receipt_issued %}<span class="badge bg-success">Yes — {{ payment.receipt_issued_date|date:"d M Y" }}</span>{% else %}<span class="badge bg-secondary">No</span>{% endif %}</td></tr>
                        {% if payment.notes %}<tr><td class="text-muted fw-bold">Notes</td><td>{{ payment.notes }}</td></tr>{% endif %}
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/finance/payment_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">{{ title }}</h1></div>
        <a href="{% url 'finance:payment_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-8">
            {% if selected_invoice %}
            <div class="alert alert-info mb-4">
                <i class="fas fa-file-invoice me-2"></i>Recording payment for invoice <strong>{{ selected_invoice.invoice_number }}</strong>
                — {{ selected_invoice.student.get_full_name }} &bull; Balance: <strong>{{ selected_invoice.balance|floatformat:0 }} XAF</strong>
            </div>
            {% endif %}
            <div class="card shadow">
                <div class="card-header py-3 bg-success text-white"><h6 class="m-0"><i class="fas fa-money-bill me-2"></i>Payment Information</h6></div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}<div class="alert alert-danger">Please correct the errors below.</div>{% endif %}

                        {% if not object %}
                        <div class="mb-3">
                            <label class="form-label fw-bold">Invoice <span class="text-danger">*</span></label>
                            {{ form.invoice }}
                            {% if form.invoice.errors %}<div class="text-danger small">{{ form.invoice.errors }}</div>{% endif %}
                        </div>
                        {% endif %}

                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Amount (XAF) <span class="text-danger">*</span></label>
                                {{ form.amount }}
                                {% if form.amount.errors %}<div class="text-danger small">{{ form.amount.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Payment Date <span class="text-danger">*</span></label>
                                {{ form.payment_date }}
                            </div>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Payment Method <span class="text-danger">*</span></label>
                                {{ form.payment_method }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Status</label>
                                {{ form.status }}
                            </div>
                        </div>

                        <div id="mobilemoneyFields" class="row mb-3" style="display:none;">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Provider</label>
                                {{ form.mobile_money_provider }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Mobile Money Number</label>
                                {{ form.mobile_money_number }}
                            </div>
                        </div>
                        <div id="bankFields" class="row mb-3" style="display:none;">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Bank Name</label>
                                {{ form.bank_name }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Cheque Number</label>
                                {{ form.cheque_number }}
                            </div>
                        </div>

                        <div class="mb-3">
                            <label class="form-label fw-bold">Transaction ID / Reference</label>
                            {{ form.transaction_id }}
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Notes</label>
                            {{ form.notes }}
                        </div>

                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'finance:payment_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-success"><i class="fas fa-save me-2"></i>{{ object|yesno:"Update Payment,Record Payment" }}</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>
document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => {
    el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
});
const methodSelect = document.querySelector('[name="payment_method"]');
function toggleFields() {
    const v = methodSelect ? methodSelect.value : '';
    document.getElementById('mobilemoneyFields').style.display = v === 'mobile_money' ? 'flex' : 'none';
    document.getElementById('bankFields').style.display = ['bank_transfer','cheque'].includes(v) ? 'flex' : 'none';
}
if (methodSelect) { methodSelect.addEventListener('change', toggleFields); toggleFields(); }
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/finance/payments.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Payments - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">

    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Payments</h1>
        <div class="btn-group">
            <a href="{% url 'finance:payment_add' %}" class="btn btn-primary">
                <i class="fas fa-plus"></i> Record Payment
            </a>
            <a href="{% url 'finance:export_payments' %}" class="btn btn-outline-secondary">
                <i class="fas fa-download"></i> Export CSV
            </a>
        </div>
    </div>

    <!-- Stats Cards -->
    <div class="row mb-4">
        <div class="col-md-4">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Total Received</div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_payments|floatformat:0 }} XAF</div>
                    <small class="text-muted">{{ payment_count }} completed payment{{ payment_count|pluralize }}</small>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Showing</div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">{{ paginator.count|default:payments|length }} payment{{ paginator.count|default:payments|length|pluralize }}</div>
                    <small class="text-muted">Based on current filters</small>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-info text-uppercase mb-1">Quick Links</div>
                    <a href="{% url 'finance:bursar_dashboard' %}" class="small me-3">
                        <i class="fas fa-tachometer-alt me-1"></i>Dashboard
                    </a>
                    <a href="{% url 'finance:invoice_list' %}" class="small">
                        <i class="fas fa-file-invoice me-1"></i>Invoices
                    </a>
                </div>
            </div>
        </div>
    </div>

    <!-- Filter -->
    <div class="card shadow mb-4">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Filter Payments</h6>
        </div>
        <div class="card-body">
            <form method="get" class="row g-3">
                <div class="col-md-3">
                    <label class="form-label small">From Date</label>
                    <input type="date" class="form-control" name="from_date" value="{{ request.GET.from_date }}">
                </div>
                <div class="col-md-3">
                    <label class="form-label small">To Date</label>
                    <input type="date" class="form-control" name="to_date" value="{{ request.GET.to_date }}">
                </div>
                <div class="col-md-2">
                    <label class="form-label small">Method</label>
                    <select class="form-control" name="method">
                        <option value="">All Methods</option>
                        {% for val, label in payment_methods %}
                        <option value="{{ val }}" {% if request.GET.method == val %}selected{% endif %}>{{ label }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-2">
                    <label class="form-label small">Status</label>
                    <select class="form-control" name="status">
                        <option value="">All</option>
                        {% for val, label in status_choices %}
                        <option value="{{ val }}" {% if request.GET.status == val %}selected{% endif %}>{{ label }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-2 d-flex align-items-end gap-2">
                    <button type="submit" class="btn btn-primary flex-fill">
                        <i class="fas fa-filter"></i> Filter
                    </button>
                    <a href="{% url 'finance:payment_list' %}" class="btn btn-outline-secondary">
                        <i class="fas fa-times"></i>
                    </a>
                </div>
            </form>
        </div>
    </div>

    <!-- Table -->
    <div class="card shadow">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Payment Records</h6>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-hover mb-0">
                    <thead class="table-light">
                        <tr>
                            <th>Payment #</th>
                            <th>Invoice #</th>
                            <th>Student</th>
                            <th>Amount (XAF)</th>
                            <th>Method</th>
                            <th>Date</th>
                            <th>Status</th>
                            <th>Receipt</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for payment in payments %}
                        <tr>
                            <td><a href="{% url 'finance:payment_detail' payment.pk %}">{{ payment.payment_number }}</a></td>
                            <td>
                                <a href="{% url 'finance:invoice_detail' payment.invoice.pk %}">
                                    {{ payment.invoice.invoice_number }}
                                </a>
                            </td>
                            <td>
                                <a href="{% url 'students:student_detail' payment.student.pk %}">
                                    {{ payment.student.get_full_name }}
                                </a>
                            </td>
                            <td class="text-success fw-bold">{{ payment.amount|floatformat:0 }}</td>
                            <td>
                                <span class="badge bg-info">{{ payment.get_payment_method_display }}</span>
                            </td>
                            <td>{{ payment.payment_date|date:"d M Y" }}</td>
                            <td>
                                <span class="badge bg-{% if payment.status == 'completed' %}success{% elif payment.status == 'pending' %}warning{% else %}danger{% endif %}">
                                    {{ payment.get_status_display }}
                                </span>
                            </td>
                            <td>
                                {% if payment.receipt_issued %}
                                <span class="badge bg-success">
                                    <i class="fas fa-check me-1"></i>{{ payment.receipt_number }}
                                </span>
                                {% else %}
                                <a href="{% url 'finance:generate_receipt' payment.pk %}" class="btn btn-sm btn-outline-secondary">
                                    <i class="fas fa-receipt"></i> Issue
                                </a>
                                {% endif %}
                            </td>
                            <td>
                                <a href="{% url 'finance:payment_detail' payment.pk %}" class="btn btn-sm btn-outline-primary" title="View">
                                    <i class="fas fa-eye"></i>
                                </a>
                                <a href="{% url 'finance:payment_edit' payment.pk %}" class="btn btn-sm btn-outline-warning" title="Edit">
                                    <i class="fas fa-edit"></i>
                                </a>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="9" class="text-center py-5 text-muted">
                                <i class="fas fa-money-bill-wave fa-3x mb-3 d-block"></i>
                                No payments found.
                                {% if not request.GET.from_date and not request.GET.method %}
                                <a href="{% url 'finance:payment_add' %}">Record the first payment</a>
                                {% endif %}
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- Pagination -->
    {% if is_paginated %}
    <nav class="mt-4">
        <ul class="pagination justify-content-center">
            {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if request.GET.from_date %}&from_date={{ request.GET.from_date }}{% endif %}{% if request.GET.to_date %}&to_date={{ request.GET.to_date }}{% endif %}{% if request.GET.method %}&method={{ request.GET.method }}{% endif %}">
                    &laquo; Previous
                </a>
            </li>
            {% endif %}
            {% for num in page_obj.paginator.page_range %}
            {% if page_obj.number == num %}
            <li class="page-item active"><a class="page-link" href="#">{{ num }}</a></li>
            {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
            <li class="page-item">
                <a class="page-link" href="?page={{ num }}{% if request.GET.from_date %}&from_date={{ request.GET.from_date }}{% endif %}{% if request.GET.method %}&method={{ request.GET.method }}{% endif %}">
                    {{ num }}
                </a>
            </li>
            {% endif %}
            {% endfor %}
            {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.next_page_number }}{% if request.GET.from_date %}&from_date={{ request.GET.from_date }}{% endif %}{% if request.GET.method %}&method={{ request.GET.method }}{% endif %}">
                    Next &raquo;
                </a>
            </li>
            {% endif %}
        </ul>
    </nav>
    {% endif %}

</div>
{% endblock %}

======================================================================
FILE: templates/finance/receipt.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Receipt {{ payment.receipt_number|default:payment.payment_number }}{% endblock %}

{% block extra_css %}
<style>
/* ── Screen wrapper ─────────────────────────────────────────── */
.receipt-actions {
    max-width: 680px;
    margin: 0 auto 16px;
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

/* ── Receipt card ───────────────────────────────────────────── */
.receipt-wrapper {
    max-width: 680px;
    margin: 0 auto;
    background: #fff;
    border: 2px solid #333;
    padding: 24px 28px 20px;
    font-family: Arial, sans-serif;
    font-size: 13px;
    color: #000;
}

/* Header */
.receipt-header {
    text-align: center;
    margin-bottom: 10px;
}
.receipt-school-name {
    font-size: 17px;
    font-weight: 900;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border: 2px solid #000;
    border-radius: 24px;
    display: inline-block;
    padding: 4px 18px;
    margin-bottom: 2px;
}
.receipt-school-sub {
    font-size: 12px;
    margin-top: 2px;
}

/* Meta row */
.receipt-meta {
    display: flex;
    justify-content: space-between;
    margin: 10px 0 4px;
    border-top: 1px solid #333;
    padding-top: 8px;
    font-weight: bold;
    font-size: 13px;
}
.receipt-name-row {
    display: flex;
    gap: 12px;
    margin-bottom: 8px;
    font-weight: bold;
    font-size: 13px;
}
.receipt-name-row .field {
    flex: 1;
    border-bottom: 1px dotted #555;
}
.receipt-name-row .label-class {
    white-space: nowrap;
}

/* Fee table */
.receipt-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 8px;
}
.receipt-table td {
    border: 1px solid #333;
    padding: 3px 7px;
    font-size: 12.5px;
    vertical-align: middle;
}
.receipt-table .col-fr   { width: 34%; }
.receipt-table .col-div  { width: 4%; text-align: center; font-weight: bold; }
.receipt-table .col-en   { width: 34%; }
.receipt-table .col-amt  { width: 28%; text-align: right; font-weight: bold; }

.receipt-table tr.total-row td {
    font-weight: 900;
    background: #f0f0f0;
    font-size: 13px;
}

/* Amount in words */
.receipt-words {
    margin: 8px 0;
    font-size: 12.5px;
}
.receipt-words span {
    font-weight: bold;
    border-bottom: 1px dotted #555;
    display: inline;
}

/* Balance */
.receipt-balance {
    font-size: 12.5px;
    font-weight: bold;
    color: {% if payment.invoice.balance > 0 %}#c0392b{% else %}#27ae60{% endif %};
    margin-bottom: 8px;
}

/* Footer */
.receipt-footer {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    margin-top: 14px;
    border-top: 1px solid #333;
    padding-top: 10px;
}
.receipt-sig-block { text-align: center; }
.receipt-sig-line {
    border-bottom: 1px solid #333;
    min-width: 160px;
    height: 36px;
    margin-bottom: 2px;
}
.receipt-sig-label { font-size: 11px; color: #444; }

/* ── Print styles ───────────────────────────────────────────── */
@media print {
    body * { visibility: hidden; }
    .receipt-wrapper, .receipt-wrapper * { visibility: visible; }
    .receipt-wrapper {
        position: fixed; top: 0; left: 0;
        width: 100%; border: none; padding: 12px;
        font-size: 12px;
    }
    .receipt-actions { display: none !important; }
}
</style>
{% endblock %}

{% block content %}
<div class="container-fluid py-3">

    <!-- Action Buttons (hidden on print) -->
    <div class="receipt-actions no-print">
        <button onclick="window.print()" class="btn btn-primary">
            <i class="fas fa-print me-2"></i>Print Receipt
        </button>
        <a href="{% url 'finance:payment_detail' payment.pk %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back to Payment
        </a>
        <a href="{% url 'finance:invoice_detail' payment.invoice.pk %}" class="btn btn-outline-info">
            <i class="fas fa-file-invoice me-2"></i>View Invoice
        </a>
        {% if payment.invoice.balance > 0 %}
        <a href="{% url 'finance:payment_add' %}?invoice={{ payment.invoice.pk }}" class="btn btn-outline-success">
            <i class="fas fa-money-bill me-2"></i>Record Next Payment
        </a>
        {% endif %}
    </div>

    <!-- ══ RECEIPT ══════════════════════════════════════════════ -->
    <div class="receipt-wrapper" id="receipt">

        <!-- School Header -->
        <div class="receipt-header">
            <div class="receipt-school-name">RAPHA-BETHEL BILINGUAL SCHOOL-BESSENGUE</div>
            <div class="receipt-school-sub">
                B.P.........Douala &nbsp;—&nbsp; Tél: 670 17 79 79 / 698 97 88 84
            </div>
        </div>

        <!-- Receipt # and Date -->
        <div class="receipt-meta">
            <div>
                CASH RECEIPT / Reçu N°&nbsp;
                <span style="border-bottom:1px dotted #555; min-width:80px; display:inline-block;">
                    {{ payment.receipt_number|default:payment.payment_number }}
                </span>
            </div>
            <div>
                Date &nbsp;
                <span style="border-bottom:1px dotted #555; min-width:90px; display:inline-block;">
                    {{ payment.payment_date|date:"d/m/Y" }}
                </span>
            </div>
        </div>

        <!-- Name & Class -->
        <div class="receipt-name-row">
            <span>Name / Nom :</span>
            <span class="field">{{ payment.student.get_full_name }}</span>
            <span class="label-class">Class / Classe :</span>
            <span style="border-bottom:1px dotted #555; min-width:60px; display:inline-block;">
                {{ payment.student.current_class|default:"—" }}
            </span>
        </div>

        <!-- Fee Line Items -->
        <table class="receipt-table">
            <tbody>
                {% for item in items %}
                <tr>
                    <td class="col-fr">{{ item.description_fr|default:item.description }}</td>
                    <td class="col-div">/</td>
                    <td class="col-en">{{ item.description }}</td>
                    <td class="col-amt">
                        {% if item.total %}{{ item.total|floatformat:0 }}{% endif %}
                    </td>
                </tr>
                {% empty %}
                {# Fall back to the standard fee rows mirroring the physical receipt #}
                <tr><td class="col-fr">Inscription</td><td class="col-div">/</td><td class="col-en">Registration</td><td class="col-amt"></td></tr>
                <tr><td class="col-fr">Pension</td><td class="col-div">/</td><td class="col-en">Tuition</td><td class="col-amt">{{ payment.amount|floatformat:0 }}</td></tr>
                <tr><td class="col-fr">Pack scolaire</td><td class="col-div">/</td><td class="col-en">Nursery supplies</td><td class="col-amt"></td></tr>
                <tr><td class="col-fr">Cantine</td><td class="col-div">/</td><td class="col-en">Canteen</td><td class="col-amt"></td></tr>
                <tr><td class="col-fr">Transport</td><td class="col-div">/</td><td class="col-en">Transport</td><td class="col-amt"></td></tr>
                <tr><td class="col-fr">Uniforme</td><td class="col-div">/</td><td class="col-en">Uniforms</td><td class="col-amt"></td></tr>
                <tr><td class="col-fr">Tenue de sport</td><td class="col-div">/</td><td class="col-en">Sports wear</td><td class="col-amt"></td></tr>
                <tr><td class="col-fr">Fournitures scolaires</td><td class="col-div">/</td><td class="col-en">School supplies</td><td class="col-amt"></td></tr>
                {% endfor %}

                <!-- Total row -->
                <tr class="total-row">
                    <td class="col-fr">Montant total reçu</td>
                    <td class="col-div">/</td>
                    <td class="col-en">Total amount received</td>
                    <td class="col-amt">{{ payment.amount|floatformat:0 }} XAF</td>
                </tr>
            </tbody>
        </table>

        <!-- Amount in words -->
        <div class="receipt-words">
            Amount in words / <em>Montant en lettres</em> :&nbsp;
            <span>{{ amount_in_words }}</span>
        </div>

        <!-- Balance remaining -->
        <div class="receipt-balance">
            {% if payment.invoice.balance > 0 %}
                Reste / Balance due: {{ payment.invoice.balance|floatformat:0 }} XAF
            {% else %}
                ✓ Fully paid / Compte soldé
            {% endif %}
        </div>

        <!-- Footer: Received by + Signature -->
        <div class="receipt-footer">
            <div class="receipt-sig-block">
                <div class="receipt-sig-line">{{ payment.received_by.get_full_name|default:"" }}</div>
                <div class="receipt-sig-label">Received by / <em>Reçu par</em></div>
            </div>
            <div class="receipt-sig-block" style="text-align:right;">
                <div class="receipt-sig-line"></div>
                <div class="receipt-sig-label">Sign / <em>Signature</em></div>
            </div>
        </div>

    </div><!-- /receipt-wrapper -->
</div>
{% endblock %}

======================================================================
FILE: templates/finance/reports.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Financial Reports - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <h1 class="h3 mb-4 text-gray-800">Financial Reports</h1>

    <div class="row">
        <div class="col-md-6 mb-4">
            <div class="card shadow">
                <div class="card-header">
                    <h6 class="m-0 font-weight-bold text-primary">Revenue Summary</h6>
                </div>
                <div class="card-body">
                    <canvas id="revenueChart" height="200"></canvas>
                </div>
            </div>
        </div>
        
        <div class="col-md-6 mb-4">
            <div class="card shadow">
                <div class="card-header">
                    <h6 class="m-0 font-weight-bold text-primary">Payment Methods</h6>
                </div>
                <div class="card-body">
                    <canvas id="paymentChart" height="200"></canvas>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-4 mb-4">
            <div class="card shadow">
                <div class="card-body text-center">
                    <h3 class="text-primary">{{ total_revenue }} XAF</h3>
                    <p class="text-muted">Total Revenue</p>
                </div>
            </div>
        </div>
        <div class="col-md-4 mb-4">
            <div class="card shadow">
                <div class="card-body text-center">
                    <h3 class="text-success">{{ collected }} XAF</h3>
                    <p class="text-muted">Amount Collected</p>
                </div>
            </div>
        </div>
        <div class="col-md-4 mb-4">
            <div class="card shadow">
                <div class="card-body text-center">
                    <h3 class="text-warning">{{ outstanding }} XAF</h3>
                    <p class="text-muted">Outstanding Balance</p>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
    // Revenue Chart
    new Chart(document.getElementById('revenueChart'), {
        type: 'line',
        data: {
            labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
            datasets: [{
                label: 'Revenue',
                data: [1200000, 1350000, 1100000, 1450000, 1600000, 1550000],
                borderColor: '#4CAF50'
            }]
        }
    });

    // Payment Methods Chart
    new Chart(document.getElementById('paymentChart'), {
        type: 'doughnut',
        data: {
            labels: ['Cash', 'Mobile Money', 'Bank Transfer'],
            datasets: [{
                data: [60, 25, 15],
                backgroundColor: ['#4CAF50', '#2196F3', '#FF9800']
            }]
        }
    });
});
</script>
{% endblock %}

======================================================================
FILE: templates/finance/school_item_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ title }} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div><h1 class="h3 mb-0">{{ title }}</h1></div>
    <a href="{% url 'finance:school_item_list' %}" class="btn btn-outline-secondary">
      <i class="fas fa-arrow-left me-1"></i>Back
    </a>
  </div>
  <div class="row justify-content-center">
    <div class="col-md-6">
      <div class="card shadow">
        <div class="card-header py-3 bg-primary text-white">
          <h6 class="m-0"><i class="fas fa-tshirt me-2"></i>Item Price Details</h6>
        </div>
        <div class="card-body">
          <form method="post">
            {% csrf_token %}
            {% if form.errors %}
            <div class="alert alert-danger">
              Please correct the errors below. {{ form.non_field_errors }}
            </div>
            {% endif %}

            <div class="row mb-3">
              <div class="col-md-6">
                <label class="form-label fw-bold">Item Type <span class="text-danger">*</span></label>
                {{ form.item_type }}
              </div>
              <div class="col-md-6">
                <label class="form-label fw-bold">Item Name <span class="text-danger">*</span></label>
                {{ form.name }}
              </div>
            </div>
            <div class="row mb-3">
              <div class="col-md-6">
                <label class="form-label fw-bold">Selling Price (XAF) <span class="text-danger">*</span></label>
                {{ form.price }}
              </div>
              <div class="col-md-6">
                <label class="form-label fw-bold">Academic Year</label>
                {{ form.academic_year }}
              </div>
            </div>
            <div class="mb-3">
              <label class="form-label fw-bold">Description / Notes</label>
              {{ form.description }}
            </div>
            <div class="mb-3">
              <div class="form-check">
                {{ form.is_active }}
                <label class="form-check-label fw-bold">Available for Sale</label>
              </div>
            </div>
            <div class="d-flex justify-content-end gap-2 mt-4">
              <a href="{% url 'finance:school_item_list' %}" class="btn btn-secondary">Cancel</a>
              <button type="submit" class="btn btn-primary">
                <i class="fas fa-save me-1"></i>Save
              </button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => {
  el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
});
</script>
{% endblock %}

======================================================================
FILE: templates/finance/school_item_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}School Item Prices — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
  <div class="d-flex justify-content-between align-items-center mb-4">
    <div>
      <h1 class="h3 mb-0">School Item Prices</h1>
      <p class="text-muted mb-0">Uniforms, sportswear, report cards, pullovers &amp; other items</p>
    </div>
    <div class="btn-group">
      <a href="{% url 'finance:school_item_add' %}" class="btn btn-primary">
        <i class="fas fa-plus me-1"></i>Add Item
      </a>
      <a href="{% url 'finance:fee_list' %}" class="btn btn-outline-secondary">
        <i class="fas fa-arrow-left me-1"></i>Fee Structures
      </a>
    </div>
  </div>

  {% if messages %}
    {% for msg in messages %}
    <div class="alert alert-{{ msg.tags|default:'info' }} alert-dismissible fade show">
      {{ msg }}<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
    </div>
    {% endfor %}
  {% endif %}

  <!-- Reference card from fee table Image 2 -->
  <div class="alert alert-light border mb-4">
    <strong><i class="fas fa-info-circle me-2 text-info"></i>Official prices from school records:</strong>
    Uniforms 5,000 XAF &nbsp;·&nbsp; Sportswear 3,500 XAF &nbsp;·&nbsp;
    Report Card 1,000 XAF &nbsp;·&nbsp; Pullovers 5,000 XAF
  </div>

  <div class="card shadow">
    <div class="card-body p-0">
      <table class="table table-hover mb-0">
        <thead class="table-dark">
          <tr>
            <th>Item</th>
            <th>Type</th>
            <th>Year</th>
            <th class="text-end">Selling Price (XAF)</th>
            <th>Status</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          {% for item in items %}
          <tr>
            <td class="fw-bold">{{ item.name }}</td>
            <td>
              <span class="badge bg-light text-dark border">
                {{ item.get_item_type_display }}
              </span>
            </td>
            <td>{{ item.academic_year }}</td>
            <td class="text-end fw-bold text-primary">{{ item.price|floatformat:0 }}</td>
            <td>
              {% if item.is_active %}
              <span class="badge bg-success">Available</span>
              {% else %}
              <span class="badge bg-secondary">Unavailable</span>
              {% endif %}
            </td>
            <td>
              <a href="{% url 'finance:school_item_edit' item.pk %}"
                 class="btn btn-sm btn-outline-warning" title="Edit">
                <i class="fas fa-edit"></i>
              </a>
            </td>
          </tr>
          {% empty %}
          <tr>
            <td colspan="6" class="text-center py-5 text-muted">
              <i class="fas fa-tshirt fa-3x d-block mb-3"></i>
              No item prices set up yet.
              <a href="{% url 'finance:school_item_add' %}">Add the first one</a>
            </td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
  </div>
</div>
{% endblock %}

======================================================================
FILE: templates/finance/student_discount_form.html
======================================================================
{% extends 'base.html' %}
{% block title %}Apply Discount to Student - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">Apply Discount to Student</h1>
        <a href="{% url 'finance:discount_list' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 bg-warning text-dark"><h6 class="m-0"><i class="fas fa-user-tag me-2"></i>Student Discount Application</h6></div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}<div class="alert alert-danger">Please correct the errors below.</div>{% endif %}
                        <div class="mb-3"><label class="form-label fw-bold">Student <span class="text-danger">*</span></label>{{ form.student }}</div>
                        <div class="mb-3"><label class="form-label fw-bold">Discount <span class="text-danger">*</span></label>{{ form.discount }}</div>
                        <div class="row mb-3">
                            <div class="col-md-6"><label class="form-label fw-bold">Academic Year</label>{{ form.academic_year }}</div>
                            <div class="col-md-6"><label class="form-label fw-bold">Term</label>{{ form.term }}</div>
                        </div>
                        <div class="mb-3"><label class="form-label fw-bold">Reason</label>{{ form.reason }}</div>
                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'finance:discount_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-warning text-dark"><i class="fas fa-save me-2"></i>Apply Discount</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>document.querySelectorAll('input:not(.form-check-input):not([type="submit"]), select, textarea').forEach(el => { el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control'); });</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/includes/footer-1.html
======================================================================
<!-- templates/includes/footer.html -->
 
<footer class="footer mt-auto py-3 bg-dark text-light">
    <div class="container">
        <div class="row">
            <div class="col-md-6">
                <h5>Rapha-Bethel BNPS</h5>
                <p>Comprehensive School Management System</p>
                <p class="mb-0">&copy; {% now "Y" %} Vi-2s-Dk Foundation. All rights reserved.</p>
            </div>
            <div class="col-md-3">
                <h5>Contact</h5>
                <ul class="list-unstyled">
                    <li><i class="fas fa-phone me-2"></i> +237 6 70 17 79 79</li>
                    <li><i class="fas fa-envelope me-2"></i> info@raphabethel.edu</li>
                    <li><i class="fas fa-map-marker-alt me-2"></i> Douala, Cameroon</li>
                </ul>
            </div>
            <div class="col-md-3">
                <h5>Quick Links</h5>
                <ul class="list-unstyled">
                    <li><a href="/admin/" class="text-light">Admin Panel</a></li>
                    <li><a href="/dashboard/" class="text-light">Dashboard</a></li>
                    <li><a href="#" class="text-light">Documentation</a></li>
                    <li><a href="https://RaphaBethel.org/BNPS" target="_blank" class="text-light">Website</a></li>
                </ul>
            </div>
        </div>
    </div>
</footer>

======================================================================
FILE: templates/includes/footer.html
======================================================================
<!-- templates/includes/footer.html -->
{% load static %}
<footer class="rb-footer">
    <div class="rb-footer-inner">

        <!-- Brand column -->
        <div class="rb-footer-brand">
            <picture>
                <source srcset="{% static 'admin/img/logo-nav.webp' %}" type="image/webp">
                <img src="{% static 'admin/img/logo-nav.png' %}" alt="Rapha-Bethel" width="40" height="40">
            </picture>
            <div>
                <div class="rb-footer-name">Rapha-Bethel BNPS</div>
                <div class="rb-footer-tagline">Bilingual Nursery &amp; Primary School</div>
                <a href="https://raphabethel.org/BNPS" target="_blank" rel="noopener" class="rb-footer-link">
                    <i class="fas fa-globe"></i> School Website
                </a>
            </div>
        </div>

        <!-- Contact column -->
        <div class="rb-footer-col">
            <div class="rb-footer-heading">Contact</div>
            <a href="tel:+237670177979" class="rb-footer-link">
                <i class="fas fa-phone-alt"></i> +237 6 70 17 79 79
            </a>
            <a href="mailto:info@raphabethel.edu" class="rb-footer-link">
                <i class="fas fa-envelope"></i> info@raphabethel.edu
            </a>
            <span class="rb-footer-link">
                <i class="fas fa-map-marker-alt"></i> Douala, Cameroon
            </span>
        </div>

        <!-- Quick Links column -->
        <div class="rb-footer-col">
            <div class="rb-footer-heading">Quick Links</div>
            {% if user.is_authenticated %}
            <a href="{% url 'dashboard' %}" class="rb-footer-link"><i class="fas fa-th-large"></i> Dashboard</a>
            <a href="{% url 'students:student_list' %}" class="rb-footer-link"><i class="fas fa-user-graduate"></i> Students</a>
            {% if user.is_superuser %}<a href="{% url 'admin:index' %}" class="rb-footer-link"><i class="fas fa-shield-alt"></i> Admin Panel</a>{% endif %}
            {% else %}
            <a href="{% url 'staff:login' %}" class="rb-footer-link"><i class="fas fa-sign-in-alt"></i> Staff Login</a>
            {% endif %}
        </div>

    </div>

    <div class="rb-footer-bottom">
        &copy; {% now "Y" %} Vi-2s-Dk Foundation &middot; All rights reserved
    </div>
</footer>


======================================================================
FILE: templates/includes/navbar.html
======================================================================
<!-- templates/includes/navbar.html -->
{% load static %}
<nav class="navbar navbar-expand-lg navbar-dark" style="background: linear-gradient(135deg, #4CAF50, #2196F3);">
    <div class="container">
        <a class="navbar-brand" href="/">
            <img src="{% static 'admin/img/logo-yellow.jpeg' %}" alt="Logo" height="40" class="me-2">
            <span class="fw-bold">Rapha-Bethel BNPS</span>
        </a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav ms-auto">
                <li class="nav-item">
                    <a class="nav-link" href="/"><i class="fas fa-home"></i> Home</a>
                </li>
                {% if user.is_authenticated %}
                <li class="nav-item">
                    <a class="nav-link" href="/dashboard/"><i class="fas fa-tachometer-alt"></i> Dashboard</a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
                        <i class="fas fa-user"></i> {{ user.username }}
                    </a>
                    <ul class="dropdown-menu">
                        <li><a class="dropdown-item" href="/admin/"><i class="fas fa-cog"></i> Admin</a></li>
                        <li><hr class="dropdown-divider"></li>
                        <li>
                            <form method="post" action="{% url 'staff:logout' %}" style="margin:0">
                                {% csrf_token %}
                                <button type="submit" class="dropdown-item"><i class="fas fa-sign-out-alt"></i> Logout</button>
                            </form>
                        </li>
                    </ul>
                </li>
                {% else %}
                <li class="nav-item">
                    <a class="nav-link" href="/admin/login/"><i class="fas fa-sign-in-alt"></i> Login</a>
                </li>
                {% endif %}
            </ul>
        </div>
    </div>
</nav>

======================================================================
FILE: templates/includes/sidebar-1.html
======================================================================
<!-- templates/includes/sidebar.html -->
{% load static %}

<div class="sidebar-sticky pt-3">
    <!-- User Info -->
    <div class="user-info text-center mb-4 p-3">
        {% if user.is_authenticated %}
            <div class="user-avatar mb-2">
                <i class="fas fa-user-circle fa-3x text-primary"></i>
            </div>
            <h6>{{ user.get_full_name|default:user.username }}</h6>
            <p class="text-muted small mb-2">
                {% if user.is_superuser %}Super Admin{% elif user.is_staff %}Staff{% else %}User{% endif %}
            </p>
            <a href="{% url 'admin:logout' %}" class="btn btn-sm btn-outline-danger">
                <i class="fas fa-sign-out-alt"></i> Logout
            </a>
        {% else %}
            <a href="{% url 'admin:login' %}" class="btn btn-sm btn-primary">
                <i class="fas fa-sign-in-alt"></i> Login
            </a>
        {% endif %}
    </div>

    <!-- DASHBOARD -->
    <h6 class="sidebar-heading px-3 mb-2 text-muted">Main</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link {% if request.path == '/dashboard/' %}active{% endif %}" 
               href="{% url 'dashboard' %}">
                <i class="fas fa-tachometer-alt me-2"></i> Dashboard
            </a>
        </li>
    </ul>

    <!-- STUDENTS SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Students</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link {% if request.path == '/students/' %}active{% endif %}" 
               href="{% url 'students:student_list' %}">
                <i class="fas fa-list me-2"></i> All Students
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'students:student_add' %}">
                <i class="fas fa-user-plus me-2"></i> Add Student
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'students:import_students_csv' %}">
                <i class="fas fa-upload me-2"></i> Import Students
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'students:export_students' %}">
                <i class="fas fa-download me-2"></i> Export Students
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'students:download_student_sample' %}">
                <i class="fas fa-file-csv me-2"></i> Download Sample
            </a>
        </li>
    </ul>

    <!-- STAFF SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Staff</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link {% if request.path == '/staff/' %}active{% endif %}" 
               href="{% url 'staff:staff_list' %}">
                <i class="fas fa-list me-2"></i> All Staff
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'staff:staff_add' %}">
                <i class="fas fa-user-plus me-2"></i> Add Staff
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'staff:staff_import' %}">
                <i class="fas fa-upload me-2"></i> Import Staff
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'staff:staff_export' %}">
                <i class="fas fa-download me-2"></i> Export Staff
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'staff:staff_dashboard' %}">
                <i class="fas fa-tachometer-alt me-2"></i> Staff Dashboard
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'staff:leave_list' %}">
                <i class="fas fa-calendar-alt me-2"></i> Leave Requests
            </a>
        </li>
        <!-- Staff Attendance - Only for admins -->
        {% if user.is_superuser or user.staff_profile.role in 'admin,head_master,head_mistress' %}
        <li class="nav-item">
            <a class="nav-link" href="{% url 'staff:attendance_list' %}">
                <i class="fas fa-clock me-2"></i> Staff Attendance
            </a>
        </li>
        {% endif %}
    </ul>

    <!-- ACADEMICS SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Academics</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link" href="{% url 'academics:class_list' %}">
                <i class="fas fa-chalkboard-teacher me-2"></i> Classes
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'academics:subject_list' %}">
                <i class="fas fa-book me-2"></i> Subjects
            </a>
        </li>
        <!-- Student Attendance via Admin -->
        <li class="nav-item">
            <a class="nav-link" href="/admin/academics/attendance/">
                <i class="fas fa-calendar-check me-2"></i> Student Attendance
            </a>
        </li>
    </ul>

    <!-- FINANCE SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Finance</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:invoice_list' %}">
                <i class="fas fa-file-invoice me-2"></i> Invoices
            </a>
        </li>
        <!-- Finance - Create Invoice (check if user has permission) -->
        {% if user.staff_profile.role in 'bursar,admin,proprietor' %}
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:invoice_create' %}">
                <i class="fas fa-plus-circle me-2"></i> Create Invoice
            </a>
        </li>
        {% endif %}
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:invoice_create' %}">
                <i class="fas fa-plus-circle me-2"></i> Create Invoice
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:payment_list' %}">
                <i class="fas fa-credit-card me-2"></i> Payments
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:payment_add' %}">
                <i class="fas fa-plus-circle me-2"></i> Record Payment
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:fee_list' %}">
                <i class="fas fa-tag me-2"></i> Fee Structure
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:bursar_dashboard' %}">
                <i class="fas fa-chart-pie me-2"></i> Bursar Dashboard
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'finance:financial_reports' %}">
                <i class="fas fa-chart-bar me-2"></i> Financial Reports
            </a>
        </li>
    </ul>

    <!-- COMMUNICATION SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Communication</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link" href="{% url 'communication:announcement_list' %}">
                <i class="fas fa-bullhorn me-2"></i> Announcements
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'communication:sms_list' %}">
                <i class="fas fa-sms me-2"></i> SMS Messages
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'communication:sms_compose' %}">
                <i class="fas fa-edit me-2"></i> Compose SMS
            </a>
        </li>
    </ul>

    <!-- PARENTS SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Parents</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link" href="{% url 'parents:parent_dashboard' %}">
                <i class="fas fa-users me-2"></i> Parent Dashboard
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'parents:parent_messages' %}">
                <i class="fas fa-envelope me-2"></i> Parent Messages
            </a>
        </li>
    </ul>

    <!-- REPORTS SECTION -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Reports</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link" href="{% url 'reports:academic_report' %}">
                <i class="fas fa-chart-line me-2"></i> Academic Reports
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'reports:attendance_report' %}">
                <i class="fas fa-calendar-check me-2"></i> Attendance Reports
            </a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{% url 'reports:financial_report' %}">
                <i class="fas fa-chart-pie me-2"></i> Financial Reports
            </a>
        </li>
    </ul>

    <!-- ADMIN SECTION (Superuser only) -->
    {% if user.is_superuser %}
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Administration</h6>
    <ul class="nav flex-column mb-3">
        <li class="nav-item">
            <a class="nav-link" href="{% url 'admin:index' %}">
                <i class="fas fa-cog me-2"></i> Django Admin
            </a>
        </li>
    </ul>
    {% endif %}

    <!-- QUICK ACTIONS -->
    <h6 class="sidebar-heading px-3 mt-3 mb-2 text-muted">Quick Actions</h6>
    <div class="px-3 mb-4">
        <div class="d-grid gap-2">
            <a href="{% url 'students:student_add' %}" class="btn btn-sm btn-outline-primary">
                <i class="fas fa-user-plus"></i> Add Student
            </a>
            <a href="{% url 'staff:staff_add' %}" class="btn btn-sm btn-outline-success">
                <i class="fas fa-user-tie"></i> Add Staff
            </a>
            <a href="{% url 'finance:invoice_create' %}" class="btn btn-sm btn-outline-warning">
                <i class="fas fa-file-invoice"></i> Create Invoice
            </a>
        </div>
    </div>
</div>

<style>
.sidebar-sticky {
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    padding-bottom: 20px;
}
.nav-link {
    color: #333;
    padding: 8px 15px;
    border-radius: 5px;
    margin: 2px 8px;
    transition: all 0.3s;
    font-size: 0.9rem;
}
.nav-link:hover {
    background-color: rgba(76, 175, 80, 0.1);
    color: #4CAF50;
    transform: translateX(5px);
}
.nav-link.active {
    background: linear-gradient(135deg, #4CAF50, #2196F3);
    color: white;
}
.nav-link i {
    width: 20px;
    text-align: center;
}
.sidebar-heading {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #6c757d;
    padding-left: 15px;
}
.user-info {
    border-bottom: 1px solid #dee2e6;
    padding-bottom: 15px;
}
.btn-sm {
    padding: 0.25rem 0.5rem;
    font-size: 0.8rem;
}
</style>

======================================================================
FILE: templates/includes/sidebar-2.html
======================================================================
{% load static %}

<!-- ── USER CARD ─────────────────────────────────────────────── -->
<div class="sb-user">
    <div class="sb-user-avatar">{{ user.get_full_name|default:user.username|first|upper }}</div>
    <div style="min-width:0;">
        <div class="sb-user-name">{{ user.get_full_name|default:user.username }}</div>
        <div class="sb-user-role">
            {% if user.is_superuser %}
                Proprietor
            {% elif user.staff_profile.role %}
                {{ user.staff_profile.get_role_display }}
            {% else %}
                Staff
            {% endif %}
        </div>
    </div>
</div>

<!-- ── MAIN ──────────────────────────────────────────────────── -->
<div class="sb-section">Main</div>
<a href="{% url 'dashboard' %}" class="sb-link">
    <i class="fas fa-th-large sb-icon"></i> Dashboard
</a>

<!-- ── STUDENTS ───────────────────────────────────────────────── -->
<div class="sb-divider"></div>
<div class="sb-section">Students</div>
<a href="{% url 'students:student_list' %}" class="sb-link">
    <i class="fas fa-user-graduate sb-icon"></i> All Students
</a>
{% if user.is_superuser or user.staff_profile.role in 'admin,head_master,head_mistress,proprietor' %}
<a href="{% url 'students:student_add' %}" class="sb-link">
    <i class="fas fa-user-plus sb-icon"></i> Add Student
</a>
{% endif %}
<a href="{% url 'students:parent_list' %}" class="sb-link">
    <i class="fas fa-users sb-icon"></i> Parents / Guardians
</a>

<!-- Import/Export — collapsible -->
{% if user.is_superuser or user.staff_profile.role in 'admin,head_master,head_mistress,proprietor' %}
<button class="sb-group-toggle" data-group="students-io" data-target="sb-students-io">
    <i class="fas fa-file-csv sb-icon"></i> Import / Export
    <i class="fas fa-chevron-right sb-chevron"></i>
</button>
<div class="sb-children" id="sb-students-io">
    <a href="{% url 'students:import_students_csv' %}" class="sb-link">
        <i class="fas fa-upload sb-icon"></i> Import CSV
    </a>
    <a href="{% url 'students:export_students' %}" class="sb-link">
        <i class="fas fa-download sb-icon"></i> Export CSV
    </a>
    <a href="{% url 'students:download_student_sample' %}" class="sb-link">
        <i class="fas fa-file sb-icon"></i> Sample Template
    </a>
</div>
{% endif %}

<!-- ── STAFF ───────────────────────────────────────────────────── -->
{% if user.is_superuser or user.staff_profile.role in 'admin,head_master,head_mistress,proprietor' %}
<div class="sb-divider"></div>
<div class="sb-section">Staff</div>
<a href="{% url 'staff:staff_list' %}" class="sb-link">
    <i class="fas fa-id-badge sb-icon"></i> All Staff
</a>
<a href="{% url 'staff:staff_add' %}" class="sb-link">
    <i class="fas fa-user-plus sb-icon"></i> Add Staff
</a>
<a href="{% url 'staff:leave_list' %}" class="sb-link">
    <i class="fas fa-calendar-minus sb-icon"></i> Leave Requests
</a>
<a href="{% url 'staff:attendance_list' %}" class="sb-link">
    <i class="fas fa-clock sb-icon"></i> Staff Attendance
</a>
{% else %}
<!-- Teachers / non-admin see only their own leave -->
<div class="sb-divider"></div>
<div class="sb-section">My HR</div>
<a href="{% url 'staff:leave_list' %}" class="sb-link">
    <i class="fas fa-calendar-minus sb-icon"></i> My Leave
</a>
<a href="{% url 'staff:leave_add' %}" class="sb-link">
    <i class="fas fa-plus sb-icon"></i> Request Leave
</a>
{% endif %}

<!-- ── ACADEMICS ───────────────────────────────────────────────── -->
<div class="sb-divider"></div>
<div class="sb-section">Academics</div>
<a href="{% url 'academics:class_list' %}" class="sb-link">
    <i class="fas fa-chalkboard sb-icon"></i> Classes
</a>
<a href="{% url 'academics:subject_list' %}" class="sb-link">
    <i class="fas fa-book-open sb-icon"></i> Subjects
</a>

<button class="sb-group-toggle" data-group="attendance" data-target="sb-attendance">
    <i class="fas fa-clipboard-check sb-icon"></i> Attendance
    <i class="fas fa-chevron-right sb-chevron"></i>
</button>
<div class="sb-children" id="sb-attendance">
    <a href="/academics/attendance/" class="sb-link">
        <i class="fas fa-list sb-icon"></i> Attendance List
    </a>
    {% if user.is_superuser or user.staff_profile.role in 'admin,head_master,head_mistress,proprietor' %}
    <a href="/admin/academics/attendance/add/" class="sb-link">
        <i class="fas fa-plus sb-icon"></i> Mark Attendance
    </a>
    {% endif %}
    <a href="{% url 'reports:attendance_report' %}" class="sb-link">
        <i class="fas fa-chart-line sb-icon"></i> Attendance Report
    </a>
</div>

<!-- ── FINANCE ────────────────────────────────────────────────── -->
{% if user.is_superuser or user.staff_profile.role in 'bursar,admin,head_master,head_mistress,proprietor' %}
<div class="sb-divider"></div>
<div class="sb-section">Finance</div>
<a href="{% url 'finance:bursar_dashboard' %}" class="sb-link">
    <i class="fas fa-chart-pie sb-icon"></i> Bursar Dashboard
</a>
<a href="{% url 'finance:invoice_list' %}" class="sb-link">
    <i class="fas fa-file-invoice sb-icon"></i> Invoices
</a>
<a href="{% url 'finance:payment_list' %}" class="sb-link">
    <i class="fas fa-money-bill-wave sb-icon"></i> Payments
</a>
<button class="sb-group-toggle" data-group="finance-more" data-target="sb-finance-more">
    <i class="fas fa-ellipsis-h sb-icon"></i> More Finance
    <i class="fas fa-chevron-right sb-chevron"></i>
</button>
<div class="sb-children" id="sb-finance-more">
    <a href="{% url 'finance:fee_list' %}" class="sb-link">
        <i class="fas fa-tags sb-icon"></i> Fee Structures
    </a>
    <a href="{% url 'finance:expense_list' %}" class="sb-link">
        <i class="fas fa-receipt sb-icon"></i> Expenses
    </a>
    <a href="{% url 'finance:discount_list' %}" class="sb-link">
        <i class="fas fa-percent sb-icon"></i> Discounts
    </a>
    <a href="{% url 'finance:financial_reports' %}" class="sb-link">
        <i class="fas fa-chart-bar sb-icon"></i> Financial Reports
    </a>
</div>
{% endif %}

<!-- ── COMMUNICATION ───────────────────────────────────────────── -->
<div class="sb-divider"></div>
<div class="sb-section">Communication</div>
<a href="{% url 'communication:announcement_list' %}" class="sb-link">
    <i class="fas fa-bullhorn sb-icon"></i> Announcements
</a>
<a href="{% url 'communication:sms_compose' %}" class="sb-link">
    <i class="fas fa-comment-sms sb-icon"></i> Send SMS
</a>
<a href="{% url 'communication:sms_list' %}" class="sb-link">
    <i class="fas fa-inbox sb-icon"></i> SMS History
</a>
<a href="{% url 'communication:parent_communication' %}" class="sb-link">
    <i class="fas fa-users sb-icon"></i> Parent Contacts
</a>

<!-- ── REPORTS ────────────────────────────────────────────────── -->
{% if user.is_superuser or user.staff_profile.role in 'admin,head_master,head_mistress,proprietor,bursar' %}
<div class="sb-divider"></div>
<div class="sb-section">Reports</div>
<a href="{% url 'reports:academic_report' %}" class="sb-link">
    <i class="fas fa-graduation-cap sb-icon"></i> Academic
</a>
<a href="{% url 'reports:attendance_report' %}" class="sb-link">
    <i class="fas fa-calendar-check sb-icon"></i> Attendance
</a>
<a href="{% url 'reports:financial_report' %}" class="sb-link">
    <i class="fas fa-coins sb-icon"></i> Financial
</a>
<a href="{% url 'reports:custom_report' %}" class="sb-link">
    <i class="fas fa-cogs sb-icon"></i> Custom Report
</a>
{% endif %}

<!-- ── ADMIN ──────────────────────────────────────────────────── -->
{% if user.is_superuser %}
<div class="sb-divider"></div>
<div class="sb-section">Administration</div>
<a href="{% url 'admin:index' %}" class="sb-link">
    <i class="fas fa-shield-alt sb-icon"></i> Django Admin
</a>
{% endif %}

<!-- ── LOGOUT ─────────────────────────────────────────────────── -->
<div class="sb-logout">
    <form method="post" action="{% url 'staff:logout' %}" style="margin:0">
        {% csrf_token %}
        <button type="submit" style="display:flex;align-items:center;gap:.65rem;padding:.6rem .85rem;border-radius:8px;color:#888;background:none;border:none;cursor:pointer;font-size:.875rem;font-weight:500;min-height:44px;width:100%;transition:background .15s,color .15s" onmouseover="this.style.background='#fff0f0';this.style.color='var(--rb-red)'" onmouseout="this.style.background='none';this.style.color='#888'">
            <i class="fas fa-sign-out-alt sb-icon"></i> Sign Out
        </button>
    </form>
</div>

<script>
(function () {
    /* ── Active link detection ── */
    const path = window.location.pathname;
    document.querySelectorAll('.sb-link').forEach(link => {
        const href = link.getAttribute('href');
        if (!href || href === '#') return;
        if (path === href || (href.length > 1 && path.startsWith(href))) {
            link.classList.add('active');
            const parent = link.closest('.sb-children');
            if (parent) {
                parent.classList.add('open');
                const btn = document.querySelector('[data-target="' + parent.id + '"]');
                if (btn) btn.classList.add('open');
            }
        }
    });

    /* ── Collapsible groups ── */
    document.querySelectorAll('.sb-group-toggle').forEach(btn => {
        const key = 'sb-' + btn.dataset.group;
        const children = document.getElementById(btn.dataset.target);
        if (!children) return;
        const saved = sessionStorage.getItem(key);
        const hasActive = children.querySelector('.active');
        if (saved === 'open' || hasActive) {
            btn.classList.add('open');
            children.classList.add('open');
        }
        btn.addEventListener('click', () => {
            const isOpen = btn.classList.toggle('open');
            children.classList.toggle('open', isOpen);
            sessionStorage.setItem(key, isOpen ? 'open' : 'closed');
        });
    });

    /* ── Close on mobile link tap ── */
    document.querySelectorAll('.sb-link').forEach(link => {
        link.addEventListener('click', () => {
            if (window.innerWidth < 992) document.body.classList.remove('sidebar-open');
        });
    });
})();
</script>

======================================================================
FILE: templates/includes/sidebar.html
======================================================================
{% load static %}

<!-- ── USER CARD ─────────────────────────────────────────────── -->
<div class="sb-user">
    <div class="sb-user-avatar">{{ user.get_full_name|default:user.username|first|upper }}</div>
    <div style="min-width:0;">
        <div class="sb-user-name">{{ user.get_full_name|default:user.username }}</div>
        <div class="sb-user-role">
            {% if user.staff_profile.role %}{{ user.staff_profile.get_role_display }}
            {% elif user.is_superuser %}Administrator
            {% else %}Staff{% endif %}
        </div>
    </div>
</div>

<!-- ── EXPAND / COLLAPSE ALL ─────────────────────────────────── -->
<div class="sb-expand-bar">
    <button class="sb-expand-btn" onclick="sbExpandAll()"><i class="fas fa-angles-down"></i> Expand all</button>
    <span class="sb-expand-sep">·</span>
    <button class="sb-expand-btn" onclick="sbCollapseAll()"><i class="fas fa-angles-up"></i> Collapse all</button>
</div>

{# Context processor injects: user_role, is_management, is_teacher_role, is_bursar_role, is_head_role, is_support_only #}

<!-- ══════════════ MAIN ══════════════ -->
<div class="sb-section-header" data-target="sbg-main"><span class="sb-section-label">Main</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-main">
    {# School-wide dashboard: management only #}
    {% if user.is_superuser or is_management %}
    <a href="{% url 'staff:staff_dashboard' %}" class="sb-link"><i class="fas fa-th-large sb-icon"></i> Dashboard</a>
    {% endif %}
    {# My Dashboard: teachers + support staff (driver, canteen, security etc.) #}
    {% if user.is_superuser or is_teacher_role or is_support_only %}
    <a href="{% url 'staff:teacher_dashboard' %}" class="sb-link"><i class="fas fa-chalkboard-teacher sb-icon"></i> My Dashboard</a>
    {% endif %}
    {# Bursar shortcut on top #}
    {% if user.is_superuser or is_bursar_role %}
    <a href="{% url 'finance:bursar_dashboard' %}" class="sb-link"><i class="fas fa-cash-register sb-icon"></i> Bursar Dashboard</a>
    {% endif %}
</div>

<!-- ══════════════ STUDENTS ══════════════ -->
{# Support staff (driver/canteen) can see student list to check registrations & fee status #}
{% if user.is_superuser or is_management or is_teacher_role or is_support_only %}
<div class="sb-section-header" data-target="sbg-students"><span class="sb-section-label">Students</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-students">
    <a href="{% url 'students:student_list' %}" class="sb-link"><i class="fas fa-user-graduate sb-icon"></i> All Students</a>
    {# Add/manage students: admin and above only #}
    {% if user.is_superuser or user_role in "proprietor,head_master,head_mistress,admin,bursar" %}
    <a href="{% url 'students:student_add' %}" class="sb-link"><i class="fas fa-user-plus sb-icon"></i> Add Student</a>
    <a href="{% url 'students:parent_list' %}" class="sb-link"><i class="fas fa-users sb-icon"></i> Parents / Guardians</a>
    <button class="sb-group-toggle" onclick="toggleGroup('sb-import')" id="btn-sb-import">
        <i class="fas fa-file-import sb-icon"></i> Import / Export<i class="fas fa-chevron-right sb-chevron"></i>
    </button>
    <div class="sb-children" id="sb-import">
        <a href="{% url 'students:import_students_csv' %}" class="sb-link"><i class="fas fa-upload sb-icon"></i> Import CSV</a>
        <a href="{% url 'students:export_students' %}" class="sb-link"><i class="fas fa-download sb-icon"></i> Export CSV</a>
        <a href="{% url 'students:download_student_sample' %}" class="sb-link"><i class="fas fa-file-csv sb-icon"></i> Sample Template</a>
    </div>
    {% endif %}
</div>
{% endif %}

<!-- ══════════════ STAFF ══════════════ -->
<div class="sb-section-header" data-target="sbg-staff"><span class="sb-section-label">Staff</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-staff">
    {# Staff directory (contact info): everyone can see colleagues #}
    <a href="{% url 'staff:staff_list' %}" class="sb-link"><i class="fas fa-id-badge sb-icon"></i> Staff Directory</a>
    {# My own profile #}
    {% if user.staff_profile %}
    <a href="{% url 'staff:staff_detail' user.staff_profile.pk %}" class="sb-link"><i class="fas fa-user-circle sb-icon"></i> My Profile</a>
    {% endif %}
    {# Add / edit staff: admin+ only #}
    {% if user.is_superuser or user_role in "proprietor,head_master,head_mistress,admin" %}
    <a href="{% url 'staff:staff_add' %}" class="sb-link"><i class="fas fa-user-tie sb-icon"></i> Add Staff</a>
    {% endif %}
    {# Leave: everyone can request and view own leave #}
    <a href="{% url 'staff:leave_list' %}" class="sb-link"><i class="fas fa-calendar-minus sb-icon"></i> Leave Requests</a>
    <a href="{% url 'staff:leave_add' %}" class="sb-link"><i class="fas fa-calendar-plus sb-icon"></i> Request Leave</a>
    {# Staff attendance tracking: management only #}
    {% if user.is_superuser or is_management %}
    <a href="{% url 'staff:attendance_list' %}" class="sb-link"><i class="fas fa-user-clock sb-icon"></i> Staff Attendance</a>
    {% endif %}
</div>

<!-- ══════════════ ACADEMICS ══════════════ -->
{# Support staff (drivers, cleaners etc.) don't need the academics section #}
{% if user.is_superuser or is_management or is_teacher_role %}
<div class="sb-section-header" data-target="sbg-academics"><span class="sb-section-label">Academics</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-academics">
    <a href="{% url 'academics:class_list' %}" class="sb-link"><i class="fas fa-chalkboard sb-icon"></i> Classes</a>
    <a href="{% url 'academics:subject_list' %}" class="sb-link"><i class="fas fa-book-open sb-icon"></i> Subjects</a>
</div>
{% endif %}

<!-- ══════════════ ATTENDANCE ══════════════ -->
{# Support staff don't mark class attendance #}
{% if user.is_superuser or is_management or is_teacher_role %}
<div class="sb-section-header" data-target="sbg-attendance"><span class="sb-section-label">Attendance</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-attendance">
    {% if user.is_superuser or is_management %}
    <a href="{% url 'attendance:attendance_list' %}" class="sb-link"><i class="fas fa-list sb-icon"></i> Attendance List</a>
    {% endif %}
    <a href="{% url 'attendance:mark_attendance' %}" class="sb-link"><i class="fas fa-clipboard-check sb-icon"></i> Mark Attendance</a>
    {% if user.is_superuser or is_management %}
    <a href="{% url 'staff:mark_attendance' %}" class="sb-link"><i class="fas fa-user-check sb-icon"></i> Mark Staff Attendance</a>
    {% endif %}
    <a href="{% url 'reports:attendance_report' %}" class="sb-link"><i class="fas fa-chart-line sb-icon"></i> Attendance Report</a>
</div>
{% endif %}

<!-- ══════════════ FINANCE ══════════════ -->
{# Full finance panel: bursar and above only #}
{% if user.is_superuser or is_bursar_role %}
<div class="sb-section-header" data-target="sbg-finance"><span class="sb-section-label">Finance</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-finance">
    <a href="{% url 'finance:bursar_dashboard' %}" class="sb-link"><i class="fas fa-tachometer-alt sb-icon"></i> Bursar Dashboard</a>
    <a href="{% url 'finance:invoice_list' %}" class="sb-link"><i class="fas fa-file-invoice sb-icon"></i> Invoices</a>
    <a href="{% url 'finance:bulk_invoice' %}" class="sb-link"><i class="fas fa-bolt sb-icon"></i> Bulk Generate</a>
    <a href="{% url 'finance:payment_list' %}" class="sb-link"><i class="fas fa-money-bill-wave sb-icon"></i> Payments</a>
    <a href="{% url 'finance:fee_list' %}" class="sb-link"><i class="fas fa-tags sb-icon"></i> Fee Structures</a>
    <a href="{% url 'finance:school_item_list' %}" class="sb-link"><i class="fas fa-tshirt sb-icon"></i> Item Prices</a>
    <a href="{% url 'finance:enrollment_fee_list' %}" class="sb-link"><i class="fas fa-user-graduate sb-icon"></i> Enrollment Fees</a>
    <a href="{% url 'finance:expense_list' %}" class="sb-link"><i class="fas fa-receipt sb-icon"></i> Expenses</a>
    <a href="{% url 'finance:expense_categories' %}" class="sb-link"><i class="fas fa-tags sb-icon"></i> Expense Categories</a>
    <a href="{% url 'finance:discount_list' %}" class="sb-link"><i class="fas fa-percent sb-icon"></i> Discounts</a>
    <a href="{% url 'finance:financial_reports' %}" class="sb-link"><i class="fas fa-chart-bar sb-icon"></i> Financial Reports</a>
</div>
{% elif user_role in "proprietor,head_master,head_mistress,admin" %}
{# Head / admin: read-only finance overview, no management actions #}
<div class="sb-section-header" data-target="sbg-finance"><span class="sb-section-label">Finance</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-finance">
    <a href="{% url 'finance:invoice_list' %}" class="sb-link"><i class="fas fa-file-invoice sb-icon"></i> Invoices</a>
    <a href="{% url 'finance:payment_list' %}" class="sb-link"><i class="fas fa-money-bill-wave sb-icon"></i> Payments</a>
    <a href="{% url 'finance:fee_list' %}" class="sb-link"><i class="fas fa-tags sb-icon"></i> Fee Structures</a>
    <a href="{% url 'finance:financial_reports' %}" class="sb-link"><i class="fas fa-chart-bar sb-icon"></i> Financial Reports</a>
</div>
{% endif %}

<!-- ══════════════ COMMUNICATION ══════════════ -->
{# Announcements visible to everyone including support staff #}
<div class="sb-section-header" data-target="sbg-comms"><span class="sb-section-label">Communication</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-comms">
    <a href="{% url 'communication:announcement_list' %}" class="sb-link"><i class="fas fa-bullhorn sb-icon"></i> Announcements</a>
    {# SMS compose: teachers and above #}
    {% if user.is_superuser or is_management or is_teacher_role %}
    <a href="{% url 'communication:sms_compose' %}" class="sb-link"><i class="fas fa-comment-sms sb-icon"></i> Send SMS</a>
    {% endif %}
    {# SMS history and parent contacts: management only #}
    {% if user.is_superuser or is_management %}
    <a href="{% url 'communication:sms_list' %}" class="sb-link"><i class="fas fa-history sb-icon"></i> SMS History</a>
    <a href="{% url 'communication:parent_communication' %}" class="sb-link"><i class="fas fa-users sb-icon"></i> Parent Contacts</a>
    {% endif %}
</div>

<!-- ══════════════ REPORTS ══════════════ -->
{% if user.is_superuser or is_management or is_teacher_role %}
<div class="sb-section-header" data-target="sbg-reports"><span class="sb-section-label">Reports</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-reports">
    <a href="{% url 'reports:academic_report' %}" class="sb-link"><i class="fas fa-graduation-cap sb-icon"></i> Academic</a>
    <a href="{% url 'reports:attendance_report' %}" class="sb-link"><i class="fas fa-calendar-check sb-icon"></i> Attendance</a>
    {% if user.is_superuser or is_management %}
    <a href="{% url 'reports:financial_report' %}" class="sb-link"><i class="fas fa-file-invoice-dollar sb-icon"></i> Financial</a>
    <a href="{% url 'reports:custom_report' %}" class="sb-link"><i class="fas fa-sliders-h sb-icon"></i> Custom Report</a>
    {% endif %}
</div>
{% endif %}

<!-- ══════════════ ADMINISTRATION ══════════════ -->
{% if user.is_superuser or is_head_role %}
<div class="sb-section-header" data-target="sbg-admin"><span class="sb-section-label">Administration</span><i class="fas fa-chevron-right sb-section-chev"></i></div>
<div class="sb-section-body" id="sbg-admin">
    <a href="{% url 'admin:index' %}" class="sb-link"><i class="fas fa-shield-alt sb-icon"></i> Backend Admin</a>
</div>
{% endif %}

<!-- Sign Out -->
<div class="sb-logout">
    <form method="post" action="{% url 'staff:logout' %}" style="margin:0">
        {% csrf_token %}
        <button type="submit" class="sb-signout-btn">
            <i class="fas fa-sign-out-alt sb-icon"></i> Sign Out
        </button>
    </form>
</div>

<script>
const SB_SECTIONS=['sbg-main','sbg-students','sbg-staff','sbg-academics','sbg-attendance','sbg-finance','sbg-comms','sbg-reports','sbg-admin'];
const SB_KEY='rb-sb-v3';

function sbSave(){
    const s={};
    SB_SECTIONS.forEach(id=>{const el=document.getElementById(id);if(el)s[id]=el.classList.contains('open')?1:0;});
    try{sessionStorage.setItem(SB_KEY,JSON.stringify(s));}catch(e){}
}
function sbOpen(id,save=true){
    const el=document.getElementById(id),hdr=document.querySelector('[data-target="'+id+'"]');
    if(!el)return;
    el.classList.add('open');if(hdr)hdr.classList.add('open');
    if(save)sbSave();
}
function sbClose(id,save=true){
    const el=document.getElementById(id),hdr=document.querySelector('[data-target="'+id+'"]');
    if(!el)return;
    el.classList.remove('open');if(hdr)hdr.classList.remove('open');
    if(save)sbSave();
}
function sbToggle(id){const el=document.getElementById(id);if(el)el.classList.contains('open')?sbClose(id):sbOpen(id);}
function sbExpandAll(){SB_SECTIONS.forEach(id=>sbOpen(id,false));sbSave();}
function sbCollapseAll(){
    const active=document.querySelector('.sb-link.active');
    const keep=active?active.closest('.sb-section-body'):null;
    SB_SECTIONS.forEach(id=>{const el=document.getElementById(id);if(el&&el!==keep)sbClose(id,false);});
    sbSave();
}

document.querySelectorAll('.sb-section-header').forEach(h=>{
    h.addEventListener('click',()=>sbToggle(h.dataset.target));
});

const path=window.location.pathname;
document.querySelectorAll('.sb-link').forEach(a=>{
    const href=a.getAttribute('href');
    if(href&&href!=='/'&&path.startsWith(href)){
        a.classList.add('active');
        const sec=a.closest('.sb-section-body');
        if(sec)sbOpen(sec.id,false);
        const sub=a.closest('.sb-children');
        if(sub){sub.style.display='block';const btn=document.getElementById('btn-'+sub.id);if(btn)btn.classList.add('open');}
    }
});

try{
    const saved=JSON.parse(sessionStorage.getItem(SB_KEY)||'{}');
    SB_SECTIONS.forEach(id=>{
        const el=document.getElementById(id);
        if(!el||el.classList.contains('open'))return;
        if(saved[id]===1)sbOpen(id,false);
    });
}catch(e){}

function toggleGroup(id){
    const el=document.getElementById(id),btn=document.getElementById('btn-'+id);
    if(!el)return;
    const open=el.style.display==='block';
    el.style.display=open?'none':'block';
    if(btn){btn.classList.toggle('open',!open);const c=btn.querySelector('.sb-chevron');if(c)c.style.transform=open?'':'rotate(90deg)';}
    try{sessionStorage.setItem('sb-'+id,open?0:1);}catch(e){}
}
document.querySelectorAll('.sb-children').forEach(el=>{
    if(el.style.display==='block')return;
    try{if(sessionStorage.getItem('sb-'+el.id)==='1'){el.style.display='block';const btn=document.getElementById('btn-'+el.id);if(btn){btn.classList.add('open');const c=btn.querySelector('.sb-chevron');if(c)c.style.transform='rotate(90deg)';}}}catch(e){}
});

document.querySelectorAll('.sb-link').forEach(a=>{
    a.addEventListener('click',()=>{if(window.innerWidth<992)document.body.classList.remove('sidebar-open');});
});
</script>

======================================================================
FILE: templates/parents/dashboard.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Parent Portal - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <h1 class="h3 mb-4 text-gray-800">Parent Portal</h1>

    <div class="row">
        {% for student in students %}
        <div class="col-md-6 mb-4">
            <div class="card shadow">
                <div class="card-header">
                    <h5 class="mb-0">{{ student.first_name }} {{ student.last_name }}</h5>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-6">
                            <p><strong>Class:</strong> {{ student.current_class }}</p>
                            <p><strong>Student ID:</strong> {{ student.student_id }}</p>
                            <p><strong>Attendance:</strong> 85% this month</p>
                        </div>
                        <div class="col-md-6">
                            <p><strong>Fee Status:</strong> <span class="badge bg-success">Paid</span></p>
                            <p><strong>Next Payment:</strong> 15 Jan 2026</p>
                            <a href="#" class="btn btn-sm btn-primary">View Details</a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <p class="text-center">No students linked to your account</p>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/parents/logout.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Logged Out — Parent Portal{% endblock %}
{% block content %}
<div class="row justify-content-center mt-5">
    <div class="col-md-5 text-center">
        <div class="card shadow border-0">
            <div class="card-body py-5">
                <i class="fas fa-sign-out-alt fa-3x text-muted mb-3"></i>
                <h4>You have been logged out</h4>
                <p class="text-muted">Thank you for using the Rapha-Bethel Parent Portal.</p>
                <a href="{% url 'parents:parent_login' %}" class="btn btn-danger mt-2"><i class="fas fa-sign-in-alt me-2"></i>Log In Again</a>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/message_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Message Detail — Parent Portal{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">Message</h1>
        <a href="{% url 'parents:parent_messages' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary"><i class="fas fa-sms me-2"></i>{{ message.get_message_type_display }}</h6>
                    <span class="text-muted small">{{ message.sent_time|date:"d M Y H:i" }}</span>
                </div>
                <div class="card-body">
                    <div class="alert alert-light" style="white-space:pre-line; font-size:1.05rem;">{{ message.message }}</div>
                    <p class="text-muted small mt-3 mb-0">Sent by Rapha-Bethel BNPS Administration</p>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/messages.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Messages — Parent Portal{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Messages</h1><p class="text-muted">Messages from the school</p></div>
        <a href="{% url 'parents:parent_dashboard' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Dashboard</a>
    </div>
    <div class="card shadow">
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark"><tr><th>Type</th><th>Preview</th><th>Date</th><th></th></tr></thead>
                <tbody>
                    {% for msg in messages %}
                    <tr>
                        <td><span class="badge bg-secondary">{{ msg.get_message_type_display }}</span></td>
                        <td>{{ msg.message|truncatechars:80 }}</td>
                        <td class="text-muted small">{{ msg.sent_time|date:"d M Y H:i"|default:"Draft" }}</td>
                        <td><a href="{% url 'parents:parent_message_detail' msg.pk %}" class="btn btn-sm btn-outline-primary"><i class="fas fa-eye"></i></a></td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="4" class="text-center py-4 text-muted"><i class="fas fa-inbox fa-2x mb-2 d-block"></i>No messages from the school yet.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/parent_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ parent.get_full_name }} - Parent/Guardian{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{{ parent.get_full_name }}</h1>
            <p class="text-muted">{{ parent.get_relationship_display }} of {{ parent.student.get_full_name }}</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary">
                <i class="fas fa-arrow-left me-2"></i>Back
            </a>
            <a href="{% url 'students:parent_edit' parent.pk %}" class="btn btn-warning">
                <i class="fas fa-edit me-2"></i>Edit
            </a>
        </div>
    </div>

    <div class="row">
        <div class="col-md-8">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Contact Information</h6>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Full Name</label>
                            <p class="fw-bold mb-0">{{ parent.get_full_name }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Relationship</label>
                            <p class="fw-bold mb-0">{{ parent.get_relationship_display }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Primary Phone</label>
                            <p class="fw-bold mb-0"><i class="fas fa-phone text-success me-2"></i>{{ parent.phone }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Alternate Phone</label>
                            <p class="fw-bold mb-0">{{ parent.alternate_phone|default:"—" }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Email</label>
                            <p class="fw-bold mb-0">{{ parent.email|default:"—" }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Address</label>
                            <p class="fw-bold mb-0">{{ parent.address|default:"—" }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Occupation</label>
                            <p class="fw-bold mb-0">{{ parent.get_occupation_display|default:"—" }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Employer</label>
                            <p class="fw-bold mb-0">{{ parent.employer|default:"—" }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Mobile Money</label>
                            <p class="fw-bold mb-0">
                                {% if parent.mobile_money_number %}
                                {{ parent.get_mobile_money_provider_display }}: {{ parent.mobile_money_number }}
                                {% else %}—{% endif %}
                            </p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Preferred Language</label>
                            <p class="fw-bold mb-0">{{ parent.get_preferred_language_display }}</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-md-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Linked Student</h6>
                </div>
                <div class="card-body">
                    <div class="d-flex align-items-center mb-3">
                        <div class="rounded-circle bg-primary bg-opacity-10 d-flex align-items-center justify-content-center me-3" style="width:50px;height:50px;">
                            <i class="fas fa-user-graduate text-primary"></i>
                        </div>
                        <div>
                            <div class="fw-bold">{{ parent.student.get_full_name }}</div>
                            <small class="text-muted">{{ parent.student.student_id }}</small>
                        </div>
                    </div>
                    <p class="mb-1"><i class="fas fa-chalkboard text-info me-2"></i>{{ parent.student.current_class|default:"No class assigned" }}</p>
                    <p class="mb-1"><i class="fas fa-circle text-{% if parent.student.status == 'active' %}success{% else %}secondary{% endif %} me-2"></i>{{ parent.student.get_status_display }}</p>
                    <a href="{% url 'students:student_detail' parent.student.pk %}" class="btn btn-outline-primary btn-sm mt-2 w-100">
                        View Student Profile
                    </a>
                </div>
            </div>

            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Notifications</h6>
                </div>
                <div class="card-body">
                    <div class="d-flex justify-content-between mb-2">
                        <span>SMS Alerts</span>
                        <span class="badge bg-{% if parent.receive_sms %}success{% else %}secondary{% endif %}">{{ parent.receive_sms|yesno:"On,Off" }}</span>
                    </div>
                    <div class="d-flex justify-content-between mb-2">
                        <span>Email Alerts</span>
                        <span class="badge bg-{% if parent.receive_email %}success{% else %}secondary{% endif %}">{{ parent.receive_email|yesno:"On,Off" }}</span>
                    </div>
                    <div class="d-flex justify-content-between">
                        <span>WhatsApp</span>
                        <span class="badge bg-{% if parent.receive_whatsapp %}success{% else %}secondary{% endif %}">{{ parent.receive_whatsapp|yesno:"On,Off" }}</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/parent_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{% if object %}Edit{% else %}Add{% endif %} Parent/Guardian - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{% if object %}Edit{% else %}Add{% endif %} Parent/Guardian</h1>
            <p class="text-muted">{% if object %}Update contact information{% else %}Register a new parent or guardian{% endif %}</p>
        </div>
        <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back
        </a>
    </div>

    <div class="row justify-content-center">
        <div class="col-md-9">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white">
                    <h6 class="m-0 font-weight-bold"><i class="fas fa-user-friends me-2"></i>Parent/Guardian Information</h6>
                </div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}
                        <div class="alert alert-danger"><i class="fas fa-exclamation-circle me-2"></i>Please correct the errors below.</div>
                        {% endif %}

                        <h6 class="text-primary border-bottom pb-2 mb-3">Basic Information</h6>
                        <div class="row mb-3">
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Student <span class="text-danger">*</span></label>
                                {{ form.student }}
                                {% if form.student.errors %}<div class="text-danger small">{{ form.student.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">First Name <span class="text-danger">*</span></label>
                                {{ form.first_name }}
                                {% if form.first_name.errors %}<div class="text-danger small">{{ form.first_name.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Last Name <span class="text-danger">*</span></label>
                                {{ form.last_name }}
                                {% if form.last_name.errors %}<div class="text-danger small">{{ form.last_name.errors }}</div>{% endif %}
                            </div>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Relationship <span class="text-danger">*</span></label>
                                {{ form.relationship }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Occupation</label>
                                {{ form.occupation }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Employer</label>
                                {{ form.employer }}
                            </div>
                        </div>

                        <h6 class="text-primary border-bottom pb-2 mb-3 mt-4">Contact Information</h6>
                        <div class="row mb-3">
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Phone <span class="text-danger">*</span></label>
                                {{ form.phone }}
                                {% if form.phone.errors %}<div class="text-danger small">{{ form.phone.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Alternate Phone</label>
                                {{ form.alternate_phone }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Email</label>
                                {{ form.email }}
                            </div>
                        </div>
                        <div class="mb-3">
                            <label class="form-label fw-bold">Address</label>
                            {{ form.address }}
                        </div>

                        <h6 class="text-primary border-bottom pb-2 mb-3 mt-4">Mobile Money & Preferences</h6>
                        <div class="row mb-3">
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Mobile Money Provider</label>
                                {{ form.mobile_money_provider }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Mobile Money Number</label>
                                {{ form.mobile_money_number }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label fw-bold">Preferred Language</label>
                                {{ form.preferred_language }}
                            </div>
                        </div>
                        <div class="row mb-3">
                            <div class="col-md-3">
                                <div class="form-check mt-2">
                                    {{ form.is_primary_contact }}
                                    <label class="form-check-label" for="{{ form.is_primary_contact.id_for_label }}">Primary Contact</label>
                                </div>
                            </div>
                            <div class="col-md-3">
                                <div class="form-check mt-2">
                                    {{ form.receive_sms }}
                                    <label class="form-check-label">Receive SMS</label>
                                </div>
                            </div>
                            <div class="col-md-3">
                                <div class="form-check mt-2">
                                    {{ form.receive_email }}
                                    <label class="form-check-label">Receive Email</label>
                                </div>
                            </div>
                            <div class="col-md-3">
                                <div class="form-check mt-2">
                                    {{ form.receive_whatsapp }}
                                    <label class="form-check-label">Receive WhatsApp</label>
                                </div>
                            </div>
                        </div>

                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'students:parent_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary">
                                <i class="fas fa-save me-2"></i>{% if object %}Update{% else %}Add{% endif %} Parent/Guardian
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

{% block extra_js %}
<script>
document.querySelectorAll('input, select, textarea').forEach(el => {
    if (!el.classList.contains('form-check-input')) {
        el.classList.add('form-control');
    }
});
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/parents/parent_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Parents & Guardians - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Parents & Guardians</h1>
            <p class="text-muted">{{ total_parents }} contact{{ total_parents|pluralize }} on record</p>
        </div>
        <a href="{% url 'students:parent_add' %}" class="btn btn-primary">
            <i class="fas fa-user-plus me-2"></i>Add Parent/Guardian
        </a>
    </div>

    <!-- Search -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-5">
                    <input type="text" name="q" class="form-control" placeholder="Search by name or phone..." value="{{ request.GET.q }}">
                </div>
                <div class="col-md-3">
                    <select name="relationship" class="form-control">
                        <option value="">All Relationships</option>
                        <option value="father" {% if request.GET.relationship == "father" %}selected{% endif %}>Father</option>
                        <option value="mother" {% if request.GET.relationship == "mother" %}selected{% endif %}>Mother</option>
                        <option value="guardian" {% if request.GET.relationship == "guardian" %}selected{% endif %}>Guardian</option>
                    </select>
                </div>
                <div class="col-md-2">
                    <button type="submit" class="btn btn-primary w-100"><i class="fas fa-search me-1"></i>Search</button>
                </div>
                <div class="col-md-2">
                    <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary w-100">Clear</a>
                </div>
            </form>
        </div>
    </div>

    <!-- Table -->
    <div class="card shadow">
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-hover mb-0">
                    <thead class="table-dark">
                        <tr>
                            <th>Name</th>
                            <th>Relationship</th>
                            <th>Phone</th>
                            <th>Student(s)</th>
                            <th>Primary Contact</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for parent in parents %}
                        <tr>
                            <td>
                                <div class="fw-bold">{{ parent.get_full_name }}</div>
                                {% if parent.email %}<small class="text-muted">{{ parent.email }}</small>{% endif %}
                            </td>
                            <td><span class="badge bg-secondary">{{ parent.get_relationship_display }}</span></td>
                            <td>
                                <i class="fas fa-phone text-success me-1"></i>{{ parent.phone }}
                                {% if parent.alternate_phone %}<br><small class="text-muted">{{ parent.alternate_phone }}</small>{% endif %}
                            </td>
                            <td>
                                <a href="{% url 'students:student_detail' parent.student.pk %}" class="text-decoration-none">
                                    {{ parent.student.get_full_name }}
                                </a>
                                <br><small class="text-muted">{{ parent.student.current_class }}</small>
                            </td>
                            <td>
                                {% if parent.is_primary_contact %}
                                <span class="badge bg-success"><i class="fas fa-star me-1"></i>Primary</span>
                                {% else %}
                                <span class="text-muted">—</span>
                                {% endif %}
                            </td>
                            <td>
                                <a href="{% url 'students:parent_detail' parent.pk %}" class="btn btn-sm btn-outline-primary me-1">
                                    <i class="fas fa-eye"></i>
                                </a>
                                <a href="{% url 'students:parent_edit' parent.pk %}" class="btn btn-sm btn-outline-warning">
                                    <i class="fas fa-edit"></i>
                                </a>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="6" class="text-center py-4 text-muted">
                                <i class="fas fa-users fa-2x mb-2 d-block"></i>No parents/guardians found.
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/profile.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}My Profile — Parent Portal{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">My Profile</h1><p class="text-muted">Manage your contact information</p></div>
        <a href="{% url 'parents:parent_profile_edit' %}" class="btn btn-warning"><i class="fas fa-edit me-2"></i>Edit Profile</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Contact Details</h6></div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr><td class="text-muted fw-bold" width="40%">Full Name</td><td class="fw-bold">{{ parent.get_full_name }}</td></tr>
                        <tr><td class="text-muted fw-bold">Relationship</td><td>{{ parent.get_relationship_display }}</td></tr>
                        <tr><td class="text-muted fw-bold">Primary Phone</td><td><i class="fas fa-phone text-success me-2"></i>{{ parent.phone }}</td></tr>
                        <tr><td class="text-muted fw-bold">Alternate Phone</td><td>{{ parent.alternate_phone|default:"—" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Email</td><td>{{ parent.email|default:"—" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Address</td><td>{{ parent.address|default:"—" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Occupation</td><td>{{ parent.get_occupation_display|default:"—" }}</td></tr>
                        <tr><td class="text-muted fw-bold">Employer</td><td>{{ parent.employer|default:"—" }}</td></tr>
                    </table>
                    <hr>
                    <h6 class="text-muted text-uppercase small mb-3">Notification Preferences</h6>
                    <div class="d-flex gap-3">
                        <span class="badge bg-{% if parent.receive_sms %}success{% else %}secondary{% endif %} p-2"><i class="fas fa-sms me-1"></i>SMS {{ parent.receive_sms|yesno:"On,Off" }}</span>
                        <span class="badge bg-{% if parent.receive_email %}success{% else %}secondary{% endif %} p-2"><i class="fas fa-envelope me-1"></i>Email {{ parent.receive_email|yesno:"On,Off" }}</span>
                        <span class="badge bg-{% if parent.receive_whatsapp %}success{% else %}secondary{% endif %} p-2"><i class="fab fa-whatsapp me-1"></i>WhatsApp {{ parent.receive_whatsapp|yesno:"On,Off" }}</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/profile_edit.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Edit Profile — Parent Portal{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">Edit Profile</h1>
        <a href="{% url 'parents:parent_profile' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-7">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white"><h6 class="m-0"><i class="fas fa-user-edit me-2"></i>Update Contact Information</h6></div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}<div class="alert alert-danger">Please correct the errors below.</div>{% endif %}
                        {% for field in form %}
                        <div class="mb-3">
                            <label class="form-label fw-bold">{{ field.label }}</label>
                            {{ field }}
                            {% if field.errors %}<div class="text-danger small">{{ field.errors }}</div>{% endif %}
                        </div>
                        {% endfor %}
                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'parents:parent_profile' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary"><i class="fas fa-save me-2"></i>Save Changes</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% block extra_js %}
<script>
document.querySelectorAll('input:not(.form-check-input), select, textarea').forEach(el => {
    if (!el.classList.contains('form-control') && !el.classList.contains('form-select')) {
        el.classList.add(el.tagName === 'SELECT' ? 'form-select' : 'form-control');
    }
});
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/parents/student_attendance.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ student.get_full_name }} — Attendance{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Attendance</h1>
            <p class="text-muted">{{ student.get_full_name }} &bull; {{ student.current_class|default:"No class" }}</p>
        </div>
        <a href="{% url 'parents:parent_student_detail' student.pk %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back
        </a>
    </div>

    <!-- Month Filter -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-4">
                    <label class="form-label">Month</label>
                    <select name="month" class="form-select">
                        {% for num, name in months %}
                        <option value="{{ num }}" {% if selected_month|stringformat:"s" == num|stringformat:"s" %}selected{% endif %}>{{ name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-4">
                    <label class="form-label">Year</label>
                    <select name="year" class="form-select">
                        {% for yr in years %}
                        <option value="{{ yr }}" {% if selected_year|stringformat:"s" == yr|stringformat:"s" %}selected{% endif %}>{{ yr }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-4">
                    <button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-1"></i>View</button>
                </div>
            </form>
        </div>
    </div>

    <!-- Records -->
    <div class="card shadow">
        <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Attendance Records</h6></div>
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark">
                    <tr><th>Date</th><th>Day</th><th>Status</th></tr>
                </thead>
                <tbody>
                    {% for att in attendances %}
                    <tr>
                        <td class="fw-bold">{{ att.date|date:"d M Y" }}</td>
                        <td class="text-muted">{{ att.date|date:"l" }}</td>
                        <td>
                            <span class="badge bg-{% if att.status == 'present' %}success{% elif att.status == 'absent' %}danger{% elif att.status == 'late' %}warning{% elif att.status == 'excused' %}info{% else %}secondary{% endif %}">
                                {{ att.get_status_display }}
                            </span>
                        </td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="3" class="text-center py-4 text-muted">No attendance records for this period.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/student_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ student.get_full_name }} — Parent Portal{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{{ student.get_full_name }}</h1>
            <p class="text-muted">{{ student.current_class|default:"No class assigned" }} &bull; {{ student.student_id }}</p>
        </div>
        <a href="{% url 'parents:parent_dashboard' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Dashboard
        </a>
    </div>

    <!-- Quick Stats -->
    <div class="row mb-4">
        <div class="col-md-4">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Attendance Rate</div>
                    <div class="h4 fw-bold {% if attendance_rate >= 80 %}text-success{% elif attendance_rate >= 60 %}text-warning{% else %}text-danger{% endif %}">{{ attendance_rate }}%</div>
                    <div class="text-muted small">{{ present_days }} / {{ total_days }} days this month</div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Student Status</div>
                    <div class="h5 fw-bold mt-1"><span class="badge bg-{% if student.status == 'active' %}success{% else %}secondary{% endif %} fs-6">{{ student.get_status_display }}</span></div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-info text-uppercase mb-1">Quick Links</div>
                    <div class="d-flex flex-column gap-1 mt-1">
                        <a href="{% url 'parents:parent_student_attendance' student.pk %}" class="btn btn-sm btn-outline-primary">Attendance</a>
                        <a href="{% url 'parents:parent_student_fees' student.pk %}" class="btn btn-sm btn-outline-warning">Fees</a>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Student Info -->
    <div class="row">
        <div class="col-md-6">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Student Information</h6></div>
                <div class="card-body">
                    <table class="table table-borderless mb-0">
                        <tr><td class="text-muted">Full Name</td><td class="fw-bold">{{ student.get_full_name }}</td></tr>
                        <tr><td class="text-muted">Student ID</td><td>{{ student.student_id }}</td></tr>
                        <tr><td class="text-muted">Date of Birth</td><td>{{ student.date_of_birth|date:"d M Y"|default:"—" }}</td></tr>
                        <tr><td class="text-muted">Gender</td><td>{{ student.get_gender_display }}</td></tr>
                        <tr><td class="text-muted">Class</td><td>{{ student.current_class|default:"—" }}</td></tr>
                        <tr><td class="text-muted">Admission Date</td><td>{{ student.admission_date|date:"d M Y"|default:"—" }}</td></tr>
                    </table>
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-success">Recent Attendance</h6></div>
                <div class="card-body p-0">
                    <table class="table table-hover mb-0">
                        <thead class="table-light"><tr><th>Date</th><th>Status</th></tr></thead>
                        <tbody>
                            {% for att in recent_attendance %}
                            <tr>
                                <td>{{ att.date|date:"d M Y" }}</td>
                                <td><span class="badge bg-{% if att.status == 'present' %}success{% elif att.status == 'absent' %}danger{% elif att.status == 'late' %}warning{% else %}info{% endif %}">{{ att.get_status_display }}</span></td>
                            </tr>
                            {% empty %}
                            <tr><td colspan="2" class="text-center text-muted py-3">No records yet</td></tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                <div class="card-footer">
                    <a href="{% url 'parents:parent_student_attendance' student.pk %}" class="btn btn-sm btn-outline-primary w-100">View Full Attendance</a>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/student_fees.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ student.get_full_name }} — Fees{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Fees & Payments</h1>
            <p class="text-muted">{{ student.get_full_name }}</p>
        </div>
        <a href="{% url 'parents:parent_student_detail' student.pk %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back
        </a>
    </div>

    <!-- Summary Cards -->
    <div class="row mb-4">
        <div class="col-md-4">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Total Invoiced</div>
                    <div class="h4 fw-bold">{{ total_invoiced|floatformat:0 }} XAF</div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Total Paid</div>
                    <div class="h4 fw-bold text-success">{{ total_paid|floatformat:0 }} XAF</div>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="card border-left-{% if balance_due > 0 %}danger{% else %}success{% endif %} shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold {% if balance_due > 0 %}text-danger{% else %}text-success{% endif %} text-uppercase mb-1">Balance Due</div>
                    <div class="h4 fw-bold {% if balance_due > 0 %}text-danger{% else %}text-success{% endif %}">{{ balance_due|floatformat:0 }} XAF</div>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="col-md-7">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Invoices</h6></div>
                <div class="card-body p-0">
                    <table class="table table-hover mb-0">
                        <thead class="table-dark"><tr><th>Invoice #</th><th>Term</th><th>Amount</th><th>Status</th><th>Due</th></tr></thead>
                        <tbody>
                            {% for invoice in invoices %}
                            <tr>
                                <td class="fw-bold">{{ invoice.invoice_number }}</td>
                                <td>{{ invoice.get_term_display }}</td>
                                <td>{{ invoice.total_amount|floatformat:0 }} XAF</td>
                                <td><span class="badge bg-{% if invoice.status == 'paid' %}success{% elif invoice.status == 'overdue' %}danger{% elif invoice.status == 'partial' %}warning{% else %}secondary{% endif %}">{{ invoice.get_status_display }}</span></td>
                                <td class="text-muted">{{ invoice.due_date|date:"d M Y" }}</td>
                            </tr>
                            {% empty %}
                            <tr><td colspan="5" class="text-center text-muted py-3">No invoices yet.</td></tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
        <div class="col-md-5">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-success">Payment History</h6></div>
                <div class="card-body p-0">
                    <table class="table table-hover mb-0">
                        <thead class="table-dark"><tr><th>Date</th><th>Amount</th><th>Method</th></tr></thead>
                        <tbody>
                            {% for payment in payments %}
                            <tr>
                                <td class="text-muted small">{{ payment.payment_date|date:"d M Y" }}</td>
                                <td class="fw-bold text-success">{{ payment.amount|floatformat:0 }}</td>
                                <td><span class="badge bg-secondary small">{{ payment.get_payment_method_display }}</span></td>
                            </tr>
                            {% empty %}
                            <tr><td colspan="3" class="text-center text-muted py-3">No payments yet.</td></tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/parents/student_reports.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ student.get_full_name }} — Reports{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Student Reports</h1><p class="text-muted">{{ student.get_full_name }}</p></div>
        <a href="{% url 'parents:parent_student_detail' student.pk %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row">
        {% for report in report_types %}
        <div class="col-md-4 mb-4">
            <div class="card shadow h-100">
                <div class="card-body text-center py-4">
                    <i class="fas fa-file-alt fa-3x text-primary mb-3"></i>
                    <h5>{{ report.name }}</h5>
                    <a href="{{ report.url }}" class="btn btn-outline-primary mt-2"><i class="fas fa-download me-2"></i>Download</a>
                </div>
            </div>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/reports/academic.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Academic Reports - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <h1 class="h3 mb-4 text-gray-800">Academic Reports</h1>

    <div class="card shadow">
        <div class="card-body">
            <form method="get" class="row g-3 mb-4">
                <div class="col-md-4">
                    <label>Class</label>
                    <select name="class" class="form-control">
                        <option value="">All Classes</option>
                        {% for class in classes %}
                        <option value="{{ class.id }}">{{ class.name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-4">
                    <label>Term</label>
                    <select name="term" class="form-control">
                        <option value="1">Term 1</option>
                        <option value="2">Term 2</option>
                        <option value="3">Term 3</option>
                    </select>
                </div>
                <div class="col-md-4 align-self-end">
                    <button type="submit" class="btn btn-primary">
                        <i class="fas fa-file-pdf"></i> Generate Report
                    </button>
                </div>
            </form>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/reports/attendance_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Attendance Report - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Attendance Report</h1><p class="text-muted">School-wide attendance overview</p></div>
        <a href="{% url 'reports:export_attendance_report' %}?from_date={{ from_date }}&to_date={{ to_date }}" class="btn btn-outline-primary"><i class="fas fa-download me-2"></i>Export CSV</a>
    </div>

    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-3"><label class="form-label">Class</label>
                    <select name="class" class="form-select">
                        <option value="">All Classes</option>
                        {% for cls in classes %}<option value="{{ cls.pk }}" {% if request.GET.class == cls.pk|stringformat:"s" %}selected{% endif %}>{{ cls }}</option>{% endfor %}
                    </select>
                </div>
                <div class="col-md-3"><label class="form-label">From Date</label><input type="date" name="from_date" class="form-control" value="{{ from_date }}"></div>
                <div class="col-md-3"><label class="form-label">To Date</label><input type="date" name="to_date" class="form-control" value="{{ to_date }}"></div>
                <div class="col-md-3"><button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-1"></i>Filter</button></div>
            </form>
        </div>
    </div>

    {% if overall_rate %}
    <div class="alert alert-info mb-4">
        <i class="fas fa-chart-line me-2"></i>Overall attendance rate for this period: <strong>{{ overall_rate }}%</strong>
    </div>
    {% endif %}

    <div class="card shadow">
        <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Attendance by Class</h6></div>
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark"><tr><th>Class</th><th>Total Records</th><th>Present</th><th>Absent</th><th>Late</th><th>Rate</th><th>Actions</th></tr></thead>
                <tbody>
                    {% for stat in stats %}
                    <tr>
                        <td class="fw-bold">{{ stat.class }}</td>
                        <td>{{ stat.total }}</td>
                        <td class="text-success">{{ stat.present }}</td>
                        <td class="text-danger">{{ stat.absent }}</td>
                        <td class="text-warning">{{ stat.late }}</td>
                        <td>
                            <div class="d-flex align-items-center gap-2">
                                <div class="progress flex-fill" style="height:8px;">
                                    <div class="progress-bar bg-{% if stat.rate >= 80 %}success{% elif stat.rate >= 60 %}warning{% else %}danger{% endif %}" style="width:{{ stat.rate }}%"></div>
                                </div>
                                <span class="fw-bold small">{{ stat.rate }}%</span>
                            </div>
                        </td>
                        <td><a href="{% url 'reports:class_attendance_report' stat.class_id %}" class="btn btn-sm btn-outline-primary">Detail</a></td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="7" class="text-center text-muted py-4">No attendance data for this period.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/reports/class_attendance_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Attendance — {{ class }}{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">{{ class }} — Monthly Attendance</h1>
        <p class="text-muted">{{ month }}/{{ year }}</p></div>
        <a href="{% url 'reports:attendance_report' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>

    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-3"><label class="form-label">Month</label>
                    <select name="month" class="form-select">
                        {% for num, name in months %}
                        <option value="{{ num }}" {% if month == num %}selected{% endif %}>{{ name }}</option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3"><label class="form-label">Year</label><input type="number" name="year" class="form-control" value="{{ year }}"></div>
                <div class="col-md-3"><button type="submit" class="btn btn-primary w-100">Apply</button></div>
            </form>
        </div>
    </div>

    <div class="card shadow">
        <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Daily Attendance Grid</h6></div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-bordered table-sm mb-0" style="font-size:0.8rem;">
                    <thead class="table-dark">
                        <tr>
                            <th style="min-width:160px;">Student</th>
                            {% for day in days %}
                            <th class="text-center {% if day.weekday >= 5 %}table-secondary{% endif %}" style="min-width:36px;" title="{{ day|date:'l, d M' }}">{{ day|date:"d" }}</th>
                            {% endfor %}
                        </tr>
                    </thead>
                    <tbody>
                        {% for row in attendance_data %}
                        <tr>
                            <td class="fw-bold">{{ row.student.get_full_name }}</td>
                            {% for att in row.attendance %}
                            <td class="text-center p-1 {% if att.is_weekend %}bg-light{% endif %}">
                                {% if att.status == 'present' %}
                                    <span class="badge bg-success" title="{{ att.date|date:'d M' }} — Present">P</span>
                                {% elif att.status == 'absent' %}
                                    <span class="badge bg-danger" title="{{ att.date|date:'d M' }} — Absent">A</span>
                                {% elif att.status == 'late' %}
                                    <span class="badge bg-warning text-dark" title="{{ att.date|date:'d M' }} — Late">L</span>
                                {% elif att.status == 'excused' %}
                                    <span class="badge bg-info" title="{{ att.date|date:'d M' }} — Excused">E</span>
                                {% elif att.status == 'weekend' %}
                                    <span class="text-muted" title="{{ att.date|date:'l' }}" style="font-size:0.65rem;">—</span>
                                {% elif att.status == 'future' %}
                                    <span class="text-muted" title="Future date" style="font-size:0.65rem;">·</span>
                                {% else %}
                                    <span class="badge bg-secondary" title="{{ att.date|date:'d M' }} — No record taken">?</span>
                                {% endif %}
                            </td>
                            {% endfor %}
                        </tr>
                        {% empty %}
                        <tr><td colspan="32" class="text-center text-muted py-4">No data available.</td></tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
        <div class="card-footer text-muted small">
            <span class="badge bg-success me-1">P</span>Present &nbsp;
            <span class="badge bg-danger me-1">A</span>Absent &nbsp;
            <span class="badge bg-warning me-1 text-dark">L</span>Late &nbsp;
            <span class="badge bg-info me-1">E</span>Excused &nbsp;
            <span class="badge bg-secondary me-1">?</span>No record taken &nbsp;
            <span class="text-muted me-1">—</span>Weekend &nbsp;
            <span class="text-muted me-1">·</span>Future date
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/reports/class_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Class Report — {{ class }}{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Class Report — {{ class }}</h1>
            <p class="text-muted">Term {{ term }} &bull; Year {{ year }} &bull; {{ students.count }} students</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'reports:academic_report' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
            <a href="{% url 'reports:generate_academic_report' %}" class="btn btn-outline-primary" onclick="this.closest('form') && this.closest('form').submit()">
                <i class="fas fa-download me-2"></i>Export CSV
            </a>
        </div>
    </div>

    <!-- Filter -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-4"><label class="form-label">Term</label>
                    <select name="term" class="form-select">
                        {% for t in "123" %}<option value="{{ t }}" {% if term|stringformat:"s" == t %}selected{% endif %}>Term {{ t }}</option>{% endfor %}
                    </select>
                </div>
                <div class="col-md-4"><label class="form-label">Year</label>
                    <input type="number" name="year" class="form-control" value="{{ year }}">
                </div>
                <div class="col-md-4"><button type="submit" class="btn btn-primary w-100">Apply</button></div>
            </form>
        </div>
    </div>

    <!-- Summary Stats -->
    {% if student_stats %}
    <div class="row mb-4">
        <div class="col-md-3"><div class="card border-left-primary shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Total Students</div><div class="h4 mb-0 fw-bold">{{ student_stats|length }}</div></div></div></div>
        <div class="col-md-3"><div class="card border-left-success shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-success text-uppercase mb-1">Avg Attendance</div><div class="h4 mb-0 fw-bold">{% with total=0 %}{% for s in student_stats %}{% endfor %}—{% endwith %}</div></div></div></div>
    </div>
    {% endif %}

    <div class="card shadow">
        <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Student Attendance Summary</h6></div>
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark">
                    <tr><th>#</th><th>Student</th><th>Total Days</th><th>Present</th><th>Absent</th><th>Late</th><th>Attendance Rate</th></tr>
                </thead>
                <tbody>
                    {% for stat in student_stats %}
                    <tr>
                        <td class="text-muted">{{ forloop.counter }}</td>
                        <td><a href="{% url 'reports:student_report' stat.student.pk %}">{{ stat.student.get_full_name }}</a></td>
                        <td>{{ stat.total_days }}</td>
                        <td class="text-success fw-bold">{{ stat.present }}</td>
                        <td class="text-danger">{{ stat.absent }}</td>
                        <td class="text-warning">{{ stat.late }}</td>
                        <td>
                            <div class="d-flex align-items-center gap-2">
                                <div class="progress flex-fill" style="height:8px;">
                                    <div class="progress-bar bg-{% if stat.attendance_rate >= 80 %}success{% elif stat.attendance_rate >= 60 %}warning{% else %}danger{% endif %}" style="width:{{ stat.attendance_rate }}%"></div>
                                </div>
                                <span class="fw-bold small">{{ stat.attendance_rate }}%</span>
                            </div>
                        </td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="7" class="text-center text-muted py-4">No data available for this period.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/reports/custom_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Custom Report Builder - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Custom Report Builder</h1><p class="text-muted">Select data source and fields to generate a custom CSV report</p></div>
    </div>
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white"><h6 class="m-0"><i class="fas fa-cogs me-2"></i>Report Configuration</h6></div>
                <div class="card-body">
                    <form method="post" action="{% url 'reports:generate_custom_report' %}">
                        {% csrf_token %}
                        <div class="mb-4">
                            <label class="form-label fw-bold">Data Source <span class="text-danger">*</span></label>
                            <div class="row g-3">
                                {% for source in data_sources %}
                                <div class="col-md-4">
                                    <div class="card border h-100">
                                        <div class="card-body text-center p-3">
                                            <div class="form-check">
                                                <input class="form-check-input" type="radio" name="data_source" id="source_{{ source.id }}" value="{{ source.id }}" required>
                                                <label class="form-check-label fw-bold" for="source_{{ source.id }}">
                                                    <i class="fas fa-{% if source.id == 'students' %}user-graduate{% elif source.id == 'attendance' %}clipboard-check{% elif source.id == 'payments' %}money-bill{% elif source.id == 'invoices' %}file-invoice{% else %}receipt{% endif %} fa-2x d-block mb-2 text-primary"></i>
                                                    {{ source.name }}
                                                </label>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                {% endfor %}
                            </div>
                        </div>

                        <div class="mb-4">
                            <label class="form-label fw-bold">Date Range (optional)</label>
                            <div class="row g-3">
                                <div class="col-md-6"><input type="date" name="from_date" class="form-control" placeholder="From date"></div>
                                <div class="col-md-6"><input type="date" name="to_date" class="form-control" placeholder="To date"></div>
                            </div>
                        </div>

                        <div class="mb-4">
                            <label class="form-label fw-bold">Additional Filters</label>
                            <textarea name="filters" class="form-control" rows="3" placeholder="Optional: describe any specific filters..."></textarea>
                        </div>

                        <div class="alert alert-info">
                            <i class="fas fa-info-circle me-2"></i>The report will be downloaded as a CSV file. Large datasets may take a moment to generate.
                        </div>

                        <div class="d-flex justify-content-end gap-2">
                            <a href="{% url 'reports:academic_report' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary"><i class="fas fa-download me-2"></i>Generate & Download</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/reports/financial_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Financial Report - Rapha-Bethel BNPS{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Financial Report</h1><p class="text-muted">{{ from_date }} to {{ to_date }}</p></div>
        <a href="{% url 'reports:export_financial_report' %}?from_date={{ from_date }}&to_date={{ to_date }}" class="btn btn-outline-primary"><i class="fas fa-download me-2"></i>Export CSV</a>
    </div>

    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-4"><label class="form-label">From Date</label><input type="date" name="from_date" class="form-control" value="{{ from_date }}"></div>
                <div class="col-md-4"><label class="form-label">To Date</label><input type="date" name="to_date" class="form-control" value="{{ to_date }}"></div>
                <div class="col-md-4"><button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-1"></i>Filter</button></div>
            </form>
        </div>
    </div>

    <div class="row mb-4">
        <div class="col-md-4"><div class="card border-left-success shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-success text-uppercase mb-1">Total Revenue</div><div class="h4 fw-bold">{{ total_revenue|floatformat:0 }} XAF</div></div></div></div>
        <div class="col-md-4"><div class="card border-left-danger shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-danger text-uppercase mb-1">Total Expenses</div><div class="h4 fw-bold">{{ total_expenses|floatformat:0 }} XAF</div></div></div></div>
        <div class="col-md-4"><div class="card border-left-{% if net_profit >= 0 %}primary{% else %}warning{% endif %} shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-uppercase mb-1">Net Profit</div><div class="h4 fw-bold {% if net_profit >= 0 %}text-primary{% else %}text-warning{% endif %}">{{ net_profit|floatformat:0 }} XAF</div></div></div></div>
    </div>

    <div class="row">
        <div class="col-md-6">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-success">Revenue by Payment Method</h6></div>
                <div class="card-body p-0">
                    <table class="table mb-0">
                        <thead class="table-light"><tr><th>Method</th><th class="text-end">Amount (XAF)</th></tr></thead>
                        <tbody>
                            {% for item in by_method %}
                            <tr><td>{{ item.method }}</td><td class="text-end fw-bold text-success">{{ item.total|floatformat:0 }}</td></tr>
                            {% empty %}
                            <tr><td colspan="2" class="text-center text-muted py-3">No data</td></tr>
                            {% endfor %}
                            <tr class="table-success fw-bold"><td>Total</td><td class="text-end">{{ total_revenue|floatformat:0 }}</td></tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-danger">Expenses by Category</h6></div>
                <div class="card-body p-0">
                    <table class="table mb-0">
                        <thead class="table-light"><tr><th>Category</th><th class="text-end">Amount (XAF)</th></tr></thead>
                        <tbody>
                            {% for item in by_category %}
                            <tr><td>{{ item.category }}</td><td class="text-end fw-bold text-danger">{{ item.total|floatformat:0 }}</td></tr>
                            {% empty %}
                            <tr><td colspan="2" class="text-center text-muted py-3">No expenses recorded</td></tr>
                            {% endfor %}
                            <tr class="table-danger fw-bold"><td>Total</td><td class="text-end">{{ total_expenses|floatformat:0 }}</td></tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/reports/student_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Student Report — {{ student.get_full_name }}{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Student Report</h1>
            <p class="text-muted">{{ student.get_full_name }} &bull; {{ student.student_id }} &bull; Term {{ term }}, {{ year }}</p>
        </div>
        <a href="{% url 'reports:academic_report' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>

    <div class="row">
        <div class="col-md-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Student Info</h6></div>
                <div class="card-body">
                    <table class="table table-borderless mb-0">
                        <tr><td class="text-muted">Name</td><td class="fw-bold">{{ student.get_full_name }}</td></tr>
                        <tr><td class="text-muted">ID</td><td>{{ student.student_id }}</td></tr>
                        <tr><td class="text-muted">Class</td><td>{{ student.current_class|default:"—" }}</td></tr>
                        <tr><td class="text-muted">Status</td><td><span class="badge bg-{% if student.status == 'active' %}success{% else %}secondary{% endif %}">{{ student.get_status_display }}</span></td></tr>
                    </table>
                </div>
            </div>
        </div>

        <div class="col-md-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-success">Attendance</h6></div>
                <div class="card-body">
                    <div class="text-center mb-3">
                        <div class="h2 fw-bold {% if attendance.rate >= 80 %}text-success{% elif attendance.rate >= 60 %}text-warning{% else %}text-danger{% endif %}">{{ attendance.rate }}%</div>
                        <div class="text-muted small">Attendance Rate</div>
                    </div>
                    <div class="progress mb-3" style="height:12px;">
                        <div class="progress-bar bg-{% if attendance.rate >= 80 %}success{% elif attendance.rate >= 60 %}warning{% else %}danger{% endif %}" style="width:{{ attendance.rate }}%"></div>
                    </div>
                    <table class="table table-borderless table-sm mb-0">
                        <tr><td class="text-muted">Total Days</td><td class="fw-bold">{{ attendance.total }}</td></tr>
                        <tr><td class="text-success">Present</td><td class="fw-bold">{{ attendance.present }}</td></tr>
                        <tr><td class="text-danger">Absent</td><td class="fw-bold">{{ attendance.absent }}</td></tr>
                        <tr><td class="text-warning">Late</td><td class="fw-bold">{{ attendance.late }}</td></tr>
                    </table>
                </div>
            </div>
        </div>

        <div class="col-md-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-warning">Fees Summary</h6></div>
                <div class="card-body">
                    <table class="table table-borderless mb-0">
                        <tr><td class="text-muted">Total Invoiced</td><td class="fw-bold">{{ fees.invoiced|floatformat:0 }} XAF</td></tr>
                        <tr><td class="text-success">Total Paid</td><td class="fw-bold text-success">{{ fees.paid|floatformat:0 }} XAF</td></tr>
                        <tr class="{% if fees.balance > 0 %}table-warning{% else %}table-success{% endif %}">
                            <td class="fw-bold">Balance Due</td><td class="fw-bold">{{ fees.balance|floatformat:0 }} XAF</td>
                        </tr>
                    </table>
                    <div class="mt-3">
                        <a href="{% url 'students:student_detail' student.pk %}" class="btn btn-outline-primary btn-sm w-100">View Full Profile</a>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Term filter -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-4"><label class="form-label">Term</label>
                    <select name="term" class="form-select">
                        {% for t in "123" %}<option value="{{ t }}" {% if term|stringformat:"s" == t %}selected{% endif %}>Term {{ t }}</option>{% endfor %}
                    </select>
                </div>
                <div class="col-md-4"><label class="form-label">Year</label><input type="number" name="year" class="form-control" value="{{ year }}"></div>
                <div class="col-md-4"><button type="submit" class="btn btn-primary w-100">Update Report</button></div>
            </form>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/reports/term_financial_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}Term {{ term }} Financial Report{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">Term {{ term }} Financial Report</h1><p class="text-muted">{{ year }}/{{ year|add:1 }} Academic Year &bull; {{ start_date }} to {{ end_date }}</p></div>
        <a href="{% url 'reports:financial_report' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row mb-4">
        <div class="col-md-4"><div class="card border-left-primary shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Total Invoiced</div><div class="h4 fw-bold">{{ total_invoiced|floatformat:0 }} XAF</div></div></div></div>
        <div class="col-md-4"><div class="card border-left-success shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-success text-uppercase mb-1">Collected</div><div class="h4 fw-bold">{{ total_collected|floatformat:0 }} XAF</div></div></div></div>
        <div class="col-md-4"><div class="card border-left-warning shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Outstanding</div><div class="h4 fw-bold">{{ outstanding|floatformat:0 }} XAF</div></div></div></div>
    </div>
    <div class="card shadow">
        <div class="card-body">
            <div class="progress mb-2" style="height:20px;">
                {% if total_invoiced > 0 %}
                <div class="progress-bar bg-success" style="width:{% widthratio total_collected total_invoiced 100 %}%" title="Collected">
                    {% widthratio total_collected total_invoiced 100 %}% Collected
                </div>
                {% endif %}
            </div>
            <p class="text-muted text-center">{{ total_collected|floatformat:0 }} XAF collected out of {{ total_invoiced|floatformat:0 }} XAF invoiced</p>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/reports/yearly_financial_report.html
======================================================================
{% extends 'base.html' %}
{% load static %}
{% block title %}{{ year }} Yearly Financial Report{% endblock %}
{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div><h1 class="h3 mb-0">{{ year }} Annual Financial Report</h1></div>
        <a href="{% url 'reports:financial_report' %}" class="btn btn-outline-secondary"><i class="fas fa-arrow-left me-2"></i>Back</a>
    </div>
    <div class="row mb-4">
        <div class="col-md-4"><div class="card border-left-success shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-success text-uppercase mb-1">Total Revenue</div><div class="h4 fw-bold">{{ total_revenue|floatformat:0 }} XAF</div></div></div></div>
        <div class="col-md-4"><div class="card border-left-danger shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-danger text-uppercase mb-1">Total Expenses</div><div class="h4 fw-bold">{{ total_expenses|floatformat:0 }} XAF</div></div></div></div>
        <div class="col-md-4"><div class="card border-left-primary shadow h-100 py-2"><div class="card-body"><div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Net Profit</div><div class="h4 fw-bold {% if total_profit >= 0 %}text-success{% else %}text-danger{% endif %}">{{ total_profit|floatformat:0 }} XAF</div></div></div></div>
    </div>
    <div class="card shadow">
        <div class="card-header py-3"><h6 class="m-0 font-weight-bold text-primary">Monthly Breakdown</h6></div>
        <div class="card-body p-0">
            <table class="table table-hover mb-0">
                <thead class="table-dark"><tr><th>Month</th><th class="text-end">Revenue (XAF)</th><th class="text-end">Expenses (XAF)</th><th class="text-end">Net (XAF)</th></tr></thead>
                <tbody>
                    {% for row in monthly_data %}
                    <tr>
                        <td class="fw-bold">{{ row.month }}</td>
                        <td class="text-end text-success">{{ row.revenue|floatformat:0 }}</td>
                        <td class="text-end text-danger">{{ row.expenses|floatformat:0 }}</td>
                        <td class="text-end fw-bold {% if row.profit >= 0 %}text-primary{% else %}text-warning{% endif %}">{{ row.profit|floatformat:0 }}</td>
                    </tr>
                    {% endfor %}
                </tbody>
                <tfoot class="table-dark">
                    <tr>
                        <td class="fw-bold">TOTAL</td>
                        <td class="text-end fw-bold text-success">{{ total_revenue|floatformat:0 }}</td>
                        <td class="text-end fw-bold text-danger">{{ total_expenses|floatformat:0 }}</td>
                        <td class="text-end fw-bold">{{ total_profit|floatformat:0 }}</td>
                    </tr>
                </tfoot>
            </table>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/staff/attendance_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Attendance Record - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0">Attendance Record</h1>
        <a href="{% url 'staff:attendance_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back to List
        </a>
    </div>

    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">
                        <i class="fas fa-clipboard-check me-2"></i>Attendance Details
                    </h6>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td class="text-muted fw-bold" width="40%">Staff Member</td>
                            <td>{{ attendance.staff.user.get_full_name }}</td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Employee ID</td>
                            <td>{{ attendance.staff.employee_id }}</td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Role</td>
                            <td>{{ attendance.staff.get_role_display }}</td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Date</td>
                            <td>{{ attendance.date|date:"l, d F Y" }}</td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Status</td>
                            <td>
                                <span class="badge bg-{% if attendance.status == 'present' %}success{% elif attendance.status == 'absent' %}danger{% elif attendance.status == 'late' %}warning{% else %}info{% endif %} fs-6">
                                    {{ attendance.get_status_display }}
                                </span>
                            </td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Check In</td>
                            <td>{{ attendance.check_in_time|default:"Not recorded" }}</td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Check Out</td>
                            <td>{{ attendance.check_out_time|default:"Not recorded" }}</td>
                        </tr>
                        <tr>
                            <td class="text-muted fw-bold">Remarks</td>
                            <td>{{ attendance.remarks|default:"—" }}</td>
                        </tr>
                    </table>
                    <div class="d-flex justify-content-end gap-2 mt-3">
                        <a href="{% url 'staff:staff_detail' attendance.staff.pk %}" class="btn btn-outline-primary">
                            <i class="fas fa-user me-2"></i>View Staff Profile
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/staff/attendance_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Staff Attendance - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Staff Attendance</h1>
            <p class="text-muted">Track and manage staff attendance records</p>
        </div>
        <a href="{% url 'staff:mark_attendance' %}" class="btn btn-primary">
            <i class="fas fa-clipboard-check me-2"></i>Mark Today's Attendance
        </a>
    </div>

    <!-- Filter Card -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <form method="get" class="row g-3 align-items-end">
                <div class="col-md-3">
                    <label class="form-label">Staff Member</label>
                    <select name="staff" class="form-control">
                        <option value="">All Staff</option>
                        {% for s in all_staff %}
                        <option value="{{ s.pk }}" {% if request.GET.staff == s.pk|stringformat:"s" %}selected{% endif %}>
                            {{ s.user.get_full_name }}
                        </option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3">
                    <label class="form-label">Date From</label>
                    <input type="date" name="date_from" class="form-control" value="{{ request.GET.date_from }}">
                </div>
                <div class="col-md-3">
                    <label class="form-label">Date To</label>
                    <input type="date" name="date_to" class="form-control" value="{{ request.GET.date_to }}">
                </div>
                <div class="col-md-3">
                    <label class="form-label">Status</label>
                    <select name="status" class="form-control">
                        <option value="">All Statuses</option>
                        <option value="present" {% if request.GET.status == "present" %}selected{% endif %}>Present</option>
                        <option value="absent" {% if request.GET.status == "absent" %}selected{% endif %}>Absent</option>
                        <option value="late" {% if request.GET.status == "late" %}selected{% endif %}>Late</option>
                        <option value="leave" {% if request.GET.status == "leave" %}selected{% endif %}>On Leave</option>
                    </select>
                </div>
                <div class="col-12">
                    <button type="submit" class="btn btn-primary me-2"><i class="fas fa-filter me-1"></i>Filter</button>
                    <a href="{% url 'staff:attendance_list' %}" class="btn btn-outline-secondary">Clear</a>
                </div>
            </form>
        </div>
    </div>

    <!-- Summary Stats -->
    <div class="row mb-4">
        <div class="col-md-3">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">Present Today</div>
                    <div class="h5 mb-0 font-weight-bold">{{ today_present|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-danger shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-danger text-uppercase mb-1">Absent Today</div>
                    <div class="h5 mb-0 font-weight-bold">{{ today_absent|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Late Today</div>
                    <div class="h5 mb-0 font-weight-bold">{{ today_late|default:"0" }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-info text-uppercase mb-1">On Leave</div>
                    <div class="h5 mb-0 font-weight-bold">{{ today_leave|default:"0" }}</div>
                </div>
            </div>
        </div>
    </div>

    <!-- Attendance Table -->
    <div class="card shadow">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Attendance Records</h6>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-hover mb-0">
                    <thead class="table-dark">
                        <tr>
                            <th>Staff Member</th>
                            <th>Role</th>
                            <th>Date</th>
                            <th>Status</th>
                            <th>Check In</th>
                            <th>Check Out</th>
                            <th>Remarks</th>
                            <th>Action</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for record in attendance_records %}
                        <tr>
                            <td>
                                <div class="fw-bold">{{ record.staff.user.get_full_name }}</div>
                                <small class="text-muted">{{ record.staff.employee_id }}</small>
                            </td>
                            <td><span class="badge bg-secondary">{{ record.staff.get_role_display }}</span></td>
                            <td>{{ record.date|date:"d M Y" }}</td>
                            <td>
                                <span class="badge bg-{% if record.status == 'present' %}success{% elif record.status == 'absent' %}danger{% elif record.status == 'late' %}warning{% elif record.status == 'leave' or record.status == 'sick' %}info{% else %}secondary{% endif %}">
                                    {{ record.get_status_display }}
                                </span>
                            </td>
                            <td>{{ record.check_in_time|default:"—" }}</td>
                            <td>{{ record.check_out_time|default:"—" }}</td>
                            <td class="text-muted small">{{ record.remarks|default:"—" }}</td>
                            <td>
                                <a href="{% url 'staff:attendance_detail' record.pk %}" class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </a>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="8" class="text-center py-4 text-muted">
                                <i class="fas fa-clipboard fa-2x mb-2 d-block"></i>
                                No attendance records found.
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    {% if is_paginated %}
    <nav class="mt-4">
        <ul class="pagination justify-content-center">
            {% if page_obj.has_previous %}
            <li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a></li>
            {% endif %}
            <li class="page-item active"><a class="page-link" href="#">{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</a></li>
            {% if page_obj.has_next %}
            <li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a></li>
            {% endif %}
        </ul>
    </nav>
    {% endif %}
</div>
{% endblock %}


======================================================================
FILE: templates/staff/dashboard-1.html
======================================================================
<!-- templates/staff/dashboard.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Staff Dashboard - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .stat-card {
        transition: transform 0.3s, box-shadow 0.3s;
        border-radius: 10px;
        overflow: hidden;
    }
    .stat-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.15);
    }
    .stat-icon {
        font-size: 2.5rem;
        opacity: 0.8;
    }
    .stat-number {
        font-size: 2rem;
        font-weight: bold;
        color: #333;
    }
    .stat-label {
        color: #666;
        font-size: 0.9rem;
        text-transform: uppercase;
        letter-spacing: 0.5px;
    }
    .role-badge {
        position: absolute;
        top: 15px;
        right: 15px;
    }
    .welcome-section {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 30px;
        border-radius: 15px;
        margin-bottom: 25px;
        box-shadow: 0 10px 30px rgba(102, 126, 234, 0.3);
    }
    .quick-action-card {
        background: white;
        border-radius: 10px;
        padding: 20px;
        text-align: center;
        transition: all 0.3s;
        cursor: pointer;
        border: 1px solid #e9ecef;
    }
    .quick-action-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.1);
        border-color: #4CAF50;
    }
    .quick-action-icon {
        font-size: 2rem;
        color: #4CAF50;
        margin-bottom: 10px;
    }
    .activity-timeline {
        max-height: 400px;
        overflow-y: auto;
        padding-right: 10px;
    }
    .timeline-item {
        padding: 15px;
        border-left: 3px solid #4CAF50;
        margin-bottom: 15px;
        background: #f8f9fc;
        border-radius: 0 8px 8px 0;
    }
    .timeline-time {
        font-size: 0.8rem;
        color: #6c757d;
        margin-bottom: 5px;
    }
    .timeline-title {
        font-weight: 600;
        margin-bottom: 5px;
    }
    .timeline-text {
        font-size: 0.9rem;
        color: #6c757d;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Welcome Section -->
    <div class="welcome-section d-flex justify-content-between align-items-center">
        <div>
            <h2 class="mb-2">
                Welcome back, 
                {% if request.user.staff_profile %}
                    {{ request.user.staff_profile.user.get_full_name }}
                {% else %}
                    {{ request.user.get_full_name }}
                {% endif %}
            </h2>
            <p class="mb-0">
                <i class="fas fa-calendar-alt me-2"></i> {{ current_date|date:"l, F d, Y" }}
            </p>
        </div>
        <div class="text-end">
            <span class="badge bg-white text-primary p-3">
                <i class="fas fa-clock me-2"></i> {{ current_time|time:"h:i A" }}
            </span>
        </div>
    </div>

    <!-- Stats Cards -->
    <div class="row">
        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="stat-label text-primary font-weight-bold mb-1">
                                TOTAL STAFF
                            </div>
                            <div class="stat-number mb-0">{{ total_staff|default:"0" }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-user-check text-success me-1"></i> {{ active_staff|default:"0" }} Active
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-users stat-icon text-primary"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="stat-label text-success font-weight-bold mb-1">
                                TEACHERS
                            </div>
                            <div class="stat-number mb-0">{{ teachers_count|default:"0" }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-chalkboard-teacher text-info me-1"></i> {{ class_teachers|default:"0" }} Class Teachers
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-chalkboard-teacher stat-icon text-success"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="stat-label text-info font-weight-bold mb-1">
                                PENDING LEAVE
                            </div>
                            <div class="stat-number mb-0">{{ pending_leaves|default:"0" }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-check-circle text-success me-1"></i> {{ approved_leaves|default:"0" }} Approved
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-calendar-alt stat-icon text-info"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="col-xl-3 col-md-6 mb-4">
            <div class="card stat-card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="row no-gutters align-items-center">
                        <div class="col mr-2">
                            <div class="stat-label text-warning font-weight-bold mb-1">
                                TODAY'S ATTENDANCE
                            </div>
                            <div class="stat-number mb-0">{{ today_attendance|default:"0" }}</div>
                            <div class="text-muted small mt-2">
                                <i class="fas fa-clock text-warning me-1"></i> {{ present_percent|default:"0" }}% Present
                            </div>
                        </div>
                        <div class="col-auto">
                            <i class="fas fa-clock stat-icon text-warning"></i>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Dashboard Type Specific Content -->
    {% if dashboard_type == 'proprietor' %}
    <!-- Proprietor Dashboard -->
    <div class="row">
        <div class="col-lg-6 mb-4">
            <div class="card shadow">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">School Overview</h6>
                    <a href="{% url 'admin:index' %}" class="btn btn-sm btn-primary">Manage</a>
                </div>
                <div class="card-body">
                    <canvas id="schoolChart" height="200"></canvas>
                </div>
            </div>
        </div>
        <div class="col-lg-6 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Quick Stats</h6>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-6 mb-3">
                            <div class="p-3 bg-light rounded text-center">
                                <h4>{{ total_students|default:"0" }}</h4>
                                <small>Total Students</small>
                            </div>
                        </div>
                        <div class="col-6 mb-3">
                            <div class="p-3 bg-light rounded text-center">
                                <h4>{{ total_classes|default:"0" }}</h4>
                                <small>Total Classes</small>
                            </div>
                        </div>
                        <div class="col-6 mb-3">
                            <div class="p-3 bg-light rounded text-center">
                                <h4>{{ monthly_revenue|default:"0" }} XAF</h4>
                                <small>Monthly Revenue</small>
                            </div>
                        </div>
                        <div class="col-6 mb-3">
                            <div class="p-3 bg-light rounded text-center">
                                <h4>{{ pending_invoices|default:"0" }}</h4>
                                <small>Pending Invoices</small>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    {% elif dashboard_type == 'head' %}
    <!-- Head Teacher Dashboard -->
    <div class="row">
        <div class="col-lg-7 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">{{ department_name }} Section - Recent Activity</h6>
                </div>
                <div class="card-body">
                    <div class="activity-timeline">
                        {% for activity in recent_activities %}
                        <div class="timeline-item">
                            <div class="timeline-time">{{ activity.timestamp|timesince }} ago</div>
                            <div class="timeline-title">{{ activity.title }}</div>
                            <div class="timeline-text">{{ activity.description }}</div>
                        </div>
                        {% empty %}
                        <p class="text-muted text-center py-3">No recent activity</p>
                        {% endfor %}
                    </div>
                </div>
            </div>
        </div>
        <div class="col-lg-5 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Quick Actions</h6>
                </div>
                <div class="card-body">
                    <div class="d-grid gap-2">
                        <a href="{% url 'students:student_add' %}" class="btn btn-outline-primary text-start">
                            <i class="fas fa-user-plus me-2"></i> Add New Student
                        </a>
                        <a href="{% url 'staff:staff_add' %}" class="btn btn-outline-success text-start">
                            <i class="fas fa-chalkboard-teacher me-2"></i> Add New Teacher
                        </a>
                        <a href="{% url 'attendance:mark_attendance' %}" class="btn btn-outline-info text-start">
                            <i class="fas fa-clipboard-check me-2"></i> Mark Attendance
                        </a>
                        <a href="{% url 'reports:attendance_report' %}" class="btn btn-outline-warning text-start">
                            <i class="fas fa-chart-bar me-2"></i> View Reports
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </div>

    {% elif dashboard_type == 'teacher' %}
    <!-- Teacher Dashboard -->
    <div class="row">
        <div class="col-lg-6 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">My Classes</h6>
                </div>
                <div class="card-body">
                    <div class="list-group">
                        {% for class in my_classes %}
                        <a href="{% url 'academics:class_detail' class.id %}" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
                            {{ class.name }}
                            <span class="badge bg-primary rounded-pill">{{ class.student_count }}</span>
                        </a>
                        {% empty %}
                        <p class="text-muted text-center py-3">No classes assigned</p>
                        {% endfor %}
                    </div>
                </div>
            </div>
        </div>
        <div class="col-lg-6 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Today's Tasks</h6>
                </div>
                <div class="card-body">
                    <div class="list-group">
                        <div class="list-group-item d-flex justify-content-between align-items-center">
                            Mark Attendance
                            <a href="{% url 'attendance:mark_attendance' %}" class="btn btn-sm btn-primary">Go</a>
                        </div>
                        <div class="list-group-item d-flex justify-content-between align-items-center">
                            Check Schedule
                            <a href="#" class="btn btn-sm btn-outline-secondary">View</a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    {% else %}
    <!-- Default Staff Dashboard -->
    <div class="row">
        <div class="col-lg-8 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">My Information</h6>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-6">
                            <p><strong>Employee ID:</strong> {{ request.user.staff_profile.employee_id }}</p>
                            <p><strong>Role:</strong> {{ request.user.staff_profile.get_role_display }}</p>
                            <p><strong>Department:</strong> {{ request.user.staff_profile.get_department_display }}</p>
                        </div>
                        <div class="col-md-6">
                            <p><strong>Phone:</strong> {{ request.user.staff_profile.phone_number }}</p>
                            <p><strong>Email:</strong> {{ request.user.email }}</p>
                            <p><strong>Hire Date:</strong> {{ request.user.staff_profile.hire_date }}</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="col-lg-4 mb-4">
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Quick Links</h6>
                </div>
                <div class="card-body">
                    <div class="list-group">
                        <a href="{% url 'staff:staff_edit' request.user.staff_profile.pk %}" class="list-group-item list-group-item-action">
                            <i class="fas fa-edit me-2"></i> Edit Profile
                        </a>
                        <a href="{% url 'staff:leave_add' %}" class="list-group-item list-group-item-action">
                            <i class="fas fa-calendar-plus me-2"></i> Request Leave
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </div>
    {% endif %}

    <!-- Recent Activity (Common for all) -->
    <div class="row">
        <div class="col-12">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Recent Activity</h6>
                </div>
                <div class="card-body">
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>Time</th>
                                    <th>User</th>
                                    <th>Action</th>
                                    <th>Details</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for activity in recent_activities %}
                                <tr>
                                    <td>{{ activity.timestamp|timesince }} ago</td>
                                    <td>{{ activity.user }}</td>
                                    <td>{{ activity.action }}</td>
                                    <td>{{ activity.details }}</td>
                                </tr>
                                {% empty %}
                                <tr>
                                    <td colspan="4" class="text-center py-3">No recent activity</td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
    // School Overview Chart (for proprietor)
    const schoolCtx = document.getElementById('schoolChart');
    if (schoolCtx) {
        new Chart(schoolCtx, {
            type: 'bar',
            data: {
                labels: ['Students', 'Staff', 'Classes', 'Parents'],
                datasets: [{
                    label: 'Counts',
                    data: [
                        {{ total_students|default:0 }},
                        {{ total_staff|default:0 }},
                        {{ total_classes|default:0 }},
                        {{ total_parents|default:0 }}
                    ],
                    backgroundColor: [
                        'rgba(76, 175, 80, 0.2)',
                        'rgba(33, 150, 243, 0.2)',
                        'rgba(255, 193, 7, 0.2)',
                        'rgba(156, 39, 176, 0.2)'
                    ],
                    borderColor: [
                        'rgba(76, 175, 80, 1)',
                        'rgba(33, 150, 243, 1)',
                        'rgba(255, 193, 7, 1)',
                        'rgba(156, 39, 176, 1)'
                    ],
                    borderWidth: 1
                }]
            },
            options: {
                scales: {
                    y: {
                        beginAtZero: true,
                        ticks: {
                            precision: 0
                        }
                    }
                },
                responsive: true,
                maintainAspectRatio: false
            }
        });
    }
});
</script>
{% endblock %}

======================================================================
FILE: templates/staff/dashboard-2.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Staff Dashboard — Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
.dash-grid   { display:grid; grid-template-columns:1fr; gap:1rem; }
@media(min-width:480px)  { .dash-grid-2   { grid-template-columns:1fr 1fr; } }
@media(min-width:768px)  { .dash-grid-4   { grid-template-columns:repeat(4,1fr); } }
@media(min-width:768px)  { .dash-grid-2-1 { grid-template-columns:2fr 1fr; } }

/* Welcome banner — on-brand red, not off-brand purple */
.staff-welcome {
    background: linear-gradient(135deg, var(--rb-red-dark) 0%, var(--rb-red) 60%, #b84a4a 100%);
    border-radius: 14px;
    padding: 1.4rem 1.5rem;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
    box-shadow: 0 4px 20px rgba(139,0,0,.25);
}
.staff-welcome h2 { font-size:1.2rem;font-weight:700;margin:0 0 .25rem; }
.staff-welcome p  { font-size:.82rem;color:rgba(255,255,255,.8);margin:0; }
.welcome-time-badge {
    background:rgba(255,255,255,.15);
    border-radius:10px;
    padding:.6rem 1rem;
    text-align:center;
    flex-shrink:0;
    display:none;
}
@media(min-width:480px){ .welcome-time-badge { display:block; } }
.welcome-time-badge .time { font-size:1.3rem;font-weight:700;line-height:1; }
.welcome-time-badge .date { font-size:.7rem;color:rgba(255,255,255,.75);margin-top:2px; }

.kpi { background:#fff;border-radius:12px;padding:1rem 1.1rem;border:1px solid #ede8e3;box-shadow:0 1px 4px rgba(0,0,0,.07);display:flex;align-items:center;gap:.9rem; }
.kpi-icon { width:46px;height:46px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0; }
.kpi-icon.blue   { background:#eff6ff;color:#3b82f6; }
.kpi-icon.green  { background:#f0fdf4;color:#22c55e; }
.kpi-icon.gold   { background:#fffbeb;color:var(--rb-gold); }
.kpi-icon.red    { background:#fef2f2;color:var(--rb-red); }
.kpi-label { font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:#999;margin-bottom:2px; }
.kpi-value { font-size:1.5rem;font-weight:700;color:#1a1a1a;line-height:1; }
.kpi-sub   { font-size:.72rem;color:#aaa;margin-top:3px; }

.rb-section-title { font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.6px;color:#999;margin:0 0 .75rem; }

/* My classes list */
.class-item { display:flex;align-items:center;gap:.75rem;padding:.65rem 0;border-bottom:1px solid #f5f0ea; }
.class-item:last-child { border-bottom:none; }
.class-bubble { width:36px;height:36px;border-radius:8px;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-red));color:#fff;font-weight:700;font-size:.75rem;display:flex;align-items:center;justify-content:center;flex-shrink:0; }
.class-name { font-weight:600;font-size:.875rem; }
.class-meta { font-size:.75rem;color:#aaa; }

/* Quick actions */
.qa-grid { display:grid;grid-template-columns:1fr 1fr;gap:.5rem; }
.qa-btn { display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;padding:.85rem .5rem;border-radius:10px;background:#fff;border:1px solid #ede8e3;text-decoration:none;color:#444;font-size:.75rem;font-weight:600;text-align:center;transition:all .15s;min-height:72px; }
.qa-btn i { font-size:1.3rem;color:var(--rb-red); }
.qa-btn:hover { border-color:var(--rb-red);background:#fff5f5;color:var(--rb-red);transform:translateY(-2px);box-shadow:0 4px 12px rgba(139,0,0,.12); }

/* Leave request mini-list */
.leave-item { display:flex;align-items:center;gap:.6rem;padding:.55rem 0;border-bottom:1px solid #f5f0ea; }
.leave-item:last-child { border-bottom:none; }

/* My profile card (default staff) */
.profile-row { display:flex;align-items:baseline;gap:.5rem;padding:.4rem 0;border-bottom:1px solid #f5f0ea;font-size:.875rem; }
.profile-row:last-child { border-bottom:none; }
.profile-label { font-weight:600;color:#555;width:110px;flex-shrink:0;font-size:.8rem; }
.profile-val { color:#333; }
</style>
{% endblock %}

{% block content %}

<!-- WELCOME BANNER -->
<div class="staff-welcome">
    <div>
        <h2>
            {% if dashboard_type == 'proprietor' %}Welcome, Proprietor{% elif dashboard_type == 'head' %}Good day, Head Teacher{% elif dashboard_type == 'teacher' %}Good day, Teacher{% else %}Welcome Back{% endif %}
            {% if request.user.staff_profile %} — {{ request.user.get_full_name|default:request.user.username }}{% endif %}
        </h2>
        <p>
            {% if dashboard_type == 'teacher' %}Your classes &amp; today's tasks are below.
            {% elif dashboard_type == 'head' %}{{ department_name }} section overview.
            {% elif dashboard_type == 'proprietor' %}Full school overview.
            {% else %}Rapha-Bethel BNPS Staff Portal.{% endif %}
        </p>
    </div>
    <div class="welcome-time-badge">
        <div class="time" id="liveTime">--:--</div>
        <div class="date">{{ current_date|date:"d M Y" }}</div>
    </div>
</div>

<!-- KPI CARDS — common to all roles -->
<div class="dash-grid dash-grid-2 dash-grid-4 mb-4">
    <div class="kpi">
        <div class="kpi-icon blue"><i class="fas fa-users"></i></div>
        <div>
            <div class="kpi-label">Total Staff</div>
            <div class="kpi-value">{{ total_staff|default:"—" }}</div>
            <div class="kpi-sub">{{ active_staff|default:0 }} active</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon green"><i class="fas fa-chalkboard-teacher"></i></div>
        <div>
            <div class="kpi-label">Teachers</div>
            <div class="kpi-value">{{ teachers_count|default:"—" }}</div>
            <div class="kpi-sub">{{ class_teachers|default:0 }} class teachers</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon gold"><i class="fas fa-calendar-minus"></i></div>
        <div>
            <div class="kpi-label">Pending Leave</div>
            <div class="kpi-value">{{ pending_leaves|default:"0" }}</div>
            <div class="kpi-sub">{{ approved_leaves|default:0 }} approved</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon red"><i class="fas fa-clock"></i></div>
        <div>
            <div class="kpi-label">Staff Present Today</div>
            <div class="kpi-value">{{ present_percent|default:"0" }}%</div>
            <div class="kpi-sub">{{ today_attendance|default:0 }} checked in</div>
        </div>
    </div>
</div>

<!-- ROLE-SPECIFIC CONTENT -->

{% if dashboard_type == 'proprietor' %}
<!-- ── PROPRIETOR VIEW ──────────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header d-flex align-items-center justify-content-between">
            <span class="rb-section-title mb-0">School Overview</span>
        </div>
        <div class="card-body">
            <div class="row g-2">
                {% with items="Students|user-graduate|blue,Classes|chalkboard|green,Monthly Revenue XAF|coins|gold,Pending Invoices|file-invoice|red" %}
                {% endwith %}
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#eff6ff">
                        <div style="font-size:1.5rem;font-weight:700;color:#3b82f6">{{ total_students|default:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Total Students</div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#f0fdf4">
                        <div style="font-size:1.5rem;font-weight:700;color:#22c55e">{{ total_classes|default:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Total Classes</div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#fffbeb">
                        <div style="font-size:1.1rem;font-weight:700;color:var(--rb-gold)">{{ monthly_revenue|default:0|floatformat:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Monthly Revenue (XAF)</div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#fef2f2">
                        <div style="font-size:1.5rem;font-weight:700;color:var(--rb-red)">{{ pending_invoices|default:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Pending Invoices</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Admin Actions</span></div>
        <div class="card-body" style="display:flex;flex-direction:column;gap:.5rem;padding-top:.6rem">
            <a href="{% url 'staff:staff_list' %}"     class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-id-badge" style="color:var(--rb-red);width:18px;text-align:center"></i> Manage Staff</a>
            <a href="{% url 'students:student_list' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-user-graduate" style="color:var(--rb-red);width:18px;text-align:center"></i> All Students</a>
            <a href="{% url 'finance:bursar_dashboard' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-chart-pie" style="color:var(--rb-red);width:18px;text-align:center"></i> Finance Dashboard</a>
            <a href="{% url 'reports:academic_report' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-chart-bar" style="color:var(--rb-red);width:18px;text-align:center"></i> View Reports</a>
            {% if user.is_superuser %}<a href="{% url 'admin:index' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-shield-alt" style="color:var(--rb-red);width:18px;text-align:center"></i> Admin Panel</a>{% endif %}
        </div>
    </div>
</div>

{% elif dashboard_type == 'head' %}
<!-- ── HEAD TEACHER VIEW ────────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">{{ department_name }} — Recent Staff Leave Requests</span></div>
        <div class="card-body">
            {% with leaves=recent_leave_requests %}
            {% if leaves %}
                {% for leave in leaves %}
                <div class="leave-item">
                    <div style="width:34px;height:34px;border-radius:8px;background:#f5ede6;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:.8rem;font-weight:700;color:var(--rb-red)">{{ leave.staff.user.first_name|first }}{{ leave.staff.user.last_name|first }}</div>
                    <div style="flex:1;min-width:0">
                        <div style="font-weight:600;font-size:.85rem">{{ leave.staff.user.get_full_name }}</div>
                        <div style="font-size:.75rem;color:#aaa">{{ leave.get_leave_type_display }} · {{ leave.start_date|date:"d M" }} – {{ leave.end_date|date:"d M" }}</div>
                    </div>
                    {% if leave.status == 'pending' %}<span class="rb-badge rb-badge-gold">Pending</span>
                    {% elif leave.status == 'approved' %}<span class="rb-badge rb-badge-green">Approved</span>
                    {% else %}<span class="rb-badge rb-badge-red">{{ leave.status|title }}</span>{% endif %}
                </div>
                {% endfor %}
            {% else %}
                <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No recent leave requests</p>
            {% endif %}
            {% endwith %}
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Head's Quick Actions</span></div>
        <div class="card-body">
            <div class="qa-grid">
                <a href="{% url 'students:student_add' %}"  class="qa-btn"><i class="fas fa-user-plus"></i>Add Student</a>
                <a href="{% url 'staff:staff_add' %}"       class="qa-btn"><i class="fas fa-user-tie"></i>Add Staff</a>
                <a href="{% url 'staff:leave_list' %}"      class="qa-btn"><i class="fas fa-calendar-check"></i>Leave List</a>
                <a href="{% url 'reports:attendance_report' %}" class="qa-btn"><i class="fas fa-chart-bar"></i>Reports</a>
            </div>
        </div>
    </div>
</div>

{% elif dashboard_type == 'teacher' %}
<!-- ── TEACHER VIEW ─────────────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header d-flex align-items-center justify-content-between">
            <span class="rb-section-title mb-0">My Assigned Classes</span>
            <a href="{% url 'academics:class_list' %}" style="font-size:.75rem;color:var(--rb-red)">All classes</a>
        </div>
        <div class="card-body" style="padding-top:.5rem">
            {% if my_classes %}
                {% for cls in my_classes %}
                <div class="class-item">
                    <div class="class-bubble">{{ cls.name|slice:":2"|upper }}</div>
                    <div style="flex:1">
                        <div class="class-name">{{ cls.name }}</div>
                        <div class="class-meta">{{ cls.student_count|default:0 }} students</div>
                    </div>
                    <a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm" style="background:#fef2f2;color:var(--rb-red);border:none;font-size:.75rem;padding:.25rem .6rem">View</a>
                </div>
                {% endfor %}
            {% else %}
                <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No classes assigned yet</p>
            {% endif %}
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Today's Tasks</span></div>
        <div class="card-body">
            <div class="qa-grid">
                <a href="/academics/attendance/" class="qa-btn"><i class="fas fa-clipboard-check"></i>Attendance</a>
                <a href="{% url 'academics:class_list' %}" class="qa-btn"><i class="fas fa-chalkboard"></i>My Classes</a>
                <a href="{% url 'staff:leave_add' %}"     class="qa-btn"><i class="fas fa-calendar-plus"></i>Request Leave</a>
                <a href="{% url 'staff:leave_list' %}"    class="qa-btn"><i class="fas fa-list"></i>My Leave</a>
            </div>
        </div>
    </div>
</div>

{% else %}
<!-- ── DEFAULT STAFF VIEW ──────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">My Profile</span></div>
        <div class="card-body" style="padding-top:.5rem">
            {% if request.user.staff_profile %}
            {% with s=request.user.staff_profile %}
            <div class="profile-row"><span class="profile-label">Employee ID</span><span class="profile-val">{{ s.employee_id }}</span></div>
            <div class="profile-row"><span class="profile-label">Role</span><span class="profile-val">{{ s.get_role_display }}</span></div>
            <div class="profile-row"><span class="profile-label">Department</span><span class="profile-val">{{ s.get_department_display }}</span></div>
            <div class="profile-row"><span class="profile-label">Phone</span><span class="profile-val">{{ s.phone_number|default:"—" }}</span></div>
            <div class="profile-row"><span class="profile-label">Email</span><span class="profile-val">{{ request.user.email|default:"—" }}</span></div>
            <div class="profile-row"><span class="profile-label">Hire Date</span><span class="profile-val">{{ s.hire_date|date:"d M Y"|default:"—" }}</span></div>
            {% endwith %}
            {% endif %}
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Quick Links</span></div>
        <div class="card-body">
            <div class="qa-grid">
                {% if request.user.staff_profile %}
                <a href="{% url 'staff:staff_edit' request.user.staff_profile.pk %}" class="qa-btn"><i class="fas fa-user-edit"></i>Edit Profile</a>
                {% endif %}
                <a href="{% url 'staff:leave_add' %}"  class="qa-btn"><i class="fas fa-calendar-plus"></i>Request Leave</a>
                <a href="{% url 'staff:leave_list' %}" class="qa-btn"><i class="fas fa-list-alt"></i>My Leave</a>
                <a href="{% url 'dashboard' %}"        class="qa-btn"><i class="fas fa-th-large"></i>Main Dashboard</a>
            </div>
        </div>
    </div>
</div>
{% endif %}

{% endblock %}

{% block extra_js %}
<script>
/* Live clock in welcome banner */
(function tick(){
    const el = document.getElementById('liveTime');
    if (el) {
        const now = new Date();
        const h = String(now.getHours()).padStart(2,'0');
        const m = String(now.getMinutes()).padStart(2,'0');
        el.textContent = h + ':' + m;
    }
    setTimeout(tick, 30000);
})();
</script>
{% endblock %}


======================================================================
FILE: templates/staff/dashboard.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Staff Dashboard — Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
.dash-grid   { display:grid; grid-template-columns:1fr; gap:1rem; }
@media(min-width:480px)  { .dash-grid-2   { grid-template-columns:1fr 1fr; } }
@media(min-width:768px)  { .dash-grid-4   { grid-template-columns:repeat(4,1fr); } }
@media(min-width:768px)  { .dash-grid-2-1 { grid-template-columns:2fr 1fr; } }

/* Welcome banner — on-brand red, not off-brand purple */
.staff-welcome {
    background: linear-gradient(135deg, var(--rb-red-dark) 0%, var(--rb-red) 60%, #b84a4a 100%);
    border-radius: 14px;
    padding: 1.4rem 1.5rem;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
    box-shadow: 0 4px 20px rgba(139,0,0,.25);
}
.staff-welcome h2 { font-size:1.2rem;font-weight:700;margin:0 0 .25rem; }
.staff-welcome p  { font-size:.82rem;color:rgba(255,255,255,.8);margin:0; }
.welcome-time-badge {
    background:rgba(255,255,255,.15);
    border-radius:10px;
    padding:.6rem 1rem;
    text-align:center;
    flex-shrink:0;
    display:none;
}
@media(min-width:480px){ .welcome-time-badge { display:block; } }
.welcome-time-badge .time { font-size:1.3rem;font-weight:700;line-height:1; }
.welcome-time-badge .date { font-size:.7rem;color:rgba(255,255,255,.75);margin-top:2px; }

.kpi { background:#fff;border-radius:12px;padding:1rem 1.1rem;border:1px solid #ede8e3;box-shadow:0 1px 4px rgba(0,0,0,.07);display:flex;align-items:center;gap:.9rem; }
.kpi-icon { width:46px;height:46px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1.2rem;flex-shrink:0; }
.kpi-icon.blue   { background:#eff6ff;color:#3b82f6; }
.kpi-icon.green  { background:#f0fdf4;color:#22c55e; }
.kpi-icon.gold   { background:#fffbeb;color:var(--rb-gold); }
.kpi-icon.red    { background:#fef2f2;color:var(--rb-red); }
.kpi-label { font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.5px;color:#999;margin-bottom:2px; }
.kpi-value { font-size:1.5rem;font-weight:700;color:#1a1a1a;line-height:1; }
.kpi-sub   { font-size:.72rem;color:#aaa;margin-top:3px; }

.rb-section-title { font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.6px;color:#999;margin:0 0 .75rem; }

/* My classes list */
.class-item { display:flex;align-items:center;gap:.75rem;padding:.65rem 0;border-bottom:1px solid #f5f0ea; }
.class-item:last-child { border-bottom:none; }
.class-bubble { width:36px;height:36px;border-radius:8px;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-red));color:#fff;font-weight:700;font-size:.75rem;display:flex;align-items:center;justify-content:center;flex-shrink:0; }
.class-name { font-weight:600;font-size:.875rem; }
.class-meta { font-size:.75rem;color:#aaa; }

/* Quick actions */
.qa-grid { display:grid;grid-template-columns:1fr 1fr;gap:.5rem; }
.qa-btn { display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;padding:.85rem .5rem;border-radius:10px;background:#fff;border:1px solid #ede8e3;text-decoration:none;color:#444;font-size:.75rem;font-weight:600;text-align:center;transition:all .15s;min-height:72px; }
.qa-btn i { font-size:1.3rem;color:var(--rb-red); }
.qa-btn:hover { border-color:var(--rb-red);background:#fff5f5;color:var(--rb-red);transform:translateY(-2px);box-shadow:0 4px 12px rgba(139,0,0,.12); }

/* Leave request mini-list */
.leave-item { display:flex;align-items:center;gap:.6rem;padding:.55rem 0;border-bottom:1px solid #f5f0ea; }
.leave-item:last-child { border-bottom:none; }

/* My profile card (default staff) */
.profile-row { display:flex;align-items:baseline;gap:.5rem;padding:.4rem 0;border-bottom:1px solid #f5f0ea;font-size:.875rem; }
.profile-row:last-child { border-bottom:none; }
.profile-label { font-weight:600;color:#555;width:110px;flex-shrink:0;font-size:.8rem; }
.profile-val { color:#333; }
</style>
{% endblock %}

{% block content %}

<!-- WELCOME BANNER -->
<div class="staff-welcome">
    <div>
        <h2>
            {% if dashboard_type == 'proprietor' %}Welcome, Proprietor{% elif dashboard_type == 'head' %}Good day, Head Teacher{% elif dashboard_type == 'teacher' %}Good day, Teacher{% else %}Welcome Back{% endif %}
            {% if request.user.staff_profile %} — {{ request.user.get_full_name|default:request.user.username }}{% endif %}
        </h2>
        <p>
            {% if dashboard_type == 'teacher' %}Your classes &amp; today's tasks are below.
            {% elif dashboard_type == 'head' %}{{ department_name }} section overview.
            {% elif dashboard_type == 'proprietor' %}Full school overview.
            {% else %}Rapha-Bethel BNPS Staff Portal.{% endif %}
        </p>
    </div>
    <div class="welcome-time-badge">
        <div class="time" id="liveTime">--:--</div>
        <div class="date">{{ current_date|date:"d M Y" }}</div>
    </div>
</div>

<!-- KPI CARDS — common to all roles -->
<div class="dash-grid dash-grid-2 dash-grid-4 mb-4">
    <div class="kpi">
        <div class="kpi-icon blue"><i class="fas fa-users"></i></div>
        <div>
            <div class="kpi-label">Total Staff</div>
            <div class="kpi-value">{{ total_staff|default:"—" }}</div>
            <div class="kpi-sub">{{ active_staff|default:0 }} active</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon green"><i class="fas fa-chalkboard-teacher"></i></div>
        <div>
            <div class="kpi-label">Teachers</div>
            <div class="kpi-value">{{ teachers_count|default:"—" }}</div>
            <div class="kpi-sub">{{ class_teachers|default:0 }} class teachers</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon gold"><i class="fas fa-calendar-minus"></i></div>
        <div>
            <div class="kpi-label">Pending Leave</div>
            <div class="kpi-value">{{ pending_leaves|default:"0" }}</div>
            <div class="kpi-sub">{{ approved_leaves|default:0 }} approved</div>
        </div>
    </div>
    <div class="kpi">
        <div class="kpi-icon red"><i class="fas fa-clock"></i></div>
        <div>
            <div class="kpi-label">Staff Present Today</div>
            <div class="kpi-value">{{ present_percent|default:"0" }}%</div>
            <div class="kpi-sub">{{ today_attendance|default:0 }} checked in</div>
        </div>
    </div>
</div>

<!-- ROLE-SPECIFIC CONTENT -->

{% if dashboard_type == 'proprietor' %}
<!-- ── PROPRIETOR VIEW ──────────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header d-flex align-items-center justify-content-between">
            <span class="rb-section-title mb-0">School Overview</span>
        </div>
        <div class="card-body">
            <div class="row g-2">
                {% with items="Students|user-graduate|blue,Classes|chalkboard|green,Monthly Revenue XAF|coins|gold,Pending Invoices|file-invoice|red" %}
                {% endwith %}
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#eff6ff">
                        <div style="font-size:1.5rem;font-weight:700;color:#3b82f6">{{ total_students|default:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Total Students</div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#f0fdf4">
                        <div style="font-size:1.5rem;font-weight:700;color:#22c55e">{{ total_classes|default:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Total Classes</div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#fffbeb">
                        <div style="font-size:1.1rem;font-weight:700;color:var(--rb-gold)">{{ monthly_revenue|default:0|floatformat:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Monthly Revenue (XAF)</div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="p-3 rounded text-center" style="background:#fef2f2">
                        <div style="font-size:1.5rem;font-weight:700;color:var(--rb-red)">{{ pending_invoices|default:0 }}</div>
                        <div style="font-size:.75rem;color:#666">Pending Invoices</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Admin Actions</span></div>
        <div class="card-body" style="display:flex;flex-direction:column;gap:.5rem;padding-top:.6rem">
            <a href="{% url 'staff:staff_list' %}"     class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-id-badge" style="color:var(--rb-red);width:18px;text-align:center"></i> Manage Staff</a>
            <a href="{% url 'students:student_list' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-user-graduate" style="color:var(--rb-red);width:18px;text-align:center"></i> All Students</a>
            <a href="{% url 'finance:bursar_dashboard' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-chart-pie" style="color:var(--rb-red);width:18px;text-align:center"></i> Finance Dashboard</a>
            <a href="{% url 'reports:academic_report' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-chart-bar" style="color:var(--rb-red);width:18px;text-align:center"></i> View Reports</a>
            {% if user.is_superuser %}<a href="{% url 'admin:index' %}" class="quick-action d-flex align-items-center gap-2" style="text-decoration:none;padding:.65rem .85rem;border-radius:8px;background:#fff;border:1px solid #ede8e3;color:#333;font-size:.875rem;font-weight:500;transition:all .15s"><i class="fas fa-shield-alt" style="color:var(--rb-red);width:18px;text-align:center"></i> Admin Panel</a>{% endif %}
        </div>
    </div>
</div>

{% elif dashboard_type == 'head' %}
<!-- ── HEAD TEACHER VIEW ────────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">{{ department_name }} — Recent Staff Leave Requests</span></div>
        <div class="card-body">
            {% with leaves=recent_leave_requests %}
            {% if leaves %}
                {% for leave in leaves %}
                <div class="leave-item">
                    <div style="width:34px;height:34px;border-radius:8px;background:#f5ede6;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-size:.8rem;font-weight:700;color:var(--rb-red)">{{ leave.staff.user.first_name|first }}{{ leave.staff.user.last_name|first }}</div>
                    <div style="flex:1;min-width:0">
                        <div style="font-weight:600;font-size:.85rem">{{ leave.staff.user.get_full_name }}</div>
                        <div style="font-size:.75rem;color:#aaa">{{ leave.get_leave_type_display }} · {{ leave.start_date|date:"d M" }} – {{ leave.end_date|date:"d M" }}</div>
                    </div>
                    {% if leave.status == 'pending' %}<span class="rb-badge rb-badge-gold">Pending</span>
                    {% elif leave.status == 'approved' %}<span class="rb-badge rb-badge-green">Approved</span>
                    {% else %}<span class="rb-badge rb-badge-red">{{ leave.status|title }}</span>{% endif %}
                </div>
                {% endfor %}
            {% else %}
                <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No recent leave requests</p>
            {% endif %}
            {% endwith %}
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Head's Quick Actions</span></div>
        <div class="card-body">
            <div class="qa-grid">
                <a href="{% url 'students:student_add' %}"  class="qa-btn"><i class="fas fa-user-plus"></i>Add Student</a>
                <a href="{% url 'staff:staff_add' %}"       class="qa-btn"><i class="fas fa-user-tie"></i>Add Staff</a>
                <a href="{% url 'staff:leave_list' %}"      class="qa-btn"><i class="fas fa-calendar-check"></i>Leave List</a>
                <a href="{% url 'reports:attendance_report' %}" class="qa-btn"><i class="fas fa-chart-bar"></i>Reports</a>
            </div>
        </div>
    </div>
</div>

{% elif dashboard_type == 'teacher' %}
<!-- ── TEACHER VIEW ─────────────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header d-flex align-items-center justify-content-between">
            <span class="rb-section-title mb-0">My Assigned Classes</span>
            <a href="{% url 'academics:class_list' %}" style="font-size:.75rem;color:var(--rb-red)">All classes</a>
        </div>
        <div class="card-body" style="padding-top:.5rem">
            {% if my_classes %}
                {% for cls in my_classes %}
                <div class="class-item">
                    <div class="class-bubble">{{ cls.name|slice:":2"|upper }}</div>
                    <div style="flex:1">
                        <div class="class-name">{{ cls.name }}</div>
                        <div class="class-meta">{{ cls.student_count|default:0 }} students</div>
                    </div>
                    <a href="{% url 'academics:class_detail' cls.pk %}" class="btn btn-sm" style="background:#fef2f2;color:var(--rb-red);border:none;font-size:.75rem;padding:.25rem .6rem">View</a>
                </div>
                {% endfor %}
            {% else %}
                <p class="text-muted text-center py-3 mb-0" style="font-size:.85rem">No classes assigned yet</p>
            {% endif %}
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Today's Tasks</span></div>
        <div class="card-body">
            <div class="qa-grid">
                <a href="{% url 'attendance:mark_attendance' %}" class="qa-btn"><i class="fas fa-clipboard-check"></i>Attendance</a>
                <a href="{% url 'academics:class_list' %}" class="qa-btn"><i class="fas fa-chalkboard"></i>My Classes</a>
                <a href="{% url 'staff:leave_add' %}"     class="qa-btn"><i class="fas fa-calendar-plus"></i>Request Leave</a>
                <a href="{% url 'staff:leave_list' %}"    class="qa-btn"><i class="fas fa-list"></i>My Leave</a>
            </div>
        </div>
    </div>
</div>

{% else %}
<!-- ── DEFAULT STAFF VIEW ──────────────────────── -->
<div class="dash-grid dash-grid-2-1 mb-4">
    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">My Profile</span></div>
        <div class="card-body" style="padding-top:.5rem">
            {% if request.user.staff_profile %}
            {% with s=request.user.staff_profile %}
            <div class="profile-row"><span class="profile-label">Employee ID</span><span class="profile-val">{{ s.employee_id }}</span></div>
            <div class="profile-row"><span class="profile-label">Role</span><span class="profile-val">{{ s.get_role_display }}</span></div>
            <div class="profile-row"><span class="profile-label">Department</span><span class="profile-val">{{ s.get_department_display }}</span></div>
            <div class="profile-row"><span class="profile-label">Phone</span><span class="profile-val">{{ s.phone_number|default:"—" }}</span></div>
            <div class="profile-row"><span class="profile-label">Email</span><span class="profile-val">{{ request.user.email|default:"—" }}</span></div>
            <div class="profile-row"><span class="profile-label">Hire Date</span><span class="profile-val">{{ s.hire_date|date:"d M Y"|default:"—" }}</span></div>
            {% endwith %}
            {% endif %}
        </div>
    </div>

    <div class="card">
        <div class="card-header"><span class="rb-section-title mb-0">Quick Links</span></div>
        <div class="card-body">
            <div class="qa-grid">
                {% if request.user.staff_profile %}
                <a href="{% url 'staff:staff_edit' request.user.staff_profile.pk %}" class="qa-btn"><i class="fas fa-user-edit"></i>Edit Profile</a>
                {% endif %}
                <a href="{% url 'staff:leave_add' %}"  class="qa-btn"><i class="fas fa-calendar-plus"></i>Request Leave</a>
                <a href="{% url 'staff:leave_list' %}" class="qa-btn"><i class="fas fa-list-alt"></i>My Leave</a>
                <a href="{% url 'dashboard' %}"        class="qa-btn"><i class="fas fa-th-large"></i>Main Dashboard</a>
            </div>
        </div>
    </div>
</div>
{% endif %}

{% endblock %}

{% block extra_js %}
<script>
/* Live clock in welcome banner */
(function tick(){
    const el = document.getElementById('liveTime');
    if (el) {
        const now = new Date();
        const h = String(now.getHours()).padStart(2,'0');
        const m = String(now.getMinutes()).padStart(2,'0');
        el.textContent = h + ':' + m;
    }
    setTimeout(tick, 30000);
})();
</script>
{% endblock %}


======================================================================
FILE: templates/staff/import.html
======================================================================
<!-- templates/staff/import.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Import Staff - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Import Staff Members</h1>
        <a href="{% url 'staff:staff_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left"></i> Back to Staff List
        </a>
    </div>

    <div class="row">
        <div class="col-md-8 mx-auto">
            <div class="card shadow">
                <div class="card-header bg-primary text-white">
                    <h5 class="mb-0"><i class="fas fa-upload"></i> Upload Staff CSV File</h5>
                </div>
                <div class="card-body">
                    <form method="post" enctype="multipart/form-data" action="{% url 'staff:staff_import' %}">
                        {% csrf_token %}
                        
                        <div class="mb-4">
                            <label class="form-label">Select CSV File</label>
                            <input type="file" name="file" class="form-control" accept=".csv" required>
                            <small class="text-muted">
                                File must be in CSV format with headers: First Name, Last Name, Role, Department, Phone, Email
                            </small>
                        </div>
                        
                        <div class="mb-4">
                            <h6>CSV Format Example:</h6>
                            <pre class="bg-light p-3 rounded">
First Name,Last Name,Role,Department,Phone,Email
Mme,Nchotu Manka,proprietor,admin,651437143,proprietor@raphabethel.org
Mr.,Ferdinand Sunyin,head_master,english,676662567,f.sunyin@raphabethel.org
Mme,Chesi Landry,bursar,finance,651620915,c.landry@raphabethel.org</pre>
                        </div>
                        
                        <div class="d-grid gap-2">
                            <a href="{% url 'staff:download_sample_csv' %}" class="btn btn-success mb-2">
                                <i class="fas fa-download"></i> Download Sample CSV Template
                            </a>
                            <button type="submit" class="btn btn-primary">
                                <i class="fas fa-upload"></i> Import Staff
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/staff/leave_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Leave Request - {{ leave.staff.get_full_name }}{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">Leave Request Detail</h1>
            <p class="text-muted">{{ leave.staff.get_full_name }} &bull; {{ leave.get_leave_type_display }}</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'staff:leave_list' %}" class="btn btn-outline-secondary">
                <i class="fas fa-arrow-left me-2"></i>Back
            </a>
            {% if leave.status == 'pending' %}
            <a href="{% url 'staff:leave_edit' leave.pk %}" class="btn btn-warning">
                <i class="fas fa-edit me-2"></i>Edit
            </a>
            {% endif %}
        </div>
    </div>

    <div class="row">
        <div class="col-md-8">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Leave Information</h6>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Staff Member</label>
                            <p class="fw-bold">{{ leave.staff.user.get_full_name }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Employee ID</label>
                            <p class="fw-bold">{{ leave.staff.employee_id }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Leave Type</label>
                            <p class="fw-bold">{{ leave.get_leave_type_display }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Status</label>
                            <p>
                                <span class="badge bg-{% if leave.status == 'approved' %}success{% elif leave.status == 'rejected' %}danger{% elif leave.status == 'cancelled' %}secondary{% else %}warning{% endif %} fs-6">
                                    {{ leave.get_status_display }}
                                </span>
                            </p>
                        </div>
                        <div class="col-md-4 mb-3">
                            <label class="text-muted small">Start Date</label>
                            <p class="fw-bold">{{ leave.start_date|date:"d M Y" }}</p>
                        </div>
                        <div class="col-md-4 mb-3">
                            <label class="text-muted small">End Date</label>
                            <p class="fw-bold">{{ leave.end_date|date:"d M Y" }}</p>
                        </div>
                        <div class="col-md-4 mb-3">
                            <label class="text-muted small">Days Requested</label>
                            <p class="fw-bold">{{ leave.days_requested }} day{{ leave.days_requested|pluralize }}</p>
                        </div>
                        <div class="col-12 mb-3">
                            <label class="text-muted small">Reason</label>
                            <p>{{ leave.reason }}</p>
                        </div>
                        {% if leave.remarks %}
                        <div class="col-12 mb-3">
                            <label class="text-muted small">Admin Remarks</label>
                            <p class="fst-italic text-muted">{{ leave.remarks }}</p>
                        </div>
                        {% endif %}
                        {% if leave.approved_by %}
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Approved/Rejected By</label>
                            <p class="fw-bold">{{ leave.approved_by.user.get_full_name }}</p>
                        </div>
                        <div class="col-md-6 mb-3">
                            <label class="text-muted small">Decision Date</label>
                            <p class="fw-bold">{{ leave.approved_date|date:"d M Y" }}</p>
                        </div>
                        {% endif %}
                    </div>
                </div>
            </div>
        </div>

        <div class="col-md-4">
            {% if leave.status == 'pending' and request.user.is_staff %}
            <div class="card shadow mb-4 border-success">
                <div class="card-header bg-success text-white">
                    <h6 class="m-0"><i class="fas fa-gavel me-2"></i>Actions</h6>
                </div>
                <div class="card-body">
                    <form method="post" action="{% url 'staff:leave_detail' leave.pk %}">
                        {% csrf_token %}
                        <div class="mb-3">
                            <label class="form-label">Remarks</label>
                            <textarea name="remarks" class="form-control" rows="3" placeholder="Optional remarks..."></textarea>
                        </div>
                        <div class="d-grid gap-2">
                            <button type="submit" name="action" value="approve" class="btn btn-success">
                                <i class="fas fa-check me-2"></i>Approve
                            </button>
                            <button type="submit" name="action" value="reject" class="btn btn-danger">
                                <i class="fas fa-times me-2"></i>Reject
                            </button>
                        </div>
                    </form>
                </div>
            </div>
            {% endif %}

            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Request Info</h6>
                </div>
                <div class="card-body">
                    <p class="mb-1 small text-muted">Submitted</p>
                    <p class="fw-bold">{{ leave.created_at|date:"d M Y H:i" }}</p>
                    <p class="mb-1 small text-muted">Last Updated</p>
                    <p class="fw-bold">{{ leave.updated_at|date:"d M Y H:i" }}</p>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/staff/leave_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{% if object %}Edit Leave Request{% else %}New Leave Request{% endif %} - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0">{% if object %}Edit Leave Request{% else %}New Leave Request{% endif %}</h1>
            <p class="text-muted">{% if object %}Modify existing leave request{% else %}Submit a new leave request{% endif %}</p>
        </div>
        <a href="{% url 'staff:leave_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left me-2"></i>Back to Leave Requests
        </a>
    </div>

    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card shadow">
                <div class="card-header py-3 bg-primary text-white">
                    <h6 class="m-0 font-weight-bold"><i class="fas fa-calendar-times me-2"></i>Leave Request Details</h6>
                </div>
                <div class="card-body">
                    <form method="post">
                        {% csrf_token %}
                        {% if form.errors %}
                        <div class="alert alert-danger">
                            <i class="fas fa-exclamation-circle me-2"></i>Please correct the errors below.
                        </div>
                        {% endif %}

                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Leave Type <span class="text-danger">*</span></label>
                                {{ form.leave_type }}
                                {% if form.leave_type.errors %}<div class="text-danger small">{{ form.leave_type.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Status</label>
                                {{ form.status }}
                            </div>
                        </div>

                        <div class="row mb-3">
                            <div class="col-md-6">
                                <label class="form-label fw-bold">Start Date <span class="text-danger">*</span></label>
                                {{ form.start_date }}
                                {% if form.start_date.errors %}<div class="text-danger small">{{ form.start_date.errors }}</div>{% endif %}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-bold">End Date <span class="text-danger">*</span></label>
                                {{ form.end_date }}
                                {% if form.end_date.errors %}<div class="text-danger small">{{ form.end_date.errors }}</div>{% endif %}
                            </div>
                        </div>

                        <div class="mb-3">
                            <label class="form-label fw-bold">Days Requested</label>
                            {{ form.days_requested }}
                        </div>

                        <div class="mb-3">
                            <label class="form-label fw-bold">Reason <span class="text-danger">*</span></label>
                            {{ form.reason }}
                            {% if form.reason.errors %}<div class="text-danger small">{{ form.reason.errors }}</div>{% endif %}
                        </div>

                        <div class="mb-3">
                            <label class="form-label fw-bold">Remarks (Admin)</label>
                            {{ form.remarks }}
                        </div>

                        <div class="d-flex justify-content-end gap-2 mt-4">
                            <a href="{% url 'staff:leave_list' %}" class="btn btn-secondary">Cancel</a>
                            <button type="submit" class="btn btn-primary">
                                <i class="fas fa-save me-2"></i>{% if object %}Update Request{% else %}Submit Request{% endif %}
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

{% block extra_js %}
<script>
// Auto-calculate days when dates change
document.addEventListener('DOMContentLoaded', function() {
    const startDate = document.querySelector('[name="start_date"]');
    const endDate = document.querySelector('[name="end_date"]');
    const daysField = document.querySelector('[name="days_requested"]');

    function calcDays() {
        if (startDate.value && endDate.value) {
            const start = new Date(startDate.value);
            const end = new Date(endDate.value);
            const diff = Math.round((end - start) / (1000 * 60 * 60 * 24)) + 1;
            if (diff > 0) daysField.value = diff;
        }
    }
    if (startDate) startDate.addEventListener('change', calcDays);
    if (endDate) endDate.addEventListener('change', calcDays);
});
</script>
{% endblock %}
{% endblock %}


======================================================================
FILE: templates/staff/leave_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Leave Requests - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Leave Requests</h1>
        <a href="{% url 'staff:leave_add' %}" class="btn btn-primary">
            <i class="fas fa-plus"></i> Request Leave
        </a>
    </div>

    <div class="card shadow">
        <div class="card-body">
            <div class="table-responsive">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>Staff</th>
                            <th>Leave Type</th>
                            <th>Start Date</th>
                            <th>End Date</th>
                            <th>Days</th>
                            <th>Status</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for leave in leaves %}
                        <tr>
                            <td>{{ leave.staff.user.get_full_name }}</td>
                            <td>{{ leave.get_leave_type_display }}</td>
                            <td>{{ leave.start_date }}</td>
                            <td>{{ leave.end_date }}</td>
                            <td>{{ leave.days_requested }}</td>
                            <td>
                                <span class="badge bg-{% if leave.status == 'approved' %}success{% elif leave.status == 'pending' %}warning{% else %}danger{% endif %}">
                                    {{ leave.get_status_display }}
                                </span>
                            </td>
                            <td>
                                <a href="{% url 'staff:leave_detail' leave.pk %}" class="btn btn-sm btn-info">
                                    <i class="fas fa-eye"></i>
                                </a>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="7" class="text-center">No leave requests found</td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/staff/logged_out.html
======================================================================
<!-- templates/staff/logged_out.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Logged Out - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card shadow text-center">
                <div class="card-body py-5">
                    <i class="fas fa-check-circle text-success fa-4x mb-3"></i>
                    <h3 class="mb-3">You have been logged out</h3>
                    <p class="text-muted mb-4">Thank you for using Rapha-Bethel BNPS</p>
                    <a href="{% url 'staff:login' %}" class="btn btn-primary">
                        <i class="fas fa-sign-in-alt me-2"></i> Log In Again
                    </a>
                    <a href="{% url 'home' %}" class="btn btn-outline-secondary ms-2">
                        <i class="fas fa-home me-2"></i> Home
                    </a>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/staff/login.html
======================================================================
<!-- templates/staff/login.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Staff Login - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .login-container {
        min-height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    }
    .login-card {
        background: white;
        border-radius: 15px;
        box-shadow: 0 20px 40px rgba(0,0,0,0.2);
        padding: 40px;
        width: 100%;
        max-width: 400px;
    }
    .login-logo {
        text-align: center;
        margin-bottom: 30px;
    }
    .login-logo img {
        max-height: 80px;
    }
    .login-title {
        text-align: center;
        color: #333;
        margin-bottom: 30px;
        font-weight: 600;
    }
    .form-group {
        margin-bottom: 20px;
    }
    .form-control {
        height: 45px;
        border-radius: 8px;
        border: 1px solid #ddd;
        padding: 0 15px;
    }
    .form-control:focus {
        border-color: #4CAF50;
        box-shadow: 0 0 0 0.2rem rgba(76, 175, 80, 0.25);
    }
    .btn-login {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        height: 45px;
        border-radius: 8px;
        font-weight: 600;
        width: 100%;
        border: none;
        cursor: pointer;
        transition: transform 0.3s;
    }
    .btn-login:hover {
        transform: translateY(-2px);
        box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
    }
    .error-message {
        color: #dc3545;
        text-align: center;
        margin-top: 15px;
        font-size: 0.9rem;
    }
    .back-link {
        text-align: center;
        margin-top: 20px;
    }
    .back-link a {
        color: #666;
        text-decoration: none;
        font-size: 0.9rem;
    }
    .back-link a:hover {
        color: #4CAF50;
    }
</style>
{% endblock %}

{% block content %}
<div class="login-container">
    <div class="login-card">
        <div class="login-logo">
            <img src="{% static 'admin/img/logo-yellow.jpeg' %}" alt="Rapha-Bethel BNPS">
        </div>
        
        <h3 class="login-title">Staff Login</h3>
        
        <form method="post" action="{% url 'staff:login' %}">
            {% csrf_token %}
            
            <div class="form-group">
                <input type="text" name="username" class="form-control" 
                       placeholder="Username" required autofocus>
            </div>
            
            <div class="form-group">
                <input type="password" name="password" class="form-control" 
                       placeholder="Password" required>
            </div>
            
            <button type="submit" class="btn-login">
                <i class="fas fa-sign-in-alt me-2"></i> Log In
            </button>
            
            {% if form.errors %}
            <div class="error-message">
                <i class="fas fa-exclamation-circle"></i>
                Invalid username or password
            </div>
            {% endif %}
        </form>
        
        <div class="back-link">
            <a href="{% url 'home' %}">
                <i class="fas fa-arrow-left me-1"></i> Back to Home
            </a>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/staff/mark_attendance-1.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Mark Staff Attendance — Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
.att-table th { font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:#888;padding:.6rem .85rem;background:#fdfaf7;border-bottom:1px solid #ede8e3; }
.att-table td { padding:.65rem .85rem;border-bottom:1px solid #f5f0ea;vertical-align:middle;font-size:.875rem; }
.att-table tbody tr:last-child td { border-bottom:none; }
.att-table tbody tr:hover td { background:#fdfaf7; }

/* Status radio buttons styled as pill selectors */
.status-pills { display:flex;gap:.35rem;flex-wrap:wrap; }
.status-pill input[type=radio] { display:none; }
.status-pill label {
    padding:.3rem .7rem;border-radius:20px;font-size:.75rem;font-weight:600;
    cursor:pointer;border:1.5px solid #e0d8d0;color:#666;transition:all .15s;
    white-space:nowrap;
}
.status-pill input[value=present]:checked + label { background:#dcfce7;border-color:#22c55e;color:#166534; }
.status-pill input[value=absent]:checked  + label { background:#fee2e2;border-color:var(--rb-red);color:#991b1b; }
.status-pill input[value=late]:checked    + label { background:#fef9c3;border-color:#ca8a04;color:#854d0e; }
.status-pill input[value=leave]:checked   + label { background:#dbeafe;border-color:#3b82f6;color:#1e40af; }
.status-pill label:hover { border-color:#aaa;color:#333; }

.staff-avatar {
    width:34px;height:34px;border-radius:8px;
    background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-red));
    color:#fff;font-weight:700;font-size:.8rem;
    display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.bulk-bar {
    background:#fff;border:1px solid #ede8e3;border-radius:10px;
    padding:.75rem 1rem;margin-bottom:1rem;
    display:flex;flex-wrap:wrap;align-items:center;gap:.6rem;
}
</style>
{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">Mark Staff Attendance</h1>
        <p class="rb-page-subtitle">{{ today|date:"l, d N Y" }}</p>
    </div>
    <a href="{% url 'staff:attendance_list' %}" class="btn btn-outline-secondary btn-sm">
        <i class="fas fa-list me-1"></i> Attendance List
    </a>
</div>

<form method="post">
    {% csrf_token %}
    <input type="hidden" name="date" value="{{ today|date:'Y-m-d' }}">

    <!-- Bulk actions -->
    <div class="bulk-bar">
        <span style="font-size:.8rem;font-weight:600;color:#666">Mark all as:</span>
        <button type="button" class="btn btn-sm" style="background:#dcfce7;color:#166534;border:none" onclick="markAll('present')">
            <i class="fas fa-check-circle me-1"></i> Present
        </button>
        <button type="button" class="btn btn-sm" style="background:#fee2e2;color:#991b1b;border:none" onclick="markAll('absent')">
            <i class="fas fa-times-circle me-1"></i> Absent
        </button>
        <button type="button" class="btn btn-sm" style="background:#fef9c3;color:#854d0e;border:none" onclick="markAll('late')">
            <i class="fas fa-clock me-1"></i> Late
        </button>
        <span style="margin-left:auto;font-size:.8rem;color:#aaa" id="markedCount">0 of {{ staff_members|length }} marked</span>
    </div>

    <div class="card mb-4">
        <div class="table-responsive">
            <table class="att-table w-100">
                <thead>
                    <tr>
                        <th>Staff Member</th>
                        <th>Role</th>
                        <th>Status</th>
                        <th style="width:180px">Notes</th>
                    </tr>
                </thead>
                <tbody>
                    {% for member in staff_members %}
                    <tr>
                        <td>
                            <div style="display:flex;align-items:center;gap:.65rem">
                                <div class="staff-avatar">{{ member.user.first_name|first }}{{ member.user.last_name|first }}</div>
                                <div>
                                    <div style="font-weight:600">{{ member.user.get_full_name }}</div>
                                    <div style="font-size:.75rem;color:#aaa">{{ member.employee_id }}</div>
                                </div>
                            </div>
                        </td>
                        <td>
                            <span class="rb-badge rb-badge-gray">{{ member.get_role_display }}</span>
                        </td>
                        <td>
                            <div class="status-pills" data-staff="{{ member.pk }}">
                                {% for val, label in "present:Present,absent:Absent,late:Late,leave:On Leave"|split:"," %}
                                {% endfor %}
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="p_{{ member.pk }}" value="present" onchange="updateCount()">
                                    <label for="p_{{ member.pk }}">Present</label>
                                </div>
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="a_{{ member.pk }}" value="absent" onchange="updateCount()">
                                    <label for="a_{{ member.pk }}">Absent</label>
                                </div>
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="l_{{ member.pk }}" value="late" onchange="updateCount()">
                                    <label for="l_{{ member.pk }}">Late</label>
                                </div>
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="lv_{{ member.pk }}" value="leave" onchange="updateCount()">
                                    <label for="lv_{{ member.pk }}">Leave</label>
                                </div>
                                <!-- Hidden field so staff_id is submitted -->
                                <input type="hidden" name="staff_ids" value="{{ member.pk }}">
                            </div>
                        </td>
                        <td>
                            <input type="text" name="notes_{{ member.pk }}" class="form-control form-control-sm" placeholder="Optional note" style="min-height:36px;font-size:.8rem">
                        </td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="4" class="text-center py-4 text-muted">No active staff members found.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>

    <div class="d-flex justify-content-end gap-2">
        <a href="{% url 'staff:attendance_list' %}" class="btn btn-outline-secondary">Cancel</a>
        <button type="submit" class="btn btn-rb-primary px-4">
            <i class="fas fa-save me-2"></i> Save Attendance
        </button>
    </div>
</form>
{% endblock %}

{% block extra_js %}
<script>
function markAll(status) {
    document.querySelectorAll(`input[type=radio][value=${status}]`).forEach(r => {
        r.checked = true;
    });
    updateCount();
}

function updateCount() {
    const rows = document.querySelectorAll('tbody tr');
    let marked = 0;
    rows.forEach(row => {
        if (row.querySelector('input[type=radio]:checked')) marked++;
    });
    const el = document.getElementById('markedCount');
    if (el) el.textContent = `${marked} of ${rows.length} marked`;
}

updateCount();
</script>
{% endblock %}


======================================================================
FILE: templates/staff/mark_attendance.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Mark Staff Attendance — Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
.att-table th { font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.4px;color:#888;padding:.6rem .85rem;background:#fdfaf7;border-bottom:1px solid #ede8e3; }
.att-table td { padding:.65rem .85rem;border-bottom:1px solid #f5f0ea;vertical-align:middle;font-size:.875rem; }
.att-table tbody tr:last-child td { border-bottom:none; }
.att-table tbody tr:hover td { background:#fdfaf7; }

.status-pills { display:flex;gap:.35rem;flex-wrap:wrap; }
.status-pill input[type=radio] { display:none; }
.status-pill label {
    padding:.3rem .7rem;border-radius:20px;font-size:.75rem;font-weight:600;
    cursor:pointer;border:1.5px solid #e0d8d0;color:#666;transition:all .15s;white-space:nowrap;
}
.status-pill input[value="present"]:checked + label { background:#dcfce7;border-color:#22c55e;color:#166534; }
.status-pill input[value="absent"]:checked  + label { background:#fee2e2;border-color:var(--rb-red);color:#991b1b; }
.status-pill input[value="late"]:checked    + label { background:#fef9c3;border-color:#ca8a04;color:#854d0e; }
.status-pill input[value="leave"]:checked   + label { background:#dbeafe;border-color:#3b82f6;color:#1e40af; }
.status-pill label:hover { border-color:#aaa;color:#333; }

.staff-avatar { width:34px;height:34px;border-radius:8px;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-red));color:#fff;font-weight:700;font-size:.8rem;display:flex;align-items:center;justify-content:center;flex-shrink:0; }
.bulk-bar { background:#fff;border:1px solid #ede8e3;border-radius:10px;padding:.75rem 1rem;margin-bottom:1rem;display:flex;flex-wrap:wrap;align-items:center;gap:.6rem; }
</style>
{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">Mark Staff Attendance</h1>
        <p class="rb-page-subtitle">{{ today|date:"l, d N Y" }}</p>
    </div>
    <a href="{% url 'staff:attendance_list' %}" class="btn btn-outline-secondary btn-sm">
        <i class="fas fa-list me-1"></i> Attendance List
    </a>
</div>

<form method="post">
    {% csrf_token %}
    <input type="hidden" name="date" value="{{ today|date:'Y-m-d' }}">

    <div class="bulk-bar">
        <span style="font-size:.8rem;font-weight:600;color:#666">Mark all as:</span>
        <button type="button" class="btn btn-sm" style="background:#dcfce7;color:#166534;border:none" onclick="markAll('present')">
            <i class="fas fa-check-circle me-1"></i> Present
        </button>
        <button type="button" class="btn btn-sm" style="background:#fee2e2;color:#991b1b;border:none" onclick="markAll('absent')">
            <i class="fas fa-times-circle me-1"></i> Absent
        </button>
        <button type="button" class="btn btn-sm" style="background:#fef9c3;color:#854d0e;border:none" onclick="markAll('late')">
            <i class="fas fa-clock me-1"></i> Late
        </button>
        <span style="margin-left:auto;font-size:.8rem;color:#aaa" id="markedCount">0 of {{ staff_members|length }} marked</span>
    </div>

    <div class="card mb-4">
        <div class="table-responsive">
            <table class="att-table w-100">
                <thead>
                    <tr>
                        <th>Staff Member</th>
                        <th>Role</th>
                        <th>Status</th>
                        <th style="width:180px">Notes</th>
                    </tr>
                </thead>
                <tbody>
                    {% for member in staff_members %}
                    <tr>
                        <td>
                            <div style="display:flex;align-items:center;gap:.65rem">
                                <div class="staff-avatar">{{ member.user.first_name|first }}{{ member.user.last_name|first }}</div>
                                <div>
                                    <div style="font-weight:600">{{ member.user.get_full_name }}</div>
                                    <div style="font-size:.75rem;color:#aaa">{{ member.employee_id }}</div>
                                </div>
                            </div>
                        </td>
                        <td><span class="rb-badge rb-badge-gray">{{ member.get_role_display }}</span></td>
                        <td>
                            <input type="hidden" name="staff_ids" value="{{ member.pk }}">
                            <div class="status-pills">
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="p_{{ member.pk }}" value="present" onchange="updateCount()">
                                    <label for="p_{{ member.pk }}">Present</label>
                                </div>
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="a_{{ member.pk }}" value="absent" onchange="updateCount()">
                                    <label for="a_{{ member.pk }}">Absent</label>
                                </div>
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="l_{{ member.pk }}" value="late" onchange="updateCount()">
                                    <label for="l_{{ member.pk }}">Late</label>
                                </div>
                                <div class="status-pill">
                                    <input type="radio" name="status_{{ member.pk }}" id="lv_{{ member.pk }}" value="leave" onchange="updateCount()">
                                    <label for="lv_{{ member.pk }}">Leave</label>
                                </div>
                            </div>
                        </td>
                        <td>
                            <input type="text" name="notes_{{ member.pk }}" class="form-control form-control-sm" placeholder="Optional note" style="min-height:36px;font-size:.8rem">
                        </td>
                    </tr>
                    {% empty %}
                    <tr><td colspan="4" class="text-center py-4 text-muted">No active staff members found.</td></tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>

    <div class="d-flex justify-content-end gap-2">
        <a href="{% url 'staff:attendance_list' %}" class="btn btn-outline-secondary">Cancel</a>
        <button type="submit" class="btn btn-rb-primary px-4">
            <i class="fas fa-save me-2"></i> Save Attendance
        </button>
    </div>
</form>
{% endblock %}

{% block extra_js %}
<script>
function markAll(status) {
    document.querySelectorAll('input[type=radio][value="' + status + '"]').forEach(r => {
        r.checked = true;
    });
    updateCount();
}
function updateCount() {
    const rows = document.querySelectorAll('tbody tr');
    let marked = 0;
    rows.forEach(row => { if (row.querySelector('input[type=radio]:checked')) marked++; });
    const el = document.getElementById('markedCount');
    if (el) el.textContent = marked + ' of ' + rows.length + ' marked';
}
updateCount();
</script>
{% endblock %}


======================================================================
FILE: templates/staff/staff_confirm_delete.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Delete Staff - {{ staff.user.get_full_name }}{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card shadow border-danger mt-5">
                <div class="card-header bg-danger text-white">
                    <h5 class="mb-0"><i class="fas fa-exclamation-triangle me-2"></i>Confirm Delete</h5>
                </div>
                <div class="card-body text-center py-4">
                    <div class="mb-4">
                        <div class="rounded-circle bg-danger bg-opacity-10 d-inline-flex align-items-center justify-content-center" style="width:80px;height:80px;">
                            <i class="fas fa-user-times fa-2x text-danger"></i>
                        </div>
                    </div>
                    <h4>Delete <strong>{{ staff.user.get_full_name }}</strong>?</h4>
                    <p class="text-muted">Employee ID: {{ staff.employee_id }} &bull; Role: {{ staff.get_role_display }}</p>
                    <div class="alert alert-warning text-start">
                        <i class="fas fa-exclamation-circle me-2"></i>
                        <strong>This action cannot be undone.</strong> This will permanently delete the staff member and their associated user account.
                    </div>
                    <div class="d-flex justify-content-center gap-3 mt-4">
                        <a href="{% url 'staff:staff_detail' staff.pk %}" class="btn btn-secondary btn-lg">
                            <i class="fas fa-arrow-left me-2"></i>Cancel
                        </a>
                        <form method="post">
                            {% csrf_token %}
                            <button type="submit" class="btn btn-danger btn-lg">
                                <i class="fas fa-trash me-2"></i>Yes, Delete
                            </button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}


======================================================================
FILE: templates/staff/staff_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ staff.get_display_name }} - Staff Details{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Staff Details</h1>
        <div>
            <a href="{% url 'staff:staff_edit' staff.pk %}" class="btn btn-warning">
                <i class="fas fa-edit"></i> Edit
            </a>
            <a href="{% url 'staff:staff_list' %}" class="btn btn-secondary">
                <i class="fas fa-arrow-left"></i> Back to List
            </a>
        </div>
    </div>

    <div class="row">
        <!-- Personal Information Card -->
        <div class="col-lg-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Personal Information</h6>
                </div>
                <div class="card-body text-center">
                    {% if staff.photo %}
                    <img src="{{ staff.photo.url }}" class="rounded-circle mb-3" width="150" height="150"
                         alt="{{ staff.get_display_name }}">
                    {% else %}
                    <div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center mx-auto mb-3"
                         style="width: 150px; height: 150px; font-size: 3rem;">
                        {{ staff.user.first_name|first|upper }}{{ staff.user.last_name|first|upper }}
                    </div>
                    {% endif %}
                    <h4>{{ staff.get_display_name }}</h4>
                    <p class="text-muted">{{ staff.get_role_display }}</p>
                    <p class="text-muted small">Employee ID: {{ staff.employee_id }}</p>
                </div>
            </div>
        </div>

        <!-- Details -->
        <div class="col-lg-8">
            <!-- Employment Details -->
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Employment Details</h6>
                </div>
                <div class="card-body">
                    <div class="table-responsive">
                        <table class="table table-bordered table-sm">
                            <tr>
                                <th style="width:200px;">Title</th>
                                <td>{{ staff.get_title_display|default:"—" }}</td>
                            </tr>
                            <tr>
                                <th>Full Name</th>
                                <td>{{ staff.user.first_name }} {{ staff.user.last_name }}</td>
                            </tr>
                            <tr>
                                <th>Username</th>
                                <td><code>{{ staff.user.username }}</code></td>
                            </tr>
                            <tr>
                                <th>Email</th>
                                <td>{{ staff.user.email|default:"—" }}</td>
                            </tr>
                            <tr>
                                <th>Primary Phone</th>
                                <td>
                                    {% if staff.phone_number %}
                                        {{ staff.phone_country_code }} {{ staff.phone_number }}
                                    {% else %}
                                        <span class="text-muted">Not provided</span>
                                    {% endif %}
                                </td>
                            </tr>
                            <tr>
                                <th>Alternate Phone</th>
                                <td>
                                    {% if staff.alternate_phone %}
                                        {{ staff.alt_phone_country_code }} {{ staff.alternate_phone }}
                                    {% else %}
                                        <span class="text-muted">—</span>
                                    {% endif %}
                                </td>
                            </tr>
                            <tr>
                                <th>Role</th>
                                <td><span class="badge bg-primary">{{ staff.get_role_display }}</span></td>
                            </tr>
                            <tr>
                                <th>Department</th>
                                <td>{{ staff.get_department_display }}</td>
                            </tr>
                            <tr>
                                <th>Employment Status</th>
                                <td>
                                    {% if staff.employment_status == 'permanent' %}
                                    <span class="badge bg-success">Permanent</span>
                                    {% elif staff.employment_status == 'contract' %}
                                    <span class="badge bg-info">Contract</span>
                                    {% else %}
                                    <span class="badge bg-warning text-dark">{{ staff.get_employment_status_display }}</span>
                                    {% endif %}
                                </td>
                            </tr>
                            <tr>
                                <th>Hire Date</th>
                                <td>{{ staff.hire_date|date:"d M Y"|default:"Not set" }}</td>
                            </tr>
                            <tr>
                                <th>Status</th>
                                <td>
                                    {% if staff.is_active %}
                                    <span class="badge bg-success">Active</span>
                                    {% else %}
                                    <span class="badge bg-secondary">Inactive</span>
                                    {% endif %}
                                </td>
                            </tr>
                        </table>
                    </div>
                </div>
            </div>

            <!-- Emergency Contact -->
            {% if staff.emergency_contact_name %}
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-danger">
                        <i class="fas fa-ambulance me-2"></i>Emergency Contact
                    </h6>
                </div>
                <div class="card-body">
                    <table class="table table-bordered table-sm">
                        <tr>
                            <th style="width:200px;">Name</th>
                            <td>{{ staff.emergency_contact_name }}</td>
                        </tr>
                        <tr>
                            <th>Phone</th>
                            <td>
                                {% if staff.emergency_contact_phone %}
                                    {{ staff.emergency_phone_country_code }} {{ staff.emergency_contact_phone }}
                                {% else %}
                                    <span class="text-muted">—</span>
                                {% endif %}
                            </td>
                        </tr>
                        <tr>
                            <th>Relationship</th>
                            <td>{{ staff.emergency_contact_relationship|default:"—" }}</td>
                        </tr>
                    </table>
                </div>
            </div>
            {% endif %}

        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/staff/staff_form.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ title }} - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    /* Paired country-code + number layout */
    .phone-row {
        display: flex;
        gap: 8px;
        align-items: center;
    }
    .phone-row .phone-code-select {
        width: 190px;
        flex-shrink: 0;
    }
    .phone-row input[type="text"] {
        flex: 1;
    }

    /* Warning banner */
    .name-warning {
        background: #fff3cd;
        border: 1px solid #ffc107;
        border-radius: 6px;
        padding: 10px 14px;
        margin-bottom: 16px;
        font-size: 0.9rem;
    }
    .name-warning strong { color: #856404; }

    /* Section headings inside the card */
    .form-section-heading {
        font-size: 0.85rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        color: #6c757d;
        border-bottom: 1px solid #dee2e6;
        padding-bottom: 6px;
        margin: 24px 0 16px;
    }
    .form-section-heading:first-of-type { margin-top: 0; }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">{{ title }}</h1>
        <a href="{% url 'staff:staff_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left"></i> Back to List
        </a>
    </div>

    <div class="row">
        <div class="col-lg-9 mx-auto">
            <form method="post" enctype="multipart/form-data">
                {% csrf_token %}

                {% if user_form %}
                <!-- ══ USER ACCOUNT ══════════════════════════════════════ -->
                <div class="card shadow mb-4">
                    <div class="card-header py-3">
                        <h6 class="m-0 font-weight-bold text-primary">
                            <i class="fas fa-user-circle me-2"></i>User Account (Login Details)
                        </h6>
                    </div>
                    <div class="card-body">

                        <div class="name-warning">
                            <strong>⚠️ Important — Name Format:</strong><br>
                            Enter the <strong>given name only</strong> in First Name (e.g. <em>Annie</em>, not <em>Mme Annie</em>).<br>
                            Set the honorific (Mr / Mme / Dr …) in the <strong>Title</strong> field in the Staff Profile below.
                        </div>

                        <div class="row g-3">
                            <div class="col-md-6">
                                <label class="form-label">{{ user_form.first_name.label }}</label>
                                {{ user_form.first_name }}
                                {% if user_form.first_name.help_text %}
                                <div class="form-text text-warning">{{ user_form.first_name.help_text }}</div>
                                {% endif %}
                                {{ user_form.first_name.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ user_form.last_name.label }}</label>
                                {{ user_form.last_name }}
                                {{ user_form.last_name.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ user_form.username.label }}</label>
                                {{ user_form.username }}
                                <div class="form-text">{{ user_form.username.help_text }}</div>
                                {{ user_form.username.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ user_form.email.label }}</label>
                                {{ user_form.email }}
                                {{ user_form.email.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ user_form.password.label }}</label>
                                {{ user_form.password }}
                                <div class="form-text">{{ user_form.password.help_text }}</div>
                                {{ user_form.password.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ user_form.confirm_password.label }}</label>
                                {{ user_form.confirm_password }}
                                {{ user_form.confirm_password.errors }}
                            </div>
                        </div>

                    </div>
                </div>
                {% endif %}

                <!-- ══ STAFF PROFILE ═════════════════════════════════════ -->
                <div class="card shadow mb-4">
                    <div class="card-header py-3">
                        <h6 class="m-0 font-weight-bold text-primary">
                            <i class="fas fa-id-card me-2"></i>Staff Profile
                        </h6>
                    </div>
                    <div class="card-body">

                        <!-- Personal -->
                        <p class="form-section-heading">Personal Information</p>
                        <div class="row g-3">
                            <div class="col-md-2">
                                <label class="form-label">{{ form.title.label }}</label>
                                {{ form.title }}
                                {{ form.title.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.gender.label }}</label>
                                {{ form.gender }}
                                {{ form.gender.errors }}
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">{{ form.date_of_birth.label }}</label>
                                {{ form.date_of_birth }}
                                {{ form.date_of_birth.errors }}
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">{{ form.marital_status.label }}</label>
                                {{ form.marital_status }}
                                {{ form.marital_status.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ form.nationality.label }}</label>
                                {{ form.nationality }}
                                {{ form.nationality.errors }}
                            </div>
                        </div>

                        <!-- Contact -->
                        <p class="form-section-heading">Contact Information</p>
                        <div class="row g-3">
                            <div class="col-md-6">
                                <label class="form-label">Primary Phone</label>
                                <div class="phone-row">
                                    {{ form.phone_country_code }}
                                    {{ form.phone_number }}
                                </div>
                                {{ form.phone_number.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">Alternate Phone</label>
                                <div class="phone-row">
                                    {{ form.alt_phone_country_code }}
                                    {{ form.alternate_phone }}
                                </div>
                                {{ form.alternate_phone.errors }}
                            </div>
                            <!--<div class="col-md-6">-->
                            <!--    <label class="form-label">{{ form.email.label }}</label>-->
                            <!--    {{ form.email }}-->
                            <!--    {{ form.email.errors }}-->
                            <!--</div>-->
                            <div class="col-md-6">
                                <label class="form-label">{{ form.city.label }}</label>
                                {{ form.city }}
                                {{ form.city.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ form.quarter.label }}</label>
                                {{ form.quarter }}
                                {{ form.quarter.errors }}
                            </div>
                            <div class="col-12">
                                <label class="form-label">{{ form.address.label }}</label>
                                {{ form.address }}
                                {{ form.address.errors }}
                            </div>
                        </div>

                        <!-- Emergency contact -->
                        <p class="form-section-heading">Emergency Contact</p>
                        <div class="row g-3">
                            <div class="col-md-4">
                                <label class="form-label">{{ form.emergency_contact_name.label }}</label>
                                {{ form.emergency_contact_name }}
                                {{ form.emergency_contact_name.errors }}
                            </div>
                            <div class="col-md-5">
                                <label class="form-label">Emergency Phone</label>
                                <div class="phone-row">
                                    {{ form.emergency_phone_country_code }}
                                    {{ form.emergency_contact_phone }}
                                </div>
                                {{ form.emergency_contact_phone.errors }}
                            </div>
                            <div class="col-md-3">
                                <label class="form-label">{{ form.emergency_contact_relationship.label }}</label>
                                {{ form.emergency_contact_relationship }}
                                {{ form.emergency_contact_relationship.errors }}
                            </div>
                        </div>

                        <!-- Employment -->
                        <p class="form-section-heading">Employment Details</p>
                        <div class="row g-3">
                            <div class="col-md-4">
                                <label class="form-label">{{ form.role.label }}</label>
                                {{ form.role }}
                                {{ form.role.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.department.label }}</label>
                                {{ form.department }}
                                {{ form.department.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.employment_status.label }}</label>
                                {{ form.employment_status }}
                                {{ form.employment_status.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.hire_date.label }}</label>
                                {{ form.hire_date }}
                                {{ form.hire_date.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.contract_end_date.label }}</label>
                                {{ form.contract_end_date }}
                                {{ form.contract_end_date.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.years_of_experience.label }}</label>
                                {{ form.years_of_experience }}
                                {{ form.years_of_experience.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ form.specialization.label }}</label>
                                {{ form.specialization }}
                                {{ form.specialization.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ form.subjects_taught.label }}</label>
                                {{ form.subjects_taught }}
                                {{ form.subjects_taught.errors }}
                            </div>
                            <div class="col-md-6">
                                <div class="form-check mt-3">
                                    {{ form.is_class_teacher }}
                                    <label class="form-check-label" for="{{ form.is_class_teacher.id_for_label }}">
                                        {{ form.is_class_teacher.label }}
                                    </label>
                                </div>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ form.homeroom_class.label }}</label>
                                {{ form.homeroom_class }}
                                {{ form.homeroom_class.errors }}
                            </div>
                            <div class="col-12">
                                <label class="form-label">{{ form.qualifications.label }}</label>
                                {{ form.qualifications }}
                                {{ form.qualifications.errors }}
                            </div>
                        </div>

                        <!-- Bank (non-sensitive) -->
                        <p class="form-section-heading">Bank Information</p>
                        <div class="row g-3">
                            <div class="col-md-6">
                                <label class="form-label">{{ form.bank_name.label }}</label>
                                {{ form.bank_name }}
                                {{ form.bank_name.errors }}
                            </div>
                            <div class="col-md-6">
                                <label class="form-label">{{ form.bank_branch.label }}</label>
                                {{ form.bank_branch }}
                                {{ form.bank_branch.errors }}
                            </div>
                        </div>

                        <!-- Documents -->
                        <p class="form-section-heading">Documents &amp; Photo</p>
                        <div class="row g-3">
                            <div class="col-md-4">
                                <label class="form-label">{{ form.photo.label }}</label>
                                {{ form.photo }}
                                {{ form.photo.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.cv_file.label }}</label>
                                {{ form.cv_file }}
                                {{ form.cv_file.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.contract_file.label }}</label>
                                {{ form.contract_file }}
                                {{ form.contract_file.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.id_document.label }}</label>
                                {{ form.id_document }}
                                {{ form.id_document.errors }}
                            </div>
                            <div class="col-md-4">
                                <label class="form-label">{{ form.diplomas.label }}</label>
                                {{ form.diplomas }}
                                {{ form.diplomas.errors }}
                            </div>
                        </div>

                        <!-- Other -->
                        <p class="form-section-heading">Other</p>
                        <div class="row g-3">
                            <div class="col-12">
                                <label class="form-label">{{ form.notes.label }}</label>
                                {{ form.notes }}
                                {{ form.notes.errors }}
                            </div>
                            <div class="col-md-4">
                                <div class="form-check">
                                    {{ form.is_active }}
                                    <label class="form-check-label" for="{{ form.is_active.id_for_label }}">
                                        {{ form.is_active.label }}
                                    </label>
                                </div>
                            </div>
                        </div>

                    </div><!-- /card-body -->
                </div><!-- /card -->

                <div class="mb-4">
                    <button type="submit" class="btn btn-primary">
                        <i class="fas fa-save"></i> Save Staff Member
                    </button>
                    <a href="{% url 'staff:staff_list' %}" class="btn btn-secondary ms-2">
                        <i class="fas fa-times"></i> Cancel
                    </a>
                </div>

            </form>
        </div>
    </div>
</div>
{% endblock %}

{% block extra_js %}
<script>
// Auto-suggest username from first + last name
(function () {
    const first = document.getElementById('id_first_name');
    const last  = document.getElementById('id_last_name');
    const uname = document.getElementById('id_username');
    if (!first || !last || !uname) return;

    function suggest() {
        // Only fill if user hasn't manually typed a username
        if (uname.dataset.manual) return;
        const f = first.value.trim().toLowerCase().replace(/\s+/g, '');
        const l = last.value.trim().toLowerCase().replace(/[\s]+/g, '_');
        if (f && l) uname.value = f + '.' + l;
    }

    uname.addEventListener('input', () => { uname.dataset.manual = '1'; });
    first.addEventListener('input', suggest);
    last.addEventListener('input', suggest);
})();
</script>
{% endblock %}

======================================================================
FILE: templates/staff/staff_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Staff Members - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .staff-card {
        transition: transform 0.3s, box-shadow 0.3s;
        border-left: 4px solid transparent;
    }
    .staff-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.1);
    }
    .staff-card.admin { border-left-color: #dc3545; }
    .staff-card.teacher { border-left-color: #28a745; }
    .staff-card.support { border-left-color: #ffc107; }
    
    .staff-avatar {
        width: 60px;
        height: 60px;
        border-radius: 50%;
        background: linear-gradient(135deg, #4CAF50, #2196F3);
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 1.5rem;
        font-weight: bold;
    }
    
    .role-badge {
        position: absolute;
        top: 10px;
        right: 10px;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Page Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0 text-gray-800">Staff Members</h1>
            <p class="text-muted">Total: {{ total_staff }} | Active: {{ active_staff }}</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'staff:staff_add' %}" class="btn btn-primary">
                <i class="fas fa-user-plus"></i> Add Staff
            </a>
            <a href="{% url 'staff:staff_import' %}" class="btn btn-success">
                <i class="fas fa-upload"></i> Import
            </a>
            <a href="{% url 'staff:staff_export' %}" class="btn btn-outline-secondary">
                <i class="fas fa-download"></i> Export
            </a>
        </div>
    </div>

    <!-- Search and Filter -->
    <div class="card shadow mb-4">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Search & Filter</h6>
        </div>
        <div class="card-body">
            <form method="get" class="row g-3">
                <div class="col-md-4">
                    <div class="input-group">
                        <input type="text" class="form-control" name="q" 
                               placeholder="Search by name, ID, or phone..." 
                               value="{{ request.GET.q }}">
                        <button class="btn btn-primary" type="submit">
                            <i class="fas fa-search"></i>
                        </button>
                    </div>
                </div>
                <div class="col-md-3">
                    <select class="form-control" name="role">
                        <option value="">All Roles</option>
                        {% for role_value, role_name in role_choices %}
                        <option value="{{ role_value }}" 
                                {% if request.GET.role == role_value %}selected{% endif %}>
                            {{ role_name }}
                        </option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3">
                    <select class="form-control" name="department">
                        <option value="">All Departments</option>
                        {% for dept_value, dept_name in department_choices %}
                        <option value="{{ dept_value }}" 
                                {% if request.GET.department == dept_value %}selected{% endif %}>
                            {{ dept_name }}
                        </option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-2">
                    <button type="submit" class="btn btn-primary w-100">
                        <i class="fas fa-filter"></i> Filter
                    </button>
                </div>
            </form>
        </div>
    </div>

    <!-- Staff Grid -->
    <div class="row">
        {% for staff in staff_members %}
        <div class="col-xl-3 col-md-4 col-sm-6 mb-4">
            <div class="card staff-card {{ staff.department }} h-100 position-relative">
                <div class="card-body">
                    <div class="role-badge">
                        <span class="badge bg-{% if staff.role == 'admin' %}danger{% elif staff.role == 'teacher' %}success{% else %}warning{% endif %}">
                            {{ staff.get_role_display }}
                        </span>
                    </div>
                    
                    <div class="d-flex align-items-center mb-3">
                        <div class="staff-avatar me-3">
                            {% if staff.photo %}
                            <img src="{{ staff.photo.url }}" class="w-100 h-100 rounded-circle" alt="{{ staff.get_display_name }}">
                            {% else %}
                            {{ staff.user.first_name|first|upper }}{{ staff.user.last_name|first|upper }}
                            {% endif %}
                        </div>
                        <div>
                            <h5 class="card-title mb-1">{{ staff.get_display_name }}</h5>
                            <p class="text-muted small mb-0">ID: {{ staff.employee_id }}</p>
                        </div>
                    </div>
                    
                    <div class="staff-info mb-3">
                        <p class="mb-1">
                            <i class="fas fa-phone text-primary me-2"></i>
                            {% if staff.phone_number %}{{ staff.phone_country_code }} {{ staff.phone_number }}{% else %}No phone{% endif %}
                        </p>
                        <p class="mb-1">
                            <i class="fas fa-building text-success me-2"></i>
                            {{ staff.get_department_display }}
                        </p>
                        <p class="mb-1">
                            <i class="fas fa-calendar-alt text-info me-2"></i>
                            Hired: {{ staff.hire_date|date:"M Y"|default:"Not set" }}
                        </p>
                    </div>
                    
                    <div class="d-flex justify-content-between align-items-center">
                        <span class="badge bg-{% if staff.is_active %}success{% else %}secondary{% endif %}">
                            {{ staff.is_active|yesno:"Active,Inactive" }}
                        </span>
                        <div>
                            <a href="{% url 'staff:staff_detail' staff.pk %}" class="btn btn-sm btn-outline-primary">
                                <i class="fas fa-eye"></i>
                            </a>
                            <a href="{% url 'staff:staff_edit' staff.pk %}" class="btn btn-sm btn-outline-warning">
                                <i class="fas fa-edit"></i>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <div class="text-center py-5">
                <i class="fas fa-users fa-3x text-muted mb-3"></i>
                <h4 class="text-muted">No staff members found</h4>
                <p class="text-muted">Add your first staff member to get started</p>
                <a href="{% url 'staff:staff_add' %}" class="btn btn-primary">
                    <i class="fas fa-user-plus"></i> Add Staff
                </a>
            </div>
        </div>
        {% endfor %}
    </div>

    <!-- Pagination -->
    {% if is_paginated %}
    <nav aria-label="Page navigation" class="mt-4">
        <ul class="pagination justify-content-center">
            {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">
                    Previous
                </a>
            </li>
            {% endif %}
            
            {% for num in page_obj.paginator.page_range %}
            {% if page_obj.number == num %}
            <li class="page-item active">
                <a class="page-link" href="#">{{ num }}</a>
            </li>
            {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
            <li class="page-item">
                <a class="page-link" href="?page={{ num }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">
                    {{ num }}
                </a>
            </li>
            {% endif %}
            {% endfor %}
            
            {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">
                    Next
                </a>
            </li>
            {% endif %}
        </ul>
    </nav>
    {% endif %}
</div>
{% endblock %}

======================================================================
FILE: templates/staff/teacher_dashboard.html
======================================================================
<!-- templates/staff/teacher_dashboard.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}My Dashboard - Teacher{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Welcome Header -->
    <div class="row mb-4">
        <div class="col-12">
            <div class="card bg-primary text-white">
                <div class="card-body">
                    <h4>Welcome back, {{ user.get_full_name }}!</h4>
                    <p class="mb-0">{{ today|date:"l, F d, Y" }}</p>
                </div>
            </div>
        </div>
    </div>

    <!-- My Classes -->
    <div class="row">
        <div class="col-12 mb-4">
            <div class="card shadow">
                <div class="card-header bg-success text-white">
                    <h5 class="mb-0"><i class="fas fa-chalkboard-teacher"></i> My Classes Today</h5>
                </div>
                <div class="card-body">
                    {% if my_classes %}
                    <div class="row">
                        {% for class_data in my_classes %}
                        <div class="col-md-6 col-lg-4 mb-3">
                            <div class="card h-100 border-left-primary">
                                <div class="card-body">
                                    <h5 class="card-title">{{ class_data.class.name }}</h5>
                                    <p class="text-muted small">
                                        <i class="fas fa-book"></i> 
                                        {% for subject in class_data.subjects %}
                                            {{ subject.name }}{% if not forloop.last %}, {% endif %}
                                        {% endfor %}
                                    </p>
                                    <p class="mb-2">
                                        <strong>Students:</strong> {{ class_data.student_count }}
                                    </p>
                                    
                                    {% if class_data.today_attendance_taken %}
                                    <div class="alert alert-success py-2 small">
                                        <i class="fas fa-check-circle"></i> Attendance taken today
                                    </div>
                                    {% else %}
                                    <div class="alert alert-warning py-2 small">
                                        <i class="fas fa-exclamation-triangle"></i> Attendance not taken
                                    </div>
                                    {% endif %}
                                    
                                    <a href="{% url 'attendance:mark_attendance' %}?class={{ class_data.class.id }}" 
                                       class="btn btn-sm btn-primary w-100">
                                        <i class="fas fa-clipboard-check"></i> 
                                        {% if class_data.today_attendance_taken %}Update{% else %}Take{% endif %} Attendance
                                    </a>
                                </div>
                            </div>
                        </div>
                        {% endfor %}
                    </div>
                    {% else %}
                    <p class="text-muted text-center py-4">No classes assigned to you yet.</p>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>

    <!-- Quick Actions -->
    <div class="row">
        <div class="col-md-6 mb-4">
            <div class="card shadow">
                <div class="card-header bg-info text-white">
                    <h5 class="mb-0"><i class="fas fa-bolt"></i> Quick Actions</h5>
                </div>
                <div class="card-body">
                    <div class="list-group">
                        <a href="{% url 'attendance:mark_attendance' %}" class="list-group-item list-group-item-action">
                            <i class="fas fa-clipboard-check text-primary me-2"></i> Mark Attendance
                        </a>
                        <a href="{% url 'students:student_list' %}" class="list-group-item list-group-item-action">
                            <i class="fas fa-users text-success me-2"></i> View All Students
                        </a>
                        <a href="{% url 'reports:attendance_report' %}" class="list-group-item list-group-item-action">
                            <i class="fas fa-chart-bar text-info me-2"></i> View Attendance Reports
                        </a>
                    </div>
                </div>
            </div>
        </div>

        <!-- Recent Activity -->
        <div class="col-md-6 mb-4">
            <div class="card shadow">
                <div class="card-header bg-warning text-dark">
                    <h5 class="mb-0"><i class="fas fa-history"></i> Recent Activity</h5>
                </div>
                <div class="card-body">
                    <div class="list-group">
                        {% for attendance in recent_attendance %}
                        <div class="list-group-item">
                            <div class="d-flex justify-content-between">
                                <small>{{ attendance.date }}</small>
                                <small class="text-muted">{{ attendance.student.first_name }}</small>
                            </div>
                            <span class="badge bg-{% if attendance.status == 'present' %}success{% elif attendance.status == 'absent' %}danger{% else %}warning{% endif %}">
                                {{ attendance.get_status_display }}
                            </span>
                        </div>
                        {% empty %}
                        <p class="text-muted text-center py-3">No recent attendance</p>
                        {% endfor %}
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/students/import.html
======================================================================
<!-- templates/students/import.html - Simplified Version -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Import Students - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Import Students</h1>
        <a href="{% url 'students:student_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left"></i> Back to Student List
        </a>
    </div>

    <div class="row">
        <div class="col-md-8 mx-auto">
            <!-- CSV Upload Card -->
            <div class="card shadow mb-4">
                <div class="card-header bg-primary text-white">
                    <h5 class="mb-0"><i class="fas fa-upload"></i> Upload Student CSV File</h5>
                </div>
                <div class="card-body">
                    <form method="post" enctype="multipart/form-data" action="{% url 'students:import_students_csv' %}">
                        {% csrf_token %}
                        
                        <div class="mb-4">
                            <label class="form-label">Select CSV File</label>
                            <input type="file" name="file" class="form-control" accept=".csv" required>
                            <small class="text-muted">
                                File must be in CSV format with headers matching your data
                            </small>
                        </div>
                        
                        <div class="mb-4">
                            <label class="form-label fw-bold">
                                Target Class
                                <span class="text-muted fw-normal ms-1">(optional override)</span>
                            </label>
                            <select name="class_id" class="form-control">
                                <option value="">-- Use Class column from CSV --</option>
                                {% for class in classes %}
                                <option value="{{ class.id }}">{{ class.name }}</option>
                                {% endfor %}
                            </select>
                            <small class="text-muted">
                                Select a class here to assign <strong>all students</strong> in the file to that class,
                                overriding the Class column in the CSV.
                            </small>
                        </div>

                        <div class="alert alert-warning py-2 mb-4" style="font-size:.85rem">
                            <i class="fas fa-exclamation-triangle me-1"></i>
                            <strong>Class is required.</strong> Every row must have a valid Class code
                            (e.g. <code>CL6-A</code>, <code>CM2-A</code>, <code>NUR1-A</code>),
                            or select a Target Class above. Rows without a class will be skipped and reported as errors.
                        </div>
                        
                        <div class="mb-4">
                            <h6>CSV Format Options:</h6>
                            <div class="row">
                                <div class="col-md-6">
                                    <div class="card">
                                        <div class="card-header bg-light">
                                            <h6 class="mb-0">Format 1: Class 6 Style</h6>
                                        </div>
                                        <div class="card-body">
                                            <pre class="small mb-0">
NAME,DATE OF BIRTH,PLACE OF BIRTH,SEX
John Doe,15/05/2015,Douala,M
Jane Smith,22/08/2015,Yaounde,F</pre>
                                        </div>
                                    </div>
                                </div>
                                <div class="col-md-6">
                                    <div class="card">
                                        <div class="card-header bg-light">
                                            <h6 class="mb-0">Format 2: Standard</h6>
                                        </div>
                                        <div class="card-body">
                                            <pre class="small mb-0">
First Name,Last Name,Date of Birth,Gender,Class,Parent Name,Parent Phone
John,Doe,15/05/2015,M,CL5-A,Peter Doe,677889900
Jane,Smith,22/08/2015,F,CL5-A,Mary Smith,699123456</pre>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        
                        <div class="d-grid gap-2">
                            <a href="{% url 'students:download_student_sample' %}" class="btn btn-success mb-2">
                                <i class="fas fa-download"></i> Download Sample CSV Template
                            </a>
                            <a href="{% url 'students:download_class6_sample' %}" class="btn btn-info mb-2">
                                <i class="fas fa-download"></i> Download Class 6 Sample
                            </a>
                            <button type="submit" class="btn btn-primary">
                                <i class="fas fa-upload"></i> Import Students
                            </button>
                        </div>
                    </form>
                </div>
            </div>

            <!-- Simple Import Option -->
            <div class="card shadow">
                <div class="card-header bg-success text-white">
                    <h5 class="mb-0"><i class="fas fa-info-circle"></i> Import Instructions</h5>
                </div>
                <div class="card-body">
                    <ol class="mb-0">
                        <li>Download the sample CSV template</li>
                        <li>Fill in your student data following the format</li>
                        <li>Upload the file using the form above</li>
                        <li>The system will automatically generate student IDs</li>
                    </ol>
                </div>
            </div>
        </div>
    </div>
</div>

<style>
    pre {
        font-size: 0.8rem;
        background: #f8f9fa;
        padding: 10px;
        border-radius: 5px;
    }
</style>
{% endblock %}

======================================================================
FILE: templates/students/parent_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ parent.first_name }} {{ parent.last_name }} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">{{ parent.first_name }} {{ parent.last_name }}</h1>
        <p class="rb-page-subtitle">
            {{ parent.get_relationship_display }}
            {% if parent.student %}
            of <a href="{% url 'students:student_detail' parent.student.pk %}" style="color:var(--rb-red)">
                {{ parent.student.first_name }} {{ parent.student.last_name }}
            </a>
            {% endif %}
        </p>
    </div>
    <div style="display:flex;gap:.5rem">
        <a href="{% url 'students:parent_edit' parent.pk %}" class="btn btn-warning btn-sm">
            <i class="fas fa-edit me-1"></i> Edit
        </a>
        <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary btn-sm">
            <i class="fas fa-arrow-left me-1"></i> Back to Parents
        </a>
    </div>
</div>

<div class="row">

    <!-- Left: Personal & Contact -->
    <div class="col-lg-5">

        <!-- Personal Information -->
        <div class="card mb-3">
            <div class="card-header">
                <span style="font-weight:600;font-size:.875rem">
                    <i class="fas fa-user me-2" style="color:var(--rb-red)"></i>Personal Information
                </span>
            </div>
            <div class="card-body" style="font-size:.875rem">
                <table class="table table-borderless mb-0">
                    <tr>
                        <td style="color:#888;width:45%">Full Name</td>
                        <td><strong>{{ parent.first_name }} {{ parent.last_name }}</strong></td>
                    </tr>
                    <tr>
                        <td style="color:#888">Relationship</td>
                        <td>{{ parent.get_relationship_display }}</td>
                    </tr>
                    {% if parent.occupation %}
                    <tr>
                        <td style="color:#888">Occupation</td>
                        <td>{{ parent.occupation }}</td>
                    </tr>
                    {% endif %}
                    {% if parent.employer %}
                    <tr>
                        <td style="color:#888">Employer</td>
                        <td>{{ parent.employer }}</td>
                    </tr>
                    {% endif %}
                    {% if parent.education_level %}
                    <tr>
                        <td style="color:#888">Education</td>
                        <td>{{ parent.get_education_level_display }}</td>
                    </tr>
                    {% endif %}
                    {% if parent.preferred_language %}
                    <tr>
                        <td style="color:#888">Language</td>
                        <td>{{ parent.get_preferred_language_display }}</td>
                    </tr>
                    {% endif %}
                </table>
            </div>
        </div>

        <!-- Contact Information -->
        <div class="card mb-3">
            <div class="card-header">
                <span style="font-weight:600;font-size:.875rem">
                    <i class="fas fa-phone me-2" style="color:var(--rb-red)"></i>Contact Information
                </span>
            </div>
            <div class="card-body" style="font-size:.875rem">
                <table class="table table-borderless mb-0">
                    <tr>
                        <td style="color:#888;width:45%">Phone</td>
                        <td>
                            <a href="tel:{{ parent.phone }}" style="color:inherit;text-decoration:none">
                                <i class="fas fa-phone-alt" style="color:var(--rb-gold);margin-right:.3rem"></i>
                                {{ parent.phone }}
                            </a>
                        </td>
                    </tr>
                    {% if parent.alternate_phone %}
                    <tr>
                        <td style="color:#888">Alt Phone</td>
                        <td>
                            <a href="tel:{{ parent.alternate_phone }}" style="color:inherit;text-decoration:none">
                                {{ parent.alternate_phone }}
                            </a>
                        </td>
                    </tr>
                    {% endif %}
                    {% if parent.email %}
                    <tr>
                        <td style="color:#888">Email</td>
                        <td>
                            <a href="mailto:{{ parent.email }}" style="color:var(--rb-red)">
                                {{ parent.email }}
                            </a>
                        </td>
                    </tr>
                    {% endif %}
                    {% if parent.address %}
                    <tr>
                        <td style="color:#888">Address</td>
                        <td>{{ parent.address }}</td>
                    </tr>
                    {% endif %}
                    {% if parent.mobile_money_number %}
                    <tr>
                        <td style="color:#888">MoMo</td>
                        <td>{{ parent.mobile_money_number }}
                            {% if parent.mobile_money_provider %}
                            <span class="rb-badge rb-badge-blue">{{ parent.mobile_money_provider }}</span>
                            {% endif %}
                        </td>
                    </tr>
                    {% endif %}
                </table>
            </div>
        </div>

        <!-- Notification Preferences -->
        <div class="card mb-3">
            <div class="card-header">
                <span style="font-weight:600;font-size:.875rem">
                    <i class="fas fa-bell me-2" style="color:var(--rb-red)"></i>Notifications
                </span>
            </div>
            <div class="card-body" style="font-size:.875rem">
                <div style="display:flex;flex-wrap:wrap;gap:.75rem">
                    <span style="color:{% if parent.receive_sms %}#166534{% else %}#aaa{% endif %}">
                        <i class="fas fa-{% if parent.receive_sms %}check-circle{% else %}times-circle{% endif %} me-1"></i>SMS
                    </span>
                    <span style="color:{% if parent.receive_email %}#166534{% else %}#aaa{% endif %}">
                        <i class="fas fa-{% if parent.receive_email %}check-circle{% else %}times-circle{% endif %} me-1"></i>Email
                    </span>
                    <span style="color:{% if parent.receive_whatsapp %}#166534{% else %}#aaa{% endif %}">
                        <i class="fas fa-{% if parent.receive_whatsapp %}check-circle{% else %}times-circle{% endif %} me-1"></i>WhatsApp
                    </span>
                    <span style="color:{% if parent.is_primary_contact %}#166534{% else %}#aaa{% endif %}">
                        <i class="fas fa-{% if parent.is_primary_contact %}check-circle{% else %}times-circle{% endif %} me-1"></i>Primary Contact
                    </span>
                    <span style="color:{% if parent.can_pick_up %}#166534{% else %}#aaa{% endif %}">
                        <i class="fas fa-{% if parent.can_pick_up %}check-circle{% else %}times-circle{% endif %} me-1"></i>Authorised Pick-up
                    </span>
                </div>
            </div>
        </div>

    </div>

    <!-- Right: Linked Student -->
    <div class="col-lg-7">
        <div class="card mb-3">
            <div class="card-header">
                <span style="font-weight:600;font-size:.875rem">
                    <i class="fas fa-user-graduate me-2" style="color:var(--rb-red)"></i>Linked Student
                </span>
            </div>
            <div class="card-body">
                {% if parent.student %}
                <div style="display:flex;align-items:center;gap:1rem;padding:.5rem 0">
                    <!-- Avatar -->
                    <div style="width:52px;height:52px;border-radius:50%;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-gold));color:#fff;font-weight:700;font-size:1.1rem;display:flex;align-items:center;justify-content:center;flex-shrink:0">
                        {{ parent.student.first_name|first }}{{ parent.student.last_name|first }}
                    </div>
                    <div>
                        <div style="font-weight:700;font-size:1rem">
                            {{ parent.student.first_name }} {{ parent.student.last_name }}
                        </div>
                        <div style="font-size:.8rem;color:#888">
                            ID: {{ parent.student.student_id }} &nbsp;•&nbsp;
                            Class: {{ parent.student.current_class|default:"Not assigned" }}
                        </div>
                        <div style="margin-top:.4rem">
                            <a href="{% url 'students:student_detail' parent.student.pk %}"
                               class="btn btn-sm btn-rb-primary" style="font-size:.78rem">
                                <i class="fas fa-eye me-1"></i> View Student Profile
                            </a>
                        </div>
                    </div>
                </div>
                {% else %}
                <p class="text-muted text-center py-3">No student linked.</p>
                {% endif %}
            </div>
        </div>

        {% if parent.notes %}
        <div class="card">
            <div class="card-header">
                <span style="font-weight:600;font-size:.875rem">
                    <i class="fas fa-sticky-note me-2" style="color:var(--rb-red)"></i>Notes
                </span>
            </div>
            <div class="card-body" style="font-size:.875rem;color:#555">
                {{ parent.notes|linebreaks }}
            </div>
        </div>
        {% endif %}

        <!-- Quick Actions -->
        <div class="card mt-3">
            <div class="card-header">
                <span style="font-weight:600;font-size:.875rem">
                    <i class="fas fa-bolt me-2" style="color:var(--rb-gold)"></i>Quick Actions
                </span>
            </div>
            <div class="card-body" style="display:flex;flex-wrap:wrap;gap:.5rem">
                {% if parent.phone %}
                <a href="tel:{{ parent.phone }}" class="btn btn-sm btn-outline-success">
                    <i class="fas fa-phone me-1"></i> Call
                </a>
                <a href="{% url 'communication:sms_compose' %}?phone={{ parent.phone }}"
                   class="btn btn-sm btn-outline-primary">
                    <i class="fas fa-comment-sms me-1"></i> Send SMS
                </a>
                {% endif %}
                {% if parent.email %}
                <a href="mailto:{{ parent.email }}" class="btn btn-sm btn-outline-secondary">
                    <i class="fas fa-envelope me-1"></i> Email
                </a>
                {% endif %}
                <a href="{% url 'students:parent_edit' parent.pk %}" class="btn btn-sm btn-warning">
                    <i class="fas fa-edit me-1"></i> Edit
                </a>
            </div>
        </div>

    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/students/parent_form.html
======================================================================
{% extends 'base.html' %}

{% block title %}{% if object %}Edit Parent{% else %}Add Parent / Guardian{% endif %} — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">{% if object %}Edit Parent / Guardian{% else %}Add Parent / Guardian{% endif %}</h1>
        {% if object %}<p class="rb-page-subtitle">{{ object.first_name }} {{ object.last_name }}</p>{% endif %}
    </div>
    <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary btn-sm">
        <i class="fas fa-arrow-left me-1"></i> Back to Parents
    </a>
</div>

<div class="row">
<div class="col-lg-8">
<form method="post">
{% csrf_token %}

<!-- Student Link -->
<div class="card mb-3">
    <div class="card-header"><span style="font-weight:600;font-size:.875rem"><i class="fas fa-user-graduate me-2" style="color:var(--rb-red)"></i>Linked Student</span></div>
    <div class="card-body">
        <div class="mb-0">
            <label class="form-label">Student <span class="text-danger">*</span></label>
            {{ form.student }}
            {% if form.student.errors %}<div class="text-danger" style="font-size:.8rem">{{ form.student.errors }}</div>{% endif %}
        </div>
    </div>
</div>

<!-- Personal Information -->
<div class="card mb-3">
    <div class="card-header"><span style="font-weight:600;font-size:.875rem"><i class="fas fa-user me-2" style="color:var(--rb-red)"></i>Personal Information</span></div>
    <div class="card-body">
        <div class="row g-3">
            <div class="col-sm-6">
                <label class="form-label">First Name <span class="text-danger">*</span></label>
                {{ form.first_name }}
                {% if form.first_name.errors %}<div class="text-danger" style="font-size:.8rem">{{ form.first_name.errors }}</div>{% endif %}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Last Name <span class="text-danger">*</span></label>
                {{ form.last_name }}
                {% if form.last_name.errors %}<div class="text-danger" style="font-size:.8rem">{{ form.last_name.errors }}</div>{% endif %}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Relationship <span class="text-danger">*</span></label>
                {{ form.relationship }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Occupation</label>
                {{ form.occupation }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Employer</label>
                {{ form.employer }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Education Level</label>
                {{ form.education_level }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Preferred Language</label>
                {{ form.preferred_language }}
            </div>
        </div>
    </div>
</div>

<!-- Contact Information -->
<div class="card mb-3">
    <div class="card-header"><span style="font-weight:600;font-size:.875rem"><i class="fas fa-phone me-2" style="color:var(--rb-red)"></i>Contact Information</span></div>
    <div class="card-body">
        <div class="row g-3">
            <div class="col-sm-6">
                <label class="form-label">Phone <span class="text-danger">*</span></label>
                {{ form.phone }}
                <div style="font-size:.75rem;color:#aaa;margin-top:.2rem">Format: +237XXXXXXXXX</div>
                {% if form.phone.errors %}<div class="text-danger" style="font-size:.8rem">{{ form.phone.errors }}</div>{% endif %}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Alternate Phone</label>
                {{ form.alternate_phone }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Email</label>
                {{ form.email }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Mobile Money Number</label>
                {{ form.mobile_money_number }}
            </div>
            <div class="col-sm-6">
                <label class="form-label">Mobile Money Provider</label>
                {{ form.mobile_money_provider }}
            </div>
            <div class="col-12">
                <label class="form-label">Address</label>
                {{ form.address }}
            </div>
        </div>
    </div>
</div>

<!-- Communication Preferences -->
<div class="card mb-3">
    <div class="card-header"><span style="font-weight:600;font-size:.875rem"><i class="fas fa-bell me-2" style="color:var(--rb-red)"></i>Notifications &amp; Permissions</span></div>
    <div class="card-body">
        <div class="row g-2">
            <div class="col-12" style="display:flex;flex-wrap:wrap;gap:1.25rem">
                <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem">
                    {{ form.receive_sms }} Receive SMS notifications
                </label>
                <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem">
                    {{ form.receive_email }} Receive email notifications
                </label>
                <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem">
                    {{ form.receive_whatsapp }} Receive WhatsApp messages
                </label>
                <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem">
                    {{ form.is_primary_contact }} Primary contact
                </label>
                <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.875rem">
                    {{ form.can_pick_up }} Authorised to pick up student
                </label>
            </div>
        </div>
        <div class="mt-3">
            <label class="form-label">Notes</label>
            {{ form.notes }}
        </div>
    </div>
</div>

<div class="d-flex justify-content-end gap-2 mb-4">
    <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary">Cancel</a>
    <button type="submit" class="btn btn-rb-primary px-4">
        <i class="fas fa-save me-2"></i> {% if object %}Save Changes{% else %}Add Parent{% endif %}
    </button>
</div>

</form>
</div>

<!-- Sidebar info -->
<div class="col-lg-4">
    <div class="card">
        <div class="card-header"><span style="font-weight:600;font-size:.875rem">Tips</span></div>
        <div class="card-body" style="font-size:.82rem;color:#666;line-height:1.6">
            <p><i class="fas fa-info-circle" style="color:var(--rb-gold)"></i> Phone numbers should include the country code: <strong>+237</strong> for Cameroon.</p>
            <p><i class="fas fa-info-circle" style="color:var(--rb-gold)"></i> Only one parent per student should be marked as <strong>Primary Contact</strong>.</p>
            <p class="mb-0"><i class="fas fa-info-circle" style="color:var(--rb-gold)"></i> Enable <strong>Receive SMS</strong> to include this parent in class broadcasts.</p>
        </div>
    </div>
</div>
</div>
{% endblock %}


======================================================================
FILE: templates/students/parent_list.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}Parents & Guardians — Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="rb-page-header">
    <div>
        <h1 class="rb-page-title">Parents &amp; Guardians</h1>
        <p class="rb-page-subtitle">{{ page_obj.paginator.count|default:parents|length }} contact{{ page_obj.paginator.count|default:parents|length|pluralize }} on record</p>
    </div>
    <a href="{% url 'students:parent_add' %}" class="btn btn-rb-primary btn-sm">
        <i class="fas fa-user-plus me-1"></i> Add Parent
    </a>
</div>

<!-- Search -->
<form method="get" class="mb-3">
    <div style="display:flex;gap:.5rem;max-width:440px">
        <input type="text" name="q" value="{{ request.GET.q }}" class="form-control" placeholder="Search name, phone, student…">
        <button type="submit" class="btn btn-rb-primary"><i class="fas fa-search"></i></button>
        {% if request.GET.q %}
        <a href="{% url 'students:parent_list' %}" class="btn btn-outline-secondary"><i class="fas fa-times"></i></a>
        {% endif %}
    </div>
</form>

<div class="card">
    <div class="table-responsive">
        <table class="table table-hover mb-0" style="font-size:.875rem">
            <thead style="background:#fdfaf7">
                <tr>
                    <th style="font-size:.7rem;text-transform:uppercase;letter-spacing:.4px;color:#888;font-weight:700">Parent / Guardian</th>
                    <th style="font-size:.7rem;text-transform:uppercase;letter-spacing:.4px;color:#888;font-weight:700">Relationship</th>
                    <th style="font-size:.7rem;text-transform:uppercase;letter-spacing:.4px;color:#888;font-weight:700">Phone</th>
                    <th style="font-size:.7rem;text-transform:uppercase;letter-spacing:.4px;color:#888;font-weight:700">Student</th>
                    <th style="font-size:.7rem;text-transform:uppercase;letter-spacing:.4px;color:#888;font-weight:700">Actions</th>
                </tr>
            </thead>
            <tbody>
                {% for parent in parents %}
                <tr>
                    <td>
                        <div style="display:flex;align-items:center;gap:.65rem">
                            <div style="width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--rb-red-dark),var(--rb-gold));color:#fff;font-weight:700;font-size:.8rem;display:flex;align-items:center;justify-content:center;flex-shrink:0">
                                {{ parent.first_name|first }}{{ parent.last_name|first }}
                            </div>
                            <div>
                                <div style="font-weight:600">{{ parent.first_name }} {{ parent.last_name }}</div>
                                {% if parent.email %}<div style="font-size:.75rem;color:#aaa">{{ parent.email }}</div>{% endif %}
                            </div>
                        </div>
                    </td>
                    <td>
                        <span class="rb-badge rb-badge-blue">{{ parent.get_relationship_display }}</span>
                    </td>
                    <td>
                        <a href="tel:{{ parent.phone }}" style="color:inherit;text-decoration:none">
                            <i class="fas fa-phone-alt" style="color:var(--rb-gold);font-size:.75rem;margin-right:.3rem"></i>{{ parent.phone }}
                        </a>
                        {% if parent.alternate_phone %}
                        <div style="font-size:.75rem;color:#aaa">{{ parent.alternate_phone }}</div>
                        {% endif %}
                    </td>
                    <td>
                        {% if parent.student %}
                        <a href="{% url 'students:student_detail' parent.student.pk %}" style="font-weight:600;color:var(--rb-red);text-decoration:none">
                            {{ parent.student.first_name }} {{ parent.student.last_name }}
                        </a>
                        <div style="font-size:.75rem;color:#aaa">{{ parent.student.current_class|default:"No class" }}</div>
                        {% else %}
                        <span class="rb-badge rb-badge-gray">No student</span>
                        {% endif %}
                    </td>
                    <td>
                        <div style="display:flex;gap:.35rem">
                            <a href="{% url 'students:parent_detail' parent.pk %}" class="btn btn-sm" style="background:#fef2f2;color:var(--rb-red);border:none;padding:.25rem .6rem;font-size:.78rem" title="View">
                                <i class="fas fa-eye"></i>
                            </a>
                            <a href="{% url 'students:parent_edit' parent.pk %}" class="btn btn-sm btn-outline-secondary" style="padding:.25rem .6rem;font-size:.78rem" title="Edit">
                                <i class="fas fa-edit"></i>
                            </a>
                            {% if parent.phone %}
                            <a href="{% url 'communication:sms_compose' %}?phone={{ parent.phone }}" class="btn btn-sm" style="background:#f0fdf4;color:#166534;border:none;padding:.25rem .6rem;font-size:.78rem" title="Send SMS">
                                <i class="fas fa-comment-sms"></i>
                            </a>
                            {% endif %}
                        </div>
                    </td>
                </tr>
                {% empty %}
                <tr>
                    <td colspan="5" class="text-center py-5">
                        <i class="fas fa-users fa-2x text-muted mb-2 d-block"></i>
                        {% if request.GET.q %}
                        <p class="text-muted mb-2">No parents found matching "<strong>{{ request.GET.q }}</strong>"</p>
                        <a href="{% url 'students:parent_list' %}">Clear search</a>
                        {% else %}
                        <p class="text-muted mb-2">No parents or guardians on record yet.</p>
                        <a href="{% url 'students:parent_add' %}" class="btn btn-rb-primary btn-sm">Add First Parent</a>
                        {% endif %}
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>

    <!-- Pagination -->
    {% if page_obj.has_other_pages %}
    <div style="padding:.75rem 1rem;border-top:1px solid #f0ebe5;display:flex;justify-content:center;gap:.35rem;flex-wrap:wrap">
        {% if page_obj.has_previous %}
        <a href="?page={{ page_obj.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}" class="btn btn-sm btn-outline-secondary">
            <i class="fas fa-chevron-left"></i>
        </a>
        {% endif %}
        {% for num in page_obj.paginator.page_range %}
        {% if page_obj.number == num %}
        <span class="btn btn-sm btn-rb-primary">{{ num }}</span>
        {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
        <a href="?page={{ num }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}" class="btn btn-sm btn-outline-secondary">{{ num }}</a>
        {% endif %}
        {% endfor %}
        {% if page_obj.has_next %}
        <a href="?page={{ page_obj.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}" class="btn btn-sm btn-outline-secondary">
            <i class="fas fa-chevron-right"></i>
        </a>
        {% endif %}
    </div>
    {% endif %}
</div>
{% endblock %}


======================================================================
FILE: templates/students/student_confirm_delete.html
======================================================================
<!-- templates/students/student_confirm_delete.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Delete Student - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card shadow">
                <div class="card-header bg-danger text-white">
                    <h4 class="mb-0"><i class="fas fa-exclamation-triangle"></i> Confirm Delete</h4>
                </div>
                <div class="card-body text-center py-5">
                    <i class="fas fa-user-graduate fa-4x text-danger mb-3"></i>
                    <h5 class="mb-3">Are you sure you want to delete?</h5>
                    <p class="lead mb-4">
                        <strong>{{ student.first_name }} {{ student.last_name }}</strong><br>
                        <span class="text-muted">ID: {{ student.student_id }}</span>
                    </p>
                    <p class="text-danger mb-4">
                        <i class="fas fa-info-circle"></i> 
                        This action cannot be undone. All associated records will also be deleted.
                    </p>
                    
                    <form method="post">
                        {% csrf_token %}
                        <div class="d-flex justify-content-center gap-3">
                            <button type="submit" class="btn btn-danger btn-lg px-5">
                                <i class="fas fa-trash"></i> Yes, Delete
                            </button>
                            <a href="{% url 'students:student_detail' student.pk %}" class="btn btn-secondary btn-lg px-5">
                                <i class="fas fa-times"></i> Cancel
                            </a>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/students/student_detail.html
======================================================================
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ student }} - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Student Header -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <div class="row">
                <div class="col-md-8">
                    <h2 class="text-primary">{{ student.first_name }} {{ student.last_name }}</h2>
                    <p class="text-muted">
                        Student ID: {{ student.student_id }} • 
                        Class: {{ student.current_class|default:"Not Assigned" }} • 
                        Status: <span class="badge badge-{{ student.status }}">{{ student.status|title }}</span>
                    </p>
                </div>
                <div class="col-md-4 text-right">
                    <a href="{% url 'students:student_edit' student.pk %}" class="btn btn-warning">
                        <i class="fas fa-edit"></i> Edit
                    </a>
                    <a href="{% url 'students:student_delete' student.pk %}"
                       onclick="return confirm('Delete {{ student.first_name }} {{ student.last_name }}? This cannot be undone.')"
                       class="btn btn-danger">
                        <i class="fas fa-trash"></i> Delete
                    </a>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <!-- Student Information -->
        <div class="col-lg-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Student Information</h6>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td><strong>Date of Birth:</strong></td>
                            <td>{{ student.date_of_birth|date:"d M Y" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Age:</strong></td>
                            <td>{{ student.get_age }} years</td>
                        </tr>
                        <tr>
                            <td><strong>Gender:</strong></td>
                            <td>{{ student.get_gender_display }}</td>
                        </tr>
                        <tr>
                            <td><strong>Admission Date:</strong></td>
                            <td>{{ student.admission_date|date:"d M Y" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Home Address:</strong></td>
                            <td>{{ student.home_address }}</td>
                        </tr>
                        <tr>
                            <td><strong>Quarter:</strong></td>
                            <td>{{ student.quarter }}</td>
                        </tr>
                    </table>
                </div>
            </div>

            <!-- Contact Information -->
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Contact Information</h6>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td><strong>Phone:</strong></td>
                            <td>{{ student.phone|default:"Not provided" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Emergency Contact:</strong></td>
                            <td>{{ student.emergency_contact|default:"Not provided" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Emergency Name:</strong></td>
                            <td>{{ student.emergency_contact_name|default:"Not provided" }}</td>
                        </tr>
                    </table>
                </div>
            </div>
        </div>

        <!-- Academic Information -->
        <div class="col-lg-8">
            <div class="row">
                <!-- Attendance Summary -->
                <div class="col-md-6">
                    <div class="card shadow mb-4">
                        <div class="card-header py-3">
                            <h6 class="m-0 font-weight-bold text-primary">Attendance (This Month)</h6>
                        </div>
                        <div class="card-body text-center">
                            <h1 class="display-4 text-success">85%</h1>
                            <p class="text-muted">Present: 17 days • Absent: 3 days</p>
                        </div>
                    </div>
                </div>

                <!-- Fee Status -->
                <div class="col-md-6">
                    <div class="card shadow mb-4">
                        <div class="card-header py-3">
                            <h6 class="m-0 font-weight-bold text-primary">Fee Status</h6>
                        </div>
                        <div class="card-body text-center">
                            <h1 class="display-4 text-{{ student.fee_status_color }}">Paid</h1>
                            <p class="text-muted">Last Payment: 15 Nov 2024</p>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Recent Activity -->
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Recent Activity</h6>
                    <button class="btn btn-sm btn-primary">View All</button>
                </div>
                <div class="card-body">
                    <div class="timeline">
                        <!-- Add timeline items here -->
                        <p class="text-muted text-center py-4">No recent activity</p>
                    </div>
                </div>
            </div>

            <!-- Parent/Guardian Information -->
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Parent/Guardian Information</h6>
                </div>
                <div class="card-body">
                    {% if parents %}
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>Name</th>
                                    <th>Relationship</th>
                                    <th>Phone</th>
                                    <th>Email</th>
                                    <th>Primary</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for parent in parents %}
                                <tr>
                                    <td>{{ parent.first_name }} {{ parent.last_name }}</td>
                                    <td>{{ parent.get_relationship_display }}</td>
                                    <td>
                                        <a href="tel:{{ parent.phone }}">{{ parent.phone }}</a>
                                    </td>
                                    <td>{{ parent.email|default:"-" }}</td>
                                    <td>
                                        {% if parent.is_primary_contact %}
                                        <span class="badge bg-success">Primary</span>
                                        {% endif %}
                                    </td>
                                    <td>
                                        <a href="{% url 'students:parent_detail' parent.pk %}"
                                           class="btn btn-sm btn-outline-primary" title="View">
                                            <i class="fas fa-eye"></i>
                                        </a>
                                        <a href="{% url 'students:parent_edit' parent.pk %}"
                                           class="btn btn-sm btn-warning" title="Edit">
                                            <i class="fas fa-edit"></i>
                                        </a>
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                    {% else %}
                    <p class="text-muted text-center py-4">No parent/guardian information on record.</p>
                    <div class="text-center">
                        <a href="{% url 'students:parent_add' %}?student={{ student.pk }}"
                           class="btn btn-primary">
                            <i class="fas fa-user-plus"></i> Add Parent/Guardian
                        </a>
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}

======================================================================
FILE: templates/students/student_form.html
======================================================================
<!-- templates/students/student_form.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ title|default:"Student Form" }} - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .form-section {
        background: white;
        border-radius: 10px;
        padding: 20px;
        margin-bottom: 20px;
        box-shadow: 0 2px 10px rgba(0,0,0,0.1);
    }
    .form-section h5 {
        color: #4CAF50;
        margin-bottom: 20px;
        padding-bottom: 10px;
        border-bottom: 2px solid #4CAF50;
    }
    .form-label {
        font-weight: 600;
        color: #333;
    }
    .required-field::after {
        content: " *";
        color: red;
    }
    .help-text {
        font-size: 0.8rem;
        color: #6c757d;
        margin-top: 5px;
    }
    .form-actions {
        position: sticky;
        bottom: 0;
        background: white;
        padding: 20px;
        border-top: 1px solid #dee2e6;
        margin-top: 30px;
        z-index: 100;
    }
    .errorlist {
        color: #dc3545;
        list-style: none;
        padding: 0;
        margin: 5px 0;
        font-size: 0.9rem;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Page Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">
            {% if student %}
                Edit Student: {{ student.first_name }} {{ student.last_name }}
            {% else %}
                Add New Student
            {% endif %}
        </h1>
        <a href="{% url 'students:student_list' %}" class="btn btn-outline-secondary">
            <i class="fas fa-arrow-left"></i> Back to Student List
        </a>
    </div>

    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
        
        <!-- Personal Information Section -->
        <div class="form-section">
            <h5><i class="fas fa-user-circle me-2"></i> Personal Information</h5>
            <div class="row">
                <div class="col-md-4 mb-3">
                    <label class="form-label required-field">First Name</label>
                    <input type="text" name="first_name" class="form-control" 
                           value="{{ form.first_name.value|default:'' }}" required>
                    {% if form.first_name.errors %}
                        <ul class="errorlist">{{ form.first_name.errors }}</ul>
                    {% endif %}
                </div>
                <div class="col-md-4 mb-3">
                    <label class="form-label required-field">Last Name</label>
                    <input type="text" name="last_name" class="form-control" 
                           value="{{ form.last_name.value|default:'' }}" required>
                    {% if form.last_name.errors %}
                        <ul class="errorlist">{{ form.last_name.errors }}</ul>
                    {% endif %}
                </div>
                <div class="col-md-4 mb-3">
                    <label class="form-label">Student ID</label>
                    <input type="text" name="student_id" class="form-control" 
                           value="{{ form.student_id.value|default:'' }}" readonly>
                    <small class="help-text">Auto-generated if left blank</small>
                </div>
            </div>

            <div class="row">
                <div class="col-md-3 mb-3">
                    <label class="form-label required-field">Date of Birth</label>
                    <input type="date" name="date_of_birth" class="form-control" 
                           value="{{ form.date_of_birth.value|date:'Y-m-d'|default:'' }}">
                    {% if form.date_of_birth.errors %}
                        <ul class="errorlist">{{ form.date_of_birth.errors }}</ul>
                    {% endif %}
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Place of Birth</label>
                    <input type="text" name="place_of_birth" class="form-control" 
                           value="{{ form.place_of_birth.value|default:'' }}">
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Gender</label>
                    <select name="gender" class="form-select">
                        <option value="">Select Gender</option>
                        <option value="M" {% if form.gender.value == 'M' %}selected{% endif %}>Male</option>
                        <option value="F" {% if form.gender.value == 'F' %}selected{% endif %}>Female</option>
                        <option value="U" {% if form.gender.value == 'U' %}selected{% endif %}>Unknown</option>
                    </select>
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Nationality</label>
                    <input type="text" name="nationality" class="form-control" 
                           value="{{ form.nationality.value|default:'Cameroonian' }}">
                </div>
            </div>
        </div>


<!-- Academic Information Section -->
        <div class="form-section">
            <h5><i class="fas fa-graduation-cap me-2"></i> Academic Information</h5>
            <div class="row">
                <div class="col-md-3 mb-3">
                    <label class="form-label">Admission Date</label>
                    <input type="date" name="admission_date" class="form-control" 
                           value="{{ form.admission_date.value|date:'Y-m-d'|default:'' }}">
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Admission Class</label>
                    <select name="admission_class" class="form-select">
                        <option value="">Select Class</option>
                        <option value="pre_nursery" {% if form.admission_class.value == 'pre_nursery' %}selected{% endif %}>Pre-Nursery</option>
                        <option value="nursery1" {% if form.admission_class.value == 'nursery1' %}selected{% endif %}>Nursery 1</option>
                        <option value="nursery2" {% if form.admission_class.value == 'nursery2' %}selected{% endif %}>Nursery 2</option>
                        <option value="sil" {% if form.admission_class.value == 'sil' %}selected{% endif %}>SIL</option>
                        <option value="cp" {% if form.admission_class.value == 'cp' %}selected{% endif %}>CP</option>
                        <option value="ce1" {% if form.admission_class.value == 'ce1' %}selected{% endif %}>CE1</option>
                        <option value="ce2" {% if form.admission_class.value == 'ce2' %}selected{% endif %}>CE2</option>
                        <option value="cm1" {% if form.admission_class.value == 'cm1' %}selected{% endif %}>CM1</option>
                        <option value="cm2" {% if form.admission_class.value == 'cm2' %}selected{% endif %}>CM2</option>
                        <option value="class1" {% if form.admission_class.value == 'class1' %}selected{% endif %}>Class 1</option>
                        <option value="class2" {% if form.admission_class.value == 'class2' %}selected{% endif %}>Class 2</option>
                        <option value="class3" {% if form.admission_class.value == 'class3' %}selected{% endif %}>Class 3</option>
                        <option value="class4" {% if form.admission_class.value == 'class4' %}selected{% endif %}>Class 4</option>
                        <option value="class5" {% if form.admission_class.value == 'class5' %}selected{% endif %}>Class 5</option>
                        <option value="class6" {% if form.admission_class.value == 'class6' %}selected{% endif %}>Class 6</option>
                    </select>
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Current Class</label>
                    <select name="current_class" class="form-select">
                        <option value="">Select Class</option>
                        {% for class in classes %}
                        <option value="{{ class.id }}" {% if form.current_class.value|stringformat:"s" == class.id|stringformat:"s" %}selected{% endif %}>
                            {{ class.name }}
                        </option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Status</label>
                    <select name="status" class="form-select">
                        <option value="active" {% if form.status.value == 'active' %}selected{% endif %}>Active</option>
                        <option value="inactive" {% if form.status.value == 'inactive' %}selected{% endif %}>Inactive</option>
                        <option value="graduated" {% if form.status.value == 'graduated' %}selected{% endif %}>Graduated</option>
                        <option value="transferred" {% if form.status.value == 'transferred' %}selected{% endif %}>Transferred</option>
                    </select>
                </div>
            </div>
        </div>


<!-- Contact Information Section -->
        <div class="form-section">
            <h5><i class="fas fa-address-book me-2"></i> Contact Information</h5>
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label class="form-label">Home Address</label>
                    <textarea name="home_address" class="form-control" rows="2">{{ form.home_address.value|default:'' }}</textarea>
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">Quarter/Neighborhood</label>
                    <input type="text" name="quarter" class="form-control" 
                           value="{{ form.quarter.value|default:'' }}">
                </div>
                <div class="col-md-3 mb-3">
                    <label class="form-label">City</label>
                    <input type="text" name="city" class="form-control" 
                           value="{{ form.city.value|default:'Douala' }}">
                </div>
            </div>

            <div class="row">
                <div class="col-md-4 mb-3">
                    <label class="form-label">Phone Number</label>
                    <input type="tel" name="phone_number" class="form-control" 
                           value="{{ form.phone_number.value|default:'' }}">
                </div>
                <div class="col-md-4 mb-3">
                    <label class="form-label">Email Address</label>
                    <input type="email" name="email" class="form-control" 
                           value="{{ form.email.value|default:'' }}">
                </div>
            </div>
        </div>


<!-- Emergency Contact Section -->
        <div class="form-section">
            <h5><i class="fas fa-phone-alt me-2"></i> Emergency Contact</h5>
            <div class="row">
                <div class="col-md-4 mb-3">
                    <label class="form-label">Contact Name</label>
                    <input type="text" name="emergency_contact_name" class="form-control" 
                           value="{{ form.emergency_contact_name.value|default:'' }}">
                </div>
                <div class="col-md-4 mb-3">
                    <label class="form-label">Contact Phone</label>
                    <input type="tel" name="emergency_contact_phone" class="form-control" 
                           value="{{ form.emergency_contact_phone.value|default:'' }}">
                </div>
                <div class="col-md-4 mb-3">
                    <label class="form-label">Relationship</label>
                    <input type="text" name="emergency_contact_relationship" class="form-control" 
                           value="{{ form.emergency_contact_relationship.value|default:'' }}">
                </div>
            </div>
        </div>


<!-- Medical Information Section -->
        <div class="form-section">
            <h5><i class="fas fa-heartbeat me-2"></i> Medical Information</h5>
            <div class="row">
                <div class="col-md-3 mb-3">
                    <label class="form-label">Blood Group</label>
                    <select name="blood_group" class="form-select">
                        <option value="">Select Blood Group</option>
                        <option value="A+" {% if form.blood_group.value == 'A+' %}selected{% endif %}>A+</option>
                        <option value="A-" {% if form.blood_group.value == 'A-' %}selected{% endif %}>A-</option>
                        <option value="B+" {% if form.blood_group.value == 'B+' %}selected{% endif %}>B+</option>
                        <option value="B-" {% if form.blood_group.value == 'B-' %}selected{% endif %}>B-</option>
                        <option value="AB+" {% if form.blood_group.value == 'AB+' %}selected{% endif %}>AB+</option>
                        <option value="AB-" {% if form.blood_group.value == 'AB-' %}selected{% endif %}>AB-</option>
                        <option value="O+" {% if form.blood_group.value == 'O+' %}selected{% endif %}>O+</option>
                        <option value="O-" {% if form.blood_group.value == 'O-' %}selected{% endif %}>O-</option>
                        <option value="unknown" {% if form.blood_group.value == 'unknown' %}selected{% endif %}>Unknown</option>
                    </select>
                </div>
                <div class="col-md-9 mb-3">
                    <label class="form-label">Allergies</label>
                    <input type="text" name="allergies" class="form-control" 
                           value="{{ form.allergies.value|default:'' }}">
                </div>
            </div>
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label class="form-label">Chronic Conditions</label>
                    <textarea name="chronic_conditions" class="form-control" rows="2">{{ form.chronic_conditions.value|default:'' }}</textarea>
                </div>
                <div class="col-md-6 mb-3">
                    <label class="form-label">Current Medications</label>
                    <textarea name="medications" class="form-control" rows="2">{{ form.medications.value|default:'' }}</textarea>
                </div>
            </div>
        </div>


<!-- Photo & Documents Section -->
        <div class="form-section">
            <h5><i class="fas fa-camera me-2"></i> Photo & Documents</h5>
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label class="form-label">Student Photo</label>
                    {% if student and student.photo %}
                        <div class="mb-2">
                            <img src="{{ student.photo.url }}" alt="{{ student.get_full_name }}" 
                                 style="max-height: 100px; border-radius: 5px;">
                        </div>
                    {% endif %}
                    <input type="file" name="photo" class="form-control" accept="image/*">
                </div>
                <div class="col-md-6 mb-3">
                    <label class="form-label">Birth Certificate</label>
                    {% if student and student.birth_certificate %}
                        <div class="mb-2">
                            <a href="{{ student.birth_certificate.url }}" target="_blank" class="btn btn-sm btn-info">
                                <i class="fas fa-file-pdf"></i> View Current
                            </a>
                        </div>
                    {% endif %}
                    <input type="file" name="birth_certificate" class="form-control" accept=".pdf,.jpg,.jpeg,.png">
                </div>
            </div>
        </div>


<!-- Additional Notes Section -->
        <div class="form-section">
            <h5><i class="fas fa-sticky-note me-2"></i> Additional Notes</h5>
            <div class="row">
                <div class="col-12 mb-3">
                    <textarea name="notes" class="form-control" rows="3">{{ form.notes.value|default:'' }}</textarea>
                </div>
            </div>
        </div>

        <!-- Form Actions -->
        <div class="form-actions">
            <div class="d-flex justify-content-center gap-3">
                <button type="submit" class="btn btn-primary btn-lg px-5">
                    <i class="fas fa-save"></i> 
                    {% if student %}Update{% else %}Save{% endif %} Student
                </button>
                <a href="{% url 'students:student_list' %}" class="btn btn-secondary btn-lg px-5">
                    <i class="fas fa-times"></i> Cancel
                </a>
            </div>
        </div>
    </form>
</div>
{% endblock %}

{% block extra_js %}
<script>
    // Auto-format phone numbers (optional)
    document.querySelector('input[name="phone_number"]').addEventListener('input', function(e) {
        let value = e.target.value.replace(/\D/g, '');
        if (value.length > 0) {
            if (value.length <= 3) {
                e.target.value = value;
            } else if (value.length <= 6) {
                e.target.value = value.slice(0, 3) + ' ' + value.slice(3);
            } else {
                e.target.value = value.slice(0, 3) + ' ' + value.slice(3, 6) + ' ' + value.slice(6, 9);
            }
        }
    });

    // Preview image before upload
    document.querySelector('input[name="photo"]').addEventListener('change', function(e) {
        if (e.target.files && e.target.files[0]) {
            const reader = new FileReader();
            reader.onload = function(e) {
                const preview = document.querySelector('.photo-preview');
                if (!preview) {
                    const img = document.createElement('img');
                    img.src = e.target.result;
                    img.style.maxHeight = '100px';
                    img.style.borderRadius = '5px';
                    img.classList.add('photo-preview', 'mt-2');
                    document.querySelector('input[name="photo"]').parentNode.appendChild(img);
                } else {
                    preview.src = e.target.result;
                }
            }
            reader.readAsDataURL(e.target.files[0]);
        }
    });
</script>
{% endblock %}

======================================================================
FILE: templates/students/student_list.html
======================================================================
<!-- templates/students/student_list.html -->
{% extends 'base.html' %}
{% load static %}

{% block title %}Students - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
.student-card { transition: transform .2s, box-shadow .2s; }
.student-card:hover { transform: translateY(-4px); box-shadow: 0 6px 20px rgba(0,0,0,.12); }
.student-avatar {
    width: 52px; height: 52px; border-radius: 50%;
    background: linear-gradient(135deg, var(--rb-red-dark, #7b1d1d), var(--rb-gold, #c9973a));
    color: #fff; font-size: 1.1rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.avatar-sm { width: 36px; height: 36px; font-size: .8rem; }
.stat-card { background:#fff; border-radius:10px; padding:14px 18px; box-shadow:0 2px 8px rgba(0,0,0,.07); text-align:center; }
.stat-number { font-size:1.75rem; font-weight:700; color:#22c55e; line-height:1; }
.stat-number.warn { color:#f59e0b; }
.stat-number.blue { color:#3b82f6; }
.stat-number.red  { color:#ef4444; }
.stat-label { font-size:.8rem; color:#888; margin-top:3px; }
.filter-bar { background:linear-gradient(135deg,#667eea,#764ba2); border-radius:10px; padding:16px 20px; margin-bottom:16px; }
.filter-bar label { color:#fff; font-size:.8rem; font-weight:600; margin-bottom:3px; display:block; }
.filter-bar .form-select, .filter-bar .form-control { font-size:.85rem; }
.result-bar { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:.5rem; margin-bottom:10px; font-size:.85rem; color:#555; }
.sort-link { color:#555; text-decoration:none; white-space:nowrap; }
.sort-link:hover { color:var(--rb-red,#7b1d1d); }
.sort-link .fa-sort-up, .sort-link .fa-sort-down { color:var(--rb-red,#7b1d1d); }
.no-class-badge { background:#fef2f2; color:#dc2626; font-size:.72rem; padding:2px 7px; border-radius:99px; font-weight:600; }
.status-active   { background:#d1fae5; color:#065f46; }
.status-inactive { background:#fee2e2; color:#991b1b; }
.status-graduated{ background:#dbeafe; color:#1e40af; }
.status-transferred { background:#fef9c3; color:#92400e; }
.status-badge { padding:3px 10px; border-radius:99px; font-size:.75rem; font-weight:600; }
.pagination-bar { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:.5rem; margin-top:16px; font-size:.85rem; }
.page-btn { display:inline-flex; align-items:center; justify-content:center; min-width:34px; height:34px;
    padding:0 10px; border-radius:6px; border:1px solid #e5e7eb; background:#fff;
    color:#555; text-decoration:none; font-size:.82rem; transition:all .15s; }
.page-btn:hover { background:#f3f4f6; color:#111; border-color:#d1d5db; }
.page-btn.active { background:var(--rb-red,#7b1d1d); color:#fff; border-color:var(--rb-red,#7b1d1d); font-weight:700; }
.page-btn.disabled { opacity:.4; pointer-events:none; }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">

    <!-- Header -->
    <div class="d-flex justify-content-between align-items-center mb-3">
        <div>
            <h1 class="h3 mb-0">Student Management</h1>
            <p class="text-muted mb-0" style="font-size:.85rem">Manage all student records in one place</p>
        </div>
        <div class="btn-group">
            <a href="{% url 'students:student_add' %}" class="btn btn-primary btn-sm">
                <i class="fas fa-user-plus me-1"></i> Add Student
            </a>
            <a href="{% url 'students:import_students_csv' %}" class="btn btn-success btn-sm">
                <i class="fas fa-upload me-1"></i> Import
            </a>
            <a href="{% url 'students:export_students' %}" class="btn btn-info btn-sm">
                <i class="fas fa-download me-1"></i> Export
            </a>
            <button class="btn btn-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown">
                <i class="fas fa-ellipsis-v"></i> More
            </button>
            <ul class="dropdown-menu dropdown-menu-end">
                <li><a class="dropdown-item" href="#" onclick="window.print()"><i class="fas fa-print me-2"></i>Print List</a></li>
                <li><a class="dropdown-item" href="{% url 'students:download_student_sample' %}"><i class="fas fa-file-csv me-2"></i>Sample CSV</a></li>
            </ul>
        </div>
    </div>

    <!-- Stats Row -->
    <div class="row g-2 mb-3">
        <div class="col-6 col-md-3">
            <div class="stat-card">
                <div class="stat-number">{{ total_students }}</div>
                <div class="stat-label">Total Students</div>
            </div>
        </div>
        <div class="col-6 col-md-3">
            <div class="stat-card">
                <div class="stat-number">{{ active_students }}</div>
                <div class="stat-label">Active</div>
            </div>
        </div>
        <div class="col-6 col-md-3">
            <div class="stat-card">
                <div class="stat-number blue">{{ total_classes }}</div>
                <div class="stat-label">Classes with Students</div>
            </div>
        </div>
        <div class="col-6 col-md-3">
            <div class="stat-card">
                <div class="stat-number {% if unassigned_count %}warn{% endif %}">{{ unassigned_count }}</div>
                <div class="stat-label">
                    No Class Assigned
                    {% if unassigned_count %}
                    <a href="?class=none" class="d-block" style="color:#f59e0b;font-size:.75rem">View →</a>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>

    <!-- Filter Bar -->
    <div class="filter-bar">
        <form method="get" id="filterForm">
            {# Preserve sort when filter changes #}
            {% if request.GET.sort %}<input type="hidden" name="sort" value="{{ request.GET.sort }}">{% endif %}
            <div class="row g-2 align-items-end">
                <div class="col-md-3 col-sm-6">
                    <label>Search</label>
                    <div class="input-group input-group-sm">
                        <input type="text" class="form-control" name="q"
                               placeholder="Name, ID, address…" value="{{ request.GET.q }}">
                        <button class="btn btn-light" type="submit"><i class="fas fa-search"></i></button>
                    </div>
                </div>
                <div class="col-md-2 col-sm-6">
                    <label>Class</label>
                    <select class="form-select form-select-sm" name="class">
                        <option value="">All Classes</option>
                        <option value="none" {% if request.GET.class == 'none' %}selected{% endif %}
                                style="color:#dc2626;font-weight:600">
                            ⚠ No Class Assigned
                        </option>
                        <optgroup label="────────────">
                        {% for class in all_classes %}
                        <option value="{{ class.id }}"
                                {% if request.GET.class == class.id|stringformat:"s" %}selected{% endif %}>
                            {{ class.name }}
                        </option>
                        {% endfor %}
                        </optgroup>
                    </select>
                </div>
                <div class="col-md-2 col-sm-4">
                    <label>Gender</label>
                    <select class="form-select form-select-sm" name="gender">
                        <option value="">All</option>
                        <option value="M" {% if request.GET.gender == 'M' %}selected{% endif %}>Male</option>
                        <option value="F" {% if request.GET.gender == 'F' %}selected{% endif %}>Female</option>
                    </select>
                </div>
                <div class="col-md-2 col-sm-4">
                    <label>Status</label>
                    <select class="form-select form-select-sm" name="status">
                        <option value="">All</option>
                        <option value="active"      {% if request.GET.status == 'active' %}selected{% endif %}>Active</option>
                        <option value="inactive"    {% if request.GET.status == 'inactive' %}selected{% endif %}>Inactive</option>
                        <option value="graduated"   {% if request.GET.status == 'graduated' %}selected{% endif %}>Graduated</option>
                        <option value="transferred" {% if request.GET.status == 'transferred' %}selected{% endif %}>Transferred</option>
                    </select>
                </div>
                <div class="col-md-3 col-sm-4 d-flex gap-2">
                    <button type="submit" class="btn btn-light btn-sm flex-grow-1">
                        <i class="fas fa-filter me-1"></i> Apply
                    </button>
                    <a href="{% url 'students:student_list' %}" class="btn btn-outline-light btn-sm">
                        <i class="fas fa-times"></i>
                    </a>
                </div>
            </div>
        </form>
    </div>

    <!-- Result bar: count + sort + view toggle -->
    <div class="result-bar">
        <div>
            {% if filtered_count != total_students %}
            <strong>{{ filtered_count }}</strong> result{{ filtered_count|pluralize }} found
            <span class="text-muted">(of {{ total_students }} total)</span>
            {% if request.GET.class == 'none' %}
            <span class="no-class-badge ms-2"><i class="fas fa-exclamation-triangle me-1"></i>No class filter active</span>
            {% endif %}
            {% else %}
            <strong>{{ total_students }}</strong> student{{ total_students|pluralize }} total
            {% endif %}
            &nbsp;·&nbsp; Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
        </div>

        <div class="d-flex align-items-center gap-3 flex-wrap">
            <!-- Sort -->
            <div class="d-flex align-items-center gap-1" style="font-size:.8rem">
                <span class="text-muted me-1">Sort:</span>
                {% with s=current_sort %}
                <a class="sort-link {% if s == 'name' or s == '-name' %}fw-bold{% endif %}"
                   href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if s == 'name' %}-name{% else %}name{% endif %}">
                    Name {% if s == 'name' %}<i class="fas fa-sort-up"></i>{% elif s == '-name' %}<i class="fas fa-sort-down"></i>{% else %}<i class="fas fa-sort text-muted"></i>{% endif %}
                </a>
                <a class="sort-link {% if s == 'class' or s == '-class' %}fw-bold{% endif %}"
                   href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if s == 'class' %}-class{% else %}class{% endif %}">
                    Class {% if s == 'class' %}<i class="fas fa-sort-up"></i>{% elif s == '-class' %}<i class="fas fa-sort-down"></i>{% else %}<i class="fas fa-sort text-muted"></i>{% endif %}
                </a>
                <a class="sort-link {% if s == 'admitted' or s == '-admitted' %}fw-bold{% endif %}"
                   href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if s == 'admitted' %}-admitted{% else %}admitted{% endif %}">
                    Admitted {% if s == 'admitted' %}<i class="fas fa-sort-up"></i>{% elif s == '-admitted' %}<i class="fas fa-sort-down"></i>{% else %}<i class="fas fa-sort text-muted"></i>{% endif %}
                </a>
                <a class="sort-link {% if s == 'age' or s == '-age' %}fw-bold{% endif %}"
                   href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if s == 'age' %}-age{% else %}age{% endif %}">
                    Age {% if s == 'age' %}<i class="fas fa-sort-up"></i>{% elif s == '-age' %}<i class="fas fa-sort-down"></i>{% else %}<i class="fas fa-sort text-muted"></i>{% endif %}
                </a>
                {% endwith %}
            </div>

            <!-- View Toggle -->
            <div class="btn-group btn-group-sm" role="group">
                <button type="button" class="btn btn-outline-primary active" id="gridViewBtn">
                    <i class="fas fa-th-large"></i> Grid
                </button>
                <button type="button" class="btn btn-outline-primary" id="tableViewBtn">
                    <i class="fas fa-table"></i> Table
                </button>
            </div>
        </div>
    </div>

    <!-- ── GRID VIEW ── -->
    <div id="gridView" class="row g-3">
        {% for student in students %}
        <div class="col-xl-3 col-lg-4 col-md-6">
            <div class="card student-card h-100">
                <div class="card-body">
                    <div class="d-flex align-items-start mb-3">
                        <div class="student-avatar me-3">
                            {{ student.first_name|first|upper }}{{ student.last_name|first|upper }}
                        </div>
                        <div class="flex-grow-1 min-w-0">
                            <div style="font-weight:700;font-size:.9rem;line-height:1.2">
                                {{ student.first_name }} {{ student.last_name }}
                            </div>
                            <div style="font-size:.75rem;color:#888">{{ student.student_id }}</div>
                            {% if student.current_class %}
                            <span class="badge bg-info" style="font-size:.7rem">{{ student.current_class.name }}</span>
                            {% else %}
                            <span class="no-class-badge"><i class="fas fa-exclamation-triangle me-1"></i>No class</span>
                            {% endif %}
                        </div>
                    </div>
                    <div style="font-size:.8rem;color:#555;line-height:1.8">
                        <div><i class="fas fa-birthday-cake text-primary me-2"></i>
                            {{ student.date_of_birth|date:"d M Y"|default:"—" }}
                            {% if student.get_age %}<span class="text-muted">({{ student.get_age }} yrs)</span>{% endif %}
                        </div>
                        <div><i class="fas fa-venus-mars text-primary me-2"></i>{{ student.get_gender_display|default:"—" }}</div>
                        <div><i class="fas fa-calendar-alt text-primary me-2"></i>{{ student.admission_date|date:"d M Y"|default:"—" }}</div>
                    </div>
                    <div class="d-flex justify-content-between align-items-center mt-3">
                        <span class="status-badge status-{{ student.status }}">{{ student.get_status_display|default:"Active" }}</span>
                        <div class="d-flex gap-1">
                            <a href="{% url 'students:student_detail' student.pk %}" class="btn btn-sm btn-outline-primary" title="View"><i class="fas fa-eye"></i></a>
                            <a href="{% url 'students:student_edit' student.pk %}" class="btn btn-sm btn-outline-warning" title="Edit"><i class="fas fa-edit"></i></a>
                            <button class="btn btn-sm btn-outline-danger" data-bs-toggle="modal"
                                    data-bs-target="#del{{ student.pk }}" title="Delete"><i class="fas fa-trash"></i></button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- Delete Modal -->
        <div class="modal fade" id="del{{ student.pk }}" tabindex="-1">
            <div class="modal-dialog modal-sm">
                <div class="modal-content">
                    <div class="modal-header bg-danger text-white py-2">
                        <h6 class="modal-title mb-0">Confirm Delete</h6>
                        <button class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
                    </div>
                    <div class="modal-body" style="font-size:.875rem">
                        Delete <strong>{{ student.first_name }} {{ student.last_name }}</strong>? This cannot be undone.
                    </div>
                    <div class="modal-footer py-2">
                        <button class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Cancel</button>
                        <form action="{% url 'students:student_delete' student.pk %}" method="post" style="display:inline">
                            {% csrf_token %}<button class="btn btn-sm btn-danger">Delete</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12 text-center py-5">
            <i class="fas fa-users fa-3x text-muted mb-3 d-block"></i>
            <h5 class="text-muted">No students found</h5>
            <p class="text-muted">Try adjusting your filters</p>
            {% if request.GET.class == 'none' %}
            <p class="text-success"><i class="fas fa-check-circle me-1"></i>All students have a class assigned!</p>
            {% endif %}
            <a href="{% url 'students:student_list' %}" class="btn btn-outline-secondary btn-sm">Clear filters</a>
        </div>
        {% endfor %}
    </div>

    <!-- ── TABLE VIEW ── -->
    <div id="tableView" style="display:none">
        <div class="card">
            <div class="table-responsive">
                <table class="table table-hover mb-0" style="font-size:.85rem">
                    <thead style="background:#fafafa">
                        <tr>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">
                                <a class="sort-link" href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if current_sort == 'id' %}-id{% else %}id{% endif %}">
                                    ID {% if current_sort == 'id' %}<i class="fas fa-sort-up"></i>{% elif current_sort == '-id' %}<i class="fas fa-sort-down"></i>{% endif %}
                                </a>
                            </th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">Photo</th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">
                                <a class="sort-link" href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if current_sort == 'name' %}-name{% else %}name{% endif %}">
                                    Name {% if current_sort == 'name' %}<i class="fas fa-sort-up"></i>{% elif current_sort == '-name' %}<i class="fas fa-sort-down"></i>{% endif %}
                                </a>
                            </th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">
                                <a class="sort-link" href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if current_sort == 'class' %}-class{% else %}class{% endif %}">
                                    Class {% if current_sort == 'class' %}<i class="fas fa-sort-up"></i>{% elif current_sort == '-class' %}<i class="fas fa-sort-down"></i>{% endif %}
                                </a>
                            </th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">Gender</th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">
                                <a class="sort-link" href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if current_sort == 'age' %}-age{% else %}age{% endif %}">
                                    DOB / Age {% if current_sort == 'age' %}<i class="fas fa-sort-up"></i>{% elif current_sort == '-age' %}<i class="fas fa-sort-down"></i>{% endif %}
                                </a>
                            </th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">Phone</th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">
                                <a class="sort-link" href="?{% if query_string %}{{ query_string }}&{% endif %}sort={% if current_sort == 'admitted' %}-admitted{% else %}admitted{% endif %}">
                                    Admitted {% if current_sort == 'admitted' %}<i class="fas fa-sort-up"></i>{% elif current_sort == '-admitted' %}<i class="fas fa-sort-down"></i>{% endif %}
                                </a>
                            </th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">Status</th>
                            <th style="font-size:.72rem;text-transform:uppercase;letter-spacing:.4px;color:#888">Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for student in students %}
                        <tr {% if not student.current_class %}style="background:#fff9f9"{% endif %}>
                            <td style="font-family:monospace;font-size:.78rem;color:#888">{{ student.student_id }}</td>
                            <td>
                                <div class="student-avatar avatar-sm">
                                    {{ student.first_name|first|upper }}{{ student.last_name|first|upper }}
                                </div>
                            </td>
                            <td><strong>{{ student.first_name }} {{ student.last_name }}</strong></td>
                            <td>
                                {% if student.current_class %}
                                {{ student.current_class.name }}
                                {% else %}
                                <span class="no-class-badge"><i class="fas fa-exclamation-triangle me-1"></i>None</span>
                                {% endif %}
                            </td>
                            <td>{{ student.get_gender_display|default:"—" }}</td>
                            <td>
                                {{ student.date_of_birth|date:"d M Y"|default:"—" }}
                                {% if student.get_age %}<span class="text-muted">({{ student.get_age }})</span>{% endif %}
                            </td>
                            <td>{{ student.phone_number|default:"—" }}</td>
                            <td>{{ student.admission_date|date:"d M Y"|default:"—" }}</td>
                            <td><span class="status-badge status-{{ student.status }}">{{ student.get_status_display|default:"Active" }}</span></td>
                            <td>
                                <div class="d-flex gap-1">
                                    <a href="{% url 'students:student_detail' student.pk %}" class="btn btn-sm btn-outline-primary" title="View"><i class="fas fa-eye"></i></a>
                                    <a href="{% url 'students:student_edit' student.pk %}" class="btn btn-sm btn-outline-warning" title="Edit"><i class="fas fa-edit"></i></a>
                                    <button class="btn btn-sm btn-outline-danger" data-bs-toggle="modal"
                                            data-bs-target="#del{{ student.pk }}" title="Delete"><i class="fas fa-trash"></i></button>
                                </div>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="10" class="text-center py-4 text-muted">No students found.</td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
    </div>

    <!-- ── PAGINATION ── -->
    {% if is_paginated %}
    <div class="pagination-bar">
        <div class="text-muted">
            Showing {{ page_obj.start_index }}–{{ page_obj.end_index }} of {{ filtered_count }}
        </div>
        <div class="d-flex gap-1 flex-wrap">
            <!-- First & Prev -->
            {% if page_obj.has_previous %}
            <a class="page-btn" href="?{% if query_string %}{{ query_string }}&{% endif %}page=1" title="First">«</a>
            <a class="page-btn" href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ page_obj.previous_page_number }}">‹ Prev</a>
            {% else %}
            <span class="page-btn disabled">«</span>
            <span class="page-btn disabled">‹ Prev</span>
            {% endif %}

            <!-- Page numbers — show window of 5 around current -->
            {% for num in page_obj.paginator.page_range %}
                {% if num == 1 or num == page_obj.paginator.num_pages %}
                    {% if num == page_obj.number %}
                    <span class="page-btn active">{{ num }}</span>
                    {% else %}
                    <a class="page-btn" href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ num }}">{{ num }}</a>
                    {% endif %}
                {% elif num >= page_obj.number|add:'-2' and num <= page_obj.number|add:'2' %}
                    {% if num == page_obj.number %}
                    <span class="page-btn active">{{ num }}</span>
                    {% else %}
                    <a class="page-btn" href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ num }}">{{ num }}</a>
                    {% endif %}
                {% elif num == page_obj.number|add:'-3' or num == page_obj.number|add:'3' %}
                <span class="page-btn disabled" style="border:none;background:none">…</span>
                {% endif %}
            {% endfor %}

            <!-- Next & Last -->
            {% if page_obj.has_next %}
            <a class="page-btn" href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ page_obj.next_page_number }}">Next ›</a>
            <a class="page-btn" href="?{% if query_string %}{{ query_string }}&{% endif %}page={{ page_obj.paginator.num_pages }}" title="Last">»</a>
            {% else %}
            <span class="page-btn disabled">Next ›</span>
            <span class="page-btn disabled">»</span>
            {% endif %}
        </div>
        <div class="text-muted">
            Page {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}
        </div>
    </div>
    {% endif %}

</div>
{% endblock %}

{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function () {
    const gridView  = document.getElementById('gridView');
    const tableView = document.getElementById('tableView');
    const gridBtn   = document.getElementById('gridViewBtn');
    const tableBtn  = document.getElementById('tableViewBtn');

    function showGrid() {
        gridView.style.display  = '';
        tableView.style.display = 'none';
        gridBtn.classList.add('active');
        tableBtn.classList.remove('active');
        localStorage.setItem('studentView', 'grid');
    }
    function showTable() {
        gridView.style.display  = 'none';
        tableView.style.display = 'block';
        tableBtn.classList.add('active');
        gridBtn.classList.remove('active');
        localStorage.setItem('studentView', 'table');
    }

    gridBtn.addEventListener('click', showGrid);
    tableBtn.addEventListener('click', showTable);

    // Restore saved preference
    if (localStorage.getItem('studentView') === 'table') showTable();

    // Auto-dismiss alerts
    setTimeout(function () {
        document.querySelectorAll('.alert').forEach(function (el) {
            el.style.transition = 'opacity 1s';
            el.style.opacity = '0';
            setTimeout(() => el.remove(), 1000);
        });
    }, 5000);
});
</script>
{% endblock %}


######################################################################
# ROOT-LEVEL PYTHON FILES
######################################################################

======================================================================
FILE: add_class6_fee_level.py
======================================================================
"""
finance/migrations/XXXX_add_class6_to_fee_class_level.py

Add 'class6' as a valid class_level choice on FeeStructure.

Instructions:
    1. Find the latest migration number in finance/migrations/
       e.g. if latest is 0005_something.py, name this 0006_add_class6_fee_level.py
    2. Update the 'dependencies' line below to match that latest migration
    3. Copy this file to finance/migrations/
    4. Run: python manage.py migrate finance --settings=backend.settings_production
"""

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        # ← UPDATE THIS to your latest finance migration number
        ('finance', '0001_initial'),
    ]

    operations = [
        migrations.AlterField(
            model_name='feestructure',
            name='class_level',
            field=models.CharField(
                max_length=20,
                choices=[
                    ('all',      'All Students'),
                    ('nursery',  'Nursery Section'),
                    ('primary',  'Primary (Class 1–5)'),
                    ('class6',   'Class 6 Only'),
                    ('specific', 'Specific Classes'),
                ],
                default='all',
            ),
        ),
    ]


======================================================================
FILE: assign_teachers_complete.py
======================================================================
# assign_teachers_complete.py
import os
import sys
import django

sys.path.append(os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
django.setup()

from staff.models import Staff
from academics.models import SchoolClass, ClassSubject, Subject

def get_or_create_section_subject(section_type):
    """Get or create subject based on section type"""
    subject_map = {
        'english': {
            'name': 'English Section Subjects',
            'code': 'ENG-ALL'
        },
        'french': {
            'name': 'French Section Subjects',
            'code': 'FR-ALL'
        },
        'bilingual': {
            'name': 'Bilingual Section Subjects',
            'code': 'BI-ALL'
        }
    }
    
    data = subject_map.get(section_type, subject_map['bilingual'])
    subject, _ = Subject.objects.get_or_create(
        name=data['name'],
        defaults={
            'code': data['code'],
            'category': 'core'
        }
    )
    return subject

def assign_teacher(teacher_name, class_name, section_type='english'):
    """Assign teacher to class with appropriate section subject"""
    
    # Find teacher
    try:
        name_parts = teacher_name.split()
        if len(name_parts) >= 3 and name_parts[0] in ['Mme', 'Mr.', 'M.']:
            first_name = name_parts[1]
            last_name = ' '.join(name_parts[2:])
        else:
            first_name = name_parts[0]
            last_name = ' '.join(name_parts[1:])
        
        print(f"   Looking for teacher: first_name='{first_name}', last_name='{last_name}'")
        
        teacher = Staff.objects.get(
            user__first_name__icontains=first_name,
            user__last_name__icontains=last_name
        )
        print(f"   ✅ Found teacher: {teacher.user.get_full_name()}")
    except Staff.DoesNotExist:
        print(f"   ❌ Teacher not found: {teacher_name}")
        return False
    except Staff.MultipleObjectsReturned:
        teachers = Staff.objects.filter(
            user__first_name__icontains=first_name,
            user__last_name__icontains=last_name
        )
        teacher = teachers.first()
        print(f"   ⚠️ Multiple found, using: {teacher.user.get_full_name()}")
    except Exception as e:
        print(f"   ❌ Error finding teacher: {e}")
        return False
    
    # Find class
    try:
        school_class = SchoolClass.objects.get(name=class_name)
        print(f"   ✅ Found class: {school_class.name}")
    except SchoolClass.DoesNotExist:
        print(f"   ❌ Class not found: {class_name}")
        return False
    except Exception as e:
        print(f"   ❌ Error finding class: {e}")
        return False
    
    # Get appropriate subject based on section
    subject = get_or_create_section_subject(section_type)
    print(f"   📚 Using subject: {subject.name}")
    
    # Create or update assignment
    try:
        assignment, created = ClassSubject.objects.get_or_create(
            school_class=school_class,
            subject=subject,
            defaults={'teacher': teacher}
        )
        
        if not created and assignment.teacher != teacher:
            assignment.teacher = teacher
            assignment.save()
            print(f"   🔄 Updated: {teacher.user.get_full_name()} → {class_name} ({section_type})")
        elif created:
            print(f"   ✅ Assigned: {teacher.user.get_full_name()} → {class_name} ({section_type})")
        else:
            print(f"   ⏭️ Already assigned: {teacher.user.get_full_name()} → {class_name}")
        
        return True
    except Exception as e:
        print(f"   ❌ Error creating assignment: {e}")
        return False

def main():
    print("=" * 60)
    print("ASSIGNING TEACHERS TO CLASSES")
    print("=" * 60)
    
    # Based on your Excel data
    assignments = [
        # English Section Teachers
        {'teacher_name': 'Mme Shey Annie', 'class_name': 'Class 6', 'section_type': 'english'},
        {'teacher_name': 'Mr. Ndem Gordon', 'class_name': 'Class 5', 'section_type': 'english'},
        {'teacher_name': 'Mr. Nebongo Celestine', 'class_name': 'Class 4', 'section_type': 'english'},
        {'teacher_name': 'Mr. Nebongo Celestine', 'class_name': 'Class 3', 'section_type': 'english'},
        {'teacher_name': 'Mme Nguveha Cecil', 'class_name': 'Class 2', 'section_type': 'english'},
        {'teacher_name': 'Mme Tabi Cynthia', 'class_name': 'Class 2', 'section_type': 'english'},  # Second teacher
        {'teacher_name': 'Mme Nguveha Cecil', 'class_name': 'Class 1', 'section_type': 'english'},
        
        # Bilingual/French Section Teachers
        {'teacher_name': 'Mme Labo Longpa Josiane', 'class_name': 'SIL', 'section_type': 'bilingual'},
        {'teacher_name': 'Mme Labo Longpa Josiane', 'class_name': 'CP', 'section_type': 'bilingual'},
        {'teacher_name': 'Mme Mbachang Melanie', 'class_name': 'CP', 'section_type': 'bilingual'},
        {'teacher_name': 'Mme Ngakwe Naomi', 'class_name': 'CE1', 'section_type': 'french'},
        {'teacher_name': 'Mme Dongmo Evine', 'class_name': 'CE2', 'section_type': 'french'},
        {'teacher_name': 'Mme Nkwain Prisca', 'class_name': 'CM1', 'section_type': 'french'},
        {'teacher_name': 'Mme Leudjeu Liliane', 'class_name': 'CM2', 'section_type': 'french'},
        
        # Nursery Teachers
        {'teacher_name': 'Mme Fongang Noella', 'class_name': 'Pre-Nursery', 'section_type': 'english'},
        {'teacher_name': 'Mme Epie Zita', 'class_name': 'Nursery 1', 'section_type': 'english'},
        {'teacher_name': 'Mme Fossem Alice', 'class_name': 'Nursery 2', 'section_type': 'english'},
        {'teacher_name': 'Mme Nkayengam Aminatou', 'class_name': 'Moyenne Section', 'section_type': 'bilingual'},
        {'teacher_name': 'Mme Charlotte Mouil', 'class_name': 'Grande Section', 'section_type': 'bilingual'},
    ]
    
    success = 0
    for i, assignment in enumerate(assignments, 1):
        print(f"\n{i}. 📝 {assignment['teacher_name']} → {assignment['class_name']}")
        if assign_teacher(
            teacher_name=assignment['teacher_name'],
            class_name=assignment['class_name'],
            section_type=assignment['section_type']
        ):
            success += 1
    
    print("\n" + "=" * 60)
    print(f"✅ SUMMARY: {success}/{len(assignments)} assignments successful")
    print("=" * 60)

if __name__ == "__main__":
    main()

======================================================================
FILE: check_urls.py
======================================================================
# check_urls.py
import sys
import os
import django

# Setup Django
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
django.setup()

from django.urls import get_resolver

def show_urls():
    print("\n" + "="*60)
    print("REGISTERED URL PATTERNS")
    print("="*60)
    
    resolver = get_resolver()
    url_patterns = []
    
    def collect_urls(patterns, prefix=''):
        for pattern in patterns:
            if hasattr(pattern, 'url_patterns'):
                # It's an included URL conf
                new_prefix = prefix + str(pattern.pattern)
                collect_urls(pattern.url_patterns, new_prefix)
            else:
                # It's a single URL pattern
                url = prefix + str(pattern.pattern)
                name = getattr(pattern, 'name', None)
                namespace = getattr(pattern, 'namespace', None)
                url_patterns.append((url, name, namespace))
    
    collect_urls(resolver.url_patterns)
    
    # Sort by URL
    url_patterns.sort(key=lambda x: x[0])
    
    # Print by app
    current_app = None
    for url, name, namespace in url_patterns:
        if namespace and namespace != current_app:
            current_app = namespace
            print(f"\n[{current_app.upper()}]")
        
        if name:
            print(f"  {url:40} - {name}")
        else:
            print(f"  {url:40}")

if __name__ == '__main__':
    show_urls()

======================================================================
FILE: deployment_check.py
======================================================================
# deployment_check.py
checklist = [
    ("✅", "Home Page", "/"),
    ("✅", "Dashboard", "/dashboard/"),
    ("✅", "Student Portal", "/students/"),
    ("📝", "Attendance Module", "/attendance/"),
    ("📝", "Finance Module", "/finance/"),
    ("⏳", "Parent Portal", "/parents/"),
    ("⏳", "Reports Module", "/reports/"),
    ("⏳", "Communication Module", "/communication/"),
    ("✅", "Admin Interface", "/admin/"),
]

print("🚀 RAPHA-BETHEL BNPS DEPLOYMENT STATUS")
print("=" * 60)
print("\nModule Status:")
for status, module, url in checklist:
    print(f"{status} {module}: http://127.0.0.1:8000{url}")

print("\n" + "=" * 60)
print("\n📈 NEXT PRIORITIES:")
print("1. Complete Attendance Module (Marking, Viewing, Reports)")
print("2. Complete Finance Module (Invoices, Payments, Fee Structure)")
print("3. Create Parent Portal (View child progress and fees)")
print("4. Add Reports (Academic, Financial, Attendance analytics)")
print("5. Mobile Responsive Optimization")

======================================================================
FILE: fix_class6_fees.py
======================================================================
#!/usr/bin/env python3
"""
fix_class6_fees.py
==================
One-time script — sets class_level='class6' on all fee structures
that currently have class_level='specific' and are linked to Class 6,
OR that have no specific_classes linked (broken migration state).

Run on DEV first:
    python fix_class6_fees.py --settings=backend.settings

Then on production:
    OPENBLAS_NUM_THREADS=1 python fix_class6_fees.py --settings=backend.settings_production
"""

import os, sys, argparse
from pathlib import Path

parser = argparse.ArgumentParser()
parser.add_argument('--settings', default='backend.settings_production')
parser.add_argument('--dry-run', action='store_true')
args = parser.parse_args()

sys.path.insert(0, str(Path(__file__).resolve().parent))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', args.settings)
os.environ.setdefault('OPENBLAS_NUM_THREADS', '1')

import django
django.setup()

from finance.models import FeeStructure
from academics.models import SchoolClass

DRY = args.dry_run
if DRY:
    print("DRY RUN — no changes written\n")

# Find the Class 6 SchoolClass object
class6 = SchoolClass.objects.filter(level='class6').first()
if not class6:
    # Try by name/code
    class6 = SchoolClass.objects.filter(
        name__icontains='class 6'
    ).first() or SchoolClass.objects.filter(code__icontains='CL6').first()

print(f"Class 6 object: {class6} (level={class6.level if class6 else 'NOT FOUND'})\n")

# Show all fee structures to understand current state
print("ALL ACTIVE MANDATORY FEE STRUCTURES:")
print(f"{'ID':<5} {'NAME':<45} {'class_level':<12} {'specific_classes'}")
print("-" * 90)

fees = FeeStructure.objects.filter(is_active=True).order_by('class_level', 'name')
for f in fees:
    linked = list(f.specific_classes.values_list('name', flat=True))
    print(f"  {f.pk:<4} {f.name[:44]:<45} {f.class_level:<12} {linked or '—'}")

print()

# Find fees that should be class6:
# 1. class_level='specific' with Class 6 in specific_classes
# 2. class_level='specific' with NO specific_classes (broken — likely Class 6 fees)
to_fix = []

for f in FeeStructure.objects.filter(is_active=True, is_mandatory=True):
    linked = list(f.specific_classes.all())
    if f.class_level == 'specific':
        if class6 and class6 in linked:
            to_fix.append((f, 'specific → class6 (was linked to Class 6)'))
        elif not linked:
            to_fix.append((f, 'specific → class6 (no specific_classes — broken migration)'))

print(f"\nFees to fix ({len(to_fix)}):")
for f, reason in to_fix:
    print(f"  [{f.pk}] {f.name} — {reason}")

if not to_fix:
    print("  Nothing to fix! Fees may already be correct.")
    print("\n  If Class 6 invoices still don't generate, check that:")
    print("  1. FeeStructure.class_level choices include 'class6'")
    print("  2. finance_views.py has the class6 branch in _fee_applies_to_student")
    sys.exit(0)

if DRY:
    print("\nDry run complete — run without --dry-run to apply.")
    sys.exit(0)

confirm = input("\nApply fixes? (yes/no): ").strip().lower()
if confirm != 'yes':
    print("Aborted.")
    sys.exit(0)

fixed = 0
for f, reason in to_fix:
    f.class_level = 'class6'
    f.save(update_fields=['class_level'])
    print(f"  Fixed: {f.name}")
    fixed += 1

print(f"\nDone. {fixed} fee structures updated to class_level='class6'.")
print("Class 6 students should now get invoices in bulk generation.")


======================================================================
FILE: migrate_to_prod.py
======================================================================
#!/usr/bin/env python3
"""
migrate_to_prod.py  v2
======================
Migrates data from local SQLite JSON fixture → production MySQL.

Fixes in v2:
  - Strips Unicode replacement chars (\\xEF\\xBF\\xBD / U+FFFD) from all text
    fields before writing — MySQL utf8mb3 tables reject them.
  - Staff users already exist in prod → builds user_map by matching username
    instead of relying on dry-run pk mapping.
  - Skips staff user creation by default (--skip-staff flag).

Usage (run on the server inside the virtualenv):

    # Classes, subjects, students, fees only (staff already in prod):
    OPENBLAS_NUM_THREADS=1 python migrate_to_prod.py \\
        --fixture all_db_backup.json --skip-staff --skip-attendance

    # Everything:
    OPENBLAS_NUM_THREADS=1 python migrate_to_prod.py --fixture all_db_backup.json

    # Dry-run preview:
    OPENBLAS_NUM_THREADS=1 python migrate_to_prod.py \\
        --fixture all_db_backup.json --dry-run --skip-staff
"""

import os, sys, json, argparse
from pathlib import Path

# ── CLI ───────────────────────────────────────────────────────────────────────
parser = argparse.ArgumentParser()
parser.add_argument('--fixture', default='all_db_backup.json')
parser.add_argument('--dry-run', action='store_true')
parser.add_argument('--skip-staff', action='store_true',
                    help='Skip user/staff creation (staff already in prod)')
parser.add_argument('--skip-attendance', action='store_true')
parser.add_argument('--settings', default='backend.settings_production')
args = parser.parse_args()

# ── Django setup ──────────────────────────────────────────────────────────────
sys.path.insert(0, str(Path(__file__).resolve().parent))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', args.settings)
os.environ.setdefault('OPENBLAS_NUM_THREADS', '1')
os.environ.setdefault('OMP_NUM_THREADS', '1')

import django
django.setup()

from core.models import CustomUser, School
from academics.models import SchoolClass, Subject, ClassSubject, Attendance
from finance.models import FeeStructure, ExpenseCategory
from staff.models import Staff
from students.models import Student

DRY = args.dry_run
if DRY:
    print("DRY RUN - nothing will be written\n")

# ── Load fixture ──────────────────────────────────────────────────────────────
fixture_path = Path(args.fixture)
if not fixture_path.exists():
    sys.exit(f"Fixture not found: {fixture_path}")

with open(fixture_path, encoding='utf-8') as f:
    raw = json.load(f)

print(f"Loaded {len(raw)} records from {fixture_path.name}\n")


# ── Helpers ───────────────────────────────────────────────────────────────────
def by_model(name):
    return [r for r in raw if r['model'] == name]

def clean(value):
    """Strip Unicode replacement characters that MySQL utf8mb3 rejects."""
    if not isinstance(value, str):
        return value
    return value.replace('\ufffd', '').replace('\x00', '').strip()

stats = {}
def log(model, action, name=''):
    stats.setdefault(model, {'created': 0, 'updated': 0, 'skipped': 0})
    stats[model][action] += 1
    sym = {'created': '+', 'updated': '~', 'skipped': '-'}[action]
    print(f"  {sym} [{model}] {action:8s}  {name}")


# ══════════════════════════════════════════════════════════════════════════════
# 1. SCHOOL
# ══════════════════════════════════════════════════════════════════════════════
print("--- 1. SCHOOL ---")

school_map = {}
for r in by_model('core.school'):
    f = r['fields']
    if DRY:
        print(f"  Would upsert: {f['name']}")
        continue
    obj, created = School.objects.update_or_create(
        code=f['code'],
        defaults={
            'name':            clean(f['name']),
            'address':         clean(f.get('address', '')),
            'city':            clean(f.get('city', '')),
            'quarter':         clean(f.get('quarter', '')),
            'phone':           clean(f.get('phone', '')),
            'email':           clean(f.get('email', '')),
            'website':         clean(f.get('website', '')),
            'principal_name':  clean(f.get('principal_name', '')),
            'principal_phone': clean(f.get('principal_phone', '')),
            'academic_year':   f.get('academic_year', '2025-2026'),
            'current_term':    f.get('current_term', 1),
            'is_bilingual':    f.get('is_bilingual', True),
        }
    )
    school_map[r['pk']] = obj
    log('school', 'created' if created else 'updated', f['name'])

default_school = School.objects.first()
# If school already existed and was updated, populate map
if not school_map:
    for r in by_model('core.school'):
        try:
            school_map[r['pk']] = School.objects.get(code=r['fields']['code'])
        except School.DoesNotExist:
            pass
if not school_map:
    school_map[1] = default_school
print()


# ══════════════════════════════════════════════════════════════════════════════
# 2. SUBJECTS
# ══════════════════════════════════════════════════════════════════════════════
print("--- 2. SUBJECTS ---")

subject_map = {}
for r in by_model('academics.subject'):
    f = r['fields']
    if DRY:
        print(f"  Would upsert: {f['name']}")
        subject_map[r['pk']] = r['pk']
        continue
    obj, created = Subject.objects.update_or_create(
        code=f['code'],
        defaults={
            'name':        clean(f['name']),
            'name_fr':     clean(f.get('name_fr', '')),
            'category':    f.get('category', 'core'),
            'description': clean(f.get('description', '')),
        }
    )
    subject_map[r['pk']] = obj
    log('subject', 'created' if created else 'updated', f['name'])
print()


# ══════════════════════════════════════════════════════════════════════════════
# 3. CLASSES  (pass 1 - no class_teacher yet)
# ══════════════════════════════════════════════════════════════════════════════
print("--- 3. SCHOOL CLASSES ---")

class_map = {}
for r in by_model('academics.schoolclass'):
    f = r['fields']
    if DRY:
        print(f"  Would upsert: {f['code']}")
        class_map[r['pk']] = r['pk']
        continue
    obj, created = SchoolClass.objects.update_or_create(
        code=f['code'],
        academic_year=f.get('academic_year', '2025-2026'),
        defaults={
            'name':         clean(f['name']),
            'level':        f['level'],
            'section':      f.get('section', 'A'),
            'section_type': f.get('section_type', 'english'),
            'capacity':     f.get('capacity', 40),
            'room_number':  f.get('room_number', ''),
            'class_teacher': None,
        }
    )
    class_map[r['pk']] = obj
    log('schoolclass', 'created' if created else 'updated', f['code'])
print()


# ══════════════════════════════════════════════════════════════════════════════
# 4. FEE STRUCTURES
# ══════════════════════════════════════════════════════════════════════════════
print("--- 4. FEE STRUCTURES ---")

for r in by_model('finance.feestructure'):
    f = r['fields']
    name    = clean(f['name'])
    name_fr = clean(f.get('name_fr', ''))
    if DRY:
        print(f"  Would upsert: {name}")
        continue
    obj, created = FeeStructure.objects.update_or_create(
        name=name,
        academic_year=f.get('academic_year', '2025-2026'),
        defaults={
            'name_fr':            name_fr,
            'fee_type':           f['fee_type'],
            'class_level':        f['class_level'],
            'term':               f['term'],
            'amount':             f['amount'],
            'payment_frequency':  f.get('payment_frequency', 'termly'),
            'is_mandatory':       f.get('is_mandatory', True),
            'description':        clean(f.get('description', '')),
            'description_fr':     clean(f.get('description_fr', '')),
            'is_active':          f.get('is_active', True),
        }
    )
    log('feestructure', 'created' if created else 'updated', name[:55])
print()


# ══════════════════════════════════════════════════════════════════════════════
# 5. EXPENSE CATEGORIES
# ══════════════════════════════════════════════════════════════════════════════
print("--- 5. EXPENSE CATEGORIES ---")

for r in by_model('finance.expensecategory'):
    f = r['fields']
    if DRY:
        print(f"  Would upsert: {f['name']}")
        continue
    obj, created = ExpenseCategory.objects.update_or_create(
        name=clean(f['name']),
        defaults={
            'name_fr':     clean(f.get('name_fr', '')),
            'description': clean(f.get('description', '')),
            'is_active':   f.get('is_active', True),
        }
    )
    log('expensecategory', 'created' if created else 'updated', f['name'])
print()


# ══════════════════════════════════════════════════════════════════════════════
# 6 & 7. USERS + STAFF
# ══════════════════════════════════════════════════════════════════════════════
user_records = {r['pk']: r['fields'] for r in by_model('core.customuser')}
user_map  = {}
staff_map = {}

if args.skip_staff:
    print("--- 6-7. USERS/STAFF --- skipped (--skip-staff)")
    # Build maps from existing prod DB so class-teacher linking works
    for old_pk, f in user_records.items():
        try:
            user_map[old_pk] = CustomUser.objects.get(username=f['username'])
        except CustomUser.DoesNotExist:
            pass
    for r in by_model('staff.staff'):
        u = user_map.get(r['fields']['user'])
        if u:
            try:
                staff_map[r['pk']] = Staff.objects.get(user=u)
            except Staff.DoesNotExist:
                pass
    print(f"  Mapped {len(user_map)} users, {len(staff_map)} staff from prod DB\n")

else:
    print("--- 6. CUSTOM USERS ---")
    for old_pk, f in user_records.items():
        if f.get('is_superuser'):
            try:
                user_map[old_pk] = CustomUser.objects.get(username=f['username'])
            except CustomUser.DoesNotExist:
                pass
            print(f"  - skipped superuser: {f['username']}")
            continue
        if DRY:
            print(f"  Would upsert: {f['username']}")
            continue
        defaults = {
            'first_name': f.get('first_name', ''),
            'last_name':  f.get('last_name', ''),
            'email':      f.get('email', ''),
            'is_staff':   f.get('is_staff', False),
            'is_active':  f.get('is_active', True),
            'user_type':  f.get('user_type', 'teacher'),
            'phone':      f.get('phone', ''),
            'mobile_money_number': f.get('mobile_money_number', ''),
            'employee_id':  f.get('employee_id'),
            'teacher_id':   f.get('teacher_id', ''),
            'access_level': f.get('access_level', 1),
            'oversees_section': f.get('oversees_section', 'none'),
            'financial_access': f.get('financial_access', False),
            'is_primary_contact': f.get('is_primary_contact', False),
        }
        obj, created = CustomUser.objects.get_or_create(
            username=f['username'], defaults=defaults)
        if not created:
            for k, v in defaults.items():
                setattr(obj, k, v)
            obj.save()
        else:
            obj.password = f['password']
            obj.save()
        user_map[old_pk] = obj
        log('customuser', 'created' if created else 'updated', f['username'])

    print()
    print("--- 7. STAFF PROFILES ---")
    for r in by_model('staff.staff'):
        f = r['fields']
        user_obj = user_map.get(f['user'])
        if not user_obj:
            log('staff', 'skipped', f"pk={r['pk']} no user")
            continue
        homeroom_obj = class_map.get(f.get('homeroom_class'))
        if DRY:
            print(f"  Would upsert staff for: {user_obj}")
            continue
        obj, created = Staff.objects.update_or_create(
            user=user_obj,
            defaults={
                'school':       school_map.get(f.get('school'), default_school),
                'employee_id':  f.get('employee_id', ''),
                'title':        f.get('title', ''),
                'date_of_birth': f.get('date_of_birth'),
                'gender':       f.get('gender', 'M'),
                'nationality':  f.get('nationality', 'Cameroonian'),
                'marital_status': f.get('marital_status', 'single'),
                'phone_country_code': f.get('phone_country_code', '+237'),
                'phone_number': f.get('phone_number', ''),
                'alt_phone_country_code': f.get('alt_phone_country_code', '+237'),
                'alternate_phone': f.get('alternate_phone', ''),
                'email':        f.get('email', ''),
                'address':      clean(f.get('address', '')),
                'quarter':      f.get('quarter', ''),
                'city':         f.get('city', 'Douala'),
                'emergency_contact_name': f.get('emergency_contact_name', ''),
                'emergency_phone_country_code': f.get('emergency_phone_country_code', '+237'),
                'emergency_contact_phone': f.get('emergency_contact_phone', ''),
                'emergency_contact_relationship': f.get('emergency_contact_relationship', ''),
                'role':         f.get('role', 'teacher'),
                'department':   f.get('department', ''),
                'employment_status': f.get('employment_status', 'permanent'),
                'hire_date':    f.get('hire_date'),
                'qualifications': clean(f.get('qualifications', '')),
                'specialization': f.get('specialization', ''),
                'years_of_experience': f.get('years_of_experience', 0),
                'is_class_teacher': f.get('is_class_teacher', False),
                'homeroom_class': homeroom_obj,
                'bank_name':    f.get('bank_name', ''),
                'notes':        clean(f.get('notes', '')),
                'is_active':    f.get('is_active', True),
            }
        )
        staff_map[r['pk']] = obj
        log('staff', 'created' if created else 'updated',
            f"{user_obj.first_name} {user_obj.last_name}")
    print()


# ══════════════════════════════════════════════════════════════════════════════
# 7b. LINK CLASS TEACHERS
# ══════════════════════════════════════════════════════════════════════════════
print("--- 7b. LINK CLASS TEACHERS ---")

for r in by_model('academics.schoolclass'):
    f = r['fields']
    old_teacher_pk = f.get('class_teacher')
    if not old_teacher_pk:
        continue
    new_class = class_map.get(r['pk'])
    new_staff = staff_map.get(old_teacher_pk)
    if not new_class or not new_staff:
        print(f"  - {f['code']} teacher pk={old_teacher_pk} not mapped")
        continue
    if DRY:
        print(f"  Would link {f['code']} -> staff_pk={old_teacher_pk}")
        continue
    new_class.class_teacher = new_staff
    new_class.save(update_fields=['class_teacher'])
    print(f"  ~ {new_class.code:10s} -> {new_staff.user.get_full_name()}")
print()


# ══════════════════════════════════════════════════════════════════════════════
# 8. STUDENTS
# ══════════════════════════════════════════════════════════════════════════════
print("--- 8. STUDENTS ---")

student_map = {}
for r in by_model('students.student'):
    f = r['fields']
    new_class = class_map.get(f.get('current_class'))
    if DRY:
        print(f"  Would upsert: {f['first_name']} {f['last_name']}")
        continue
    obj, created = Student.objects.update_or_create(
        student_id=f['student_id'],
        defaults={
            'first_name':    clean(f['first_name']),
            'last_name':     clean(f['last_name']),
            'date_of_birth': f.get('date_of_birth'),
            'place_of_birth': clean(f.get('place_of_birth') or ''),
            'gender':        f.get('gender', 'M'),
            'nationality':   f.get('nationality', 'Cameroonian'),
            'home_address':  clean(f.get('home_address', '')),
            'quarter':       f.get('quarter', ''),
            'city':          f.get('city', 'Douala'),
            'phone_number':  f.get('phone_number', ''),
            'email':         f.get('email', ''),
            'emergency_contact_name':  f.get('emergency_contact_name', ''),
            'emergency_contact_phone': f.get('emergency_contact_phone', ''),
            'emergency_contact_relationship': f.get('emergency_contact_relationship', ''),
            'blood_group':   f.get('blood_group', 'unknown'),
            'allergies':     f.get('allergies', ''),
            'chronic_conditions': f.get('chronic_conditions', ''),
            'medications':   f.get('medications', ''),
            'admission_date': f.get('admission_date'),
            'admission_class': f.get('admission_class', ''),
            'current_class': new_class,
            'status':        f.get('status', 'active'),
            'notes':         clean(f.get('notes', '')),
            'imported_from': f.get('imported_from', ''),
        }
    )
    student_map[r['pk']] = obj
    log('student', 'created' if created else 'updated',
        f"{f['first_name']} {f['last_name']} ({f['student_id']})")
print()


# ══════════════════════════════════════════════════════════════════════════════
# 9. CLASS SUBJECTS
# ══════════════════════════════════════════════════════════════════════════════
print("--- 9. CLASS SUBJECT ASSIGNMENTS ---")

for r in by_model('academics.classsubject'):
    f = r['fields']
    new_class   = class_map.get(f['school_class'])
    new_subject = subject_map.get(f['subject'])
    new_teacher = staff_map.get(f.get('teacher'))

    if not new_class or not new_subject:
        print(f"  - skipped: class_pk={f['school_class']} subject_pk={f['subject']} not mapped")
        continue
    if DRY:
        print(f"  Would upsert: class_pk={f['school_class']} / subject_pk={f['subject']}")
        continue
    obj, created = ClassSubject.objects.update_or_create(
        school_class=new_class,
        subject=new_subject,
        defaults={
            'teacher':       new_teacher,
            'hours_per_week': f.get('hours_per_week', 0),
        }
    )
    log('classsubject', 'created' if created else 'updated',
        f"{new_class.code} / {new_subject.name}")
print()


# ══════════════════════════════════════════════════════════════════════════════
# 10. ATTENDANCE
# ══════════════════════════════════════════════════════════════════════════════
attendance_records = by_model('academics.attendance')
if args.skip_attendance:
    print(f"--- 10. ATTENDANCE --- skipped ({len(attendance_records)} records)\n")
else:
    print(f"--- 10. ATTENDANCE ({len(attendance_records)} records) ---")
    n_created = n_skipped = 0
    for r in attendance_records:
        f = r['fields']
        new_student = student_map.get(f['student'])
        new_class   = class_map.get(f['school_class'])
        marked_by   = user_map.get(f.get('marked_by'))
        if not new_student or not new_class or DRY:
            n_skipped += 1
            continue
        obj, created = Attendance.objects.get_or_create(
            student=new_student, date=f['date'], school_class=new_class,
            defaults={
                'status':    f.get('status', 'present'),
                'period':    f.get('period', 'full_day'),
                'marked_by': marked_by,
                'remarks':   f.get('remarks', ''),
            }
        )
        if created: n_created += 1
        else: n_skipped += 1
    print(f"  + created: {n_created}  |  - already existed: {n_skipped}")
    print()


# ══════════════════════════════════════════════════════════════════════════════
# SUMMARY
# ══════════════════════════════════════════════════════════════════════════════
print("--- SUMMARY ---")
for model, counts in stats.items():
    print(f"  {model:22s}  +{counts['created']:3d} created  "
          f"~{counts['updated']:3d} updated  -{counts['skipped']:3d} skipped")
print()
if DRY:
    print("DRY RUN complete - nothing written.")
else:
    print("Migration complete!")
    print("Verify at:")
    print("  https://raphabethel.org/portal/staff/")
    print("  https://raphabethel.org/portal/students/")
    print("  https://raphabethel.org/portal/academics/classes/")
    print("  https://raphabethel.org/portal/finance/fees/")

======================================================================
FILE: next-steps.py
======================================================================
# next_steps.py
import os
import subprocess

def setup_next_features():
    print("🚀 SETTING UP NEXT FEATURES FOR RAPHA-BETHEL BNPS")
    print("=" * 60)
    
    steps = [
        {
            "title": "1. Enhanced Dashboard with Charts",
            "description": "Add interactive charts for attendance, revenue, and enrollment",
            "status": "✅ Already implemented above"
        },
        {
            "title": "2. Student Portal",
            "description": "Create student list and detail pages with search and filters",
            "status": "📝 Ready to implement"
        },
        {
            "title": "3. Attendance Management",
            "description": "Create daily attendance marking interface",
            "files": [
                "academics/views.py - AttendanceMarkingView",
                "templates/attendance/mark.html",
                "templates/attendance/report.html"
            ]
        },
        {
            "title": "4. Fee Management",
            "description": "Create invoice generation and payment tracking",
            "files": [
                "finance/views.py - InvoiceListView, PaymentView",
                "templates/finance/invoices.html",
                "templates/finance/payments.html"
            ]
        },
        {
            "title": "5. Parent Portal",
            "description": "Create portal for parents to view student progress and fees",
            "files": [
                "parents/views.py - ParentDashboardView",
                "templates/parents/dashboard.html"
            ]
        },
        {
            "title": "6. Reports Module",
            "description": "Generate academic and financial reports",
            "files": [
                "reports/views.py - ReportView",
                "templates/reports/academic.html",
                "templates/reports/financial.html"
            ]
        },
        {
            "title": "7. Mobile Responsive Design",
            "description": "Ensure all pages work perfectly on mobile devices",
            "status": "📱 In progress"
        },
        {
            "title": "8. API Endpoints",
            "description": "Create REST API for potential mobile app integration",
            "files": [
                "api/views.py - API endpoints",
                "api/serializers.py - Data serializers"
            ]
        }
    ]
    
    for step in steps:
        print(f"\n{step['title']}")
        print(f"   {step['description']}")
        if 'status' in step:
            print(f"   Status: {step['status']}")
        if 'files' in step:
            print(f"   Files to create:")
            for file in step['files']:
                print(f"     - {file}")
    
    print("\n" + "=" * 60)
    print("\n📋 QUICK START COMMANDS:")
    print("""
# Create student portal templates
mkdir -p templates/students
touch templates/students/student_list.html
touch templates/students/student_detail.html

# Create attendance templates
mkdir -p templates/attendance
touch templates/attendance/mark.html
touch templates/attendance/report.html

# Create finance templates
mkdir -p templates/finance
touch templates/finance/invoices.html
touch templates/finance/payments.html

# Update URLs
echo '
# Add to backend/urls.py
path("attendance/", include("academics.urls")),
path("finance/", include("finance.urls")),
' >> backend/urls.py
""")

def create_student_portal():
    print("\n🎓 CREATING STUDENT PORTAL TEMPLATES...")
    
    base_dir = os.path.dirname(os.path.abspath(__file__))
    
    # Create student list template
    student_list_content = '''{% extends 'base.html' %}
{% load static %}

{% block title %}Students - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Students ({{ total_count }})</h1>
        <div class="btn-group">
            <a href="/admin/students/student/add/" class="btn btn-primary">
                <i class="fas fa-user-plus"></i> Add Student
            </a>
            <button class="btn btn-outline-primary" onclick="window.print()">
                <i class="fas fa-print"></i> Print
            </button>
        </div>
    </div>

    <!-- Stats -->
    <div class="row mb-4">
        <div class="col-md-3">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
                        Total Students
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">{{ total_count }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
                        Active Students
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">{{ active_count }}</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-info shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-info text-uppercase mb-1">
                        Male Students
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">
                        {{ students|dictsort:"gender"|length }}  <!-- Update with actual count -->
                    </div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
                        Female Students
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">
                        {{ students|dictsortreversed:"gender"|length }}  <!-- Update with actual count -->
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Search and Filter -->
    <div class="card shadow mb-4">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Search & Filter</h6>
        </div>
        <div class="card-body">
            <form method="get" class="row g-3">
                <div class="col-md-4">
                    <input type="text" class="form-control" name="q" placeholder="Search by name or ID...">
                </div>
                <div class="col-md-3">
                    <select class="form-control" name="class">
                        <option value="">All Classes</option>
                        <!-- Add class options dynamically -->
                    </select>
                </div>
                <div class="col-md-3">
                    <select class="form-control" name="status">
                        <option value="">All Status</option>
                        <option value="active">Active</option>
                        <option value="inactive">Inactive</option>
                        <option value="graduated">Graduated</option>
                    </select>
                </div>
                <div class="col-md-2">
                    <button type="submit" class="btn btn-primary w-100">
                        <i class="fas fa-search"></i> Filter
                    </button>
                </div>
            </form>
        </div>
    </div>

    <!-- Student Table -->
    <div class="card shadow">
        <div class="card-body">
            <div class="table-responsive">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>Student ID</th>
                            <th>Name</th>
                            <th>Class</th>
                            <th>Gender</th>
                            <th>Admission Date</th>
                            <th>Status</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for student in students %}
                        <tr>
                            <td>
                                <strong>{{ student.student_id }}</strong>
                            </td>
                            <td>
                                {{ student.first_name }} {{ student.last_name }}<br>
                                <small class="text-muted">{{ student.date_of_birth|date:"d M Y" }}</small>
                            </td>
                            <td>
                                {% if student.current_class %}
                                <span class="badge badge-info">{{ student.current_class }}</span>
                                {% else %}
                                <span class="badge badge-secondary">Not Assigned</span>
                                {% endif %}
                            </td>
                            <td>
                                {% if student.gender == 'M' %}
                                <span class="badge badge-primary">Male</span>
                                {% else %}
                                <span class="badge badge-pink">Female</span>
                                {% endif %}
                            </td>
                            <td>{{ student.admission_date|date:"d M Y" }}</td>
                            <td>
                                {% if student.status == 'active' %}
                                <span class="badge badge-success">Active</span>
                                {% elif student.status == 'graduated' %}
                                <span class="badge badge-secondary">Graduated</span>
                                {% else %}
                                <span class="badge badge-warning">{{ student.status|title }}</span>
                                {% endif %}
                            </td>
                            <td>
                                <a href="{% url 'student_detail' student.pk %}" class="btn btn-sm btn-info">
                                    <i class="fas fa-eye"></i>
                                </a>
                                <a href="/admin/students/student/{{ student.pk }}/change/" 
                                   class="btn btn-sm btn-warning">
                                    <i class="fas fa-edit"></i>
                                </a>
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="7" class="text-center py-4">
                                <i class="fas fa-users fa-2x text-muted mb-3"></i>
                                <p class="text-muted">No students found</p>
                                <a href="/admin/students/student/add/" class="btn btn-primary">
                                    <i class="fas fa-user-plus"></i> Add First Student
                                </a>
                            </td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>
            
            <!-- Pagination -->
            {% if is_paginated %}
            <nav aria-label="Page navigation">
                <ul class="pagination justify-content-center">
                    {% if page_obj.has_previous %}
                    <li class="page-item">
                        <a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
                    </li>
                    {% endif %}
                    
                    {% for num in page_obj.paginator.page_range %}
                    <li class="page-item {% if page_obj.number == num %}active{% endif %}">
                        <a class="page-link" href="?page={{ num }}">{{ num }}</a>
                    </li>
                    {% endfor %}
                    
                    {% if page_obj.has_next %}
                    <li class="page-item">
                        <a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a>
                    </li>
                    {% endif %}
                </ul>
            </nav>
            {% endif %}
        </div>
    </div>
</div>
{% endblock %}
'''
    
    student_list_path = os.path.join(base_dir, 'templates', 'students', 'student_list.html')
    os.makedirs(os.path.dirname(student_list_path), exist_ok=True)
    
    with open(student_list_path, 'w', encoding='utf-8') as f:
        f.write(student_list_content)
    print(f"✅ Created: templates/students/student_list.html")
    
    # Create student detail template
    student_detail_content = '''{% extends 'base.html' %}
{% load static %}

{% block title %}{{ student }} - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Student Header -->
    <div class="card shadow mb-4">
        <div class="card-body">
            <div class="row">
                <div class="col-md-8">
                    <h2 class="text-primary">{{ student.first_name }} {{ student.last_name }}</h2>
                    <p class="text-muted">
                        Student ID: {{ student.student_id }} • 
                        Class: {{ student.current_class|default:"Not Assigned" }} • 
                        Status: <span class="badge badge-{{ student.status }}">{{ student.status|title }}</span>
                    </p>
                </div>
                <div class="col-md-4 text-right">
                    <a href="/admin/students/student/{{ student.pk }}/change/" class="btn btn-warning">
                        <i class="fas fa-edit"></i> Edit
                    </a>
                    <a href="/admin/students/student/{{ student.pk }}/delete/" class="btn btn-danger">
                        <i class="fas fa-trash"></i> Delete
                    </a>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <!-- Student Information -->
        <div class="col-lg-4">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Student Information</h6>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td><strong>Date of Birth:</strong></td>
                            <td>{{ student.date_of_birth|date:"d M Y" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Age:</strong></td>
                            <td>{{ student.get_age }} years</td>
                        </tr>
                        <tr>
                            <td><strong>Gender:</strong></td>
                            <td>{{ student.get_gender_display }}</td>
                        </tr>
                        <tr>
                            <td><strong>Admission Date:</strong></td>
                            <td>{{ student.admission_date|date:"d M Y" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Home Address:</strong></td>
                            <td>{{ student.home_address }}</td>
                        </tr>
                        <tr>
                            <td><strong>Quarter:</strong></td>
                            <td>{{ student.quarter }}</td>
                        </tr>
                    </table>
                </div>
            </div>

            <!-- Contact Information -->
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Contact Information</h6>
                </div>
                <div class="card-body">
                    <table class="table table-borderless">
                        <tr>
                            <td><strong>Phone:</strong></td>
                            <td>{{ student.phone|default:"Not provided" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Emergency Contact:</strong></td>
                            <td>{{ student.emergency_contact|default:"Not provided" }}</td>
                        </tr>
                        <tr>
                            <td><strong>Emergency Name:</strong></td>
                            <td>{{ student.emergency_contact_name|default:"Not provided" }}</td>
                        </tr>
                    </table>
                </div>
            </div>
        </div>

        <!-- Academic Information -->
        <div class="col-lg-8">
            <div class="row">
                <!-- Attendance Summary -->
                <div class="col-md-6">
                    <div class="card shadow mb-4">
                        <div class="card-header py-3">
                            <h6 class="m-0 font-weight-bold text-primary">Attendance (This Month)</h6>
                        </div>
                        <div class="card-body text-center">
                            <h1 class="display-4 text-success">85%</h1>
                            <p class="text-muted">Present: 17 days • Absent: 3 days</p>
                        </div>
                    </div>
                </div>

                <!-- Fee Status -->
                <div class="col-md-6">
                    <div class="card shadow mb-4">
                        <div class="card-header py-3">
                            <h6 class="m-0 font-weight-bold text-primary">Fee Status</h6>
                        </div>
                        <div class="card-body text-center">
                            <h1 class="display-4 text-{{ student.fee_status_color }}">Paid</h1>
                            <p class="text-muted">Last Payment: 15 Nov 2024</p>
                        </div>
                    </div>
                </div>
            </div>

            <!-- Recent Activity -->
            <div class="card shadow mb-4">
                <div class="card-header py-3 d-flex justify-content-between align-items-center">
                    <h6 class="m-0 font-weight-bold text-primary">Recent Activity</h6>
                    <button class="btn btn-sm btn-primary">View All</button>
                </div>
                <div class="card-body">
                    <div class="timeline">
                        <!-- Add timeline items here -->
                        <p class="text-muted text-center py-4">No recent activity</p>
                    </div>
                </div>
            </div>

            <!-- Parent/Guardian Information -->
            <div class="card shadow">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Parent/Guardian Information</h6>
                </div>
                <div class="card-body">
                    {% if student.parentguardian_set.all %}
                    <div class="table-responsive">
                        <table class="table table-hover">
                            <thead>
                                <tr>
                                    <th>Name</th>
                                    <th>Relationship</th>
                                    <th>Phone</th>
                                    <th>Email</th>
                                    <th>Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for parent in student.parentguardian_set.all %}
                                <tr>
                                    <td>{{ parent.full_name }}</td>
                                    <td>{{ parent.relationship }}</td>
                                    <td>{{ parent.phone }}</td>
                                    <td>{{ parent.email|default:"-" }}</td>
                                    <td>
                                        <a href="/admin/students/parentguardian/{{ parent.pk }}/change/" 
                                           class="btn btn-sm btn-warning">
                                            <i class="fas fa-edit"></i>
                                        </a>
                                    </td>
                                </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                    {% else %}
                    <p class="text-muted text-center py-4">No parent/guardian information</p>
                    <div class="text-center">
                        <a href="/admin/students/parentguardian/add/?student={{ student.pk }}" 
                           class="btn btn-primary">
                            <i class="fas fa-user-plus"></i> Add Parent/Guardian
                        </a>
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}
'''
    
    student_detail_path = os.path.join(base_dir, 'templates', 'students', 'student_detail.html')
    with open(student_detail_path, 'w', encoding='utf-8') as f:
        f.write(student_detail_content)
    print(f"✅ Created: templates/students/student_detail.html")
    
    print("\n🎉 Student portal templates created!")
    print("\n🔗 URLs to test:")
    print("   http://127.0.0.1:8000/students/  - Student List")
    print("   http://127.0.0.1:8000/students/1/ - Student Detail (replace 1 with actual ID)")

if __name__ == "__main__":
    setup_next_features()
    create_student_portal()

======================================================================
FILE: passenger_wsgi.py
======================================================================
import os
import sys

sys.path.insert(0, '/home/dnjill5/raphabethel.org/portal')
os.environ['DJANGO_SETTINGS_MODULE'] = 'backend.settings_production'

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()


======================================================================
FILE: rename_student_ids.py
======================================================================
#!/usr/bin/env python3
"""
rename_student_ids.py
=====================
One-time script — renames all existing IMP-XXXX student IDs
to the new RB-YY-NNNN format.

Run on the server:
    OPENBLAS_NUM_THREADS=1 python rename_student_ids.py [--dry-run]
"""

import os, sys, argparse
from pathlib import Path

parser = argparse.ArgumentParser()
parser.add_argument('--dry-run', action='store_true')
parser.add_argument('--settings', default='backend.settings_production')
args = parser.parse_args()

sys.path.insert(0, str(Path(__file__).resolve().parent))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', args.settings)
os.environ.setdefault('OPENBLAS_NUM_THREADS', '1')

import django
django.setup()

from students.models import Student
from django.db import transaction

DRY = args.dry_run
if DRY:
    print("DRY RUN — no changes written\n")

# ── Gather all students ordered by current ID to keep sequence stable ─────────
students = list(Student.objects.all().order_by('student_id'))

print(f"Total students: {len(students)}")
print()

# ── Determine admission year per student ─────────────────────────────────────
# Use admission_date if set, else fall back to 2026 (this academic year)
from datetime import date

def get_yy(student):
    if student.admission_date:
        return str(student.admission_date.year)[-2:]
    return '26'   # default for all current students

# ── Build rename map: old_id -> new_id ───────────────────────────────────────
# Sequence is GLOBAL — just counts 1, 2, 3… regardless of year
rename_map = {}
seq = 1
for s in students:
    yy     = get_yy(s)
    new_id = f'RB-{yy}-{seq:04d}'
    rename_map[s.student_id] = new_id
    seq += 1

# ── Preview ───────────────────────────────────────────────────────────────────
print(f"{'OLD ID':<15}  {'NEW ID':<15}  {'NAME'}")
print("-" * 55)
for s in students:
    old = s.student_id
    new = rename_map[old]
    print(f"  {old:<15}  {new:<15}  {s.first_name} {s.last_name}")

print()

if DRY:
    print("Dry run complete — run without --dry-run to apply.")
    sys.exit(0)

# ── Apply — use a temp prefix first to avoid unique constraint mid-rename ─────
confirm = input("Apply these renames? (yes/no): ").strip().lower()
if confirm != 'yes':
    print("Aborted.")
    sys.exit(0)

print("\nRenaming...")
with transaction.atomic():
    # Pass 1: rename to TEMP-N to free up all old IDs
    for i, s in enumerate(students):
        s.student_id = f'TEMP-{i+1:04d}'
        s.save(update_fields=['student_id'])

    # Pass 2: rename to final RB-YY-NNNN
    for s in students:
        old_id = [k for k, v in rename_map.items()][students.index(s)]
        s.student_id = rename_map[old_id]
        s.save(update_fields=['student_id'])
        print(f"  {old_id:<15} -> {s.student_id}")

print(f"\nDone. {len(students)} students renamed to RB-YY-NNNN format.")
print("Next new student will be assigned RB-26-{seq:04d}".format(seq=len(students)+1))


======================================================================
FILE: setup_all_modules.py
======================================================================
# setup_all_modules.py
import os
import sys

def create_directory_structure():
    base_dir = os.path.dirname(os.path.abspath(__file__))
    
    print("🚀 CREATING COMPLETE SCHOOL MANAGEMENT SYSTEM")
    print("=" * 60)
    
    # Create all template directories
    directories = [
        'templates/students',
        'templates/academics',
        'templates/attendance',
        'templates/finance',
        'templates/parents',
        'templates/reports',
        'templates/communication',
        'templates/auth',
    ]
    
    for directory in directories:
        dir_path = os.path.join(base_dir, directory)
        os.makedirs(dir_path, exist_ok=True)
        print(f"✅ Created: {directory}")
    
    return base_dir

def create_student_portal(base_dir):
    print("\n🎓 CREATING STUDENT PORTAL...")
    
    # Create student list view
    student_views = '''# students/views.py
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.db.models import Q
from .models import Student, ParentGuardian

class StudentListView(LoginRequiredMixin, ListView):
    model = Student
    template_name = 'students/student_list.html'
    context_object_name = 'students'
    paginate_by = 20
    
    def get_queryset(self):
        queryset = super().get_queryset()
        
        # Search functionality
        search_query = self.request.GET.get('q', '')
        if search_query:
            queryset = queryset.filter(
                Q(first_name__icontains=search_query) |
                Q(last_name__icontains=search_query) |
                Q(student_id__icontains=search_query) |
                Q(home_address__icontains=search_query)
            )
        
        # Filter by class
        class_filter = self.request.GET.get('class')
        if class_filter:
            queryset = queryset.filter(current_class=class_filter)
        
        # Filter by status
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        return queryset.order_by('-admission_date')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_students'] = Student.objects.count()
        context['active_students'] = Student.objects.filter(status='active').count()
        
        # Get unique classes for filter dropdown
        from academics.models import SchoolClass
        context['all_classes'] = SchoolClass.objects.all()
        
        return context

class StudentDetailView(LoginRequiredMixin, DetailView):
    model = Student
    template_name = 'students/student_detail.html'
    context_object_name = 'student'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Add attendance records
        from academics.models import Attendance
        context['attendance_records'] = Attendance.objects.filter(
            student=self.object
        ).order_by('-date')[:10]
        
        # Add fee records
        from finance.models import Invoice
        context['invoice_records'] = Invoice.objects.filter(
            student=self.object
        ).order_by('-created_at')[:10]
        
        return context

class StudentCreateView(LoginRequiredMixin, CreateView):
    model = Student
    template_name = 'students/student_form.html'
    fields = '__all__'
    success_url = reverse_lazy('student_list')
    
class StudentUpdateView(LoginRequiredMixin, UpdateView):
    model = Student
    template_name = 'students/student_form.html'
    fields = '__all__'
    success_url = reverse_lazy('student_list')
'''
    
    views_path = os.path.join(base_dir, 'students', 'views.py')
    with open(views_path, 'w', encoding='utf-8') as f:
        f.write(student_views)
    print("✅ Created: students/views.py")
    
    # Create student list template
    student_list_template = '''{% extends 'base.html' %}
{% load static %}

{% block title %}Students - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .student-card {
        transition: transform 0.3s;
    }
    .student-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 5px 15px rgba(0,0,0,0.1);
    }
    .student-avatar {
        width: 60px;
        height: 60px;
        border-radius: 50%;
        background: #4CAF50;
        color: white;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 1.5rem;
        font-weight: bold;
    }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <!-- Page Header -->
    <div class="d-flex justify-content-between align-items-center mb-4">
        <div>
            <h1 class="h3 mb-0 text-gray-800">Students</h1>
            <p class="text-muted">Total: {{ total_students }} | Active: {{ active_students }}</p>
        </div>
        <div>
            <a href="/admin/students/student/add/" class="btn btn-primary">
                <i class="fas fa-user-plus"></i> Add New Student
            </a>
            <a href="/students/export/" class="btn btn-outline-secondary">
                <i class="fas fa-download"></i> Export
            </a>
        </div>
    </div>

    <!-- Search and Filter Card -->
    <div class="card shadow mb-4">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Search & Filter</h6>
        </div>
        <div class="card-body">
            <form method="get" class="row g-3">
                <div class="col-md-5">
                    <div class="input-group">
                        <input type="text" class="form-control" name="q" 
                               placeholder="Search by name, ID, or address..." 
                               value="{{ request.GET.q }}">
                        <button class="btn btn-primary" type="submit">
                            <i class="fas fa-search"></i>
                        </button>
                    </div>
                </div>
                <div class="col-md-3">
                    <select class="form-control" name="class">
                        <option value="">All Classes</option>
                        {% for class in all_classes %}
                        <option value="{{ class.id }}" 
                                {% if request.GET.class == class.id|stringformat:"s" %}selected{% endif %}>
                            {{ class }}
                        </option>
                        {% endfor %}
                    </select>
                </div>
                <div class="col-md-2">
                    <select class="form-control" name="status">
                        <option value="">All Status</option>
                        <option value="active" {% if request.GET.status == 'active' %}selected{% endif %}>Active</option>
                        <option value="inactive" {% if request.GET.status == 'inactive' %}selected{% endif %}>Inactive</option>
                        <option value="graduated" {% if request.GET.status == 'graduated' %}selected{% endif %}>Graduated</option>
                    </select>
                </div>
                <div class="col-md-2">
                    <button type="submit" class="btn btn-primary w-100">
                        <i class="fas fa-filter"></i> Filter
                    </button>
                </div>
            </form>
        </div>
    </div>

    <!-- Students Grid/Table -->
    <div class="row">
        {% for student in students %}
        <div class="col-xl-3 col-md-4 col-sm-6 mb-4">
            <div class="card student-card h-100">
                <div class="card-body">
                    <div class="d-flex align-items-start mb-3">
                        <div class="student-avatar me-3">
                            {{ student.first_name.0 }}{{ student.last_name.0 }}
                        </div>
                        <div>
                            <h5 class="card-title mb-1">{{ student.first_name }} {{ student.last_name }}</h5>
                            <p class="text-muted small mb-0">ID: {{ student.student_id }}</p>
                            {% if student.current_class %}
                            <span class="badge bg-info">{{ student.current_class }}</span>
                            {% endif %}
                        </div>
                    </div>
                    
                    <div class="student-info mb-3">
                        <p class="mb-1">
                            <i class="fas fa-birthday-cake text-primary me-2"></i>
                            {{ student.date_of_birth|date:"d M Y" }} ({{ student.get_age }} yrs)
                        </p>
                        <p class="mb-1">
                            <i class="fas fa-venus-mars text-primary me-2"></i>
                            {{ student.get_gender_display }}
                        </p>
                        <p class="mb-1">
                            <i class="fas fa-calendar-alt text-primary me-2"></i>
                            Admitted: {{ student.admission_date|date:"d M Y" }}
                        </p>
                    </div>
                    
                    <div class="d-flex justify-content-between align-items-center">
                        <span class="badge bg-{{ student.status }}">
                            {{ student.status|title }}
                        </span>
                        <div>
                            <a href="{% url 'student_detail' student.pk %}" 
                               class="btn btn-sm btn-outline-primary">
                                <i class="fas fa-eye"></i>
                            </a>
                            <a href="/admin/students/student/{{ student.pk }}/change/" 
                               class="btn btn-sm btn-outline-warning">
                                <i class="fas fa-edit"></i>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        {% empty %}
        <div class="col-12">
            <div class="text-center py-5">
                <i class="fas fa-users fa-3x text-muted mb-3"></i>
                <h4 class="text-muted">No students found</h4>
                <p class="text-muted">Try adjusting your search or add a new student</p>
                <a href="/admin/students/student/add/" class="btn btn-primary">
                    <i class="fas fa-user-plus"></i> Add First Student
                </a>
            </div>
        </div>
        {% endfor %}
    </div>

    <!-- Pagination -->
    {% if is_paginated %}
    <nav aria-label="Page navigation" class="mt-4">
        <ul class="pagination justify-content-center">
            {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">
                    Previous
                </a>
            </li>
            {% endif %}
            
            {% for num in page_obj.paginator.page_range %}
            {% if page_obj.number == num %}
            <li class="page-item active">
                <a class="page-link" href="#">{{ num }}</a>
            </li>
            {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
            <li class="page-item">
                <a class="page-link" href="?page={{ num }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">
                    {{ num }}
                </a>
            </li>
            {% endif %}
            {% endfor %}
            
            {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.next_page_number }}{% if request.GET.q %}&q={{ request.GET.q }}{% endif %}">
                    Next
                </a>
            </li>
            {% endif %}
        </ul>
    </nav>
    {% endif %}
</div>
{% endblock %}
'''
    
    list_path = os.path.join(base_dir, 'templates', 'students', 'student_list.html')
    with open(list_path, 'w', encoding='utf-8') as f:
        f.write(student_list_template)
    print("✅ Created: templates/students/student_list.html")

def create_attendance_module(base_dir):
    print("\n📊 CREATING ATTENDANCE MODULE...")
    
    # Create attendance views
    attendance_views = '''# academics/views.py (attendance section)
from django.views.generic import ListView, CreateView, TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect
from django.contrib import messages
from django.db.models import Count, Q
from datetime import date, timedelta
from .models import Attendance, SchoolClass

class AttendanceMarkingView(LoginRequiredMixin, TemplateView):
    template_name = 'attendance/mark.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        today = date.today()
        
        # Get classes
        context['classes'] = SchoolClass.objects.all()
        
        # Get selected class
        class_id = self.request.GET.get('class')
        if class_id:
            try:
                selected_class = SchoolClass.objects.get(id=class_id)
                context['selected_class'] = selected_class
                
                # Get students in this class
                from students.models import Student
                students = Student.objects.filter(current_class=selected_class, status='active')
                context['students'] = students
                
                # Get today's attendance for these students
                attendance_today = Attendance.objects.filter(
                    date=today,
                    student__in=students
                ).select_related('student')
                
                # Create attendance dict for quick lookup
                attendance_dict = {att.student_id: att.status for att in attendance_today}
                context['attendance_dict'] = attendance_dict
                
            except SchoolClass.DoesNotExist:
                pass
        
        context['today'] = today
        return context
    
    def post(self, request, *args, **kwargs):
        today = date.today()
        class_id = request.POST.get('class_id')
        
        if class_id:
            from students.models import Student
            students = Student.objects.filter(current_class_id=class_id, status='active')
            
            for student in students:
                status = request.POST.get(f'status_{student.id}', 'absent')
                
                # Update or create attendance record
                Attendance.objects.update_or_create(
                    student=student,
                    date=today,
                    defaults={
                        'school_class_id': class_id,
                        'status': status,
                        'remarks': request.POST.get(f'remarks_{student.id}', '')
                    }
                )
            
            messages.success(request, f'Attendance marked successfully for {today}')
            return redirect(f'/attendance/mark/?class={class_id}')
        
        return redirect('/attendance/mark/')

class AttendanceListView(LoginRequiredMixin, ListView):
    model = Attendance
    template_name = 'attendance/list.html'
    context_object_name = 'attendances'
    paginate_by = 50
    
    def get_queryset(self):
        queryset = super().get_queryset().select_related('student', 'school_class')
        
        # Date filter
        date_filter = self.request.GET.get('date')
        if date_filter:
            queryset = queryset.filter(date=date_filter)
        else:
            # Default to today
            queryset = queryset.filter(date=date.today())
        
        # Class filter
        class_filter = self.request.GET.get('class')
        if class_filter:
            queryset = queryset.filter(school_class_id=class_filter)
        
        # Status filter
        status_filter = self.request.GET.get('status')
        if status_filter:
            queryset = queryset.filter(status=status_filter)
        
        return queryset.order_by('-date', 'school_class', 'student__first_name')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['classes'] = SchoolClass.objects.all()
        context['today'] = date.today()
        return context

class AttendanceReportView(LoginRequiredMixin, TemplateView):
    template_name = 'attendance/report.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        from datetime import datetime
        
        # Get date range (default: this month)
        year = self.request.GET.get('year', datetime.now().year)
        month = self.request.GET.get('month', datetime.now().month)
        
        # Get attendance summary
        from django.db.models import Count, Case, When, IntegerField
        from django.db.models.functions import TruncMonth
        
        summary = Attendance.objects.filter(
            date__year=year,
            date__month=month
        ).values('school_class__name').annotate(
            total=Count('id'),
            present=Count(Case(When(status='present', then=1), output_field=IntegerField())),
            absent=Count(Case(When(status='absent', then=1), output_field=IntegerField())),
            late=Count(Case(When(status='late', then=1), output_field=IntegerField())),
        ).order_by('school_class__name')
        
        context['summary'] = summary
        context['selected_year'] = year
        context['selected_month'] = month
        
        return context
'''
    
    # Create attendance views file or append to existing
    views_path = os.path.join(base_dir, 'academics', 'views.py')
    if os.path.exists(views_path):
        with open(views_path, 'a', encoding='utf-8') as f:
            f.write('\n\n' + attendance_views)
    else:
        with open(views_path, 'w', encoding='utf-8') as f:
            f.write(attendance_views)
    print("✅ Created/updated: academics/views.py")
    
    # Create attendance templates
    attendance_mark_template = '''{% extends 'base.html' %}
{% load static %}

{% block title %}Mark Attendance - Rapha-Bethel BNPS{% endblock %}

{% block extra_css %}
<style>
    .attendance-btn {
        width: 100px;
    }
    .status-present { background-color: #d4edda !important; }
    .status-absent { background-color: #f8d7da !important; }
    .status-late { background-color: #fff3cd !important; }
    .status-excused { background-color: #d1ecf1 !important; }
</style>
{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Mark Attendance</h1>
        <div class="btn-group">
            <a href="/attendance/" class="btn btn-outline-primary">
                <i class="fas fa-list"></i> View Attendance
            </a>
            <a href="/attendance/report/" class="btn btn-outline-secondary">
                <i class="fas fa-chart-pie"></i> Reports
            </a>
        </div>
    </div>

    <!-- Class Selection -->
    <div class="card shadow mb-4">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">Select Class</h6>
        </div>
        <div class="card-body">
            <form method="get" class="row g-3">
                <div class="col-md-6">
                    <select class="form-control" name="class" onchange="this.form.submit()">
                        <option value="">-- Select Class --</option>
                        {% for class in classes %}
                        <option value="{{ class.id }}" 
                                {% if selected_class.id == class.id %}selected{% endif %}>
                            {{ class.name }} ({{ class.level|upper }} - {{ class.section }})
                        </option>
                        {% endfor %}
                    </select>
                </div>
            </form>
        </div>
    </div>

    {% if selected_class %}
    <!-- Attendance Form -->
    <div class="card shadow">
        <div class="card-header py-3 d-flex justify-content-between align-items-center">
            <h6 class="m-0 font-weight-bold text-primary">
                {{ selected_class.name }} - {{ today|date:"d M Y" }}
            </h6>
            <div>
                <span class="badge bg-success">Present: ✅</span>
                <span class="badge bg-danger">Absent: ❌</span>
                <span class="badge bg-warning">Late: ⏰</span>
                <span class="badge bg-info">Excused: 📝</span>
            </div>
        </div>
        <div class="card-body">
            <form method="post">
                {% csrf_token %}
                <input type="hidden" name="class_id" value="{{ selected_class.id }}">
                
                <div class="table-responsive">
                    <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>Roll No.</th>
                                <th>Student Name</th>
                                <th>Attendance Status</th>
                                <th>Remarks</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for student in students %}
                            {% with status=attendance_dict|get_item:student.id %}
                            <tr class="status-{{ status|default:'absent' }}">
                                <td>{{ forloop.counter }}</td>
                                <td>
                                    <strong>{{ student.first_name }} {{ student.last_name }}</strong><br>
                                    <small class="text-muted">ID: {{ student.student_id }}</small>
                                </td>
                                <td>
                                    <div class="btn-group btn-group-sm" role="group">
                                        <input type="radio" class="btn-check" name="status_{{ student.id }}" 
                                               id="present_{{ student.id }}" value="present" 
                                               {% if status == 'present' %}checked{% endif %} autocomplete="off">
                                        <label class="btn btn-outline-success" for="present_{{ student.id }}">
                                            ✅ Present
                                        </label>
                                        
                                        <input type="radio" class="btn-check" name="status_{{ student.id }}" 
                                               id="absent_{{ student.id }}" value="absent"
                                               {% if not status or status == 'absent' %}checked{% endif %} autocomplete="off">
                                        <label class="btn btn-outline-danger" for="absent_{{ student.id }}">
                                            ❌ Absent
                                        </label>
                                        
                                        <input type="radio" class="btn-check" name="status_{{ student.id }}" 
                                               id="late_{{ student.id }}" value="late"
                                               {% if status == 'late' %}checked{% endif %} autocomplete="off">
                                        <label class="btn btn-outline-warning" for="late_{{ student.id }}">
                                            ⏰ Late
                                        </label>
                                        
                                        <input type="radio" class="btn-check" name="status_{{ student.id }}" 
                                               id="excused_{{ student.id }}" value="excused"
                                               {% if status == 'excused' %}checked{% endif %} autocomplete="off">
                                        <label class="btn btn-outline-info" for="excused_{{ student.id }}">
                                            📝 Excused
                                        </label>
                                    </div>
                                </td>
                                <td>
                                    <input type="text" class="form-control form-control-sm" 
                                           name="remarks_{{ student.id }}" 
                                           placeholder="Remarks (optional)" 
                                           value="{{ attendance_dict|get_item:student.id }}">
                                </td>
                            </tr>
                            {% endwith %}
                            {% empty %}
                            <tr>
                                <td colspan="4" class="text-center py-4">
                                    <i class="fas fa-users-slash fa-2x text-muted mb-3"></i>
                                    <p class="text-muted">No students in this class</p>
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                
                <div class="mt-4 text-center">
                    <button type="submit" class="btn btn-primary btn-lg px-5">
                        <i class="fas fa-save"></i> Save Attendance
                    </button>
                    <a href="/attendance/" class="btn btn-secondary btn-lg px-5">
                        <i class="fas fa-times"></i> Cancel
                    </a>
                </div>
            </form>
        </div>
    </div>
    {% endif %}
</div>
{% endblock %}

{% block extra_js %}
<script>
// Add custom template filter for dictionary lookup
if (typeof django !== 'undefined' && django.jQuery) {
    django.jQuery.extend(django.jQuery.fn, {
        get_item: function(key) {
            return this[key];
        }
    });
}

// Quick status selection with keyboard shortcuts
document.addEventListener('keydown', function(e) {
    if (e.ctrlKey) {
        const rows = document.querySelectorAll('tbody tr');
        const currentRow = document.activeElement.closest('tr');
        if (currentRow) {
            const index = Array.from(rows).indexOf(currentRow);
            if (index !== -1) {
                switch(e.key) {
                    case '1': // Present
                        rows[index].querySelector('input[value="present"]').click();
                        break;
                    case '2': // Absent
                        rows[index].querySelector('input[value="absent"]').click();
                        break;
                    case '3': // Late
                        rows[index].querySelector('input[value="late"]').click();
                        break;
                    case '4': // Excused
                        rows[index].querySelector('input[value="excused"]').click();
                        break;
                }
            }
        }
    }
});
</script>
{% endblock %}
'''
    
    mark_path = os.path.join(base_dir, 'templates', 'attendance', 'mark.html')
    with open(mark_path, 'w', encoding='utf-8') as f:
        f.write(attendance_mark_template)
    print("✅ Created: templates/attendance/mark.html")

def create_finance_module(base_dir):
    print("\n💰 CREATING FINANCE MODULE...")
    
    # Create finance templates
    finance_invoices = '''{% extends 'base.html' %}
{% load static %}

{% block title %}Invoices - Rapha-Bethel BNPS{% endblock %}

{% block content %}
<div class="container-fluid">
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1 class="h3 mb-0 text-gray-800">Fee Invoices</h1>
        <div class="btn-group">
            <a href="/finance/invoices/create/" class="btn btn-primary">
                <i class="fas fa-plus"></i> Create Invoice
            </a>
            <a href="/finance/invoices/export/" class="btn btn-outline-secondary">
                <i class="fas fa-download"></i> Export
            </a>
        </div>
    </div>

    <!-- Stats Cards -->
    <div class="row mb-4">
        <div class="col-md-3">
            <div class="card border-left-primary shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-primary text-uppercase mb-1">
                        Total Invoices
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">$24,000</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-success shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-success text-uppercase mb-1">
                        Paid Invoices
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">$18,500</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-warning shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-warning text-uppercase mb-1">
                        Pending Invoices
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">$4,200</div>
                </div>
            </div>
        </div>
        <div class="col-md-3">
            <div class="card border-left-danger shadow h-100 py-2">
                <div class="card-body">
                    <div class="text-xs font-weight-bold text-danger text-uppercase mb-1">
                        Overdue Invoices
                    </div>
                    <div class="h5 mb-0 font-weight-bold text-gray-800">$1,300</div>
                </div>
            </div>
        </div>
    </div>

    <!-- Invoices Table -->
    <div class="card shadow">
        <div class="card-header py-3">
            <h6 class="m-0 font-weight-bold text-primary">All Invoices</h6>
        </div>
        <div class="card-body">
            <div class="table-responsive">
                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>Invoice #</th>
                            <th>Student</th>
                            <th>Class</th>
                            <th>Amount</th>
                            <th>Due Date</th>
                            <th>Status</th>
                            <th>Actions</th>
                        </tr>
                    </thead>
                    <tbody>
                        <!-- Sample data - replace with actual data -->
                        <tr>
                            <td>INV-2024-001</td>
                            <td>John Doe</td>
                            <td>Class 5A</td>
                            <td>$500.00</td>
                            <td>15 Dec 2024</td>
                            <td><span class="badge bg-success">Paid</span></td>
                            <td>
                                <button class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </button>
                                <button class="btn btn-sm btn-outline-warning">
                                    <i class="fas fa-edit"></i>
                                </button>
                            </td>
                        </tr>
                        <tr>
                            <td>INV-2024-002</td>
                            <td>Jane Smith</td>
                            <td>Class 6B</td>
                            <td>$500.00</td>
                            <td>15 Dec 2024</td>
                            <td><span class="badge bg-warning">Pending</span></td>
                            <td>
                                <button class="btn btn-sm btn-outline-primary">
                                    <i class="fas fa-eye"></i>
                                </button>
                                <button class="btn btn-sm btn-outline-warning">
                                    <i class="fas fa-edit"></i>
                                </button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}
'''
    
    invoices_path = os.path.join(base_dir, 'templates', 'finance', 'invoices.html')
    with open(invoices_path, 'w', encoding='utf-8') as f:
        f.write(finance_invoices)
    print("✅ Created: templates/finance/invoices.html")

def create_urls_config(base_dir):
    print("\n🔗 CREATING URL CONFIGURATION...")
    
    urls_content = '''# backend/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from core.views import HomeView, DashboardView

urlpatterns = [
    # Home & Dashboard
    path('', HomeView.as_view(), name='home'),
    path('dashboard/', DashboardView.as_view(), name='dashboard'),
    
    # Students
    path('students/', include('students.urls')),
    
    # Academics
    path('attendance/', include('academics.urls_attendance')),
    path('classes/', include('academics.urls_classes')),
    
    # Finance
    path('finance/', include('finance.urls')),
    
    # Parents
    path('parents/', include('parents.urls')),
    
    # Reports
    path('reports/', include('reports.urls')),
    
    # Communication
    path('communication/', include('communication.urls')),
    
    # Admin
    path('admin/', admin.site.urls),
]

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
'''
    
    urls_path = os.path.join(base_dir, 'backend', 'urls.py')
    with open(urls_path, 'w', encoding='utf-8') as f:
        f.write(urls_content)
    print("✅ Created: backend/urls.py")
    
    # Create app-specific URL files
    app_urls = {
        'students/urls.py': '''from django.urls import path
from .views import StudentListView, StudentDetailView

urlpatterns = [
    path('', StudentListView.as_view(), name='student_list'),
    path('<int:pk>/', StudentDetailView.as_view(), name='student_detail'),
]''',
        
        'academics/urls_attendance.py': '''from django.urls import path
from .views import AttendanceMarkingView, AttendanceListView, AttendanceReportView

urlpatterns = [
    path('mark/', AttendanceMarkingView.as_view(), name='mark_attendance'),
    path('', AttendanceListView.as_view(), name='attendance_list'),
    path('report/', AttendanceReportView.as_view(), name='attendance_report'),
]''',
        
        'finance/urls.py': '''from django.urls import path
from .views import InvoiceListView, PaymentListView

urlpatterns = [
    path('invoices/', InvoiceListView.as_view(), name='invoice_list'),
    path('payments/', PaymentListView.as_view(), name='payment_list'),
]''',
    }
    
    for url_file, content in app_urls.items():
        url_path = os.path.join(base_dir, url_file)
        os.makedirs(os.path.dirname(url_path), exist_ok=True)
        with open(url_path, 'w', encoding='utf-8') as f:
            f.write(content)
        print(f"✅ Created: {url_file}")

def create_complete_setup_script():
    base_dir = create_directory_structure()
    create_student_portal(base_dir)
    create_attendance_module(base_dir)
    create_finance_module(base_dir)
    create_urls_config(base_dir)
    
    print("\n" + "=" * 60)
    print("🎉 COMPLETE SYSTEM SETUP READY!")
    print("=" * 60)
    print("\n📋 NEXT STEPS:")
    print("1. Run migrations: python manage.py makemigrations")
    print("2. Apply migrations: python manage.py migrate")
    print("3. Create superuser: python manage.py createsuperuser")
    print("4. Run server: python manage.py runserver")
    print("\n🔗 AVAILABLE PAGES:")
    print("   • Home: http://127.0.0.1:8000/")
    print("   • Dashboard: http://127.0.0.1:8000/dashboard/")
    print("   • Students: http://127.0.0.1:8000/students/")
    print("   • Attendance: http://127.0.0.1:8000/attendance/")
    print("   • Finance: http://127.0.0.1:8000/finance/invoices/")
    print("\n⚡ QUICK START:")
    print("   Run: python manage.py runserver")
    print("   Login with admin credentials")
    print("   Start using all modules!")

if __name__ == "__main__":
    create_complete_setup_script()

======================================================================
FILE: snapshot_project.py
======================================================================
"""
snapshot_project.py
-------------------
Run this from the ROOT of your Django project (same folder as manage.py):

    python snapshot_project.py

It produces a single file  →  project_snapshot.txt

Paste that file's contents into Claude for a complete picture of your
codebase with zero secrets exposed.

Safe to run: reads only Python/HTML/CSS/JS source files.
Skips: .env, secrets, media, migrations, __pycache__, venv, staticfiles.
"""

import os
import sys

# ── Configuration ────────────────────────────────────────────────────────────

OUTPUT_FILE = "project_snapshot.txt"

# Folders to skip entirely
SKIP_DIRS = {
    "venv", ".venv", "env", "__pycache__", ".git",
    "node_modules", "staticfiles", "media", "logs",
    "migrations",          # skip migration files — too noisy, not useful
    ".mypy_cache", ".pytest_cache",
}

# File extensions to include
INCLUDE_EXTS = {".py", ".html", ".css", ".js", ".json", ".txt", ".md", ".cfg", ".ini", ".toml"}

# Files to skip by name (secrets / noise)
SKIP_FILES = {
    ".env", ".env.local", ".env.production",
    "secrets.py", "local_settings.py",
    "db.sqlite3", "*.pyc",
}

# Keys in settings.py whose VALUES we redact
REDACT_KEYS = {
    "SECRET_KEY", "PASSWORD", "DATABASE_URL", "EMAIL_HOST_PASSWORD",
    "AWS_SECRET", "API_KEY", "TOKEN", "SENDGRID", "TWILIO",
}

# Max bytes to read per file (skip giant files)
MAX_FILE_BYTES = 60_000

# Django apps — we dump these fully
DJANGO_APPS = [
    "academics", "api", "backend", "communication", "core",
    "finance", "parents", "reports", "scripts", "staff",
    "students", "sync", "templates",
]

# ── Helpers ──────────────────────────────────────────────────────────────────

def should_skip_dir(name):
    return name in SKIP_DIRS or name.startswith(".")

def should_skip_file(name):
    if name in SKIP_FILES:
        return True
    if any(name.endswith(ext) for ext in [".pyc", ".pyo", ".pyd"]):
        return True
    return False

def redact_settings(content):
    """Replace secret values in settings files with [REDACTED]."""
    lines = []
    for line in content.splitlines():
        upper = line.upper()
        if any(k in upper for k in REDACT_KEYS) and "=" in line:
            key_part = line.split("=")[0]
            lines.append(f"{key_part} = '[REDACTED]'")
        else:
            lines.append(line)
    return "\n".join(lines)

def read_file(path):
    try:
        size = os.path.getsize(path)
        if size > MAX_FILE_BYTES:
            return f"[FILE TOO LARGE — {size:,} bytes — skipped]"
        with open(path, "r", encoding="utf-8", errors="replace") as f:
            content = f.read()
        if "settings" in os.path.basename(path).lower():
            content = redact_settings(content)
        return content
    except Exception as e:
        return f"[ERROR READING FILE: {e}]"

def walk_app(app_dir, out):
    """Walk a single Django app directory and write all relevant files."""
    for root, dirs, files in os.walk(app_dir):
        # Prune skip dirs in-place
        dirs[:] = [d for d in sorted(dirs) if not should_skip_dir(d)]
        for fname in sorted(files):
            if should_skip_file(fname):
                continue
            ext = os.path.splitext(fname)[1].lower()
            if ext not in INCLUDE_EXTS:
                continue
            fpath = os.path.join(root, fname)
            rel = os.path.relpath(fpath)
            content = read_file(fpath)
            out.append(f"\n{'='*70}")
            out.append(f"FILE: {rel}")
            out.append('='*70)
            out.append(content)

# ── Main ─────────────────────────────────────────────────────────────────────

def main():
    cwd = os.getcwd()
    if not os.path.exists(os.path.join(cwd, "manage.py")):
        print("ERROR: Run this script from the Django project root (where manage.py lives).")
        sys.exit(1)

    print("Scanning project…")
    out = []

    # ── Header ────────────────────────────────────────────────────────────
    out.append("RAPHA-BETHEL BNPS — PROJECT SNAPSHOT")
    out.append(f"Generated from: {cwd}")
    out.append("")

    # ── Directory tree (top level only) ──────────────────────────────────
    out.append("=" * 70)
    out.append("TOP-LEVEL DIRECTORY STRUCTURE")
    out.append("=" * 70)
    try:
        entries = sorted(os.listdir(cwd))
        for e in entries:
            full = os.path.join(cwd, e)
            kind = "DIR " if os.path.isdir(full) else "FILE"
            out.append(f"  {kind}  {e}")
    except Exception as e:
        out.append(f"[ERROR: {e}]")

    # ── manage.py ────────────────────────────────────────────────────────
    manage = os.path.join(cwd, "manage.py")
    if os.path.exists(manage):
        out.append("\n" + "="*70)
        out.append("FILE: manage.py")
        out.append("="*70)
        out.append(read_file(manage))

    # ── requirements / dependencies ───────────────────────────────────────
    for req in ["requirements.txt", "requirements/base.txt",
                "requirements/prod.txt", "Pipfile", "pyproject.toml"]:
        rpath = os.path.join(cwd, req)
        if os.path.exists(rpath):
            out.append("\n" + "="*70)
            out.append(f"FILE: {req}")
            out.append("="*70)
            out.append(read_file(rpath))

    # ── Each Django app ───────────────────────────────────────────────────
    for app in DJANGO_APPS:
        app_path = os.path.join(cwd, app)
        if os.path.isdir(app_path):
            out.append(f"\n\n{'#'*70}")
            out.append(f"# APP: {app.upper()}")
            out.append(f"{'#'*70}")
            walk_app(app_path, out)
        else:
            out.append(f"\n[APP NOT FOUND: {app}]")

    # ── Any top-level .py files not already captured ───────────────────
    out.append(f"\n\n{'#'*70}")
    out.append("# ROOT-LEVEL PYTHON FILES")
    out.append(f"{'#'*70}")
    for fname in sorted(os.listdir(cwd)):
        if fname.endswith(".py") and fname != "manage.py" and not should_skip_file(fname):
            fpath = os.path.join(cwd, fname)
            if os.path.isfile(fpath):
                out.append(f"\n{'='*70}")
                out.append(f"FILE: {fname}")
                out.append("="*70)
                out.append(read_file(fpath))

    # ── Write output ──────────────────────────────────────────────────────
    full_output = "\n".join(out)
    with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
        f.write(full_output)

    size_kb = os.path.getsize(OUTPUT_FILE) / 1024
    print(f"\nDone. Output written to: {OUTPUT_FILE}")
    print(f"File size: {size_kb:.1f} KB")
    print("")
    print("Next steps:")
    print("  1. Open project_snapshot.txt and check nothing sensitive slipped through.")
    print("  2. Paste its full contents into Claude.")
    print("  3. Claude will give you exact, file-specific integration code.")
    print("")
    if size_kb > 400:
        print("NOTE: File is large. If Claude's context fills up, you can split it:")
        print("  - Paste just the 'academics' and 'students' sections first.")
        print("  - Then paste 'reports', 'backend', and 'templates' in a follow-up.")

if __name__ == "__main__":
    main()


======================================================================
FILE: test_all_models.py
======================================================================
#!/usr/bin/env python
"""
Test all school system models
"""
import os
import sys
import django
from datetime import date, timedelta

# Setup Django
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
django.setup()

print("=" * 60)
print("🧪 TESTING ALL SCHOOL SYSTEM MODELS")
print("=" * 60)

try:
    # Test 1: Import all models
    from core.models import CustomUser, School
    from students.models import Student, ParentGuardian
    from academics.models import SchoolClass, Subject, Attendance
    from finance.models import FeeStructure, Invoice, Payment
    from communication.models import SMSMessage, Announcement
    
    print("✅ All models imported successfully!")
    
    # Test 2: Create test data
    print("\n📊 Creating test data...")
    
    # Create a school
    school, created = School.objects.get_or_create(
        code="DOU-PRIMARY",
        defaults={
            'name': 'Douala Primary School',
            'address': 'Bonapriso, Douala',
            'city': 'Douala',
            'quarter': 'Bonapriso',
            'phone': '+237 233 000 000',
            'principal_name': 'Mr. Emmanuel',
        }
    )
    
    # Create a student
    student, created = Student.objects.get_or_create(
        student_id="2025-001",
        defaults={
            'first_name': 'Test',
            'last_name': 'Student',
            'date_of_birth': date(2018, 5, 15),
            'gender': 'M',
            'home_address': 'Test Address',
            'quarter': 'Bonapriso',
            'emergency_contact_phone': '+237 6xx xxx xxx',
            'emergency_contact_name': 'Test Parent',
            'emergency_contact_relationship': 'Guardian',
            'admission_date': date.today(),
        }
    )
    
    # Create a class
    school_class, created = SchoolClass.objects.get_or_create(
        code="CP-A",
        defaults={
            'level': 'cp',
            'section': 'A',
        }
    )
    
    # Create attendance
    attendance, created = Attendance.objects.get_or_create(
        student=student,
        date=date.today(),
        defaults={
            'school_class': school_class,
            'status': 'present',
        }
    )
    
    # Create fee structure
    fee, created = FeeStructure.objects.get_or_create(
        name="Tuition Fee",
        academic_year="2023-2024",
        defaults={
            'fee_type': 'tuition',
            'amount': 50000,
            'payment_frequency': 'termly',
        }
    )
    
    print(f"✅ Created: {school}")
    print(f"✅ Created: {student}")
    print(f"✅ Created: {school_class}")
    print(f"✅ Created: Attendance for {attendance.date}")
    print(f"✅ Created: {fee}")
    
    # Test 3: Count records
    print("\n📈 Model Statistics:")
    print(f"  Schools: {School.objects.count()}")
    print(f"  Students: {Student.objects.count()}")
    print(f"  Classes: {SchoolClass.objects.count()}")
    print(f"  Attendance records: {Attendance.objects.count()}")
    print(f"  Fee structures: {FeeStructure.objects.count()}")
    
    # Test 4: Verify relationships work
    print("\n🔗 Testing relationships...")
    print(f"  Student age: {student.get_age()} years")
    print(f"  Class full name: {school_class}")
    print(f"  Fee amount: {fee.amount} XAF")
    
    print("\n" + "=" * 60)
    print("🎉 ALL MODEL TESTS PASSED!")
    print("=" * 60)
    print("\n✅ Your school system is ready!")
    print(f"\n🔗 Admin URL: http://127.0.0.1:8000/admin/")
    print(f"📱 API Base URL: http://127.0.0.1:8000/api/")
    
except Exception as e:
    print(f"\n❌ ERROR: {str(e)}")
    import traceback
    traceback.print_exc()