from psycopg2 import IntegrityError from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase from odoo.tools import mute_logger class TestExam(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() cls.year = cls.env["mc.academic.year"].create({ "name": "TEST-EXAM-2026-27", "date_start": "2026-06-01", "date_end": "2027-04-30", }) cls.term = cls.env["mc.academic.term"].create({ "name": "TEST EXAM Term", "year_id": cls.year.id, "date_start": "2026-06-01", "date_end": "2026-09-30", }) cls.program = cls.env["mc.program"].create({ "name": "TEST EXAM Program", "code": "TEST-EXAM-P1", "sequence_no": 1, "display_label": "Test Grade", }) cls.batch = cls.env["mc.batch"].create({ "name": "TEST EXAM Batch", "program_id": cls.program.id, "year_id": cls.year.id, }) cls.subject = cls.env["mc.subject"].create({"name": "TEST EXAM Subject", "code": "TEST-EXAM-S1"}) cls.exam = cls.env["mc.exam"].create({ "name": "TEST EXAM Midterm", "term_id": cls.term.id, "batch_id": cls.batch.id, "subject_id": cls.subject.id, "max_marks": 100, "pass_marks": 35, "date": "2026-07-01", }) cls.student1 = cls.env["mc.student"].create({ "partner_id": cls.env["res.partner"].create({"name": "EXAM Student One"}).id, "name": "EXAM Student One", }) cls.student2 = cls.env["mc.student"].create({ "partner_id": cls.env["res.partner"].create({"name": "EXAM Student Two"}).id, "name": "EXAM Student Two", }) cls.env["mc.enrollment"].create({ "student_id": cls.student1.id, "program_id": cls.program.id, "batch_id": cls.batch.id, "year_id": cls.year.id, "state": "active", }) cls.env["mc.enrollment"].create({ "student_id": cls.student2.id, "program_id": cls.program.id, "batch_id": cls.batch.id, "year_id": cls.year.id, "state": "active", }) def test_pass_marks_cannot_exceed_max_marks(self): with self.assertRaises(ValidationError): self.env["mc.exam"].create({ "name": "Bad Exam", "term_id": self.term.id, "batch_id": self.batch.id, "subject_id": self.subject.id, "max_marks": 100, "pass_marks": 150, "date": "2026-07-02", }) @mute_logger("odoo.sql_db") def test_duplicate_mark_for_same_student_exam_rejected(self): self.env["mc.mark"].create({ "exam_id": self.exam.id, "student_id": self.student1.id, "marks_obtained": 80, }) with self.assertRaises(IntegrityError): with self.cr.savepoint(): self.env["mc.mark"].create({ "exam_id": self.exam.id, "student_id": self.student1.id, "marks_obtained": 90, }) def test_enter_marks_creates_a_row_per_active_enrollment(self): action = self.exam.action_enter_marks() self.assertEqual(action["domain"], [("exam_id", "=", self.exam.id)]) marks = self.env["mc.mark"].search(action["domain"]) self.assertEqual(set(marks.mapped("student_id")), {self.student1, self.student2}) self.assertTrue(all(m.marks_obtained == 0 for m in marks)) def test_enter_marks_does_not_duplicate_existing_rows(self): self.env["mc.mark"].create({ "exam_id": self.exam.id, "student_id": self.student1.id, "marks_obtained": 75, }) self.exam.action_enter_marks() marks = self.env["mc.mark"].search([("exam_id", "=", self.exam.id)]) self.assertEqual(len(marks), 2) student1_mark = marks.filtered(lambda m: m.student_id == self.student1) self.assertEqual(student1_mark.marks_obtained, 75) # untouched, not reset to 0