HH/apps/organizations/management/commands/populate_staff_contact.py

229 lines
8.7 KiB
Python

"""
Management command to populate existing staff with random emails and phone numbers
"""
import random
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.db.models import Q
from apps.organizations.models import Staff
class Command(BaseCommand):
help = 'Populate existing staff records with random emails and phone numbers'
def add_arguments(self, parser):
parser.add_argument(
'--hospital-code',
type=str,
help='Target hospital code (default: all hospitals)'
)
parser.add_argument(
'--email-only',
action='store_true',
help='Only populate email addresses'
)
parser.add_argument(
'--phone-only',
action='store_true',
help='Only populate phone numbers'
)
parser.add_argument(
'--overwrite',
action='store_true',
help='Overwrite existing email/phone (default: fill missing only)'
)
parser.add_argument(
'--dry-run',
action='store_true',
help='Preview changes without updating database'
)
def handle(self, *args, **options):
hospital_code = options['hospital_code']
email_only = options['email_only']
phone_only = options['phone_only']
overwrite = options['overwrite']
dry_run = options['dry_run']
self.stdout.write(f"\n{'='*60}")
self.stdout.write("Staff Contact Information Populator")
self.stdout.write(f"{'='*60}\n")
# Base queryset
queryset = Staff.objects.all()
# Filter by hospital if specified
if hospital_code:
queryset = queryset.filter(hospital__code__iexact=hospital_code)
self.stdout.write(f"Target hospital: {hospital_code}")
else:
self.stdout.write("Target: All hospitals")
# Filter staff needing updates
if not overwrite:
if email_only:
queryset = queryset.filter(Q(email__isnull=True) | Q(email=''))
elif phone_only:
queryset = queryset.filter(Q(phone__isnull=True) | Q(phone=''))
else:
# Both email and phone
queryset = queryset.filter(
Q(email__isnull=True) | Q(email='') |
Q(phone__isnull=True) | Q(phone='')
)
total_staff = queryset.count()
if total_staff == 0:
self.stdout.write(
self.style.SUCCESS("✓ All staff already have contact information.")
)
return
self.stdout.write(f"\nFound {total_staff} staff to update")
self.stdout.write(f" Email only: {email_only}")
self.stdout.write(f" Phone only: {phone_only}")
self.stdout.write(f" Overwrite existing: {overwrite}")
self.stdout.write(f" Dry run: {dry_run}\n")
# Track statistics
updated_emails = 0
updated_phones = 0
skipped = 0
with transaction.atomic():
for staff in queryset:
update_email = False
update_phone = False
# Determine which fields to update
should_update_email = email_only or (not email_only and not phone_only)
should_update_phone = phone_only or (not email_only and not phone_only)
# Determine if we should update email
if should_update_email:
if overwrite or not staff.email or not staff.email.strip():
if not staff.first_name or not staff.last_name:
self.stdout.write(
self.style.WARNING(f" ⚠ Skipping staff {staff.id}: Missing first/last name")
)
skipped += 1
continue
update_email = True
# Determine if we should update phone
if should_update_phone:
if overwrite or not staff.phone or not staff.phone.strip():
update_phone = True
if not update_email and not update_phone:
skipped += 1
continue
# Generate new values
new_email = None
new_phone = None
if update_email:
new_email = self.generate_email(staff)
updated_emails += 1
if update_phone:
new_phone = self.generate_phone_number()
updated_phones += 1
# Display what will be updated
if dry_run:
updates = []
if new_email:
old_email = staff.email if staff.email else 'None'
updates.append(f"email: {old_email}{new_email}")
if new_phone:
old_phone = staff.phone if staff.phone else 'None'
updates.append(f"phone: {old_phone}{new_phone}")
name = staff.name if staff.name else f"{staff.first_name} {staff.last_name}"
self.stdout.write(f" Would update: {name}")
for update in updates:
self.stdout.write(f" - {update}")
else:
# Apply updates
if new_email:
staff.email = new_email
if new_phone:
staff.phone = new_phone
staff.save()
name = staff.name if staff.name else f"{staff.first_name} {staff.last_name}"
self.stdout.write(f" ✓ Updated: {name}")
if new_email:
self.stdout.write(f" Email: {new_email}")
if new_phone:
self.stdout.write(f" Phone: {new_phone}")
# Summary
self.stdout.write("\n" + "="*60)
self.stdout.write("Summary:")
self.stdout.write(f" Total staff processed: {total_staff}")
self.stdout.write(f" Emails populated: {updated_emails}")
self.stdout.write(f" Phone numbers populated: {updated_phones}")
self.stdout.write(f" Skipped: {skipped}")
self.stdout.write("="*60 + "\n")
if dry_run:
self.stdout.write(self.style.WARNING("DRY RUN: No changes were made\n"))
else:
self.stdout.write(self.style.SUCCESS("Contact information populated successfully!\n"))
def generate_email(self, staff):
"""Generate unique email for staff"""
# Use staff.name if available, otherwise use first_name + last_name
if staff.name and staff.name.strip():
# Try to split name into first and last
name_parts = staff.name.strip().split()
if len(name_parts) >= 2:
first_name = name_parts[0]
last_name = name_parts[-1]
else:
first_name = staff.name.strip()
last_name = staff.last_name if staff.last_name else ''
else:
first_name = staff.first_name if staff.first_name else 'user'
last_name = staff.last_name if staff.last_name else 'unknown'
# Clean up names for email (remove spaces and special characters)
clean_first = ''.join(c.lower() for c in first_name if c.isalnum() or c == ' ')
clean_last = ''.join(c.lower() for c in last_name if c.isalnum() or c == ' ')
# Get hospital code for domain
hospital_code = staff.hospital.code if staff.hospital else 'hospital'
hospital_code = hospital_code.lower().replace(' ', '')
base = f"{clean_first.replace(' ', '.')}.{clean_last.replace(' ', '.')}"
email = f"{base}@{hospital_code}.sa"
# Add random suffix if email already exists
counter = 1
while Staff.objects.filter(email=email).exists():
random_num = random.randint(1, 999)
email = f"{base}{random_num}@{hospital_code}.sa"
counter += 1
if counter > 100: # Safety limit
break
return email
def generate_phone_number(self):
"""Generate random Saudi phone number (+966 5X XXX XXXX)"""
# Saudi mobile format: +966 5X XXX XXXX
# X is random digit
second_digit = random.randint(0, 9)
group1 = random.randint(100, 999)
group2 = random.randint(100, 999)
phone = f"+966 5{second_digit} {group1} {group2}"
return phone