HH/apps/projects/migrations/0004_qi_multi_department.py
2026-07-05 14:49:45 +03:00

82 lines
3.2 KiB
Python

# Generated for QI multi-department support.
#
# Order matters:
# 1. Add the new `departments` M2M (blank).
# 2. Copy each existing `department_id` into the M2M, then rebuild the derived
# `team_members` set from each department's champion + manager (and the
# project lead). The sync logic is inlined here (not imported from the
# model) so the migration stays stable as the model method evolves.
# 3. Remove the old single `department` FK.
from django.db import migrations, models
def copy_department_and_sync_team(apps, schema_editor):
QIProject = apps.get_model("projects", "QIProject")
Staff = apps.get_model("organizations", "Staff")
missing_manager_profile = 0
for project in QIProject.objects.exclude(department__isnull=True):
old_dept = project.department
# M2M add via the through manager (project has just been saved with the new field).
if old_dept and old_dept not in project.departments.all():
project.departments.add(old_dept)
# Rebuild derived team_members: champion (Staff) + manager.staff_profile (Staff),
# plus the project lead. De-duped; nulls skipped.
pks = set()
for dept in project.departments.all():
champion_id = getattr(dept, "champion_id", None)
if champion_id:
pks.add(champion_id)
manager_user_id = getattr(dept, "manager_id", None)
if manager_user_id:
manager_user = dept.manager
if manager_user is not None and hasattr(manager_user, "staff_profile"):
sp = manager_user.staff_profile
if sp is not None and sp.id:
pks.add(sp.id)
else:
missing_manager_profile += 1
if project.project_lead_id:
pks.add(project.project_lead_id)
if pks:
project.team_members.set(Staff.objects.filter(pk__in=pks))
if missing_manager_profile:
# Surface how many manager links could not be added (no staff_profile).
print(f" [qi_multi_department] {missing_manager_profile} department manager(s) "
f"had no staff_profile and were excluded from the derived team.")
def remove_team_backreference(apps, schema_editor):
# Reverse is a no-op: we cannot reconstruct the single FK from the M2M losslessly.
pass
class Migration(migrations.Migration):
dependencies = [
("organizations", "0015_hospital_branding"),
("projects", "0003_alter_qiproject_project_lead_and_more"),
]
operations = [
migrations.AddField(
model_name="qiproject",
name="departments",
field=models.ManyToManyField(
blank=True,
help_text="Departments involved in this QI project. Team membership is derived from each department's champion and manager.",
related_name="qi_projects",
to="organizations.department",
),
),
migrations.RunPython(copy_department_and_sync_team, remove_team_backreference),
migrations.RemoveField(
model_name="qiproject",
name="department",
),
]