2026-09-15 10:47:19 +05:30

162 lines
6.7 KiB
Python

# pyrefly: ignore [missing-import]
from odoo import api, fields, models
# pyrefly: ignore [missing-import]
from odoo.exceptions import ValidationError
class EducationAttendanceSession(models.Model):
_name = 'education.attendance.session'
_description = 'Attendance Session'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = 'attendance_date desc, period asc, id desc'
name = fields.Char(string='Session Title', required=True, tracking=True)
campus_id = fields.Many2one('education.campus', string='Campus', required=True, index=True)
department_id = fields.Many2one('education.department', string='Department', required=True, index=True)
program_id = fields.Many2one('education.program', string='Program', required=True, index=True)
academic_year_id = fields.Many2one('education.academic.year', string='Academic Year', required=True, index=True)
academic_term_id = fields.Many2one('education.academic.term', string='Academic Term', required=True, index=True)
academic_level_id = fields.Many2one('education.academic.level', string='Academic Level', required=True, index=True)
attendance_date = fields.Date(string='Attendance Date', required=True, default=fields.Date.context_today, index=True, tracking=True)
period = fields.Selection([
('period_1', 'Period 1'),
('period_2', 'Period 2'),
('period_3', 'Period 3'),
('period_4', 'Period 4'),
('period_5', 'Period 5'),
('period_6', 'Period 6'),
('period_7', 'Period 7'),
('period_8', 'Period 8')
], string='Period', required=True, default='period_1', tracking=True)
faculty_id = fields.Many2one('res.users', string='Faculty', required=True, index=True, default=lambda self: self.env.user, tracking=True)
state = fields.Selection([
('draft', 'Draft'),
('open', 'Open'),
('completed', 'Completed'),
('cancelled', 'Cancelled')
], string='Status', default='draft', required=True, index=True, tracking=True)
line_ids = fields.One2many('education.attendance.line', 'session_id', string='Attendance Lines', copy=True)
active = fields.Boolean(default=True)
company_id = fields.Many2one(
'res.company',
string='Company',
required=True,
default=lambda self: self.env.company,
index=True,
)
_sql_constraints = [
('uniq_session_period', 'unique(attendance_date, period, program_id, academic_level_id, company_id)', 'An attendance session has already been created for this period, program, and academic level on this date.'),
]
def action_open(self):
for rec in self:
if rec.state != 'draft':
continue
# Auto-populate attendance lines with active students
students = self.env['education.student'].search([
('campus_id', '=', rec.campus_id.id),
('department_id', '=', rec.department_id.id),
('program_id', '=', rec.program_id.id),
('academic_year_id', '=', rec.academic_year_id.id),
('academic_term_id', '=', rec.academic_term_id.id),
('level_id', '=', rec.academic_level_id.id),
('status', '=', 'active'),
])
if not students:
raise ValidationError("No active students found matching the selected academic criteria.")
# Create lines
lines_vals = []
for student in students:
lines_vals.append({
'session_id': rec.id,
'student_id': student.id,
'status': 'present',
'company_id': rec.company_id.id,
})
self.env['education.attendance.line'].create(lines_vals)
rec.state = 'open'
def action_complete(self):
for rec in self:
if rec.state != 'open':
continue
if not rec.line_ids:
raise ValidationError("Cannot complete session without any student lines.")
# Copy to permanent history table
history_vals = []
for line in rec.line_ids:
history_vals.append({
'student_id': line.student_id.id,
'date': rec.attendance_date,
'session_id': rec.id,
'status': line.status,
'faculty_id': rec.faculty_id.id,
'remarks': line.remarks,
'company_id': rec.company_id.id,
})
self.env['education.attendance'].create(history_vals)
rec.state = 'completed'
# Invalidate student attendance cache
students = rec.line_ids.mapped('student_id')
students.invalidate_recordset()
def action_cancel(self):
for rec in self:
if rec.state == 'completed':
# Delete permanent history
history = self.env['education.attendance'].search([('session_id', '=', rec.id)])
history.unlink()
# Delete lines
rec.line_ids.unlink()
rec.state = 'cancelled'
def action_draft(self):
for rec in self:
# Delete permanent history if completed
if rec.state == 'completed':
history = self.env['education.attendance'].search([('session_id', '=', rec.id)])
history.unlink()
# Delete lines
rec.line_ids.unlink()
rec.state = 'draft'
# Bulk marking actions
def action_bulk_present(self):
self.ensure_one()
if self.state != 'open':
raise ValidationError("Bulk marking is only allowed when the session is Open.")
self.line_ids.write({'status': 'present'})
def action_bulk_absent(self):
self.ensure_one()
if self.state != 'open':
raise ValidationError("Bulk marking is only allowed when the session is Open.")
self.line_ids.write({'status': 'absent'})
def action_bulk_late(self):
self.ensure_one()
if self.state != 'open':
raise ValidationError("Bulk marking is only allowed when the session is Open.")
self.line_ids.write({'status': 'late'})
def action_bulk_medical(self):
self.ensure_one()
if self.state != 'open':
raise ValidationError("Bulk marking is only allowed when the session is Open.")
self.line_ids.write({'status': 'medical_leave'})
def action_bulk_duty(self):
self.ensure_one()
if self.state != 'open':
raise ValidationError("Bulk marking is only allowed when the session is Open.")
self.line_ids.write({'status': 'on_duty'})