############################################################################### # # OpenEduCat Inc # Copyright (C) 2009-TODAY OpenEduCat Inc(). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # ############################################################################### import datetime from odoo import _, api, fields, models from odoo.exceptions import ValidationError class OpExam(models.Model): _name = "op.exam" _inherit = "mail.thread" _description = "Exam" session_id = fields.Many2one('op.exam.session', 'Exam Session', domain=[('state', 'not in', ['cancel', 'done'])]) course_id = fields.Many2one( 'op.course', related='session_id.course_id', store=True, readonly=True) batch_id = fields.Many2one( 'op.batch', 'Batch', related='session_id.batch_id', store=True, readonly=True) subject_id = fields.Many2one('op.subject', 'Subject', required=True) exam_code = fields.Char('Exam Code', size=16, required=True) attendees_line = fields.One2many( 'op.exam.attendees', 'exam_id', 'Attendees', readonly=True) start_time = fields.Datetime('Start Time', required=True) end_time = fields.Datetime('End Time', required=True) state = fields.Selection( [('draft', 'Draft'), ('schedule', 'Scheduled'), ('held', 'Held'), ('result_updated', 'Result Updated'), ('cancel', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, default='draft', tracking=True) note = fields.Text('Note') responsible_id = fields.Many2many('op.faculty', string='Responsible') name = fields.Char('Exam', size=256, required=True) total_marks = fields.Integer('Total Marks', required=True) min_marks = fields.Integer('Passing Marks', required=True) active = fields.Boolean(default=True) attendees_count = fields.Integer(string='Attendees Count', compute='_compute_attendees_count') _sql_constraints = [ ('unique_exam_code', 'unique(exam_code)', 'Code should be unique per exam!')] @api.constrains('total_marks', 'min_marks') def _check_marks(self): if self.total_marks <= 0.0 or self.min_marks <= 0.0: raise ValidationError(_('Enter proper marks!')) if self.min_marks > self.total_marks: raise ValidationError(_( "Passing Marks can't be greater than Total Marks")) @api.constrains('start_time', 'end_time') def _check_date_time(self): session_start = datetime.datetime.combine( fields.Date.from_string(self.session_id.start_date), datetime.time.min) session_end = datetime.datetime.combine( fields.Date.from_string(self.session_id.end_date), datetime.time.max) start_time = fields.Datetime.from_string(self.start_time) end_time = fields.Datetime.from_string(self.end_time) if start_time > end_time: raise ValidationError(_('End Time cannot be set before Start Time.')) elif start_time < session_start or start_time > session_end or \ end_time < session_start or end_time > session_end: raise ValidationError( _('Exam Time should in between Exam Session Dates.')) def open_exam_attendees(self): return { "type": "ir.actions.act_window", "res_model": "op.exam.attendees", "domain": [("exam_id", "=", self.id)], "name": "Students", "view_mode": "list,form", } def _compute_attendees_count(self): for record in self: record.attendees_count = self.env["op.exam.attendees"].search_count( [("exam_id", "=", record.id)]) @api.constrains('subject_id', 'start_time', 'end_time') def _check_overlapping_times(self): for record in self: existing_exams = self.env['op.exam'].search([ ('subject_id', '=', record.subject_id.id), ('id', '!=', record.id), ('start_time', '<', record.end_time), ('end_time', '>', record.start_time), ]) if existing_exams: raise ValidationError(_('The exam time overlaps with an existing exam for the same subject.')) # noqa def act_result_updated(self): self.state = 'result_updated' def act_done(self): self.state = 'done' def act_draft(self): self.state = 'draft' def act_cancel(self): self.state = 'cancel'