#!/usr/bin/env python3 """ Location Accuracy Database Utilities Additional utility functions for managing location accuracy data in your attendance system database. Usage: python location_accuracy_utils.py [command] [options] Commands: check-schema Verify database schema for location accuracy add-field Add location_accuracy field to attendance_data table stats Show location accuracy statistics export-report Export detailed location accuracy report verify-data Verify data integrity for location accuracy Author: Attendance System Enhancement Team """ import sys import os import csv from datetime import datetime, date import json # Add your app directory to path sys.path.append(os.path.dirname(os.path.abspath(__file__))) try: from app import app, db, AttendanceData, QRCode from app import get_location_accuracy_level_enhanced from sqlalchemy import text, inspect except ImportError as e: print(f"āŒ Error importing modules: {e}") sys.exit(1) class LocationAccuracyUtils: """Utility class for location accuracy database management""" def __init__(self): self.app = app def check_database_schema(self): """Check if the database schema supports location accuracy""" print("šŸ” CHECKING DATABASE SCHEMA") print("=" * 50) with self.app.app_context(): inspector = inspect(db.engine) # Check attendance_data table try: columns = inspector.get_columns('attendance_data') column_names = [col['name'] for col in columns] print("šŸ“‹ Attendance Data Table Columns:") required_fields = [ 'id', 'qr_code_id', 'employee_id', 'check_in_date', 'check_in_time', 'latitude', 'longitude', 'address', 'location_accuracy' ] for field in required_fields: status = "āœ…" if field in column_names else "āŒ" print(f" {status} {field}") # Check for location_accuracy field specifically has_accuracy_field = 'location_accuracy' in column_names if has_accuracy_field: # Get field details accuracy_col = next((col for col in columns if col['name'] == 'location_accuracy'), None) if accuracy_col: print(f"\nšŸ“Š location_accuracy field details:") print(f" Type: {accuracy_col['type']}") print(f" Nullable: {accuracy_col['nullable']}") print(f" Default: {accuracy_col.get('default', 'None')}") return has_accuracy_field except Exception as e: print(f"āŒ Error checking schema: {e}") return False def add_location_accuracy_field(self): """Add location_accuracy field to attendance_data table if missing""" print("šŸ”§ ADDING LOCATION ACCURACY FIELD") print("=" * 50) with self.app.app_context(): try: # Check if field already exists if self.check_database_schema(): print("ā„¹ļø location_accuracy field already exists") return True print("āž• Adding location_accuracy field...") # Add the field db.session.execute(text(""" ALTER TABLE attendance_data ADD COLUMN location_accuracy FLOAT """)) db.session.commit() print("āœ… Successfully added location_accuracy field") # Verify addition if self.check_database_schema(): print("āœ… Field addition verified") return True else: print("āŒ Field addition verification failed") return False except Exception as e: print(f"āŒ Error adding field: {e}") db.session.rollback() return False def show_location_accuracy_stats(self): """Show comprehensive statistics about location accuracy data""" print("šŸ“Š LOCATION ACCURACY STATISTICS") print("=" * 60) with self.app.app_context(): try: # Basic counts total_records = db.session.query(AttendanceData).count() records_with_location = db.session.query(AttendanceData).filter( AttendanceData.latitude.isnot(None), AttendanceData.longitude.isnot(None) ).count() records_with_accuracy = db.session.query(AttendanceData).filter( AttendanceData.location_accuracy.isnot(None) ).count() print(f"Total Records: {total_records:,}") print(f"Records with GPS Data: {records_with_location:,}") print(f"Records with Accuracy: {records_with_accuracy:,}") if total_records > 0: gps_percentage = (records_with_location / total_records) * 100 accuracy_percentage = (records_with_accuracy / total_records) * 100 print(f"GPS Coverage: {gps_percentage:.1f}%") print(f"Accuracy Coverage: {accuracy_percentage:.1f}%") # Accuracy level distribution if records_with_accuracy > 0: print("\nšŸ“ˆ ACCURACY LEVEL DISTRIBUTION") print("-" * 40) accuracy_records = db.session.query(AttendanceData.location_accuracy).filter( AttendanceData.location_accuracy.isnot(None) ).all() levels = {} total_distance = 0 for record in accuracy_records: accuracy = record[0] level = get_location_accuracy_level_enhanced(accuracy) levels[level] = levels.get(level, 0) + 1 total_distance += accuracy for level in ['excellent', 'very_good', 'good', 'fair', 'poor', 'very_poor']: count = levels.get(level, 0) percentage = (count / records_with_accuracy) * 100 if records_with_accuracy > 0 else 0 print(f"{level.replace('_', ' ').title():12} {count:6,} ({percentage:5.1f}%)") avg_accuracy = total_distance / len(accuracy_records) print(f"\nAverage Distance: {avg_accuracy:.4f} miles") # Recent activity print("\nšŸ“… RECENT ACTIVITY (Last 7 Days)") print("-" * 40) seven_days_ago = date.today().replace(day=date.today().day - 7) if date.today().day > 7 else date.today().replace(month=date.today().month - 1, day=date.today().day + 30 - 7) recent_records = db.session.query(AttendanceData).filter( AttendanceData.check_in_date >= seven_days_ago ).count() recent_with_accuracy = db.session.query(AttendanceData).filter( AttendanceData.check_in_date >= seven_days_ago, AttendanceData.location_accuracy.isnot(None) ).count() print(f"Recent Check-ins: {recent_records:,}") print(f"Recent with Accuracy: {recent_with_accuracy:,}") if recent_records > 0: recent_percentage = (recent_with_accuracy / recent_records) * 100 print(f"Recent Accuracy Rate: {recent_percentage:.1f}%") except Exception as e: print(f"āŒ Error generating statistics: {e}") def export_location_accuracy_report(self, output_file=None): """Export detailed location accuracy report to CSV""" if not output_file: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_file = f"location_accuracy_report_{timestamp}.csv" print(f"šŸ“„ EXPORTING LOCATION ACCURACY REPORT") print(f"Output File: {output_file}") print("=" * 60) with self.app.app_context(): try: # Query all records with their QR code information query = db.session.query(AttendanceData, QRCode).join( QRCode, AttendanceData.qr_code_id == QRCode.id ).order_by(AttendanceData.check_in_date.desc(), AttendanceData.check_in_time.desc()) records = query.all() print(f"Found {len(records)} records to export") # Write CSV file with open(output_file, 'w', newline='', encoding='utf-8') as csvfile: fieldnames = [ 'attendance_id', 'employee_id', 'check_in_date', 'check_in_time', 'location_name', 'qr_address', 'checkin_address', 'checkin_latitude', 'checkin_longitude', 'gps_accuracy_meters', 'location_accuracy_miles', 'accuracy_level', 'has_gps_data', 'has_location_accuracy', 'device_info' ] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for attendance, qr_code in records: accuracy_level = 'unknown' if attendance.location_accuracy: accuracy_level = get_location_accuracy_level_enhanced(attendance.location_accuracy) writer.writerow({ 'attendance_id': attendance.id, 'employee_id': attendance.employee_id, 'check_in_date': attendance.check_in_date.isoformat(), 'check_in_time': attendance.check_in_time.isoformat(), 'location_name': attendance.location_name, 'qr_address': qr_code.location_address, 'checkin_address': attendance.address or 'Not captured', 'checkin_latitude': attendance.latitude, 'checkin_longitude': attendance.longitude, 'gps_accuracy_meters': attendance.accuracy, 'location_accuracy_miles': attendance.location_accuracy, 'accuracy_level': accuracy_level, 'has_gps_data': attendance.latitude is not None and attendance.longitude is not None, 'has_location_accuracy': attendance.location_accuracy is not None, 'device_info': attendance.device_info or 'Unknown' }) print(f"āœ… Report exported successfully to {output_file}") return output_file except Exception as e: print(f"āŒ Error exporting report: {e}") return None def verify_data_integrity(self): """Verify data integrity for location accuracy calculations""" print("šŸ” VERIFYING DATA INTEGRITY") print("=" * 50) with self.app.app_context(): try: issues = [] # Check for records with coordinates but no address no_address_with_coords = db.session.query(AttendanceData).filter( AttendanceData.latitude.isnot(None), AttendanceData.longitude.isnot(None), AttendanceData.address.is_(None) ).count() if no_address_with_coords > 0: issues.append(f"{no_address_with_coords} records have GPS coordinates but no address") # Check for invalid coordinates invalid_coords = db.session.query(AttendanceData).filter( db.or_( AttendanceData.latitude < -90, AttendanceData.latitude > 90, AttendanceData.longitude < -180, AttendanceData.longitude > 180 ) ).count() if invalid_coords > 0: issues.append(f"{invalid_coords} records have invalid GPS coordinates") # Check for QR codes without addresses qr_no_address = db.session.query(QRCode).filter( db.or_( QRCode.location_address.is_(None), QRCode.location_address == '' ) ).count() if qr_no_address > 0: issues.append(f"{qr_no_address} QR codes have no address defined") # Check for impossible accuracy values extreme_accuracy = db.session.query(AttendanceData).filter( db.or_( AttendanceData.location_accuracy < 0, AttendanceData.location_accuracy > 1000 # More than 1000 miles seems extreme ) ).count() if extreme_accuracy > 0: issues.append(f"{extreme_accuracy} records have extreme location accuracy values") # Report results if issues: print("āš ļø Data integrity issues found:") for issue in issues: print(f" • {issue}") else: print("āœ… No data integrity issues found") return len(issues) == 0 except Exception as e: print(f"āŒ Error during verification: {e}") return False def main(): """Main entry point for utility commands""" if len(sys.argv) < 2: print(""" Usage: python location_accuracy_utils.py [command] Commands: check-schema Check database schema add-field Add location_accuracy field stats Show statistics export-report Export CSV report verify-data Verify data integrity help Show this help """) sys.exit(1) command = sys.argv[1].lower() utils = LocationAccuracyUtils() if command == 'check-schema': utils.check_database_schema() elif command == 'add-field': utils.add_location_accuracy_field() elif command == 'stats': utils.show_location_accuracy_stats() elif command == 'export-report': output_file = sys.argv[2] if len(sys.argv) > 2 else None utils.export_location_accuracy_report(output_file) elif command == 'verify-data': utils.verify_data_integrity() elif command == 'help': print(__doc__) else: print(f"āŒ Unknown command: {command}") print("Use 'help' to see available commands") sys.exit(1) if __name__ == '__main__': main()