from odoo import api, fields, models from odoo.exceptions import ValidationError class CourseStudentScore(models.Model): _name = 'course.student.score' _description = '学生成绩' _rec_name = 'display_name' _order = 'course_id, student_id' _inherit = ['mail.thread'] display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True) @api.depends('course_name', 'stu_name') def _compute_display_name(self): for record in self: record.display_name = f"{record.stu_name} - {record.course_name}" course_id = fields.Many2one('learning.course', string='课程', required=True, ondelete='cascade') # 课程扩展只读字段(替代视图嵌套写法) course_code = fields.Char(string="课程代码", related="course_id.code", readonly=True) course_credit = fields.Float(string="学分", related="course_id.credit", readonly=True) course_exam_type = fields.Selection(string="考核方式", related="course_id.exam_type", readonly=True) course_name = fields.Char(related='course_id.name', string='课程', required=True, ondelete='cascade') student_id = fields.Many2one('student.info', string='学生', required=True) student_no = fields.Char(string="学号", related="student_id.stu_num", readonly=True) student_class_id = fields.Many2one( string="班级", related="student_id.class_id", readonly=True) student_major_id = fields.Many2one( string="专业", related="student_id.major_id", readonly=True) stu_name=fields.Char(related='student_id.stu_name',required=True, ondelete='cascade',string='学生姓名') score_ids = fields.One2many('course.student.score.detail', 'student_score_id', string='成绩明细') teaching_class_id=fields.Many2one('course.teaching_class',string='教学班') # 教学班相关只读关联字段 teaching_class_name = fields.Char(string="教学班名称", related="teaching_class_id.display_name", readonly=True) teaching_class_semester = fields.Selection(string="学期", related="teaching_class_id.semester", readonly=True) teaching_class_main_teacher = fields.Many2one('hr.employee', string="主讲教师", related="teaching_class_id.main_teacher_id", readonly=True) total_score = fields.Float(string='综合成绩', compute='_compute_total_score', store=True) grade_level = fields.Selection([ ('A', '优秀(A)'), ('B', '良好(B)'), ('C', '中等(C)'), ('D', '及格(D)'), ('F', '不及格(F)'), ], string='等级', compute='_compute_total_score', store=True) @api.depends('score_ids.score', 'score_ids.weight') def _compute_total_score(self): for record in self: total = 0.0 for detail in record.score_ids: if detail.score and detail.weight: total += detail.score * detail.weight / 100 record.total_score = round(total, 2) if record.total_score >= 90: record.grade_level = 'A' elif record.total_score >= 80: record.grade_level = 'B' elif record.total_score >= 70: record.grade_level = 'C' elif record.total_score >= 60: record.grade_level = 'D' else: record.grade_level = 'F' class CourseStudentScoreDetail(models.Model): _name = 'course.student.score.detail' _description = '学生成绩明细' _rec_name = 'display_name' _order = 'student_score_id, score_item_id' _inherit = ['mail.thread'] display_name = fields.Char(string='显示名称', compute='_compute_display_name', store=True) @api.depends('student_score_displayname', 'score_item_id.name') def _compute_display_name(self): for record in self: record.display_name = f"{record.student_score_displayname} - {record.score_item_id.name}" # 关联学生成绩主表 student_score_id = fields.Many2one('course.student.score', string='学生成绩', required=True, ondelete='cascade') student_score_displayname=fields.Char(related='student_score_id.display_name',required=True, ondelete='cascade',string='显示名称') # 关联成绩项目 score_item_id = fields.Many2one('course.score.item', string='成绩项目', required=True, ondelete='restrict') # 得分 score = fields.Float(string='得分', help='该项目实际得分') # 从成绩项目继承的字段(用于显示和计算) weight = fields.Float(string='权重(%)', related='score_item_id.weight', store=True, readonly=True) full_score = fields.Float(string='满分', related='score_item_id.full_score', store=True, readonly=True) score_type = fields.Selection(string='成绩类型', related='score_item_id.score_type', store=True, readonly=True) # 备注 remark = fields.Char(string='备注') # 关联课程和学生(用于视图显示) course_id = fields.Many2one('learning.course', string='课程', related='student_score_id.course_id', store=True, readonly=True) student_id = fields.Many2one('student.info', string='学生', related='student_score_id.student_id', store=True, readonly=True) # 完成率(得分/满分) completion_rate = fields.Float(string='完成率(%)', compute='_compute_completion_rate', store=True) @api.depends('score', 'full_score') def _compute_completion_rate(self): for record in self: if record.full_score and record.score: record.completion_rate = round(record.score / record.full_score * 100, 1) else: record.completion_rate = 0.0 @api.constrains('score', 'full_score') def _check_score(self): for record in self: if record.score and record.full_score and record.score > record.full_score: raise ValidationError(f'得分({record.score})不能超过满分({record.full_score})') if record.score and record.score < 0: raise ValidationError('得分不能为负数')