229 lines
8.7 KiB
Python
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
|