170 lines
6.4 KiB
Python
170 lines
6.4 KiB
Python
from odoo import api, fields, models
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class DanceRehearsal(models.Model):
|
|
_name = "dance.rehearsal"
|
|
_description = "Dance Event Rehearsal"
|
|
_order = "date desc, start_time desc, id desc"
|
|
|
|
name = fields.Char(compute="_compute_name", store=True)
|
|
event_id = fields.Many2one("dance.event", required=True, ondelete="cascade")
|
|
date = fields.Date(required=True, default=fields.Date.context_today)
|
|
start_time = fields.Float(string="Start Time", required=True)
|
|
end_time = fields.Float(string="End Time")
|
|
display_time = fields.Char(compute="_compute_display_time")
|
|
room = fields.Char()
|
|
status = fields.Selection(
|
|
[
|
|
("scheduled", "Scheduled"),
|
|
("completed", "Completed"),
|
|
("cancelled", "Cancelled"),
|
|
],
|
|
default="scheduled",
|
|
required=True,
|
|
)
|
|
attendance_ids = fields.One2many(
|
|
"dance.rehearsal.attendance",
|
|
"rehearsal_id",
|
|
string="Attendance",
|
|
)
|
|
attendance_count = fields.Integer(compute="_compute_attendance_counts")
|
|
present_count = fields.Integer(compute="_compute_attendance_counts")
|
|
absent_count = fields.Integer(compute="_compute_attendance_counts")
|
|
late_count = fields.Integer(compute="_compute_attendance_counts")
|
|
notes = fields.Text()
|
|
|
|
@api.depends("event_id", "date", "start_time")
|
|
def _compute_name(self):
|
|
for rehearsal in self:
|
|
if rehearsal.event_id and rehearsal.date:
|
|
rehearsal.name = "%s rehearsal - %s" % (
|
|
rehearsal.event_id.name,
|
|
rehearsal.date,
|
|
)
|
|
else:
|
|
rehearsal.name = "New Rehearsal"
|
|
|
|
@api.depends("start_time", "end_time")
|
|
def _compute_display_time(self):
|
|
for rehearsal in self:
|
|
rehearsal.display_time = rehearsal._float_to_time(rehearsal.start_time)
|
|
if rehearsal.end_time:
|
|
rehearsal.display_time += " - %s" % rehearsal._float_to_time(rehearsal.end_time)
|
|
|
|
@api.depends("attendance_ids.status")
|
|
def _compute_attendance_counts(self):
|
|
for rehearsal in self:
|
|
rehearsal.attendance_count = len(rehearsal.attendance_ids)
|
|
rehearsal.present_count = len(
|
|
rehearsal.attendance_ids.filtered(lambda line: line.status == "present")
|
|
)
|
|
rehearsal.absent_count = len(
|
|
rehearsal.attendance_ids.filtered(lambda line: line.status == "absent")
|
|
)
|
|
rehearsal.late_count = len(
|
|
rehearsal.attendance_ids.filtered(lambda line: line.status == "late")
|
|
)
|
|
|
|
@api.constrains("start_time", "end_time")
|
|
def _check_times(self):
|
|
for rehearsal in self:
|
|
if rehearsal.end_time and rehearsal.start_time and rehearsal.end_time <= rehearsal.start_time:
|
|
raise ValidationError("End time must be after start time.")
|
|
|
|
def action_load_students(self):
|
|
for rehearsal in self:
|
|
students = rehearsal.event_id.performance_ids.mapped("student_id") or rehearsal.event_id.student_ids
|
|
existing_student_ids = set(rehearsal.attendance_ids.mapped("student_id").ids)
|
|
vals_list = []
|
|
for student in students:
|
|
if student.id in existing_student_ids:
|
|
continue
|
|
vals_list.append(
|
|
{
|
|
"rehearsal_id": rehearsal.id,
|
|
"student_id": student.id,
|
|
"status": "present",
|
|
}
|
|
)
|
|
if vals_list:
|
|
self.env["dance.rehearsal.attendance"].create(vals_list)
|
|
return True
|
|
|
|
def action_mark_all_present(self):
|
|
for rehearsal in self:
|
|
if not rehearsal.attendance_ids:
|
|
rehearsal.action_load_students()
|
|
rehearsal.attendance_ids.write({"status": "present"})
|
|
return True
|
|
|
|
def action_complete(self):
|
|
self.write({"status": "completed"})
|
|
return True
|
|
|
|
def action_cancel(self):
|
|
self.write({"status": "cancelled"})
|
|
return True
|
|
|
|
def action_send_rehearsal_reminder(self):
|
|
for rehearsal in self:
|
|
students = rehearsal.attendance_ids.mapped("student_id") or rehearsal.event_id.performance_ids.mapped("student_id") or rehearsal.event_id.student_ids
|
|
rehearsal.event_id._create_whatsapp_logs(
|
|
"rehearsal_reminder",
|
|
students,
|
|
rehearsal=rehearsal,
|
|
)
|
|
return True
|
|
|
|
def _float_to_time(self, value):
|
|
hours = int(value or 0)
|
|
minutes = int(round(((value or 0) - hours) * 60))
|
|
suffix = "AM" if hours < 12 else "PM"
|
|
display_hours = hours % 12 or 12
|
|
return "%d:%02d %s" % (display_hours, minutes, suffix)
|
|
|
|
|
|
class DanceRehearsalAttendance(models.Model):
|
|
_name = "dance.rehearsal.attendance"
|
|
_description = "Dance Rehearsal Attendance"
|
|
_order = "rehearsal_id desc, student_id"
|
|
|
|
rehearsal_id = fields.Many2one("dance.rehearsal", required=True, ondelete="cascade")
|
|
event_id = fields.Many2one(related="rehearsal_id.event_id", store=True, readonly=True)
|
|
student_id = fields.Many2one(
|
|
"res.partner",
|
|
required=True,
|
|
domain="[('is_student', '=', True)]",
|
|
ondelete="restrict",
|
|
)
|
|
date = fields.Date(related="rehearsal_id.date", store=True, readonly=True)
|
|
status = fields.Selection(
|
|
[
|
|
("present", "Present"),
|
|
("absent", "Absent"),
|
|
("late", "Late"),
|
|
],
|
|
default="present",
|
|
required=True,
|
|
)
|
|
remarks = fields.Text()
|
|
|
|
_sql_constraints = [
|
|
(
|
|
"unique_rehearsal_attendance",
|
|
"unique(student_id, rehearsal_id)",
|
|
"Attendance is already marked for this student in this rehearsal.",
|
|
),
|
|
]
|
|
|
|
@api.constrains("student_id", "rehearsal_id")
|
|
def _check_student_in_event(self):
|
|
for attendance in self:
|
|
if attendance.student_id and attendance.rehearsal_id:
|
|
event = attendance.rehearsal_id.event_id
|
|
event_students = event.performance_ids.mapped("student_id") or event.student_ids
|
|
if attendance.student_id not in event_students:
|
|
raise ValidationError(
|
|
"Attendance can only be marked for students participating in this event."
|
|
)
|