# pyrefly: ignore [missing-import] from odoo import models, fields, api # pyrefly: ignore [missing-import] from odoo.exceptions import ValidationError, AccessError class EducationLMSAssignment(models.Model): _name = 'education.lms.assignment' _description = 'LMS Assignment' course_id = fields.Many2one('education.lms.course', string='Course', required=True, ondelete='cascade') section_id = fields.Many2one('education.lms.section', string='Section', ondelete='set null') lesson_id = fields.Many2one('education.lms.lesson', string='Lesson', ondelete='set null') subject_id = fields.Many2one('education.subject', related='course_id.subject_id', store=True, string='Subject') faculty_id = fields.Many2one('res.users', related='course_id.faculty_id', store=True, string='Faculty') title = fields.Char(string='Title', required=True) instructions = fields.Html(string='Instructions') assigned_date = fields.Date(string='Assigned Date', required=True, default=fields.Date.context_today) due_date = fields.Date(string='Due Date', required=True) maximum_marks = fields.Float(string='Maximum Marks', required=True, default=100.0) attachment_ids = fields.Many2many('ir.attachment', string='Attachments') active = fields.Boolean(default=True) published = fields.Boolean(default=False) state = fields.Selection([ ('draft', 'Draft'), ('published', 'Published'), ('closed', 'Closed') ], string='State', default='draft', required=True) @api.constrains('assigned_date', 'due_date') def _check_dates(self): for record in self: if record.assigned_date and record.due_date and record.due_date < record.assigned_date: raise ValidationError("Due Date cannot be before Assigned Date.") @api.constrains('maximum_marks') def _check_marks(self): for record in self: if record.maximum_marks <= 0: raise ValidationError("Maximum marks must be greater than zero.") @api.constrains('course_id', 'section_id', 'lesson_id') def _check_hierarchy(self): for record in self: if record.section_id and record.section_id.course_id.id != record.course_id.id: raise ValidationError("The selected Section does not belong to the selected Course.") if record.lesson_id and record.lesson_id.section_id.id != record.section_id.id: raise ValidationError("The selected Lesson does not belong to the selected Section.") @api.constrains('state', 'course_id') def _check_publishing(self): for record in self: if record.state in ['published', 'closed'] or record.published: if record.course_id.state != 'published': raise ValidationError("Cannot publish or close an assignment for an unpublished course.") if record.state == 'closed' and not record.published: raise ValidationError("An assignment must be published before it can be closed.") @api.constrains('course_id') def _check_faculty_ownership(self): if self.env.su or self.env.user.has_group('education_lms.group_education_lms_admin'): return for record in self: if record.course_id.faculty_id.id != self.env.user.id: raise AccessError("Faculty members can only create assignments for their own courses.") def action_publish(self): for record in self: record.write({'state': 'published', 'published': True}) def action_close(self): for record in self: record.write({'state': 'closed'}) def write(self, vals): is_admin = self.env.su or self.env.user.has_group('education_lms.group_education_lms_admin') for record in self: # Lifecycle protections if record.state == 'closed' and vals.get('state') in ['draft', 'published']: raise ValidationError("Closed assignments cannot return to Draft or Published state.") # Faculty restrictions if not is_admin: if record.course_id.faculty_id.id != self.env.user.id: raise AccessError("You can only edit assignments for courses assigned to you.") # Prevent bypassing lifecycle by changing course if 'course_id' in vals and record.state != 'draft' and vals['course_id'] != record.course_id.id: raise AccessError("Cannot change the course of an assignment after it has been published.") return super().write(vals) def unlink(self): if not self.env.su and not self.env.user.has_group('education_lms.group_education_lms_admin'): for record in self: if record.course_id.faculty_id.id != self.env.user.id: raise AccessError("You can only delete assignments for courses assigned to you.") return super().unlink()