123 lines
5.0 KiB
Python
123 lines
5.0 KiB
Python
"""
|
|
Management command to assign managers (report_to) to staff members.
|
|
|
|
This command assigns department heads as managers for staff in their department.
|
|
For staff without a department head, it assigns the first available manager.
|
|
"""
|
|
from django.core.management.base import BaseCommand
|
|
from django.db import transaction
|
|
from apps.organizations.models import Staff, Department
|
|
|
|
|
|
class Command(BaseCommand):
|
|
help = 'Assign managers (report_to) to staff members who do not have one assigned'
|
|
|
|
def add_arguments(self, parser):
|
|
parser.add_argument(
|
|
'--dry-run',
|
|
action='store_true',
|
|
dest='dry_run',
|
|
default=False,
|
|
help='Show what would be done without making changes',
|
|
)
|
|
parser.add_argument(
|
|
'--hospital-id',
|
|
dest='hospital_id',
|
|
default=None,
|
|
help='Only process staff for a specific hospital ID',
|
|
)
|
|
|
|
def handle(self, *args, **options):
|
|
dry_run = options['dry_run']
|
|
hospital_id = options['hospital_id']
|
|
|
|
# Get staff without managers
|
|
staff_queryset = Staff.objects.filter(report_to__isnull=True, status='active')
|
|
|
|
if hospital_id:
|
|
staff_queryset = staff_queryset.filter(hospital_id=hospital_id)
|
|
|
|
staff_without_managers = staff_queryset.select_related('department', 'hospital')
|
|
|
|
if not staff_without_managers.exists():
|
|
self.stdout.write(self.style.SUCCESS('All staff members already have managers assigned.'))
|
|
return
|
|
|
|
self.stdout.write(f'Found {staff_without_managers.count()} staff members without managers.')
|
|
|
|
assigned_count = 0
|
|
skipped_count = 0
|
|
|
|
for staff in staff_without_managers:
|
|
manager = self._find_manager_for_staff(staff)
|
|
|
|
if manager:
|
|
if dry_run:
|
|
self.stdout.write(f' [DRY RUN] Would assign: {staff} -> manager: {manager}')
|
|
else:
|
|
staff.report_to = manager
|
|
staff.save(update_fields=['report_to'])
|
|
self.stdout.write(self.style.SUCCESS(f' Assigned: {staff} -> manager: {manager}'))
|
|
assigned_count += 1
|
|
else:
|
|
self.stdout.write(self.style.WARNING(f' No manager found for: {staff} (Dept: {staff.department})'))
|
|
skipped_count += 1
|
|
|
|
if dry_run:
|
|
self.stdout.write(self.style.WARNING(f'\n[DRY RUN] Would assign {assigned_count} managers, skip {skipped_count}'))
|
|
else:
|
|
self.stdout.write(self.style.SUCCESS(f'\nAssigned managers to {assigned_count} staff members.'))
|
|
if skipped_count > 0:
|
|
self.stdout.write(self.style.WARNING(f'Could not find managers for {skipped_count} staff members.'))
|
|
|
|
def _find_manager_for_staff(self, staff):
|
|
"""Find an appropriate manager for a staff member."""
|
|
|
|
# Strategy 1: Find another staff member in the same department who has people reporting to them
|
|
if staff.department:
|
|
dept_managers = Staff.objects.filter(
|
|
department=staff.department,
|
|
status='active',
|
|
direct_reports__isnull=False
|
|
).exclude(id=staff.id).distinct()
|
|
|
|
if dept_managers.exists():
|
|
return dept_managers.first()
|
|
|
|
# Strategy 2: Find any staff member with a higher job title in the same department
|
|
# Look for staff with "Manager", "Director", "Head", "Chief", "Supervisor" in job title
|
|
manager_titles = ['manager', 'director', 'head', 'chief', 'supervisor', 'lead', 'senior']
|
|
for title in manager_titles:
|
|
potential_managers = Staff.objects.filter(
|
|
department=staff.department,
|
|
status='active',
|
|
job_title__icontains=title
|
|
).exclude(id=staff.id)
|
|
|
|
if potential_managers.exists():
|
|
return potential_managers.first()
|
|
|
|
# Strategy 3: Find any manager in the same hospital
|
|
hospital_managers = Staff.objects.filter(
|
|
hospital=staff.hospital,
|
|
status='active',
|
|
direct_reports__isnull=False
|
|
).exclude(id=staff.id).distinct()
|
|
|
|
if hospital_managers.exists():
|
|
return hospital_managers.first()
|
|
|
|
# Strategy 4: Find any senior staff in the same hospital
|
|
manager_titles = ['manager', 'director', 'head', 'chief', 'supervisor', 'lead']
|
|
for title in manager_titles:
|
|
potential_managers = Staff.objects.filter(
|
|
hospital=staff.hospital,
|
|
status='active',
|
|
job_title__icontains=title
|
|
).exclude(id=staff.id)
|
|
|
|
if potential_managers.exists():
|
|
return potential_managers.first()
|
|
|
|
return None
|