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)