159 lines
5.4 KiB
Python
159 lines
5.4 KiB
Python
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class ResPartner(models.Model):
|
|
_inherit = "res.partner"
|
|
|
|
is_student = fields.Boolean(string="Is Student", default=False, index=True)
|
|
student_code = fields.Char(string="Student ID", copy=False, readonly=True, index=True)
|
|
|
|
guardian_id = fields.Many2one(
|
|
"res.partner",
|
|
string="Primary Guardian",
|
|
domain="[('is_student', '=', False)]",
|
|
)
|
|
guardian_ids = fields.Many2many(
|
|
"res.partner",
|
|
"student_guardian_rel",
|
|
"student_id",
|
|
"guardian_id",
|
|
string="Guardians",
|
|
domain="[('is_student', '=', False)]",
|
|
)
|
|
guardian_phone = fields.Char(string="Guardian Phone")
|
|
sibling_ids = fields.Many2many(
|
|
"res.partner",
|
|
"student_sibling_rel",
|
|
"student_id",
|
|
"sibling_id",
|
|
string="Sibling Students",
|
|
domain="[('is_student', '=', True)]",
|
|
)
|
|
|
|
date_of_birth = fields.Date(string="Date of Birth")
|
|
age = fields.Integer(string="Age", compute="_compute_age", store=True)
|
|
gender = fields.Selection(
|
|
[
|
|
("male", "Male"),
|
|
("female", "Female"),
|
|
("other", "Other"),
|
|
],
|
|
string="Gender",
|
|
)
|
|
|
|
medical_notes = fields.Text(string="Medical Notes")
|
|
|
|
dance_style = fields.Selection(
|
|
[
|
|
("bharatanatyam", "Bharatanatyam"),
|
|
("kathak", "Kathak"),
|
|
("hiphop", "Hip-Hop"),
|
|
("contemporary", "Contemporary"),
|
|
("zumba", "Zumba"),
|
|
],
|
|
string="Dance Style",
|
|
)
|
|
level = fields.Selection(
|
|
[
|
|
("beginner", "Beginner"),
|
|
("intermediate", "Intermediate"),
|
|
("advanced", "Advanced"),
|
|
],
|
|
string="Level",
|
|
)
|
|
|
|
student_status = fields.Selection(
|
|
[
|
|
("trial", "Trial"),
|
|
("active", "Active"),
|
|
("hold", "On Hold"),
|
|
("dropped", "Dropped"),
|
|
("alumni", "Alumni"),
|
|
],
|
|
default="trial",
|
|
string="Student Status",
|
|
tracking=True,
|
|
)
|
|
join_date = fields.Date(string="Join Date")
|
|
|
|
_sql_constraints = [
|
|
(
|
|
"student_code_unique",
|
|
"unique(student_code)",
|
|
"Student ID must be unique.",
|
|
),
|
|
]
|
|
|
|
@api.depends("date_of_birth")
|
|
def _compute_age(self):
|
|
today = fields.Date.today()
|
|
for partner in self:
|
|
partner.age = (
|
|
relativedelta(today, partner.date_of_birth).years
|
|
if partner.date_of_birth
|
|
else 0
|
|
)
|
|
|
|
@api.onchange("guardian_id")
|
|
def _onchange_guardian_id(self):
|
|
for partner in self:
|
|
if partner.guardian_id:
|
|
partner.guardian_phone = partner.guardian_id.phone or partner.guardian_id.mobile
|
|
|
|
@api.constrains("sibling_ids")
|
|
def _check_sibling_ids(self):
|
|
for partner in self:
|
|
if partner in partner.sibling_ids:
|
|
raise ValidationError("A student cannot be linked as their own sibling.")
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if vals.get("is_student") and not vals.get("student_code"):
|
|
vals["student_code"] = self._get_next_student_code()
|
|
if vals.get("guardian_id") and not vals.get("guardian_phone"):
|
|
guardian = self.env["res.partner"].browse(vals["guardian_id"])
|
|
vals["guardian_phone"] = guardian.phone or guardian.mobile
|
|
partners = super().create(vals_list)
|
|
partners._sync_sibling_links()
|
|
return partners
|
|
|
|
def write(self, vals):
|
|
old_sibling_map = {}
|
|
if "sibling_ids" in vals and not self.env.context.get("skip_sibling_sync"):
|
|
old_sibling_map = {partner.id: set(partner.sibling_ids.ids) for partner in self}
|
|
if vals.get("guardian_id") and "guardian_phone" not in vals:
|
|
guardian = self.env["res.partner"].browse(vals["guardian_id"])
|
|
vals = dict(vals, guardian_phone=guardian.phone or guardian.mobile)
|
|
result = super().write(vals)
|
|
if "sibling_ids" in vals and not self.env.context.get("skip_sibling_sync"):
|
|
self._sync_sibling_links(old_sibling_map)
|
|
return result
|
|
|
|
def _sync_sibling_links(self, old_sibling_map=None):
|
|
old_sibling_map = old_sibling_map or {}
|
|
for partner in self:
|
|
current_siblings = partner.sibling_ids.filtered(lambda sibling: sibling != partner)
|
|
old_siblings = self.browse(old_sibling_map.get(partner.id, set()))
|
|
removed_siblings = old_siblings - current_siblings
|
|
if removed_siblings:
|
|
removed_siblings.with_context(skip_sibling_sync=True).write(
|
|
{"sibling_ids": [(3, partner.id)]}
|
|
)
|
|
for sibling in current_siblings:
|
|
if partner not in sibling.sibling_ids:
|
|
sibling.with_context(skip_sibling_sync=True).write(
|
|
{"sibling_ids": [(4, partner.id)]}
|
|
)
|
|
|
|
def _get_next_student_code(self):
|
|
sequence = self.env["ir.sequence"]
|
|
for _attempt in range(100):
|
|
student_code = sequence.next_by_code("dance.student")
|
|
if not self.search_count([("student_code", "=", student_code)]):
|
|
return student_code
|
|
raise ValidationError("Could not generate a unique Student ID.")
|