105 lines
4.9 KiB
Python
105 lines
4.9 KiB
Python
# 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()
|