Implement boxes management module with auto-numbered box creation
- Add boxes_crates database table with BIGINT IDs and 8-digit auto-numbered box_numbers - Implement boxes CRUD operations (add, edit, update, delete, delete_multiple) - Create boxes route handlers with POST actions for all operations - Add boxes.html template with 3-panel layout matching warehouse locations module - Implement barcode generation and printing with JsBarcode and QZ Tray integration - Add browser print fallback for when QZ Tray is not available - Simplify create box form to single button with auto-generation - Fix JavaScript null reference errors with proper element validation - Convert tuple data to dictionaries for Jinja2 template compatibility - Register boxes blueprint in Flask app initialization
This commit is contained in:
@@ -7,6 +7,8 @@ import hashlib
|
||||
import secrets
|
||||
from datetime import datetime, timedelta
|
||||
from app.database import get_db
|
||||
from app.modules.settings.stats import get_all_stats
|
||||
from app.modules.settings.logs import get_log_files, get_log_content, get_log_file_path, get_log_statistics, search_in_logs
|
||||
import subprocess
|
||||
import os
|
||||
import json
|
||||
@@ -19,11 +21,30 @@ settings_bp = Blueprint('settings', __name__, url_prefix='/settings')
|
||||
|
||||
@settings_bp.route('/', methods=['GET'])
|
||||
def settings_index():
|
||||
"""Settings module main page"""
|
||||
"""Settings module main page with app overview"""
|
||||
if 'user_id' not in session:
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
return render_template('modules/settings/index.html')
|
||||
# Get all app statistics
|
||||
try:
|
||||
stats = get_all_stats()
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting stats in settings_index: {e}", exc_info=True)
|
||||
stats = {
|
||||
'user_count': 0,
|
||||
'database_size_mb': 0,
|
||||
'logs_size_mb': 0,
|
||||
'database_count': 0,
|
||||
'backup_count': 0,
|
||||
'printer_keys_count': 0,
|
||||
'app_key_availability': {
|
||||
'available': False,
|
||||
'count': 0,
|
||||
'status': 'Error loading data'
|
||||
}
|
||||
}
|
||||
|
||||
return render_template('modules/settings/index.html', stats=stats)
|
||||
|
||||
|
||||
@settings_bp.route('/general', methods=['GET', 'POST'])
|
||||
@@ -1254,3 +1275,100 @@ def toggle_backup_schedule(schedule_id):
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Log Explorer Routes
|
||||
# ============================================================================
|
||||
|
||||
@settings_bp.route('/logs', methods=['GET'])
|
||||
def logs_explorer():
|
||||
"""Log explorer main page - list all log files"""
|
||||
if 'user_id' not in session:
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
try:
|
||||
log_files = get_log_files()
|
||||
log_stats = get_log_statistics()
|
||||
|
||||
return render_template('modules/settings/logs_explorer.html',
|
||||
log_files=log_files,
|
||||
log_stats=log_stats)
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading logs explorer: {e}")
|
||||
flash(f"Error loading logs: {str(e)}", 'error')
|
||||
return render_template('modules/settings/logs_explorer.html',
|
||||
log_files=[],
|
||||
log_stats={})
|
||||
|
||||
|
||||
@settings_bp.route('/logs/view/<filename>', methods=['GET'])
|
||||
def view_log(filename):
|
||||
"""View content of a specific log file"""
|
||||
if 'user_id' not in session:
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
try:
|
||||
lines = request.args.get('lines', default=100, type=int)
|
||||
log_data = get_log_content(filename, lines=lines)
|
||||
|
||||
if not log_data.get('success'):
|
||||
flash(log_data.get('error', 'Error reading log file'), 'error')
|
||||
return redirect(url_for('settings.logs_explorer'))
|
||||
|
||||
return render_template('modules/settings/view_log.html', log_data=log_data)
|
||||
except Exception as e:
|
||||
logger.error(f"Error viewing log {filename}: {e}")
|
||||
flash(f"Error viewing log: {str(e)}", 'error')
|
||||
return redirect(url_for('settings.logs_explorer'))
|
||||
|
||||
|
||||
@settings_bp.route('/logs/download/<filename>', methods=['GET'])
|
||||
def download_log(filename):
|
||||
"""Download a log file"""
|
||||
if 'user_id' not in session:
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
try:
|
||||
filepath = get_log_file_path(filename)
|
||||
|
||||
if not filepath:
|
||||
flash('Invalid file or file not found', 'error')
|
||||
return redirect(url_for('settings.logs_explorer'))
|
||||
|
||||
return send_file(
|
||||
filepath,
|
||||
as_attachment=True,
|
||||
download_name=f"{filename}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error downloading log {filename}: {e}")
|
||||
flash(f"Error downloading log: {str(e)}", 'error')
|
||||
return redirect(url_for('settings.logs_explorer'))
|
||||
|
||||
|
||||
@settings_bp.route('/logs/search', methods=['GET'])
|
||||
def search_logs():
|
||||
"""Search for terms in log files"""
|
||||
if 'user_id' not in session:
|
||||
return redirect(url_for('main.login'))
|
||||
|
||||
try:
|
||||
search_term = request.args.get('q', '').strip()
|
||||
filename = request.args.get('file', default=None)
|
||||
|
||||
results = []
|
||||
if search_term:
|
||||
results = search_in_logs(search_term, filename=filename)
|
||||
|
||||
log_files = get_log_files()
|
||||
|
||||
return render_template('modules/settings/search_logs.html',
|
||||
search_term=search_term,
|
||||
results=results,
|
||||
log_files=log_files,
|
||||
selected_file=filename)
|
||||
except Exception as e:
|
||||
logger.error(f"Error searching logs: {e}")
|
||||
flash(f"Error searching logs: {str(e)}", 'error')
|
||||
return redirect(url_for('settings.logs_explorer'))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user