from odoo import fields, models class McGradingScale(models.Model): _name = "mc.grading.scale" _description = "Grading Scale" _order = "name" _rec_name = "name" name = fields.Char( string="Name", required=True, help="e.g. CBSE, ICSE, IB, Cambridge, Ontario, Percentage.", ) interval_ids = fields.One2many("mc.grading.interval", "scale_id", string="Grade Intervals") _name_uniq = models.Constraint( "unique(name)", "A grading scale with this name already exists.", ) def get_grade_interval(self, percentage): """The grade for a percentage is the interval with the highest threshold at or below it - e.g. "90 and above = A1", "80-89 = A2". Grading rules live here, as data on mc.grading.interval, so a different board is configuration, never a code change (O6 spec, shared/DOMAIN_MODEL.md sec 5 - the moment you write `if board == "CBSE"` you have already gotten this wrong). """ self.ensure_one() candidates = self.interval_ids.filtered(lambda i: percentage >= i.threshold) return candidates.sorted("threshold", reverse=True)[:1] class McGradingInterval(models.Model): _name = "mc.grading.interval" _description = "Grading Interval" _order = "threshold desc" _rec_name = "letter" scale_id = fields.Many2one("mc.grading.scale", string="Scale", required=True, ondelete="cascade") threshold = fields.Float(string="Threshold %", required=True) letter = fields.Char(string="Letter", required=True) point = fields.Float(string="Grade Point") description = fields.Char(string="Description") _scale_threshold_uniq = models.Constraint( "unique(scale_id, threshold)", "This scale already has an interval at this threshold.", ) _threshold_range = models.Constraint( "check(threshold >= 0 and threshold <= 100)", "A threshold must be between 0 and 100.", )