#!/usr/bin/env python3 """ Verify that all apps are properly reflecting the Phase 4 model changes. This script checks for common issues after the core consolidation. """ import os import re from pathlib import Path # Color codes for terminal output GREEN = '\033[92m' RED = '\033[91m' YELLOW = '\033[93m' BLUE = '\033[94m' RESET = '\033[0m' class ModelChangeVerifier: def __init__(self, project_root): self.project_root = Path(project_root) self.issues = [] self.warnings = [] self.successes = [] def log_issue(self, file_path, line_num, issue): self.issues.append(f"{RED}✗{RESET} {file_path}:{line_num} - {issue}") def log_warning(self, file_path, line_num, warning): self.warnings.append(f"{YELLOW}⚠{RESET} {file_path}:{line_num} - {warning}") def log_success(self, message): self.successes.append(f"{GREEN}✓{RESET} {message}") def check_file(self, file_path): """Check a single Python file for issues.""" try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() lines = content.split('\n') rel_path = file_path.relative_to(self.project_root) # Check for old model references old_patterns = [ (r'from patients\.models import PatientProfile', "Should import from core.Patient instead of patients.PatientProfile for patient identity"), (r'models\.ForeignKey\(["\']patients\.PatientProfile["\']', "ForeignKey should reference 'core.Patient' not 'patients.PatientProfile'"), (r'AuditLogEntry', "Should use 'AuditEvent' instead of 'AuditLogEntry'"), (r'\.first_name', "Patient first_name is now 'given_name' in core.Patient"), (r'\.last_name', "Patient last_name is now 'family_name' in core.Patient"), (r'\.date_of_birth', "Patient date_of_birth is now 'birth_date' in core.Patient"), (r'\.gender(?!_)', "Patient gender is now 'administrative_gender' in core.Patient"), ] for line_num, line in enumerate(lines, 1): for pattern, message in old_patterns: if re.search(pattern, line) and not line.strip().startswith('#'): # Skip if it's in a comment if '#' in line and line.index('#') < line.find(pattern): continue self.log_warning(rel_path, line_num, message) # Check for proper imports in models.py files if file_path.name == 'models.py': if 'from core.models import' in content: self.log_success(f"{rel_path} - Imports from core.models") # Check if TenantScopedModel is used if 'TenantScopedModel' in content: self.log_success(f"{rel_path} - Uses TenantScopedModel") # Check forms.py files if file_path.name == 'forms.py': # Check for fields that don't exist problematic_fields = [ 'first_name', 'last_name', 'date_of_birth', 'gender', 'id_number', 'subscriber_id_number' ] for field in problematic_fields: pattern = f"['\"]{ field}['\"]" if re.search(pattern, content): # Check if it's in a PatientProfile or Patient form if 'PatientProfileForm' in content or 'PatientForm' in content: for line_num, line in enumerate(lines, 1): if re.search(pattern, line) and not line.strip().startswith('#'): self.log_warning(rel_path, line_num, f"Field '{field}' may not exist in model") except Exception as e: self.log_issue(file_path, 0, f"Error reading file: {e}") def check_app(self, app_name): """Check all Python files in an app.""" app_path = self.project_root / app_name if not app_path.exists(): return print(f"\n{BLUE}Checking app: {app_name}{RESET}") # Check models.py models_file = app_path / 'models.py' if models_file.exists(): self.check_file(models_file) # Check forms.py forms_file = app_path / 'forms.py' if forms_file.exists(): self.check_file(forms_file) # Check views.py views_file = app_path / 'views.py' if views_file.exists(): self.check_file(views_file) # Check admin.py admin_file = app_path / 'admin.py' if admin_file.exists(): self.check_file(admin_file) def run_verification(self): """Run verification on all apps.""" apps = [ 'core', 'accounts', 'patients', 'emr', 'appointments', 'inpatients', 'pharmacy', 'laboratory', 'radiology', 'operating_theatre', 'billing', 'inventory', 'hr', 'analytics', 'communications', 'integration', 'quality', 'facility_management', 'blood_bank', 'insurance_approvals' ] print(f"{BLUE}{'='*80}{RESET}") print(f"{BLUE}Phase 4 Model Changes Verification{RESET}") print(f"{BLUE}{'='*80}{RESET}") for app in apps: self.check_app(app) # Print summary print(f"\n{BLUE}{'='*80}{RESET}") print(f"{BLUE}Verification Summary{RESET}") print(f"{BLUE}{'='*80}{RESET}") if self.successes: print(f"\n{GREEN}Successes ({len(self.successes)}):{RESET}") for success in self.successes[:10]: # Show first 10 print(f" {success}") if len(self.successes) > 10: print(f" ... and {len(self.successes) - 10} more") if self.warnings: print(f"\n{YELLOW}Warnings ({len(self.warnings)}):{RESET}") for warning in self.warnings: print(f" {warning}") if self.issues: print(f"\n{RED}Issues ({len(self.issues)}):{RESET}") for issue in self.issues: print(f" {issue}") if not self.issues and not self.warnings: print(f"\n{GREEN}✓ All checks passed! No issues found.{RESET}") elif not self.issues: print(f"\n{YELLOW}⚠ No critical issues, but {len(self.warnings)} warnings to review.{RESET}") else: print(f"\n{RED}✗ Found {len(self.issues)} issues that need to be fixed.{RESET}") print(f"\n{BLUE}{'='*80}{RESET}\n") return len(self.issues) == 0 if __name__ == '__main__': import sys # Get project root (parent of tools directory) project_root = Path(__file__).parent.parent verifier = ModelChangeVerifier(project_root) success = verifier.run_verification() sys.exit(0 if success else 1)