Updated location address accuracy

This commit is contained in:
2025-08-07 21:29:50 -04:00
parent 75291274c3
commit 80a72d3458
3 changed files with 761 additions and 588 deletions
+83 -16
View File
@@ -663,10 +663,55 @@ def process_location_data(location_data):
return processed
def reverse_geocode_coordinates(latitude, longitude):
"""
Convert GPS coordinates to human-readable address using reverse geocoding
Returns address string or None if failed
"""
if not latitude or not longitude:
return None
try:
print(f"🌍 Reverse geocoding coordinates: {latitude}, {longitude}")
# Using Nominatim (OpenStreetMap) reverse geocoding service
url = "https://nominatim.openstreetmap.org/reverse"
params = {
'lat': latitude,
'lon': longitude,
'format': 'json',
'addressdetails': 1,
'zoom': 18 # High detail level
}
headers = {
'User-Agent': 'QR-Attendance-System/1.0'
}
response = requests.get(url, params=params, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data and 'display_name' in data:
address = data['display_name']
print(f"✅ Reverse geocoded address: {address}")
return address
else:
print(f"⚠️ No address found for coordinates")
return None
else:
print(f"⚠️ Reverse geocoding API returned status: {response.status_code}")
return None
except Exception as e:
print(f"❌ Error in reverse geocoding: {e}")
return None
def process_location_data_enhanced(form_data):
"""
Enhanced processing of location data from form submission
Validates and cleans location data for storage
Validates and cleans location data for storage, including reverse geocoding
"""
processed = {
'latitude': None,
@@ -707,13 +752,33 @@ def process_location_data_enhanced(form_data):
alt = float(form_data['altitude'])
processed['altitude'] = alt
# Process address (limit length for database storage)
# Process address - First check if address was provided
if form_data.get('address'):
address = form_data['address'].strip()
if address and address not in ['null', '', 'undefined']:
processed['address'] = address[:500] # Limit to 500 characters
# Check if the address is just coordinates (like "38.8104192000, -77.1850240000")
if re.match(r'^-?\d+\.\d+,?\s*-?\d+\.\d+$', address.replace(' ', '')):
print(f"🔍 Detected coordinate-format address: {address}")
# This is just coordinates, we need to reverse geocode
processed['address'] = None # Reset so reverse geocoding will trigger
else:
# This is a real address
processed['address'] = address[:500] # Limit to 500 characters
print(f"✅ Using provided address: {processed['address'][:100]}...")
print(f"📍 Processed location data:")
# CRITICAL: If we have coordinates but no real address, perform reverse geocoding
if (processed['latitude'] is not None and processed['longitude'] is not None
and not processed['address']):
print(f"🌍 Performing reverse geocoding for coordinates: {processed['latitude']}, {processed['longitude']}")
reverse_geocoded_address = reverse_geocode_coordinates(processed['latitude'], processed['longitude'])
if reverse_geocoded_address:
processed['address'] = reverse_geocoded_address[:500]
print(f"✅ Reverse geocoded address: {processed['address']}")
else:
print(f"⚠️ Could not reverse geocode coordinates, keeping coordinates as fallback")
processed['address'] = f"{processed['latitude']:.10f}, {processed['longitude']:.10f}"
print(f"📍 Final processed location data:")
print(f" Coordinates: {processed['latitude']}, {processed['longitude']}")
print(f" GPS Accuracy: {processed['accuracy']}m")
print(f" Source: {processed['source']}")
@@ -1932,6 +1997,7 @@ def qr_checkin(qr_url):
"""
Enhanced staff check-in with location accuracy calculation
Allows multiple check-ins with minimum 30-minute intervals between them
PRESERVES coordinate-to-address conversion functionality
"""
try:
print(f"\n🚀 STARTING ENHANCED CHECK-IN PROCESS")
@@ -1980,23 +2046,23 @@ def qr_checkin(qr_url):
# Check if 30 minutes have passed since the last check-in
if recent_checkin_datetime > thirty_minutes_ago:
minutes_remaining = 30 - int((current_time - recent_checkin_datetime).total_seconds() / 60)
print(f"⚠️ Too soon for another submission for {employee_id}")
print(f" Last submission: {recent_checkin.check_in_time.strftime('%H:%M')}")
print(f"⚠️ Too soon for another check-in for {employee_id}")
print(f" Last check-in: {recent_checkin.check_in_time.strftime('%H:%M')}")
print(f" Minutes remaining: {minutes_remaining}")
return jsonify({
'success': False,
'message': f'You can submit again in {minutes_remaining} minutes. Last submission was at {recent_checkin.check_in_time.strftime("%H:%M")}.'
'message': f'You can check in again in {minutes_remaining} minutes. Last check-in was at {recent_checkin.check_in_time.strftime("%H:%M")}.'
}), 400
else:
print(f"✅ 30-minute interval satisfied. Allowing new check-in for {employee_id}")
else:
print(f"✅ First submission today for {employee_id}")
print(f"✅ First check-in today for {employee_id}")
# Process location data
# PRESERVED: Process location data with coordinate-to-address conversion
location_data = process_location_data_enhanced(request.form)
# Get device and network info
# PRESERVED: Get device and network info
user_agent_string = request.headers.get('User-Agent', '')
device_info = detect_device_info(user_agent_string)
client_ip = get_client_ip()
@@ -2005,7 +2071,7 @@ def qr_checkin(qr_url):
print(f"🌐 IP Address: {client_ip}")
print(f"📍 Location Data: {location_data}")
# Create attendance record
# PRESERVED: Create attendance record
print(f"\n💾 CREATING ATTENDANCE RECORD:")
attendance = AttendanceData(
@@ -2022,13 +2088,13 @@ def qr_checkin(qr_url):
accuracy=location_data['accuracy'],
altitude=location_data['altitude'],
location_source=location_data['source'],
address=location_data['address'],
address=location_data['address'], # This now includes converted address
status='present'
)
print(f"✅ Created base attendance record")
# Calculate location accuracy
# PRESERVED: Calculate location accuracy
print(f"\n🎯 CALCULATING LOCATION ACCURACY...")
location_accuracy = None
@@ -2050,13 +2116,13 @@ def qr_checkin(qr_url):
except Exception as e:
print(f"❌ Error in location accuracy calculation: {e}")
# Save to database
# PRESERVED: Save to database
try:
db.session.add(attendance)
db.session.commit()
print(f"✅ Successfully saved attendance record with ID: {attendance.id}")
# Count total check-ins for today for this employee at this location
# NEW: Count total check-ins for today for this employee at this location
today_checkin_count = AttendanceData.query.filter_by(
qr_code_id=qr_code.id,
employee_id=employee_id.upper(),
@@ -2073,7 +2139,7 @@ def qr_checkin(qr_url):
'message': 'Database error occurred.'
}), 500
# Return success response
# ENHANCED: Return success response with sequence information
response_data = {
'success': True,
'message': f'Check-in successful! {checkin_sequence_text} for today.',
@@ -2101,6 +2167,7 @@ def qr_checkin(qr_url):
print(f" Employee: {attendance.employee_id}")
print(f" Time: {attendance.check_in_time}")
print(f" Location: {attendance.location_name}")
print(f" Address: {attendance.address}")
print(f" Today's count: {today_checkin_count}")
return jsonify(response_data), 200
+28 -5
View File
@@ -45,7 +45,7 @@ const translations = {
error: "Error en el registro. Por favor intente de nuevo.",
duplicate: "Ya se ha registrado hoy.",
tooSoon: "Por favor espere antes de registrarse nuevamente.",
multipleSuccess: "Submitted successful!!",
multipleSuccess: "Submitted successfully!!",
invalidId: "Por favor ingrese un ID de empleado válido.",
locationError: "No se pudo obtener datos de ubicación.",
networkError: "Error de red. Verifique su conexión.",
@@ -225,7 +225,7 @@ function handleCheckinResponse(data) {
// ENHANCED SUCCESS HANDLING WITH MULTIPLE CHECK-IN INFO
function handleCheckinSuccess(data) {
console.log("✅ Submitted successful!");
console.log("✅ Submitted successfully!");
const responseData = data.data || data || {};
const checkinCount = responseData.checkin_count_today || 1;
@@ -515,9 +515,32 @@ function handleLocationError(error) {
}
function reverseGeocode(lat, lng) {
// This would typically use a geocoding service
// For now, just set a placeholder
userLocation.address = `${lat.toFixed(10)}, ${lng.toFixed(10)}`;
console.log(`🌍 Starting reverse geocoding for: ${lat}, ${lng}`);
// Using Nominatim (OpenStreetMap) reverse geocoding service
const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&addressdetails=1&zoom=18`;
fetch(url, {
method: "GET",
headers: {
"User-Agent": "QR-Attendance-System/1.0",
},
})
.then((response) => response.json())
.then((data) => {
if (data && data.display_name) {
userLocation.address = data.display_name;
console.log(`✅ Reverse geocoded address: ${userLocation.address}`);
} else {
console.log(`⚠️ No address found, using coordinates as fallback`);
userLocation.address = `${lat.toFixed(10)}, ${lng.toFixed(10)}`;
}
})
.catch((error) => {
console.error(`❌ Reverse geocoding error:`, error);
// Fallback to coordinates if reverse geocoding fails
userLocation.address = `${lat.toFixed(10)}, ${lng.toFixed(10)}`;
});
}
// Language functionality remains unchanged
File diff suppressed because it is too large Load Diff