From 16f7b3f68df83e92fa02ea84fca36820cfc8391b Mon Sep 17 00:00:00 2001 From: NguyenND Date: Fri, 10 Oct 2025 13:20:21 -0400 Subject: [PATCH] Updated import functions --- app.py | 73 ++- templates/time_attendance_import.html | 14 +- .../time_attendance_import_progress.html | 301 +++++++++++ templates/time_attendance_invalid_review.html | 485 ++++++++++++++++++ time_attendance_import_service.py | 165 +++++- 5 files changed, 1033 insertions(+), 5 deletions(-) create mode 100644 templates/time_attendance_import_progress.html create mode 100644 templates/time_attendance_invalid_review.html diff --git a/app.py b/app.py index 0923227..fc65ca7 100644 --- a/app.py +++ b/app.py @@ -6597,6 +6597,20 @@ def import_time_attendance(): else: flash('No duplicates found. Proceeding with import.', 'info') + # Check for invalid rows and show review if any + analyze_invalid = request.form.get('analyze_invalid', 'false').lower() == 'true' + + if analyze_invalid: + invalid_analysis = import_service.analyze_for_invalid_rows(temp_path) + + if invalid_analysis['invalid_rows'] > 0: + # Show invalid row review page + return render_template('time_attendance_invalid_review.html', + analysis=invalid_analysis, + filename=filename) + else: + flash('All rows are valid. Proceeding with import.', 'info') + # Validate file validation_result = import_service.validate_excel_file(temp_path) @@ -6741,7 +6755,64 @@ def analyze_import_duplicates(): 'success': False, 'message': f'Analysis failed: {str(e)}' }), 500 - + +@app.route('/time-attendance/import/analyze-invalid', methods=['POST']) +@login_required +def analyze_import_invalid(): + """AJAX endpoint to analyze file for invalid rows""" + try: + if 'file' not in request.files: + return jsonify({'success': False, 'message': 'No file provided'}), 400 + + file = request.files['file'] + if file.filename == '': + return jsonify({'success': False, 'message': 'No file selected'}), 400 + + if not file.filename.lower().endswith(('.xlsx', '.xls')): + return jsonify({'success': False, 'message': 'Invalid file format'}), 400 + + # Save temporarily + filename = secure_filename(file.filename) + temp_path = os.path.join(app.config.get('UPLOAD_FOLDER', '/tmp'), + f"analyze_invalid_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{filename}") + + os.makedirs(os.path.dirname(temp_path), exist_ok=True) + file.save(temp_path) + + # Store in session + session['pending_import_file'] = temp_path + session['pending_import_filename'] = filename + + try: + import_service = TimeAttendanceImportService(db, logger_handler) + analysis = import_service.analyze_for_invalid_rows(temp_path) + + # Convert datetime objects to strings for JSON + for invalid in analysis.get('invalid_details', []): + if 'row_data' in invalid: + if invalid['row_data'].get('attendance_date'): + invalid['row_data']['attendance_date'] = str(invalid['row_data']['attendance_date']) + if invalid['row_data'].get('attendance_time'): + invalid['row_data']['attendance_time'] = str(invalid['row_data']['attendance_time']) + + return jsonify({ + 'success': True, + 'analysis': analysis + }) + + except Exception as e: + logger_handler.logger.error(f"Invalid row analysis error: {e}") + return jsonify({ + 'success': False, + 'message': f'Analysis failed: {str(e)}' + }), 500 + + except Exception as e: + logger_handler.logger.error(f"Invalid row analysis error: {e}") + return jsonify({ + 'success': False, + 'message': f'Analysis failed: {str(e)}' + }), 500 @app.route('/time-attendance/import/cancel-pending') @login_required diff --git a/templates/time_attendance_import.html b/templates/time_attendance_import.html index 9d371f2..380415d 100644 --- a/templates/time_attendance_import.html +++ b/templates/time_attendance_import.html @@ -377,15 +377,23 @@
- +
+ +
+ + +
- +
- +