196 lines
7.2 KiB
Python
196 lines
7.2 KiB
Python
from odoo import api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
STYLE_SELECTION = [
|
|
("bharatanatyam", "Bharatanatyam"),
|
|
("kathak", "Kathak"),
|
|
("hiphop", "Hip-Hop"),
|
|
("contemporary", "Contemporary"),
|
|
("zumba", "Zumba"),
|
|
]
|
|
LEVEL_SELECTION = [
|
|
("beginner", "Beginner"),
|
|
("intermediate", "Intermediate"),
|
|
("advanced", "Advanced"),
|
|
]
|
|
|
|
|
|
class DanceEnrollmentRequest(models.Model):
|
|
_name = "dance.enrollment.request"
|
|
_description = "Website Enrollment Request"
|
|
_inherit = ["mail.thread"]
|
|
_order = "create_date desc, id desc"
|
|
_rec_name = "reference"
|
|
|
|
reference = fields.Char(default="New", readonly=True, copy=False, index=True)
|
|
student_name = fields.Char(string="Student Name", required=True, tracking=True)
|
|
date_of_birth = fields.Date()
|
|
gender = fields.Selection(
|
|
[("male", "Male"), ("female", "Female"), ("other", "Other")]
|
|
)
|
|
guardian_name = fields.Char(string="Parent / Guardian", required=True, tracking=True)
|
|
guardian_email = fields.Char(string="Email", required=True, tracking=True)
|
|
guardian_phone = fields.Char(string="Phone", required=True, tracking=True)
|
|
dance_style = fields.Selection(STYLE_SELECTION, string="Dance Style", tracking=True)
|
|
preferred_level = fields.Selection(LEVEL_SELECTION, string="Preferred Level")
|
|
batch_id = fields.Many2one("dance.batch", string="Preferred Batch")
|
|
message = fields.Text()
|
|
state = fields.Selection(
|
|
[
|
|
("new", "New Request"),
|
|
("contacted", "Contacted"),
|
|
("approved", "Approved"),
|
|
("rejected", "Rejected"),
|
|
("converted", "Enrolled"),
|
|
],
|
|
default="new",
|
|
required=True,
|
|
tracking=True,
|
|
)
|
|
student_id = fields.Many2one(
|
|
"res.partner", string="Student Record", readonly=True, copy=False
|
|
)
|
|
enrollment_id = fields.Many2one(
|
|
"dance.enrollment", string="Enrollment", readonly=True, copy=False
|
|
)
|
|
portal_user_id = fields.Many2one(
|
|
"res.users", string="Guardian Login", readonly=True, copy=False
|
|
)
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if vals.get("reference", "New") in ("New", False):
|
|
vals["reference"] = (
|
|
self.env["ir.sequence"].next_by_code("dance.enrollment.request")
|
|
or "New"
|
|
)
|
|
return super().create(vals_list)
|
|
|
|
# ── Workflow ──────────────────────────────────────────────────────────────
|
|
def action_mark_contacted(self):
|
|
self.filtered(lambda r: r.state == "new").write({"state": "contacted"})
|
|
|
|
def action_approve(self):
|
|
self.filtered(lambda r: r.state in ("new", "contacted")).write(
|
|
{"state": "approved"}
|
|
)
|
|
|
|
def action_reject(self):
|
|
self.filtered(lambda r: r.state not in ("converted",)).write(
|
|
{"state": "rejected"}
|
|
)
|
|
|
|
def action_reset_to_new(self):
|
|
self.filtered(lambda r: r.state != "converted").write({"state": "new"})
|
|
|
|
def action_convert(self):
|
|
for req in self:
|
|
if req.state == "converted":
|
|
continue
|
|
if req.state != "approved":
|
|
raise UserError(
|
|
"Only approved requests can be converted into an enrollment."
|
|
)
|
|
guardian = req._find_or_create_guardian()
|
|
student = req._create_student(guardian)
|
|
enrollment = self.env["dance.enrollment"]
|
|
if req.batch_id:
|
|
enrollment = enrollment.create(
|
|
{
|
|
"student_id": student.id,
|
|
"batch_id": req.batch_id.id,
|
|
"status": "active",
|
|
}
|
|
)
|
|
req.write(
|
|
{
|
|
"student_id": student.id,
|
|
"enrollment_id": enrollment.id if enrollment else False,
|
|
"state": "converted",
|
|
}
|
|
)
|
|
req._grant_guardian_portal(guardian)
|
|
req.message_post(
|
|
body="Enrollment request converted — student record %s created."
|
|
% student.display_name
|
|
)
|
|
return True
|
|
|
|
def action_open_student(self):
|
|
self.ensure_one()
|
|
return {
|
|
"type": "ir.actions.act_window",
|
|
"res_model": "res.partner",
|
|
"res_id": self.student_id.id,
|
|
"view_mode": "form",
|
|
}
|
|
|
|
# ── Conversion helpers ────────────────────────────────────────────────────
|
|
def _find_or_create_guardian(self):
|
|
self.ensure_one()
|
|
Partner = self.env["res.partner"]
|
|
guardian = Partner.browse()
|
|
if self.guardian_email:
|
|
guardian = Partner.search(
|
|
[("email", "=ilike", self.guardian_email)], limit=1
|
|
)
|
|
if not guardian:
|
|
guardian = Partner.create(
|
|
{
|
|
"name": self.guardian_name,
|
|
"email": self.guardian_email,
|
|
"phone": self.guardian_phone,
|
|
"is_student": False,
|
|
}
|
|
)
|
|
return guardian
|
|
|
|
def _create_student(self, guardian):
|
|
self.ensure_one()
|
|
return self.env["res.partner"].create(
|
|
{
|
|
"name": self.student_name,
|
|
"is_student": True,
|
|
"date_of_birth": self.date_of_birth,
|
|
"gender": self.gender,
|
|
"dance_style": self.dance_style,
|
|
"level": self.preferred_level,
|
|
"guardian_id": guardian.id,
|
|
"guardian_ids": [(4, guardian.id)],
|
|
"guardian_phone": self.guardian_phone,
|
|
"student_status": "active",
|
|
"join_date": fields.Date.context_today(self),
|
|
}
|
|
)
|
|
|
|
def _grant_guardian_portal(self, guardian):
|
|
"""Create a portal login for the guardian so they can reach /parent."""
|
|
self.ensure_one()
|
|
if self.portal_user_id or not guardian.email:
|
|
return
|
|
Users = self.env["res.users"].sudo()
|
|
existing = Users.with_context(active_test=False).search(
|
|
[("login", "=", guardian.email)], limit=1
|
|
)
|
|
if existing:
|
|
self.portal_user_id = existing
|
|
return
|
|
portal_group = self.env.ref("base.group_portal")
|
|
user = Users.with_context(no_reset_password=True).create(
|
|
{
|
|
"name": guardian.name,
|
|
"login": guardian.email,
|
|
"email": guardian.email,
|
|
"partner_id": guardian.id,
|
|
"groups_id": [(6, 0, [portal_group.id])],
|
|
}
|
|
)
|
|
self.portal_user_id = user
|
|
try:
|
|
user.with_context(create_user=True).action_reset_password()
|
|
except Exception:
|
|
# Mail server may not be configured — login still works once a
|
|
# password is set manually. Don't block the conversion.
|
|
pass
|