160 lines
6.7 KiB
Python
160 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,
|
|
)
|
|
|
|
_uniq_session_period = models.Constraint('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'})
|