HH/apps/accounts/management/commands/create_default_roles.py
ismail 7369d08012
All checks were successful
Build and Push Docker Image / build (push) Successful in 4m14s
feat: unified reference numbers + feedback modules QA audit
Reference numbers (unified scheme PREFIX-YYYYMM-HOSP-NNNN, e.g. CMP-202606-HHN-0001):
- new ReferenceSequence model + generate_reference() helper (apps/core)
- Complaint/Inquiry/Observation/Appreciation/Suggestion emit unified refs via save()
- prefix-based auto-routing in public track API (CMP/INQ/OBS trackable; APR/SGT internal-only)
- removed legacy CMP-/INQ- generators in ui_views, integrations, px_sources
- migrations: core.0003_referencesequence, appreciation.0006, feedback.0008, observations.0012
- unit tests (format, sanitization, monthly reset, 40-thread concurrency)

QA audit:
- isolated E2E hospital sandbox mirroring HH-N + 10 role users (create_e2e_isolated_env)
- feedback-modules-audit.spec.ts + audit helper (headed, run-to-completion)
- reports/feedback-modules-qa-report.md

Also bundles accumulated in-progress work across complaints, observations,
organizations, templates, and other modules.
2026-06-14 14:29:23 +03:00

203 lines
8.0 KiB
Python

"""
Management command to create default roles and groups for PX360.
"""
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.management.base import BaseCommand
from apps.accounts.models import Role
class Command(BaseCommand):
help = "Create default roles and groups for PX360 system"
def handle(self, *args, **options):
"""Create default roles"""
roles_config = [
{
"name": "px_admin",
"display_name": "PX Admin",
"description": "Full system access. Can manage all hospitals, departments, and configurations.",
"level": 100,
},
{
"name": "hospital_admin",
"display_name": "Hospital Admin",
"description": "Hospital-level access. Can manage their hospital and its departments.",
"level": 80,
},
{
"name": "department_manager",
"display_name": "Department Manager",
"description": "Department-level access. Can manage their department.",
"level": 60,
},
{
"name": "director",
"display_name": "Director",
"description": "Multi-department access. Can view data for departments where their direct reports (via report_to) work.",
"level": 70,
},
{
"name": "px_management",
"display_name": "PX Management",
"description": "Can manage PX actions, complaints, and surveys.",
"level": 50,
},
{
"name": "px_employee",
"display_name": "PX Employee",
"description": "Can work with complaints, inquiries, observations, appreciation, suggestions, QI projects, departments, staff surveys, physician dashboard, government tickets, communication requests, and reports. View-only access to references and standards.",
"level": 40,
},
{
"name": "staff",
"display_name": "Staff",
"description": "Basic staff access.",
"level": 20,
},
{
"name": "viewer",
"display_name": "Viewer",
"description": "Read-only access to reports and dashboards.",
"level": 10,
},
{
"name": "executive",
"display_name": "Executive",
"description": "C-Suite and top management. System-wide analytics, executive summaries, and predictive insights access.",
"level": 90,
},
{
"name": "px_source_user",
"display_name": "PX Source User",
"description": "External source users who can create complaints and inquiries from their assigned source. Limited access to their own created data only.",
"level": 5,
},
]
created_count = 0
updated_count = 0
for role_data in roles_config:
# Get or create group
group, group_created = Group.objects.get_or_create(name=role_data["display_name"])
if group_created:
self.stdout.write(self.style.SUCCESS(f"Created group: {group.name}"))
# Get or create role
role, role_created = Role.objects.get_or_create(
name=role_data["name"],
defaults={
"display_name": role_data["display_name"],
"description": role_data["description"],
"group": group,
"level": role_data["level"],
},
)
if role_created:
created_count += 1
self.stdout.write(self.style.SUCCESS(f"✓ Created role: {role.display_name} (level {role.level})"))
else:
# Update existing role
role.display_name = role_data["display_name"]
role.description = role_data["description"]
role.level = role_data["level"]
role.group = group
role.save()
updated_count += 1
self.stdout.write(self.style.WARNING(f"↻ Updated role: {role.display_name}"))
# Assign permissions based on role level
self._assign_permissions(role, group)
self.stdout.write(
self.style.SUCCESS(f"\n✓ Roles setup complete: {created_count} created, {updated_count} updated")
)
self.stdout.write(self.style.SUCCESS(f"Total roles: {Role.objects.count()}"))
def _assign_permissions(self, role, group):
"""
Assign permissions to group based on role level.
This is a basic implementation - expand as needed.
"""
# Clear existing permissions
group.permissions.clear()
# Get all permissions
all_permissions = Permission.objects.all()
# PX Admin gets all permissions
if role.name == "px_admin":
group.permissions.set(all_permissions)
return
# Hospital Admin gets most permissions except user management
if role.name == "hospital_admin":
permissions = Permission.objects.exclude(
content_type__app_label="auth", codename__in=["add_user", "delete_user", "change_user"]
)
group.permissions.set(permissions)
return
# Department Manager gets department-level permissions
if role.name == "department_manager":
# Add view permissions for most models
view_permissions = Permission.objects.filter(codename__startswith="view_")
group.permissions.set(view_permissions)
return
# Director gets view permissions (same as Department Manager)
if role.name == "director":
view_permissions = Permission.objects.filter(codename__startswith="view_")
group.permissions.set(view_permissions)
return
# Department Respondent gets view + inquiry response permissions
if role.name == "department_respondent":
respondent_permissions = Permission.objects.filter(
content_type__app_label__in=["complaints", "organizations", "observations"],
codename__startswith="view_",
)
group.permissions.set(respondent_permissions)
return
# PX Employee gets complaint and action permissions
if role.name == "px_employee":
staff_permissions = Permission.objects.filter(
content_type__app_label__in=["complaints", "px_action_center", "surveys"]
)
group.permissions.set(staff_permissions)
return
# Executive gets view permissions system-wide + executive_summary access
if role.name == "executive":
view_permissions = Permission.objects.filter(codename__startswith="view_")
exec_perms = Permission.objects.filter(content_type__app_label="executive_summary")
group.permissions.set(list(view_permissions) + list(exec_perms))
return
# PX Source User gets limited complaint/inquiry permissions
if role.name == "px_source_user":
source_user_perms = Permission.objects.filter(
content_type__app_label__in=["complaints"],
codename__in=[
"add_complaint",
"view_complaint",
"change_complaint",
"add_inquiry",
"view_inquiry",
"change_inquiry",
],
)
group.permissions.set(source_user_perms)
return
# Others get basic view permissions
view_permissions = Permission.objects.filter(codename__startswith="view_")
group.permissions.set(view_permissions)