CP_AUTOMATION/scripts/process_students.py
2025-12-12 19:54:54 +05:30

338 lines
12 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Systematic Student Processing Script
This script processes multiple students from an Excel file:
1. Reads student credentials from Excel
2. For each student:
- Logs in
- Handles password reset (sets to Admin@123)
- Completes profile to 100%
- Generates synthetic data report
3. Tracks progress and generates summary report
"""
import sys
import time
import json
from pathlib import Path
from datetime import datetime
import pandas as pd
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))
from selenium.webdriver.common.by import By
from pages.login_page import LoginPage
from pages.mandatory_reset_page import MandatoryResetPage
from pages.profile_incomplete_page import ProfileIncompletePage
from pages.profile_editor_page import ProfileEditorPage
from utils.driver_manager import DriverManager
from config.config import ENVIRONMENT, BASE_URL, TEST_NEW_PASSWORD
class StudentProcessor:
"""Process students systematically"""
def __init__(self, excel_path, headless=False):
"""
Initialize Student Processor
Args:
excel_path: Path to Excel file with student data
headless: Run browser in headless mode
"""
self.excel_path = Path(excel_path)
self.headless = headless
self.results = []
self.driver = None
def load_students(self):
"""Load students from Excel file"""
try:
df = pd.read_excel(self.excel_path)
print(f"✅ Loaded {len(df)} students from {self.excel_path}")
return df.to_dict('records')
except Exception as e:
print(f"❌ Error loading Excel file: {e}")
return []
def process_student(self, student_data):
"""
Process a single student
Args:
student_data: Dictionary with student information
Returns:
dict: Processing result
"""
cpid = student_data.get('Student CPID', '')
password = student_data.get('Password', '')
first_name = student_data.get('First Name', '')
last_name = student_data.get('Last Name', '')
result = {
'cpid': cpid,
'first_name': first_name,
'last_name': last_name,
'status': 'pending',
'error': None,
'steps_completed': [],
'timestamp': datetime.now().isoformat()
}
try:
print(f"\n{'='*80}")
print(f"Processing: {first_name} {last_name} ({cpid})")
print(f"{'='*80}")
# Initialize driver
driver_manager = DriverManager()
self.driver = driver_manager.get_driver(headless=self.headless)
# Step 1: Login
print("\n[STEP 1] Logging in...")
login_page = LoginPage(self.driver)
login_page.login(identifier=cpid, password=password)
time.sleep(2)
result['steps_completed'].append('login')
# Step 2: Handle Password Reset
print("\n[STEP 2] Checking for Password Reset...")
reset_page = MandatoryResetPage(self.driver)
if reset_page.is_modal_present():
print(" ✅ Password reset modal found")
print(" Automatically handling password reset...")
reset_page.reset_password(
current_password=password,
new_password=TEST_NEW_PASSWORD,
confirm_password=TEST_NEW_PASSWORD
)
print(" ✅ Password reset completed")
result['steps_completed'].append('password_reset')
# Update password for future use
password = TEST_NEW_PASSWORD
else:
print(" ✅ No password reset required")
# Step 3: Handle Profile Incomplete Modal
print("\n[STEP 3] Checking for Profile Incomplete Modal...")
profile_incomplete = ProfileIncompletePage(self.driver)
if profile_incomplete.is_modal_present():
progress = profile_incomplete.get_progress_value()
print(f" Profile incomplete - Current Progress: {progress}")
print(" Clicking Complete Profile button...")
profile_incomplete.click_complete()
time.sleep(3)
result['steps_completed'].append('profile_modal_handled')
# Step 4: Complete Profile
print("\n[STEP 4] Completing Profile...")
profile_editor = ProfileEditorPage(self.driver)
profile_editor.wait_for_page_load()
# Fill profile with student data
self._fill_profile(profile_editor, student_data)
# Save profile
print(" Saving profile...")
profile_editor.click_save()
time.sleep(3)
# Verify completion
progress = profile_editor.get_progress_value()
print(f" Profile completion: {progress}")
if "100%" in progress:
result['steps_completed'].append('profile_completed')
result['status'] = 'success'
print(" ✅ Profile completed successfully!")
else:
result['status'] = 'partial'
result['error'] = f"Profile not 100% complete: {progress}"
print(f" ⚠️ Profile not fully complete: {progress}")
except Exception as e:
result['status'] = 'error'
result['error'] = str(e)
print(f" ❌ Error: {e}")
finally:
if self.driver:
self.driver.quit()
self.driver = None
return result
def _fill_profile(self, profile_editor, student_data):
"""Fill profile with student data"""
print(" Filling profile fields...")
# Step 1: Personal Information
profile_editor.fill_personal_information(
first_name=student_data.get('First Name'),
last_name=student_data.get('Last Name'),
gender=student_data.get('Gender'),
dob=student_data.get('Date of Birth'),
roll_number=str(student_data.get('Roll Number', '')),
nationality=student_data.get('Nationality')
)
# Fill additional personal info fields if available
if student_data.get('Language'):
profile_editor.send_keys(profile_editor.LANGUAGE_INPUT, student_data['Language'])
if student_data.get('Student ID Number'):
profile_editor.send_keys(profile_editor.STUDENT_ID_INPUT, str(student_data['Student ID Number']))
if student_data.get('Student CPID'):
profile_editor.send_keys(profile_editor.STUDENT_CPID_INPUT, student_data['Student CPID'])
# Navigate to next step
profile_editor.click_next()
time.sleep(1)
# Step 2: Contact Information
profile_editor.fill_contact_information(
email=student_data.get('Email'),
phone=str(student_data.get('Phone', '')),
address=student_data.get('Address'),
city=student_data.get('City'),
state=student_data.get('State'),
zip_code=str(student_data.get('Pin code', '')),
native_state=student_data.get('Native State')
)
profile_editor.click_next()
time.sleep(1)
# Step 3: Parent/Guardian
profile_editor.fill_parent_guardian(
father_name=student_data.get('Father Name'),
mother_name=student_data.get('Mother Name'),
guardian_name=student_data.get('Guardian Name'),
guardian_phone=str(student_data.get('Guardian Phone', ''))
)
profile_editor.click_next()
time.sleep(1)
# Step 4: Education Details
profile_editor.fill_education_details(
full_name=student_data.get('Full Name'),
current_grade=str(student_data.get('Class', '')),
section=student_data.get('Section'),
board_stream=student_data.get('Board/Stream', 'CBSE')
)
# Steps 5-9: Use synthetic data or defaults
# For now, we'll navigate through and let user fill manually
# Or use synthetic data generator
print(" ✅ Profile fields filled")
def process_all(self, start_index=0, end_index=None):
"""
Process all students
Args:
start_index: Start processing from this index
end_index: End processing at this index (None = all)
"""
students = self.load_students()
if not students:
print("❌ No students to process")
return
if end_index is None:
end_index = len(students)
students_to_process = students[start_index:end_index]
print(f"\n{'='*80}")
print(f"PROCESSING {len(students_to_process)} STUDENTS")
print(f"{'='*80}")
print(f"Start Index: {start_index}")
print(f"End Index: {end_index}")
print(f"{'='*80}\n")
for idx, student in enumerate(students_to_process, start=start_index):
print(f"\n[{idx+1}/{len(students_to_process)}] Processing student...")
result = self.process_student(student)
self.results.append(result)
# Save progress after each student
self._save_progress()
# Small delay between students
time.sleep(2)
# Generate final report
self._generate_report()
def _save_progress(self):
"""Save progress to JSON file"""
report_dir = Path(__file__).parent.parent / "reports" / "student_processing"
report_dir.mkdir(parents=True, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
report_file = report_dir / f"progress_{timestamp}.json"
with open(report_file, 'w') as f:
json.dump(self.results, f, indent=2)
def _generate_report(self):
"""Generate final processing report"""
total = len(self.results)
successful = len([r for r in self.results if r['status'] == 'success'])
partial = len([r for r in self.results if r['status'] == 'partial'])
errors = len([r for r in self.results if r['status'] == 'error'])
print(f"\n{'='*80}")
print("PROCESSING SUMMARY")
print(f"{'='*80}")
print(f"Total Students: {total}")
print(f"✅ Successful: {successful}")
print(f"⚠️ Partial: {partial}")
print(f"❌ Errors: {errors}")
print(f"{'='*80}")
if errors > 0:
print("\nErrors:")
for result in self.results:
if result['status'] == 'error':
print(f" - {result['cpid']}: {result['error']}")
def main():
"""Main entry point"""
import argparse
parser = argparse.ArgumentParser(description='Process students from Excel file')
parser.add_argument('--excel', type=str, required=True, help='Path to Excel file with student data')
parser.add_argument('--headless', action='store_true', help='Run in headless mode')
parser.add_argument('--start', type=int, default=0, help='Start index (default: 0)')
parser.add_argument('--end', type=int, default=None, help='End index (default: all)')
parser.add_argument('--single', type=str, default=None, help='Process single student by CPID')
args = parser.parse_args()
processor = StudentProcessor(args.excel, headless=args.headless)
if args.single:
# Process single student
students = processor.load_students()
student = next((s for s in students if s.get('Student CPID') == args.single), None)
if student:
result = processor.process_student(student)
print(f"\nResult: {result}")
else:
print(f"❌ Student with CPID {args.single} not found")
else:
# Process all students
processor.process_all(start_index=args.start, end_index=args.end)
if __name__ == "__main__":
main()