odoo_18_Education_management/models/gradesheet.py

243 lines
8.9 KiB
Python

from odoo import models, fields, api
from odoo.exceptions import ValidationError, UserError
class SchoolGradesheet(models.Model):
_name = 'school.gradesheet'
_description = 'Student Gradesheet Report'
_order = 'session, class_name, course_id'
_inherit = ['mail.thread', 'mail.activity.mixin']
# Filter Fields
session = fields.Char(string="Session", required=True, help="Academic Session (e.g., 2024-2025)")
# application_id = fields.Many2one('school.application', string="Application", required=True)
# student_id = fields.Many2one('res.partner', string='Student', required=True)
# roll_number = fields.Char(string="Roll Number")
obtained_marks = fields.Float(
string="Obtained Marks",
default=0.0
)
total_marks = fields.Float(
string="Total Marks",
default=100.0
)
percentage = fields.Float(
string="Percentage (%)",
compute="_compute_percentage",
store=True
)
final_grade = fields.Selection([
('A+', 'A+ (90-100%)'),
('A', 'A (80-89%)'),
('B+', 'B+ (70-79%)'),
('B', 'B (60-69%)'),
('C', 'C (50-59%)'),
('D', 'D (40-49%)'),
('F', 'F (Below 40%)')
], string="Grade", default='F')
status = fields.Selection([
('pass', 'Pass'),
('fail', 'Fail')
], string="Status", default='fail')
remarks = fields.Text(string="Remarks")
class_name = fields.Selection([
('1', 'Class 1'), ('2', 'Class 2'), ('3', 'Class 3'),
('4', 'Class 4'), ('5', 'Class 5'), ('6', 'Class 6'),
('7', 'Class 7'), ('8', 'Class 8'), ('9', 'Class 9'),
('10', 'Class 10'), ('11', 'Class 11'), ('12', 'Class 12'),
], string="Class", required=True)
course_id = fields.Many2one('school.course', string="Course", required=True)
subject_id = fields.Many2one('school.subject', string="Subject")
# Report Generation Status
state = fields.Selection([
('draft', 'Draft'),
('generated', 'Generated'),
('finalized', 'Finalized')
], string="Status", default='draft', tracking=True)
# Generated Data
student_grade_ids = fields.One2many(
'school.gradesheet.line', 'gradesheet_id', string="Student Grades"
)
# Report Info
generated_date = fields.Datetime(string="Generated Date", readonly=True)
generated_by = fields.Many2one('res.users', string="Generated By", readonly=True)
total_students = fields.Integer(string="Total Students", compute="_compute_student_stats", store=True)
passed_students = fields.Integer(string="Passed Students", compute="_compute_student_stats", store=True)
failed_students = fields.Integer(string="Failed Students", compute="_compute_student_stats", store=True)
pass_percentage = fields.Float(string="Pass Percentage", compute="_compute_student_stats", store=True)
@api.depends('student_grade_ids', 'student_grade_ids.final_grade', 'student_grade_ids.status')
def _compute_student_stats(self):
for record in self:
total = len(record.student_grade_ids)
passed = len(record.student_grade_ids.filtered(lambda x: x.status == 'pass'))
failed = total - passed
record.total_students = total
record.passed_students = passed
record.failed_students = failed
record.pass_percentage = (passed / total * 100) if total > 0 else 0.0
@api.onchange('class_name')
def _onchange_class_name(self):
if self.class_name:
return {
'domain': {
'course_id': [('class_id.name', '=', f'Class {self.class_name}')],
'subject_id': [('class_name', '=', f'Class {self.class_name}')], #Add this
}
}
return {
'domain': {
'course_id': [],
'subject_id': [],
}
}
def action_fetch_student_marks(self):
"""Fetch student marks and generate gradesheet"""
self.ensure_one()
if not all([self.session, self.class_name, self.course_id]):
raise UserError("Please fill all required fields: Session, Class, and Course.")
# Clear existing lines
self.student_grade_ids.unlink()
# Get enrolled students for the course
enrollments = self.env['school.enrollment'].search([
('course_id', '=', self.course_id.id),
('class_name', '=', self.class_name),
('session', '=', self.session),
('status', '=', 'confirmed')
])
if not enrollments:
raise UserError(f"No enrolled students found for Class {self.class_name}, Course {self.course_id.name}, Session {self.session}")
grade_lines = []
for enrollment in enrollments:
# Get student marks (you may need to adapt this based on your marks/exam model)
student_marks = self._get_student_marks(enrollment)
grade_lines.append({
'gradesheet_id': self.id,
'student_id': enrollment.student_id.id,
'enrollment_id': enrollment.id,
'student_name': enrollment.student_id.name,
'roll_number': enrollment.application_id.roll_no if enrollment.application_id else '',
'obtained_marks': student_marks.get('obtained_marks', 0),
'total_marks': student_marks.get('total_marks', 100),
'percentage': student_marks.get('percentage', 0),
'final_grade': student_marks.get('grade', 'F'),
'status': student_marks.get('status', 'fail'),
'remarks': student_marks.get('remarks', ''),
'subject_id': self.subject_id.id,
})
# Create grade lines
self.env['school.gradesheet.line'].create(grade_lines)
# Update gradesheet status
self.write({
'state': 'generated',
'generated_date': fields.Datetime.now(),
'generated_by': self.env.user.id,
})
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'message': f'Gradesheet generated successfully! Found {len(grade_lines)} students.',
'type': 'success',
'sticky': False,
}
}
def _get_student_marks(self, enrollment):
"""
Get student marks from your existing marks/exam system
This is a placeholder - adapt according to your actual marks model
"""
# Example: If you have a student.marks model or exam.result model
# marks_record = self.env['student.marks'].search([
# ('student_id', '=', enrollment.student_id.id),
# ('course_id', '=', self.course_id.id),
# ('session', '=', self.session)
# ], limit=1)
# For demo purposes, generating sample marks
# Replace this with actual marks fetching logic
import random
obtained = random.randint(30, 95)
total = 100
percentage = (obtained / total) * 100
# Grade calculation
if percentage >= 90:
grade = 'A+'
status = 'pass'
elif percentage >= 80:
grade = 'A'
status = 'pass'
elif percentage >= 70:
grade = 'B+'
status = 'pass'
elif percentage >= 60:
grade = 'B'
status = 'pass'
elif percentage >= 50:
grade = 'C'
status = 'pass'
elif percentage >= 40:
grade = 'D'
status = 'pass'
else:
grade = 'F'
status = 'fail'
return {
'obtained_marks': obtained,
'total_marks': total,
'percentage': percentage,
'grade': grade,
'status': status,
'remarks': 'Good' if status == 'pass' else 'Needs Improvement'
}
def action_finalize_gradesheet(self):
"""Finalize the gradesheet"""
self.ensure_one()
if self.state != 'generated':
raise UserError("Please generate the gradesheet first.")
self.state = 'finalized'
return True
def action_reset_to_draft(self):
"""Reset gradesheet to draft"""
self.ensure_one()
self.student_grade_ids.unlink()
self.write({
'state': 'draft',
'generated_date': False,
'generated_by': False,
})
return True
def action_print_gradesheet(self):
"""Print gradesheet report"""
self.ensure_one()
if not self.student_grade_ids:
raise UserError("No student data found. Please fetch student marks first.")
return self.env.ref('school_management.report_school_gradesheet').report_action(self)