419 lines
15 KiB
Python
419 lines
15 KiB
Python
# ============================================================
|
|
# Rhythm & Grace Dance Academy — DEMO DATA SEED
|
|
# Run with: docker exec -i odoo_dance odoo shell -d dance_school_erp \
|
|
# --no-http < scripts/seed_demo.py
|
|
# ============================================================
|
|
import random
|
|
from datetime import date, timedelta
|
|
|
|
random.seed(42)
|
|
today = date.today()
|
|
PWD = "Dance@2026"
|
|
|
|
|
|
def section(title):
|
|
print("\n" + "=" * 60)
|
|
print(" " + title)
|
|
print("=" * 60)
|
|
|
|
|
|
Employee = env["hr.employee"]
|
|
Users = env["res.users"]
|
|
Partner = env["res.partner"]
|
|
Batch = env["dance.batch"]
|
|
Enrollment = env["dance.enrollment"]
|
|
Session = env["dance.session"]
|
|
Attendance = env["dance.attendance"]
|
|
Move = env["account.move"]
|
|
Request = env["dance.enrollment.request"]
|
|
|
|
internal_group = env.ref("base.group_user")
|
|
portal_group = env.ref("base.group_portal")
|
|
|
|
# ------------------------------------------------------------
|
|
# 1. TEACHERS — employee + internal user login
|
|
# ------------------------------------------------------------
|
|
section("TEACHERS")
|
|
teacher_specs = [
|
|
("Ananya Rao", "ananya.teacher@demo.com", "Senior Bharatanatyam Instructor"),
|
|
("Rahul Menon", "rahul.teacher@demo.com", "Hip-Hop Instructor"),
|
|
("Sophia Williams", "sophia.teacher@demo.com", "Contemporary Instructor"),
|
|
("Meera Iyer", "meera.teacher@demo.com", "Kathak & Zumba Instructor"),
|
|
]
|
|
teachers = {}
|
|
for name, login, title in teacher_specs:
|
|
emp = Employee.search([("name", "=", name)], limit=1)
|
|
if not emp:
|
|
emp = Employee.create({"name": name, "job_title": title})
|
|
else:
|
|
emp.job_title = title
|
|
user = Users.search([("login", "=", login)], limit=1)
|
|
if not user:
|
|
user = Users.with_context(no_reset_password=True).create(
|
|
{
|
|
"name": name,
|
|
"login": login,
|
|
"email": login,
|
|
"password": PWD,
|
|
"groups_id": [(6, 0, [internal_group.id])],
|
|
}
|
|
)
|
|
if not emp.user_id:
|
|
emp.user_id = user.id
|
|
if not emp.work_email:
|
|
emp.work_email = login
|
|
teachers[name] = emp
|
|
print(" teacher:", name, "->", login)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 2. PARENTS — partner + portal user login
|
|
# ------------------------------------------------------------
|
|
section("PARENTS")
|
|
parent_specs = [
|
|
("Priya Sharma", "priya.parent@demo.com", "+1 555 0101"),
|
|
("Marcus Johnson", "marcus.parent@demo.com", "+1 555 0102"),
|
|
("Aisha Patel", "aisha.parent@demo.com", "+1 555 0103"),
|
|
("David Chen", "david.parent@demo.com", "+1 555 0104"),
|
|
]
|
|
parents = {}
|
|
for name, login, phone in parent_specs:
|
|
partner = Partner.search([("email", "=", login)], limit=1)
|
|
if not partner:
|
|
partner = Partner.create(
|
|
{"name": name, "email": login, "phone": phone, "is_student": False}
|
|
)
|
|
user = Users.search([("login", "=", login)], limit=1)
|
|
if not user:
|
|
user = Users.with_context(no_reset_password=True).create(
|
|
{
|
|
"name": name,
|
|
"login": login,
|
|
"email": login,
|
|
"password": PWD,
|
|
"partner_id": partner.id,
|
|
"groups_id": [(6, 0, [portal_group.id])],
|
|
}
|
|
)
|
|
parents[name] = partner
|
|
print(" parent:", name, "->", login)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 3. STUDENTS
|
|
# ------------------------------------------------------------
|
|
section("STUDENTS")
|
|
student_specs = [
|
|
("Diya Sharma", "Priya Sharma", "bharatanatyam", "intermediate", date(2014, 3, 12)),
|
|
("Arjun Sharma", "Priya Sharma", "hiphop", "beginner", date(2016, 7, 5)),
|
|
("Liam Johnson", "Marcus Johnson", "hiphop", "advanced", date(2011, 1, 22)),
|
|
("Emma Johnson", "Marcus Johnson", "contemporary", "intermediate", date(2013, 9, 9)),
|
|
("Zara Patel", "Aisha Patel", "kathak", "beginner", date(2017, 5, 2)),
|
|
("Aryan Patel", "Aisha Patel", "bharatanatyam", "beginner", date(2015, 11, 30)),
|
|
("Lucas Chen", "David Chen", "contemporary", "advanced", date(2010, 6, 18)),
|
|
("Mia Chen", "David Chen", "zumba", "intermediate", date(2012, 2, 14)),
|
|
]
|
|
students = {}
|
|
for name, parent_name, style, level, dob in student_specs:
|
|
s = Partner.search([("name", "=", name), ("is_student", "=", True)], limit=1)
|
|
if not s:
|
|
s = Partner.create(
|
|
{
|
|
"name": name,
|
|
"is_student": True,
|
|
"guardian_id": parents[parent_name].id,
|
|
"guardian_ids": [(4, parents[parent_name].id)],
|
|
"dance_style": style,
|
|
"level": level,
|
|
"date_of_birth": dob,
|
|
"student_status": "active",
|
|
"join_date": today - timedelta(days=random.randint(120, 600)),
|
|
}
|
|
)
|
|
students[name] = s
|
|
print(" student:", name, "(", s.student_code or "-", ") guardian", parent_name)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 4. BATCHES
|
|
# ------------------------------------------------------------
|
|
section("BATCHES")
|
|
# name, style, level, teacher, room, start, end, days
|
|
batch_specs = [
|
|
("Bharatanatyam — Intermediate", "bharatanatyam", "intermediate",
|
|
"Ananya Rao", "Studio A", 16.0, 17.5, "Mon/Wed"),
|
|
("Hip-Hop — Juniors", "hiphop", "beginner",
|
|
"Rahul Menon", "Studio B", 17.5, 18.5, "Tue/Thu"),
|
|
("Hip-Hop — Advanced", "hiphop", "advanced",
|
|
"Rahul Menon", "Studio B", 18.5, 20.0, "Tue/Thu"),
|
|
("Contemporary — All Levels", "contemporary", "intermediate",
|
|
"Sophia Williams", "Studio C", 17.0, 18.5, "Wed/Fri"),
|
|
("Kathak — Beginners", "kathak", "beginner",
|
|
"Meera Iyer", "Studio D", 16.0, 17.0, "Sat"),
|
|
("Zumba Fitness", "zumba", "intermediate",
|
|
"Meera Iyer", "Studio E", 18.0, 19.0, "Sat"),
|
|
]
|
|
batch_days = {
|
|
"Bharatanatyam — Intermediate": [0, 2],
|
|
"Hip-Hop — Juniors": [1, 3],
|
|
"Hip-Hop — Advanced": [1, 3],
|
|
"Contemporary — All Levels": [2, 4],
|
|
"Kathak — Beginners": [5],
|
|
"Zumba Fitness": [5],
|
|
}
|
|
batches = {}
|
|
for name, style, level, teacher, room, st, et, days in batch_specs:
|
|
b = Batch.search([("name", "=", name)], limit=1)
|
|
if not b:
|
|
b = Batch.create(
|
|
{
|
|
"name": name,
|
|
"dance_style": style,
|
|
"level": level,
|
|
"instructor_id": teachers[teacher].id,
|
|
"room": room,
|
|
"capacity": 16,
|
|
"start_date": today - timedelta(days=180),
|
|
"end_date": today + timedelta(days=180),
|
|
"start_time": st,
|
|
"end_time": et,
|
|
"schedule_days": days,
|
|
"status": "active",
|
|
}
|
|
)
|
|
batches[name] = b
|
|
print(" batch:", name, "-", teacher)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 5. ENROLLMENTS
|
|
# ------------------------------------------------------------
|
|
section("ENROLLMENTS")
|
|
enroll_map = [
|
|
("Diya Sharma", "Bharatanatyam — Intermediate"),
|
|
("Diya Sharma", "Contemporary — All Levels"),
|
|
("Arjun Sharma", "Hip-Hop — Juniors"),
|
|
("Liam Johnson", "Hip-Hop — Advanced"),
|
|
("Liam Johnson", "Zumba Fitness"),
|
|
("Emma Johnson", "Contemporary — All Levels"),
|
|
("Zara Patel", "Kathak — Beginners"),
|
|
("Aryan Patel", "Bharatanatyam — Intermediate"),
|
|
("Lucas Chen", "Contemporary — All Levels"),
|
|
("Mia Chen", "Zumba Fitness"),
|
|
("Mia Chen", "Kathak — Beginners"),
|
|
]
|
|
batch_students = {}
|
|
for sname, bname in enroll_map:
|
|
s, b = students[sname], batches[bname]
|
|
e = Enrollment.search(
|
|
[("student_id", "=", s.id), ("batch_id", "=", b.id)], limit=1
|
|
)
|
|
if not e:
|
|
e = Enrollment.create(
|
|
{
|
|
"student_id": s.id,
|
|
"batch_id": b.id,
|
|
"status": "active",
|
|
"enrollment_date": today - timedelta(days=random.randint(60, 300)),
|
|
}
|
|
)
|
|
batch_students.setdefault(bname, []).append(s)
|
|
print(" enrolled:", sname, "in", bname)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 6. SESSIONS (6 weeks past .. 3 weeks ahead)
|
|
# ------------------------------------------------------------
|
|
section("SESSIONS")
|
|
sessions_by_batch = {}
|
|
created_sessions = 0
|
|
for bname, b in batches.items():
|
|
days = batch_days[bname]
|
|
recs = []
|
|
d = today - timedelta(days=42)
|
|
horizon = today + timedelta(days=21)
|
|
while d <= horizon:
|
|
if d.weekday() in days:
|
|
existing = Session.search(
|
|
[("batch_id", "=", b.id), ("date", "=", d)], limit=1
|
|
)
|
|
if existing:
|
|
recs.append(existing)
|
|
else:
|
|
status = "completed" if d < today else "scheduled"
|
|
try:
|
|
rec = Session.create(
|
|
{"batch_id": b.id, "date": d, "status": status}
|
|
)
|
|
recs.append(rec)
|
|
created_sessions += 1
|
|
except Exception as ex:
|
|
print(" ! skipped session", bname, d, "-", ex)
|
|
d += timedelta(days=1)
|
|
sessions_by_batch[bname] = recs
|
|
print(" sessions created:", created_sessions)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 7. ATTENDANCE (completed sessions only)
|
|
# ------------------------------------------------------------
|
|
section("ATTENDANCE")
|
|
att_created = 0
|
|
for bname, recs in sessions_by_batch.items():
|
|
studs = batch_students.get(bname, [])
|
|
for sess in recs:
|
|
if sess.status != "completed":
|
|
continue
|
|
for stud in studs:
|
|
if Attendance.search(
|
|
[("session_id", "=", sess.id), ("student_id", "=", stud.id)],
|
|
limit=1,
|
|
):
|
|
continue
|
|
roll = random.random()
|
|
status = "present" if roll < 0.82 else ("late" if roll < 0.92 else "absent")
|
|
try:
|
|
Attendance.create(
|
|
{
|
|
"session_id": sess.id,
|
|
"student_id": stud.id,
|
|
"status": status,
|
|
}
|
|
)
|
|
att_created += 1
|
|
except Exception as ex:
|
|
print(" ! skipped attendance", "-", ex)
|
|
# mark completed sessions done
|
|
for sess in recs:
|
|
if sess.status == "completed" and sess.status != "completed":
|
|
pass
|
|
print(" attendance records created:", att_created)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
# 8. FEE INVOICES (3 months: 2 paid, current month mixed)
|
|
# ------------------------------------------------------------
|
|
section("FEE INVOICES")
|
|
income = env["account.account"].search([("account_type", "=", "income")], limit=1)
|
|
fee_by_level = {"beginner": 80.0, "intermediate": 110.0, "advanced": 140.0}
|
|
|
|
this_month = today.replace(day=1)
|
|
m1 = (this_month - timedelta(days=1)).replace(day=1)
|
|
m2 = (m1 - timedelta(days=1)).replace(day=1)
|
|
invoice_months = [(m2, True), (m1, True), (this_month, None)] # None = random
|
|
|
|
paid_count = open_count = 0
|
|
for sname, bname in enroll_map:
|
|
student, batch = students[sname], batches[bname]
|
|
amount = fee_by_level.get(batch.level, 100.0)
|
|
for inv_date, pay in invoice_months:
|
|
dup = Move.search(
|
|
[
|
|
("move_type", "=", "out_invoice"),
|
|
("partner_id", "=", student.id),
|
|
("invoice_date", "=", inv_date),
|
|
("dance_batch_id", "=", batch.id),
|
|
],
|
|
limit=1,
|
|
)
|
|
if dup:
|
|
continue
|
|
line = {
|
|
"name": "Monthly Tuition — %s" % batch.name,
|
|
"quantity": 1,
|
|
"price_unit": amount,
|
|
"tax_ids": [(6, 0, [])],
|
|
}
|
|
if income:
|
|
line["account_id"] = income.id
|
|
try:
|
|
move = Move.create(
|
|
{
|
|
"move_type": "out_invoice",
|
|
"partner_id": student.id,
|
|
"dance_student_id": student.id,
|
|
"dance_batch_id": batch.id,
|
|
"invoice_date": inv_date,
|
|
"invoice_line_ids": [(0, 0, line)],
|
|
}
|
|
)
|
|
move.action_post()
|
|
except Exception as ex:
|
|
print(" ! invoice failed", sname, inv_date, "-", ex)
|
|
continue
|
|
should_pay = pay if pay is not None else (random.random() < 0.5)
|
|
if should_pay:
|
|
try:
|
|
wiz = (
|
|
env["account.payment.register"]
|
|
.with_context(
|
|
active_model="account.move", active_ids=move.ids
|
|
)
|
|
.create({})
|
|
)
|
|
wiz.action_create_payments()
|
|
paid_count += 1
|
|
except Exception as ex:
|
|
print(" ! payment failed", sname, "-", ex)
|
|
open_count += 1
|
|
else:
|
|
open_count += 1
|
|
env.cr.commit()
|
|
print(" invoices paid:", paid_count, " open:", open_count)
|
|
# report payment states
|
|
states = {}
|
|
for mv in Move.search(
|
|
[("move_type", "=", "out_invoice"), ("dance_student_id", "!=", False)]
|
|
):
|
|
states[mv.payment_state] = states.get(mv.payment_state, 0) + 1
|
|
print(" invoice payment_state breakdown:", states)
|
|
|
|
# ------------------------------------------------------------
|
|
# 9. WEBSITE ENROLLMENT REQUESTS (approval pipeline demo)
|
|
# ------------------------------------------------------------
|
|
section("ENROLLMENT REQUESTS")
|
|
req_specs = [
|
|
("Noah Williams", "Jessica Williams", "jessica.w@example.com",
|
|
"+1 555 0201", "hiphop", "beginner", "new"),
|
|
("Ava Martinez", "Carlos Martinez", "carlos.m@example.com",
|
|
"+1 555 0202", "contemporary", "intermediate", "contacted"),
|
|
("Sofia Kapoor", "Anjali Kapoor", "anjali.k@example.com",
|
|
"+1 555 0203", "bharatanatyam", "beginner", "approved"),
|
|
("Ethan Brown", "Laura Brown", "laura.b@example.com",
|
|
"+1 555 0204", "zumba", "intermediate", "new"),
|
|
]
|
|
for sn, gn, ge, gp, style, lvl, state in req_specs:
|
|
if Request.search([("student_name", "=", sn)], limit=1):
|
|
continue
|
|
r = Request.create(
|
|
{
|
|
"student_name": sn,
|
|
"guardian_name": gn,
|
|
"guardian_email": ge,
|
|
"guardian_phone": gp,
|
|
"dance_style": style,
|
|
"preferred_level": lvl,
|
|
"message": "Submitted via the website Enroll Now form.",
|
|
}
|
|
)
|
|
if state == "contacted":
|
|
r.action_mark_contacted()
|
|
elif state == "approved":
|
|
r.action_approve()
|
|
print(" request:", sn, "[", state, "]", r.reference)
|
|
env.cr.commit()
|
|
|
|
# ------------------------------------------------------------
|
|
section("DONE — SUMMARY")
|
|
print(" students :", Partner.search_count([("is_student", "=", True)]))
|
|
print(" batches :", Batch.search_count([]))
|
|
print(" enrollments :", Enrollment.search_count([]))
|
|
print(" sessions :", Session.search_count([]))
|
|
print(" attendance :", Attendance.search_count([]))
|
|
print(" invoices :", Move.search_count(
|
|
[("move_type", "=", "out_invoice"), ("dance_student_id", "!=", False)]))
|
|
print(" requests :", Request.search_count([]))
|
|
print("\n All demo logins use password:", PWD)
|
|
env.cr.commit()
|
|
print("\nSEED COMPLETE.\n")
|