updated reports
This commit is contained in:
Binary file not shown.
@@ -23,6 +23,23 @@ from .settings import (
|
|||||||
bp = Blueprint('main', __name__)
|
bp = Blueprint('main', __name__)
|
||||||
warehouse_bp = Blueprint('warehouse', __name__)
|
warehouse_bp = Blueprint('warehouse', __name__)
|
||||||
|
|
||||||
|
def format_cell_data(cell):
|
||||||
|
"""Helper function to format cell data, especially dates and times"""
|
||||||
|
if isinstance(cell, datetime):
|
||||||
|
# Format date as dd/mm/yyyy
|
||||||
|
return cell.strftime('%d/%m/%Y')
|
||||||
|
elif isinstance(cell, timedelta):
|
||||||
|
# Convert timedelta to HH:MM:SS format
|
||||||
|
total_seconds = int(cell.total_seconds())
|
||||||
|
hours, remainder = divmod(total_seconds, 3600)
|
||||||
|
minutes, seconds = divmod(remainder, 60)
|
||||||
|
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
||||||
|
elif hasattr(cell, 'date'): # Handle date objects
|
||||||
|
# Format date as dd/mm/yyyy
|
||||||
|
return cell.strftime('%d/%m/%Y')
|
||||||
|
else:
|
||||||
|
return cell
|
||||||
|
|
||||||
@bp.route('/store_articles')
|
@bp.route('/store_articles')
|
||||||
def store_articles():
|
def store_articles():
|
||||||
return render_template('store_articles.html')
|
return render_template('store_articles.html')
|
||||||
@@ -278,68 +295,90 @@ def get_report_data():
|
|||||||
conn = get_db_connection()
|
conn = get_db_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if report == "1": # Logic for the 1-day report
|
if report == "1": # Logic for the 1-day report (today's records)
|
||||||
one_day_ago = datetime.now() - timedelta(days=1)
|
today = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
print(f"DEBUG: Daily report searching for records on date: {today}")
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE date = ?
|
||||||
|
ORDER BY date DESC, time DESC
|
||||||
|
""", (today,))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Daily report found {len(rows)} rows for today ({today}):", rows)
|
||||||
|
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
|
elif report == "2": # Logic for the 5-day report (last 5 days including today)
|
||||||
|
five_days_ago = datetime.now() - timedelta(days=4) # Last 4 days + today = 5 days
|
||||||
|
start_date = five_days_ago.strftime('%Y-%m-%d')
|
||||||
|
print(f"DEBUG: 5-day report searching for records from {start_date} onwards")
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
FROM scan1_orders
|
FROM scan1_orders
|
||||||
WHERE date >= ?
|
WHERE date >= ?
|
||||||
ORDER BY date DESC, time DESC
|
ORDER BY date DESC, time DESC
|
||||||
""", (one_day_ago.strftime('%Y-%m-%d'),))
|
""", (start_date,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
print("Fetched rows for report 1 (last 1 day):", rows)
|
print(f"DEBUG: 5-day report found {len(rows)} rows from {start_date} onwards:", rows)
|
||||||
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
data["rows"] = [[str(cell) if isinstance(cell, (datetime, timedelta)) else cell for cell in row] for row in rows]
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
elif report == "2": # Logic for the 5-day report
|
elif report == "3": # Logic for the report with non-zero quality_code (today only)
|
||||||
five_days_ago = datetime.now() - timedelta(days=5)
|
today = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
print(f"DEBUG: Quality defects report (today) searching for records on {today} with quality issues")
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
FROM scan1_orders
|
FROM scan1_orders
|
||||||
WHERE date >= ?
|
WHERE date = ? AND quality_code != 0
|
||||||
ORDER BY date DESC, time DESC
|
ORDER BY date DESC, time DESC
|
||||||
""", (five_days_ago.strftime('%Y-%m-%d'),))
|
""", (today,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
print("Fetched rows for report 2 (last 5 days):", rows)
|
print(f"DEBUG: Quality defects report (today) found {len(rows)} rows with quality issues for {today}:", rows)
|
||||||
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
data["headers"] = ["Id", "Operator Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
data["rows"] = [[str(cell) if isinstance(cell, (datetime, timedelta)) else cell for cell in row] for row in rows]
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
elif report == "3": # Logic for the report with non-zero quality_code (1 day)
|
elif report == "4": # Logic for the report with non-zero quality_code (last 5 days)
|
||||||
one_day_ago = datetime.now() - timedelta(days=1)
|
five_days_ago = datetime.now() - timedelta(days=4) # Last 4 days + today = 5 days
|
||||||
|
start_date = five_days_ago.strftime('%Y-%m-%d')
|
||||||
|
print(f"DEBUG: Quality defects report (5 days) searching for records from {start_date} onwards with quality issues")
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
FROM scan1_orders
|
FROM scan1_orders
|
||||||
WHERE date >= ? AND quality_code != 0
|
WHERE date >= ? AND quality_code != 0
|
||||||
ORDER BY date DESC, time DESC
|
ORDER BY date DESC, time DESC
|
||||||
""", (one_day_ago.strftime('%Y-%m-%d'),))
|
""", (start_date,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
print("Fetched rows for report 3 (non-zero quality_code, last 1 day):", rows)
|
print(f"DEBUG: Quality defects report (5 days) found {len(rows)} rows with quality issues from {start_date} onwards:", rows)
|
||||||
data["headers"] = ["Id", "Operator Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
data["headers"] = ["Id", "Operator Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
data["rows"] = [[str(cell) if isinstance(cell, (datetime, timedelta)) else cell for cell in row] for row in rows]
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
elif report == "4": # Logic for the report with non-zero quality_code (5 days)
|
|
||||||
five_days_ago = datetime.now() - timedelta(days=5)
|
|
||||||
cursor.execute("""
|
|
||||||
SELECT Id, operator_code, CP_full_code, OC1_code, OC2 Code, quality_code, date, time, approved_quantity, rejected_quantity
|
|
||||||
FROM scan1_orders
|
|
||||||
WHERE date >= ? AND quality_code != 0
|
|
||||||
ORDER BY date DESC, time DESC
|
|
||||||
""", (five_days_ago.strftime('%Y-%m-%d'),))
|
|
||||||
rows = cursor.fetchall()
|
|
||||||
print("Fetched rows for report 4 (non-zero quality_code, last 5 days):", rows)
|
|
||||||
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
|
||||||
data["rows"] = [[str(cell) if isinstance(cell, (datetime, timedelta)) else cell for cell in row] for row in rows]
|
|
||||||
|
|
||||||
elif report == "5": # Logic for the 5-ft report (all rows)
|
elif report == "5": # Logic for the 5-ft report (all rows)
|
||||||
|
# First check if table exists and has any data
|
||||||
|
try:
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM scan1_orders")
|
||||||
|
total_count = cursor.fetchone()[0]
|
||||||
|
print(f"DEBUG: Total records in scan1_orders table: {total_count}")
|
||||||
|
|
||||||
|
if total_count == 0:
|
||||||
|
print("DEBUG: No data found in scan1_orders table")
|
||||||
|
data["headers"] = ["Id", "Operator Code", "CP Base Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity of order", "Rejected Quantity of order"]
|
||||||
|
data["rows"] = []
|
||||||
|
data["message"] = "No scan data available in the database. Please ensure scanning operations have been performed and data has been recorded."
|
||||||
|
else:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT Id, operator_code, CP_base_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
SELECT Id, operator_code, CP_base_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
FROM scan1_orders
|
FROM scan1_orders
|
||||||
ORDER BY date DESC, time DESC
|
ORDER BY date DESC, time DESC
|
||||||
""")
|
""")
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
print("Fetched rows for report 5 (all rows):", rows)
|
print(f"DEBUG: Fetched {len(rows)} rows for report 5 (all rows)")
|
||||||
data["headers"] = ["Id", "Operator Code", "CP Base Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity of order", "Rejected Quantity of order"]
|
data["headers"] = ["Id", "Operator Code", "CP Base Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity of order", "Rejected Quantity of order"]
|
||||||
data["rows"] = [[str(cell) if isinstance(cell, (datetime, timedelta)) else cell for cell in row] for row in rows]
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
|
except mariadb.Error as table_error:
|
||||||
|
print(f"DEBUG: Table access error: {table_error}")
|
||||||
|
data["error"] = f"Database table error: {table_error}"
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
except mariadb.Error as e:
|
except mariadb.Error as e:
|
||||||
@@ -352,6 +391,8 @@ def get_report_data():
|
|||||||
@bp.route('/generate_report', methods=['GET'])
|
@bp.route('/generate_report', methods=['GET'])
|
||||||
def generate_report():
|
def generate_report():
|
||||||
"""Generate report for specific date (calendar-based report)"""
|
"""Generate report for specific date (calendar-based report)"""
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
report = request.args.get('report')
|
report = request.args.get('report')
|
||||||
selected_date = request.args.get('date')
|
selected_date = request.args.get('date')
|
||||||
data = {"headers": [], "rows": []}
|
data = {"headers": [], "rows": []}
|
||||||
@@ -361,6 +402,14 @@ def generate_report():
|
|||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if report == "6" and selected_date: # Custom date report
|
if report == "6" and selected_date: # Custom date report
|
||||||
|
print(f"DEBUG: Searching for date: {selected_date}")
|
||||||
|
|
||||||
|
# First, let's check what dates exist in the database
|
||||||
|
cursor.execute("SELECT DISTINCT date FROM scan1_orders ORDER BY date DESC LIMIT 10")
|
||||||
|
existing_dates = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Available dates in database: {existing_dates}")
|
||||||
|
|
||||||
|
# Try exact match first
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
FROM scan1_orders
|
FROM scan1_orders
|
||||||
@@ -368,18 +417,320 @@ def generate_report():
|
|||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
""", (selected_date,))
|
""", (selected_date,))
|
||||||
rows = cursor.fetchall()
|
rows = cursor.fetchall()
|
||||||
print(f"Fetched rows for report 6 (custom date {selected_date}):", rows)
|
print(f"DEBUG: Exact match found {len(rows)} rows")
|
||||||
|
|
||||||
|
# If no exact match, try with DATE() function to handle different formats
|
||||||
|
if len(rows) == 0:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE DATE(date) = ?
|
||||||
|
ORDER BY time DESC
|
||||||
|
""", (selected_date,))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: DATE() function match found {len(rows)} rows")
|
||||||
|
|
||||||
|
# If still no match, try LIKE pattern
|
||||||
|
if len(rows) == 0:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE date LIKE ?
|
||||||
|
ORDER BY time DESC
|
||||||
|
""", (f"{selected_date}%",))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: LIKE pattern match found {len(rows)} rows")
|
||||||
|
|
||||||
|
print(f"DEBUG: Final result - {len(rows)} rows for date {selected_date}")
|
||||||
|
if len(rows) > 0:
|
||||||
|
print(f"DEBUG: Sample row: {rows[0]}")
|
||||||
|
|
||||||
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
data["rows"] = [[str(cell) if isinstance(cell, (datetime, timedelta)) else cell for cell in row] for row in rows]
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
|
# Add helpful message if no data found
|
||||||
|
if len(rows) == 0:
|
||||||
|
data["message"] = f"No scan data found for {selected_date}. Please select a date when scanning operations were performed."
|
||||||
|
|
||||||
|
elif report == "7": # Date Range Report
|
||||||
|
start_date = request.args.get('start_date')
|
||||||
|
end_date = request.args.get('end_date')
|
||||||
|
|
||||||
|
if start_date and end_date:
|
||||||
|
print(f"DEBUG: Date range report - Start: {start_date}, End: {end_date}")
|
||||||
|
|
||||||
|
# Validate date format and order
|
||||||
|
try:
|
||||||
|
start_dt = datetime.strptime(start_date, '%Y-%m-%d')
|
||||||
|
end_dt = datetime.strptime(end_date, '%Y-%m-%d')
|
||||||
|
|
||||||
|
if start_dt > end_dt:
|
||||||
|
data["error"] = "Start date cannot be after end date."
|
||||||
|
conn.close()
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
data["error"] = "Invalid date format. Please use YYYY-MM-DD format."
|
||||||
|
conn.close()
|
||||||
|
return jsonify(data)
|
||||||
|
|
||||||
|
# First, check what dates exist in the database for the range
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT DISTINCT date FROM scan1_orders
|
||||||
|
WHERE date >= ? AND date <= ?
|
||||||
|
ORDER BY date DESC
|
||||||
|
""", (start_date, end_date))
|
||||||
|
existing_dates = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Available dates in range: {existing_dates}")
|
||||||
|
|
||||||
|
# Query for all records in the date range
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_base_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE date >= ? AND date <= ?
|
||||||
|
ORDER BY date DESC, time DESC
|
||||||
|
""", (start_date, end_date))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Date range query found {len(rows)} rows from {start_date} to {end_date}")
|
||||||
|
|
||||||
|
data["headers"] = ["Id", "Operator Code", "CP Base Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
|
# Add helpful message if no data found
|
||||||
|
if len(rows) == 0:
|
||||||
|
data["message"] = f"No scan data found between {start_date} and {end_date}. Please select dates when scanning operations were performed."
|
||||||
|
else:
|
||||||
|
# Add summary information
|
||||||
|
total_approved = sum(row[8] for row in rows if row[8] is not None)
|
||||||
|
total_rejected = sum(row[9] for row in rows if row[9] is not None)
|
||||||
|
data["summary"] = {
|
||||||
|
"total_records": len(rows),
|
||||||
|
"date_range": f"{start_date} to {end_date}",
|
||||||
|
"total_approved": total_approved,
|
||||||
|
"total_rejected": total_rejected,
|
||||||
|
"dates_with_data": len(existing_dates)
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
data["error"] = "Both start date and end date are required for date range report."
|
||||||
|
|
||||||
|
elif report == "8" and selected_date: # Custom date quality defects report
|
||||||
|
print(f"DEBUG: Quality defects report for specific date: {selected_date}")
|
||||||
|
|
||||||
|
# First, let's check what dates exist in the database
|
||||||
|
cursor.execute("SELECT DISTINCT date FROM scan1_orders ORDER BY date DESC LIMIT 10")
|
||||||
|
existing_dates = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Available dates in database: {existing_dates}")
|
||||||
|
|
||||||
|
# Try exact match first for defects (quality_code != 0)
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE date = ? AND quality_code != 0
|
||||||
|
ORDER BY quality_code DESC, time DESC
|
||||||
|
""", (selected_date,))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Quality defects exact match found {len(rows)} rows for {selected_date}")
|
||||||
|
|
||||||
|
# If no exact match, try with DATE() function to handle different formats
|
||||||
|
if len(rows) == 0:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE DATE(date) = ? AND quality_code != 0
|
||||||
|
ORDER BY quality_code DESC, time DESC
|
||||||
|
""", (selected_date,))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Quality defects DATE() function match found {len(rows)} rows")
|
||||||
|
|
||||||
|
# If still no match, try LIKE pattern
|
||||||
|
if len(rows) == 0:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT Id, operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity
|
||||||
|
FROM scan1_orders
|
||||||
|
WHERE date LIKE ? AND quality_code != 0
|
||||||
|
ORDER BY quality_code DESC, time DESC
|
||||||
|
""", (f"{selected_date}%",))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Quality defects LIKE pattern match found {len(rows)} rows")
|
||||||
|
|
||||||
|
print(f"DEBUG: Final quality defects result - {len(rows)} rows for date {selected_date}")
|
||||||
|
if len(rows) > 0:
|
||||||
|
print(f"DEBUG: Sample defective item: {rows[0]}")
|
||||||
|
|
||||||
|
data["headers"] = ["Id", "Operator Code", "CP Full Code", "OC1 Code", "OC2 Code", "Quality Code", "Date", "Time", "Approved Quantity", "Rejected Quantity"]
|
||||||
|
data["rows"] = [[format_cell_data(cell) for cell in row] for row in rows]
|
||||||
|
|
||||||
|
# Add helpful message if no data found
|
||||||
|
if len(rows) == 0:
|
||||||
|
data["message"] = f"No quality defects found for {selected_date}. This could mean no scanning was performed or all items passed quality control."
|
||||||
|
else:
|
||||||
|
# Add summary for quality defects
|
||||||
|
total_defective_items = len(rows)
|
||||||
|
total_rejected_qty = sum(row[9] for row in rows if row[9] is not None)
|
||||||
|
unique_quality_codes = len(set(row[5] for row in rows if row[5] != 0))
|
||||||
|
|
||||||
|
data["defects_summary"] = {
|
||||||
|
"total_defective_items": total_defective_items,
|
||||||
|
"total_rejected_quantity": total_rejected_qty,
|
||||||
|
"unique_defect_types": unique_quality_codes,
|
||||||
|
"date": selected_date
|
||||||
|
}
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
except mariadb.Error as e:
|
except mariadb.Error as e:
|
||||||
print(f"Error fetching custom date report: {e}")
|
print(f"Error fetching custom date report: {e}")
|
||||||
data["error"] = f"Error fetching report data for {selected_date}."
|
data["error"] = f"Error fetching report data for {selected_date if report == '6' or report == '8' else 'date range'}."
|
||||||
|
|
||||||
print("Custom date report data being returned:", data)
|
print("Custom date report data being returned:", data)
|
||||||
return jsonify(data)
|
return jsonify(data)
|
||||||
|
|
||||||
|
@bp.route('/debug_dates', methods=['GET'])
|
||||||
|
def debug_dates():
|
||||||
|
"""Debug route to check available dates in database"""
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Get all distinct dates
|
||||||
|
cursor.execute("SELECT DISTINCT date FROM scan1_orders ORDER BY date DESC")
|
||||||
|
dates = cursor.fetchall()
|
||||||
|
|
||||||
|
# Get total count
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM scan1_orders")
|
||||||
|
total_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# Get sample data
|
||||||
|
cursor.execute("SELECT date, time FROM scan1_orders ORDER BY date DESC LIMIT 5")
|
||||||
|
sample_data = cursor.fetchall()
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"total_records": total_count,
|
||||||
|
"available_dates": [str(date[0]) for date in dates],
|
||||||
|
"sample_data": [{"date": str(row[0]), "time": str(row[1])} for row in sample_data]
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)})
|
||||||
|
|
||||||
|
@bp.route('/test_database', methods=['GET'])
|
||||||
|
def test_database():
|
||||||
|
"""Test database connection and query the scan1_orders table"""
|
||||||
|
try:
|
||||||
|
print("DEBUG: Testing database connection...")
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
print("DEBUG: Database connection successful!")
|
||||||
|
|
||||||
|
# Test 1: Check if table exists
|
||||||
|
try:
|
||||||
|
cursor.execute("SHOW TABLES LIKE 'scan1_orders'")
|
||||||
|
table_exists = cursor.fetchone()
|
||||||
|
print(f"DEBUG: Table scan1_orders exists: {table_exists is not None}")
|
||||||
|
|
||||||
|
if not table_exists:
|
||||||
|
conn.close()
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"message": "Table 'scan1_orders' does not exist in the database"
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error checking table existence: {e}")
|
||||||
|
conn.close()
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"message": f"Error checking table existence: {e}"
|
||||||
|
})
|
||||||
|
|
||||||
|
# Test 2: Get table structure
|
||||||
|
try:
|
||||||
|
cursor.execute("DESCRIBE scan1_orders")
|
||||||
|
table_structure = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Table structure: {table_structure}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error getting table structure: {e}")
|
||||||
|
table_structure = []
|
||||||
|
|
||||||
|
# Test 3: Count total records
|
||||||
|
try:
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM scan1_orders")
|
||||||
|
total_count = cursor.fetchone()[0]
|
||||||
|
print(f"DEBUG: Total records in table: {total_count}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error counting records: {e}")
|
||||||
|
total_count = -1
|
||||||
|
|
||||||
|
# Test 4: Get sample data (if any exists)
|
||||||
|
sample_data = []
|
||||||
|
try:
|
||||||
|
cursor.execute("SELECT * FROM scan1_orders LIMIT 5")
|
||||||
|
raw_data = cursor.fetchall()
|
||||||
|
print(f"DEBUG: Sample data (first 5 rows): {raw_data}")
|
||||||
|
|
||||||
|
# Convert data to JSON-serializable format using consistent formatting
|
||||||
|
sample_data = []
|
||||||
|
for row in raw_data:
|
||||||
|
converted_row = [format_cell_data(item) for item in row]
|
||||||
|
sample_data.append(converted_row)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error getting sample data: {e}")
|
||||||
|
|
||||||
|
# Test 5: Get distinct dates (if any exist)
|
||||||
|
available_dates = []
|
||||||
|
try:
|
||||||
|
cursor.execute("SELECT DISTINCT date FROM scan1_orders ORDER BY date DESC LIMIT 10")
|
||||||
|
date_rows = cursor.fetchall()
|
||||||
|
available_dates = [str(row[0]) for row in date_rows]
|
||||||
|
print(f"DEBUG: Available dates: {available_dates}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error getting dates: {e}")
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Test 6: Add a current date sample record for testing daily reports
|
||||||
|
try:
|
||||||
|
from datetime import datetime
|
||||||
|
current_date = datetime.now().strftime('%Y-%m-%d')
|
||||||
|
current_time = datetime.now().strftime('%H:%M:%S')
|
||||||
|
|
||||||
|
# Check if we already have a record for today
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM scan1_orders WHERE date = ?", (current_date,))
|
||||||
|
today_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
if today_count == 0:
|
||||||
|
print(f"DEBUG: No records found for today ({current_date}), adding sample record...")
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO scan1_orders (operator_code, CP_full_code, OC1_code, OC2_code, quality_code, date, time, approved_quantity, rejected_quantity)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
""", ('OP01', 'CP99999999-0001', 'OC01', 'OC02', 0, current_date, current_time, 1, 0))
|
||||||
|
conn.commit()
|
||||||
|
print(f"DEBUG: Added sample record for today ({current_date})")
|
||||||
|
message_addendum = " Added sample record for today to test daily reports."
|
||||||
|
else:
|
||||||
|
print(f"DEBUG: Found {today_count} records for today ({current_date})")
|
||||||
|
message_addendum = f" Found {today_count} records for today."
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Error adding sample record: {e}")
|
||||||
|
message_addendum = " Could not add sample record for testing."
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"database_connection": "OK",
|
||||||
|
"table_exists": table_exists is not None,
|
||||||
|
"table_structure": [{"field": row[0], "type": row[1], "null": row[2]} for row in table_structure],
|
||||||
|
"total_records": total_count,
|
||||||
|
"sample_data": sample_data,
|
||||||
|
"available_dates": available_dates,
|
||||||
|
"message": f"Database test completed. Found {total_count} records in scan1_orders table.{message_addendum}"
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"DEBUG: Database test failed: {e}")
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"message": f"Database connection failed: {e}"
|
||||||
|
})
|
||||||
|
|
||||||
@bp.route('/etichete')
|
@bp.route('/etichete')
|
||||||
def etichete():
|
def etichete():
|
||||||
if 'role' not in session or session['role'] not in ['superadmin', 'etichete']:
|
if 'role' not in session or session['role'] not in ['superadmin', 'etichete']:
|
||||||
|
|||||||
@@ -32,14 +32,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
updateThemeToggleButtonText(); // Update the button text after toggling
|
updateThemeToggleButtonText(); // Update the button text after toggling
|
||||||
});
|
});
|
||||||
|
|
||||||
// Helper function to format dates
|
// Date formatting is now handled consistently on the backend
|
||||||
function formatDate(dateString) {
|
|
||||||
const date = new Date(dateString);
|
|
||||||
if (!isNaN(date)) {
|
|
||||||
return date.toISOString().split('T')[0]; // Format as yyyy-mm-dd
|
|
||||||
}
|
|
||||||
return dateString; // Fallback if not a valid date
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to populate the table with data
|
// Function to populate the table with data
|
||||||
function populateTable(data) {
|
function populateTable(data) {
|
||||||
@@ -50,7 +43,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
tableHead.innerHTML = '';
|
tableHead.innerHTML = '';
|
||||||
tableBody.innerHTML = '';
|
tableBody.innerHTML = '';
|
||||||
|
|
||||||
if (data.headers && data.rows) {
|
if (data.headers && data.rows && data.rows.length > 0) {
|
||||||
// Populate table headers
|
// Populate table headers
|
||||||
data.headers.forEach((header) => {
|
data.headers.forEach((header) => {
|
||||||
const th = document.createElement('th');
|
const th = document.createElement('th');
|
||||||
@@ -64,23 +57,32 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
row.forEach((cell, index) => {
|
row.forEach((cell, index) => {
|
||||||
const td = document.createElement('td');
|
const td = document.createElement('td');
|
||||||
|
|
||||||
// Format the "Date" column
|
// Use the cell data as-is since backend now handles formatting
|
||||||
if (data.headers[index].toLowerCase() === 'date' && cell) {
|
|
||||||
td.textContent = formatDate(cell);
|
|
||||||
} else {
|
|
||||||
td.textContent = cell;
|
td.textContent = cell;
|
||||||
}
|
|
||||||
|
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
});
|
});
|
||||||
tableBody.appendChild(tr);
|
tableBody.appendChild(tr);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// No data available
|
// Handle no data scenarios
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
const td = document.createElement('td');
|
const td = document.createElement('td');
|
||||||
|
|
||||||
|
// Use custom message if provided, otherwise use default
|
||||||
|
if (data.message) {
|
||||||
|
td.textContent = data.message;
|
||||||
|
} else if (data.error) {
|
||||||
|
td.textContent = `Error: ${data.error}`;
|
||||||
|
} else {
|
||||||
td.textContent = 'No data available.';
|
td.textContent = 'No data available.';
|
||||||
td.colSpan = data.headers ? data.headers.length : 1;
|
}
|
||||||
|
|
||||||
|
td.colSpan = data.headers ? data.headers.length || 1 : 1;
|
||||||
|
td.style.textAlign = 'center';
|
||||||
|
td.style.padding = '20px';
|
||||||
|
td.style.fontStyle = 'italic';
|
||||||
|
td.style.color = '#666';
|
||||||
tr.appendChild(td);
|
tr.appendChild(td);
|
||||||
tableBody.appendChild(tr);
|
tableBody.appendChild(tr);
|
||||||
}
|
}
|
||||||
@@ -115,9 +117,20 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// Handle report button clicks
|
// Handle report button clicks
|
||||||
reportButtons.forEach((button) => {
|
reportButtons.forEach((button) => {
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
|
// Skip buttons that have their own handlers
|
||||||
|
if (button.id === 'select-day-report' || button.id === 'date-range-report' || button.id === 'select-day-defects-report') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const reportNumber = button.dataset.report;
|
const reportNumber = button.dataset.report;
|
||||||
const reportLabel = button.textContent.trim();
|
const reportLabel = button.textContent.trim();
|
||||||
|
|
||||||
|
// Check if reportNumber exists
|
||||||
|
if (!reportNumber) {
|
||||||
|
console.warn('Report button clicked but no data-report attribute found:', button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Update the title dynamically
|
// Update the title dynamically
|
||||||
reportTitle.textContent = `Data for "${reportLabel}"`;
|
reportTitle.textContent = `Data for "${reportLabel}"`;
|
||||||
|
|
||||||
@@ -131,6 +144,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log("Fetched data:", data); // Debugging
|
console.log("Fetched data:", data); // Debugging
|
||||||
|
|
||||||
|
// Update title with additional info
|
||||||
|
if (data.message) {
|
||||||
|
reportTitle.textContent = data.message;
|
||||||
|
} else if (data.rows && data.rows.length > 0) {
|
||||||
|
reportTitle.textContent = `${reportLabel} (${data.rows.length} records)`;
|
||||||
|
} else {
|
||||||
|
reportTitle.textContent = `${reportLabel} - No data found`;
|
||||||
|
}
|
||||||
|
|
||||||
populateTable(data);
|
populateTable(data);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@@ -153,6 +176,79 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
exportTableToCSV(filename);
|
exportTableToCSV(filename);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Test Database Button
|
||||||
|
const testDatabaseBtn = document.getElementById('test-database');
|
||||||
|
if (testDatabaseBtn) {
|
||||||
|
testDatabaseBtn.addEventListener('click', () => {
|
||||||
|
console.log('Testing database connection...');
|
||||||
|
reportTitle.textContent = 'Testing Database Connection...';
|
||||||
|
|
||||||
|
fetch('/test_database')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('Database test results:', data);
|
||||||
|
|
||||||
|
if (data.success) {
|
||||||
|
reportTitle.textContent = `Database Test Results - ${data.total_records} records found`;
|
||||||
|
|
||||||
|
// Create a detailed results table
|
||||||
|
const thead = reportTable.querySelector('thead tr');
|
||||||
|
const tbody = reportTable.querySelector('tbody');
|
||||||
|
|
||||||
|
// Clear existing content
|
||||||
|
thead.innerHTML = '';
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
|
// Add headers
|
||||||
|
const headers = ['Test Item', 'Result', 'Details'];
|
||||||
|
headers.forEach(header => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
th.textContent = header;
|
||||||
|
thead.appendChild(th);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add test results
|
||||||
|
const results = [
|
||||||
|
['Database Connection', data.database_connection, 'Connection successful'],
|
||||||
|
['Table Exists', data.table_exists ? 'YES' : 'NO', 'scan1_orders table check'],
|
||||||
|
['Total Records', data.total_records, 'Number of rows in table'],
|
||||||
|
['Table Structure', `${data.table_structure.length} columns`, data.table_structure.map(col => `${col.field} (${col.type})`).join(', ')],
|
||||||
|
['Available Dates', data.available_dates.length, data.available_dates.join(', ') || 'No dates found'],
|
||||||
|
['Sample Data', data.sample_data.length > 0 ? 'Available' : 'Empty', `${data.sample_data.length} sample rows`]
|
||||||
|
];
|
||||||
|
|
||||||
|
results.forEach(result => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
result.forEach(cell => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.textContent = cell;
|
||||||
|
row.appendChild(td);
|
||||||
|
});
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show alert with summary
|
||||||
|
alert(`Database Test Complete!\n\nConnection: ${data.database_connection}\nTable exists: ${data.table_exists}\nTotal records: ${data.total_records}\nMessage: ${data.message}`);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
reportTitle.textContent = 'Database Test Failed';
|
||||||
|
alert(`Database test failed: ${data.message}`);
|
||||||
|
|
||||||
|
// Show error in table
|
||||||
|
const thead = reportTable.querySelector('thead tr');
|
||||||
|
const tbody = reportTable.querySelector('tbody');
|
||||||
|
thead.innerHTML = '<th>Error</th>';
|
||||||
|
tbody.innerHTML = `<tr><td>${data.message}</td></tr>`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Database test error:', error);
|
||||||
|
reportTitle.textContent = 'Database Test Error';
|
||||||
|
alert(`Error testing database: ${error.message}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Placeholder for PDF export functionality
|
// Placeholder for PDF export functionality
|
||||||
exportPdfButton.addEventListener('click', () => {
|
exportPdfButton.addEventListener('click', () => {
|
||||||
alert('Exporting current report as PDF...');
|
alert('Exporting current report as PDF...');
|
||||||
@@ -307,6 +403,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Show calendar modal for quality defects report
|
||||||
|
const selectDayDefectsReportBtn = document.getElementById('select-day-defects-report');
|
||||||
|
if (selectDayDefectsReportBtn) {
|
||||||
|
selectDayDefectsReportBtn.addEventListener('click', () => {
|
||||||
|
console.log('DEBUG: Select Day Quality Defects Report button clicked!');
|
||||||
|
calendarModal.style.display = 'block';
|
||||||
|
generateCalendar(currentDate);
|
||||||
|
|
||||||
|
// Mark this as a defects report by setting a flag
|
||||||
|
calendarModal.setAttribute('data-report-type', 'defects');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Close modal events
|
// Close modal events
|
||||||
if (closeModal) {
|
if (closeModal) {
|
||||||
closeModal.addEventListener('click', closeCalendarModal);
|
closeModal.addEventListener('click', closeCalendarModal);
|
||||||
@@ -340,14 +449,33 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// Confirm date selection
|
// Confirm date selection
|
||||||
if (confirmDate) {
|
if (confirmDate) {
|
||||||
confirmDate.addEventListener('click', () => {
|
confirmDate.addEventListener('click', () => {
|
||||||
|
console.log('DEBUG: Calendar Generate Report button clicked!');
|
||||||
if (selectedDate) {
|
if (selectedDate) {
|
||||||
// Format date as YYYY-MM-DD
|
// Format date as YYYY-MM-DD (timezone-safe)
|
||||||
const formattedDate = selectedDate.toISOString().split('T')[0];
|
const year = selectedDate.getFullYear();
|
||||||
|
const month = String(selectedDate.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(selectedDate.getDate()).padStart(2, '0');
|
||||||
|
const formattedDate = `${year}-${month}-${day}`;
|
||||||
|
console.log(`DEBUG: Selected date object:`, selectedDate);
|
||||||
|
console.log(`DEBUG: Selected date formatted as: ${formattedDate}`);
|
||||||
|
|
||||||
|
// Check if this is a defects report or regular report
|
||||||
|
const reportType = calendarModal.getAttribute('data-report-type');
|
||||||
|
console.log(`DEBUG: Report type: ${reportType}`);
|
||||||
|
|
||||||
closeCalendarModal();
|
closeCalendarModal();
|
||||||
|
|
||||||
// Fetch report data for the selected date
|
// Fetch appropriate report data for the selected date
|
||||||
|
if (reportType === 'defects') {
|
||||||
|
console.log('DEBUG: About to call fetchCustomDefectsReport');
|
||||||
|
fetchCustomDefectsReport(formattedDate);
|
||||||
|
} else {
|
||||||
|
console.log('DEBUG: About to call fetchCustomDateReport');
|
||||||
fetchCustomDateReport(formattedDate);
|
fetchCustomDateReport(formattedDate);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log('DEBUG: No date selected when Generate Report clicked');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,6 +484,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
selectedDate = null;
|
selectedDate = null;
|
||||||
confirmDate.disabled = true;
|
confirmDate.disabled = true;
|
||||||
|
|
||||||
|
// Clear report type
|
||||||
|
calendarModal.removeAttribute('data-report-type');
|
||||||
|
|
||||||
// Remove selected class from all days
|
// Remove selected class from all days
|
||||||
const selectedDays = document.querySelectorAll('.calendar-day.selected');
|
const selectedDays = document.querySelectorAll('.calendar-day.selected');
|
||||||
selectedDays.forEach(day => day.classList.remove('selected'));
|
selectedDays.forEach(day => day.classList.remove('selected'));
|
||||||
@@ -417,23 +548,387 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function fetchCustomDateReport(dateString) {
|
function fetchCustomDateReport(dateString) {
|
||||||
reportTitle.textContent = `Loading report for ${dateString}...`;
|
console.log(`DEBUG: fetchCustomDateReport called with date: ${dateString}`);
|
||||||
|
|
||||||
fetch(`/generate_report?report=6&date=${dateString}`)
|
// Get elements directly to avoid scope issues
|
||||||
.then(response => response.json())
|
const reportTitleElement = document.getElementById('report-title');
|
||||||
.then(data => {
|
const reportTableElement = document.getElementById('report-table');
|
||||||
if (data.error) {
|
|
||||||
reportTitle.textContent = `Error: ${data.error}`;
|
console.log(`DEBUG: reportTitle element:`, reportTitleElement);
|
||||||
populateTable({ headers: [], rows: [] });
|
console.log(`DEBUG: reportTable element:`, reportTableElement);
|
||||||
|
|
||||||
|
if (!reportTitleElement) {
|
||||||
|
console.error('ERROR: report-title element not found!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reportTitleElement.textContent = `Loading report for ${dateString}...`;
|
||||||
|
|
||||||
|
// Local function to populate table to avoid scope issues
|
||||||
|
function localPopulateTable(data) {
|
||||||
|
const tableHead = reportTableElement.querySelector('thead tr');
|
||||||
|
const tableBody = reportTableElement.querySelector('tbody');
|
||||||
|
|
||||||
|
// Clear existing table content
|
||||||
|
tableHead.innerHTML = '';
|
||||||
|
tableBody.innerHTML = '';
|
||||||
|
|
||||||
|
if (data.headers && data.rows && data.rows.length > 0) {
|
||||||
|
// Populate table headers
|
||||||
|
data.headers.forEach((header) => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
th.textContent = header;
|
||||||
|
tableHead.appendChild(th);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Populate table rows
|
||||||
|
data.rows.forEach((row) => {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
row.forEach((cell, index) => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
// Format dates properly
|
||||||
|
if (data.headers[index].toLowerCase() === 'date' && cell) {
|
||||||
|
td.textContent = cell; // Use as-is since backend already formats it
|
||||||
} else {
|
} else {
|
||||||
reportTitle.textContent = `Daily Report for ${dateString}`;
|
td.textContent = cell;
|
||||||
populateTable(data);
|
}
|
||||||
|
tr.appendChild(td);
|
||||||
|
});
|
||||||
|
tableBody.appendChild(tr);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Handle no data scenarios
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.colSpan = 10; // Span all columns
|
||||||
|
td.textContent = 'No data available.';
|
||||||
|
td.style.textAlign = 'center';
|
||||||
|
tr.appendChild(td);
|
||||||
|
tableBody.appendChild(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `/generate_report?report=6&date=${dateString}`;
|
||||||
|
console.log(`DEBUG: Making request to URL: ${url}`);
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
console.log(`DEBUG: Response status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('DEBUG: Response data:', data);
|
||||||
|
if (data.error) {
|
||||||
|
reportTitleElement.textContent = `Error: ${data.error}`;
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
} else if (data.message) {
|
||||||
|
reportTitleElement.textContent = data.message;
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
} else if (data.rows && data.rows.length === 0) {
|
||||||
|
reportTitleElement.textContent = `No data found for ${dateString}`;
|
||||||
|
localPopulateTable(data);
|
||||||
|
} else {
|
||||||
|
reportTitleElement.textContent = `Daily Report for ${dateString} (${data.rows ? data.rows.length : 0} records)`;
|
||||||
|
localPopulateTable(data);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error fetching custom date report:', error);
|
console.error('Error fetching custom date report:', error);
|
||||||
reportTitle.textContent = 'Error loading report';
|
reportTitleElement.textContent = 'Error loading report';
|
||||||
populateTable({ headers: [], rows: [] });
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to fetch quality defects report for specific date
|
||||||
|
function fetchCustomDefectsReport(dateString) {
|
||||||
|
console.log(`DEBUG: fetchCustomDefectsReport called with date: ${dateString}`);
|
||||||
|
|
||||||
|
// Get elements directly to avoid scope issues
|
||||||
|
const reportTitleElement = document.getElementById('report-title');
|
||||||
|
const reportTableElement = document.getElementById('report-table');
|
||||||
|
|
||||||
|
console.log(`DEBUG: reportTitle element:`, reportTitleElement);
|
||||||
|
console.log(`DEBUG: reportTable element:`, reportTableElement);
|
||||||
|
|
||||||
|
if (!reportTitleElement) {
|
||||||
|
console.error('ERROR: report-title element not found!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reportTitleElement.textContent = `Loading quality defects report for ${dateString}...`;
|
||||||
|
|
||||||
|
// Local function to populate table to avoid scope issues
|
||||||
|
function localPopulateTable(data) {
|
||||||
|
const tableHead = reportTableElement.querySelector('thead tr');
|
||||||
|
const tableBody = reportTableElement.querySelector('tbody');
|
||||||
|
|
||||||
|
// Clear existing table content
|
||||||
|
tableHead.innerHTML = '';
|
||||||
|
tableBody.innerHTML = '';
|
||||||
|
|
||||||
|
if (data.headers && data.rows && data.rows.length > 0) {
|
||||||
|
// Populate table headers
|
||||||
|
data.headers.forEach((header) => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
th.textContent = header;
|
||||||
|
tableHead.appendChild(th);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Populate table rows
|
||||||
|
data.rows.forEach((row) => {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
row.forEach((cell, index) => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
// Highlight quality code column for defects
|
||||||
|
if (data.headers[index] === 'Quality Code' && cell != '0') {
|
||||||
|
td.style.backgroundColor = '#ffebee'; // Light red background
|
||||||
|
td.style.fontWeight = 'bold';
|
||||||
|
}
|
||||||
|
td.textContent = cell;
|
||||||
|
tr.appendChild(td);
|
||||||
|
});
|
||||||
|
tableBody.appendChild(tr);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Handle no data scenarios
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.colSpan = 10; // Span all columns
|
||||||
|
td.textContent = 'No quality defects found for this date.';
|
||||||
|
td.style.textAlign = 'center';
|
||||||
|
tr.appendChild(td);
|
||||||
|
tableBody.appendChild(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `/generate_report?report=8&date=${dateString}`;
|
||||||
|
console.log(`DEBUG: Making request to URL: ${url}`);
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
console.log(`DEBUG: Response status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('DEBUG: Quality defects response data:', data);
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
reportTitleElement.textContent = `Error: ${data.error}`;
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
} else if (data.message) {
|
||||||
|
reportTitleElement.textContent = data.message;
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
} else if (data.rows && data.rows.length === 0) {
|
||||||
|
reportTitleElement.textContent = `No quality defects found for ${dateString}`;
|
||||||
|
localPopulateTable(data);
|
||||||
|
} else {
|
||||||
|
let titleText = `Quality Defects Report for ${dateString} (${data.rows ? data.rows.length : 0} defective items)`;
|
||||||
|
|
||||||
|
// Add defects summary info if available
|
||||||
|
if (data.defects_summary) {
|
||||||
|
const summary = data.defects_summary;
|
||||||
|
titleText += ` | ${summary.unique_defect_types} defect types, ${summary.total_rejected_quantity} rejected items`;
|
||||||
|
}
|
||||||
|
|
||||||
|
reportTitleElement.textContent = titleText;
|
||||||
|
localPopulateTable(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error fetching quality defects report:', error);
|
||||||
|
reportTitleElement.textContent = 'Error loading quality defects report';
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== DATE RANGE MODAL FUNCTIONALITY =====
|
||||||
|
|
||||||
|
const dateRangeReportBtn = document.getElementById('date-range-report');
|
||||||
|
const dateRangeModal = document.getElementById('date-range-modal');
|
||||||
|
const closeDateRange = document.getElementById('close-date-range');
|
||||||
|
const cancelDateRange = document.getElementById('cancel-date-range');
|
||||||
|
const confirmDateRange = document.getElementById('confirm-date-range');
|
||||||
|
const startDateInput = document.getElementById('start-date');
|
||||||
|
const endDateInput = document.getElementById('end-date');
|
||||||
|
|
||||||
|
if (dateRangeReportBtn && dateRangeModal) {
|
||||||
|
// Open date range modal
|
||||||
|
dateRangeReportBtn.addEventListener('click', () => {
|
||||||
|
console.log('DEBUG: Date Range Report button clicked!');
|
||||||
|
|
||||||
|
// Set default dates (last 7 days to today)
|
||||||
|
const today = new Date();
|
||||||
|
const weekAgo = new Date();
|
||||||
|
weekAgo.setDate(today.getDate() - 6); // Last 7 days including today
|
||||||
|
|
||||||
|
const todayStr = formatDateForInput(today);
|
||||||
|
const weekAgoStr = formatDateForInput(weekAgo);
|
||||||
|
|
||||||
|
startDateInput.value = weekAgoStr;
|
||||||
|
endDateInput.value = todayStr;
|
||||||
|
|
||||||
|
console.log(`DEBUG: Default date range set to ${weekAgoStr} - ${todayStr}`);
|
||||||
|
|
||||||
|
dateRangeModal.style.display = 'block';
|
||||||
|
validateDateRange(); // Enable/disable confirm button based on inputs
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close modal functions
|
||||||
|
function closeDateRangeModal() {
|
||||||
|
dateRangeModal.style.display = 'none';
|
||||||
|
startDateInput.value = '';
|
||||||
|
endDateInput.value = '';
|
||||||
|
confirmDateRange.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDateRange.addEventListener('click', closeDateRangeModal);
|
||||||
|
cancelDateRange.addEventListener('click', closeDateRangeModal);
|
||||||
|
|
||||||
|
// Close modal when clicking outside
|
||||||
|
window.addEventListener('click', (e) => {
|
||||||
|
if (e.target === dateRangeModal) {
|
||||||
|
closeDateRangeModal();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validate date range and enable/disable confirm button
|
||||||
|
function validateDateRange() {
|
||||||
|
const startDate = startDateInput.value;
|
||||||
|
const endDate = endDateInput.value;
|
||||||
|
|
||||||
|
if (startDate && endDate) {
|
||||||
|
const start = new Date(startDate);
|
||||||
|
const end = new Date(endDate);
|
||||||
|
|
||||||
|
if (start <= end) {
|
||||||
|
confirmDateRange.disabled = false;
|
||||||
|
console.log(`DEBUG: Valid date range: ${startDate} to ${endDate}`);
|
||||||
|
} else {
|
||||||
|
confirmDateRange.disabled = true;
|
||||||
|
console.log('DEBUG: Invalid date range: start date is after end date');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
confirmDateRange.disabled = true;
|
||||||
|
console.log('DEBUG: Missing start or end date');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate when dates change
|
||||||
|
startDateInput.addEventListener('change', validateDateRange);
|
||||||
|
endDateInput.addEventListener('change', validateDateRange);
|
||||||
|
|
||||||
|
// Confirm date range selection
|
||||||
|
confirmDateRange.addEventListener('click', () => {
|
||||||
|
const startDate = startDateInput.value;
|
||||||
|
const endDate = endDateInput.value;
|
||||||
|
|
||||||
|
console.log(`DEBUG: Generating date range report from ${startDate} to ${endDate}`);
|
||||||
|
closeDateRangeModal();
|
||||||
|
|
||||||
|
// Fetch report data for the selected date range
|
||||||
|
fetchDateRangeReport(startDate, endDate);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to format date for input field
|
||||||
|
function formatDateForInput(date) {
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
return `${year}-${month}-${day}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to fetch date range report
|
||||||
|
function fetchDateRangeReport(startDate, endDate) {
|
||||||
|
console.log(`DEBUG: Fetching date range report from ${startDate} to ${endDate}`);
|
||||||
|
|
||||||
|
// Get elements directly to avoid scope issues
|
||||||
|
const reportTitleElement = document.getElementById('report-title');
|
||||||
|
const reportTableElement = document.getElementById('report-table');
|
||||||
|
|
||||||
|
if (!reportTitleElement) {
|
||||||
|
console.error('ERROR: report-title element not found!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reportTitleElement.textContent = `Loading report for ${startDate} to ${endDate}...`;
|
||||||
|
|
||||||
|
// Local function to populate table to avoid scope issues
|
||||||
|
function localPopulateTable(data) {
|
||||||
|
const tableHead = reportTableElement.querySelector('thead tr');
|
||||||
|
const tableBody = reportTableElement.querySelector('tbody');
|
||||||
|
|
||||||
|
// Clear existing table content
|
||||||
|
tableHead.innerHTML = '';
|
||||||
|
tableBody.innerHTML = '';
|
||||||
|
|
||||||
|
if (data.headers && data.rows && data.rows.length > 0) {
|
||||||
|
// Populate table headers
|
||||||
|
data.headers.forEach((header) => {
|
||||||
|
const th = document.createElement('th');
|
||||||
|
th.textContent = header;
|
||||||
|
tableHead.appendChild(th);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Populate table rows
|
||||||
|
data.rows.forEach((row) => {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
row.forEach((cell, index) => {
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.textContent = cell;
|
||||||
|
tr.appendChild(td);
|
||||||
|
});
|
||||||
|
tableBody.appendChild(tr);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Handle no data scenarios
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
const td = document.createElement('td');
|
||||||
|
td.colSpan = 10; // Span all columns
|
||||||
|
td.textContent = 'No data available for the selected date range.';
|
||||||
|
td.style.textAlign = 'center';
|
||||||
|
tr.appendChild(td);
|
||||||
|
tableBody.appendChild(tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = `/generate_report?report=7&start_date=${startDate}&end_date=${endDate}`;
|
||||||
|
console.log(`DEBUG: Making date range request to URL: ${url}`);
|
||||||
|
|
||||||
|
fetch(url)
|
||||||
|
.then(response => {
|
||||||
|
console.log(`DEBUG: Response status: ${response.status}`);
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
console.log('DEBUG: Date range response data:', data);
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
reportTitleElement.textContent = `Error: ${data.error}`;
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
} else if (data.message) {
|
||||||
|
reportTitleElement.textContent = data.message;
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
|
} else if (data.rows && data.rows.length === 0) {
|
||||||
|
reportTitleElement.textContent = `No data found for ${startDate} to ${endDate}`;
|
||||||
|
localPopulateTable(data);
|
||||||
|
} else {
|
||||||
|
const recordCount = data.rows ? data.rows.length : 0;
|
||||||
|
let titleText = `Date Range Report: ${startDate} to ${endDate} (${recordCount} records)`;
|
||||||
|
|
||||||
|
// Add summary info if available
|
||||||
|
if (data.summary) {
|
||||||
|
titleText += ` | Approved: ${data.summary.total_approved}, Rejected: ${data.summary.total_rejected}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
reportTitleElement.textContent = titleText;
|
||||||
|
localPopulateTable(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error fetching date range report:', error);
|
||||||
|
reportTitleElement.textContent = 'Error loading date range report';
|
||||||
|
localPopulateTable({ headers: [], rows: [] });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -748,6 +748,16 @@ body.dark-mode .export-description {
|
|||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.test-db-btn {
|
||||||
|
background-color: #6c757d !important; /* Gray color for test button */
|
||||||
|
border-color: #6c757d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.test-db-btn:hover {
|
||||||
|
background-color: #5a6268 !important;
|
||||||
|
border-color: #545b62 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.report-form-card .export-section .form-centered.last-buttons {
|
.report-form-card .export-section .form-centered.last-buttons {
|
||||||
padding: 5px 0; /* Reduced padding for export section */
|
padding: 5px 0; /* Reduced padding for export section */
|
||||||
}
|
}
|
||||||
@@ -829,13 +839,14 @@ body.dark-mode .export-description {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
background-color: #fefefe;
|
background-color: #ffffff;
|
||||||
margin: 5% auto;
|
margin: 5% auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 90%;
|
max-width: 90%;
|
||||||
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
|
||||||
|
border: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-header {
|
.modal-header {
|
||||||
@@ -843,7 +854,7 @@ body.dark-mode .export-description {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
background-color: #f8f9fa;
|
background-color: #f4f4f9;
|
||||||
border-radius: 8px 8px 0 0;
|
border-radius: 8px 8px 0 0;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
@@ -851,6 +862,7 @@ body.dark-mode .export-description {
|
|||||||
.modal-header h4 {
|
.modal-header h4 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-modal {
|
.close-modal {
|
||||||
@@ -859,6 +871,7 @@ body.dark-mode .export-description {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
transition: color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.close-modal:hover {
|
.close-modal:hover {
|
||||||
@@ -867,6 +880,7 @@ body.dark-mode .export-description {
|
|||||||
|
|
||||||
.modal-body {
|
.modal-body {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
background-color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-footer {
|
.modal-footer {
|
||||||
@@ -876,7 +890,152 @@ body.dark-mode .export-description {
|
|||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
border-top: 1px solid #ddd;
|
border-top: 1px solid #ddd;
|
||||||
border-radius: 0 0 8px 8px;
|
border-radius: 0 0 8px 8px;
|
||||||
background-color: #f8f9fa;
|
background-color: #f4f4f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark Mode Support for Calendar Modal */
|
||||||
|
body.dark-mode .modal-content {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
border: 1px solid #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-header {
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
border-bottom: 1px solid #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-header h4 {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .close-modal {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .close-modal:hover {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-body {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-footer {
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
border-top: 1px solid #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal Button Styling */
|
||||||
|
.modal-footer .btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-primary {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-primary:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-primary:disabled {
|
||||||
|
background-color: #6c757d;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-secondary {
|
||||||
|
background-color: #6c757d;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer .btn-secondary:hover {
|
||||||
|
background-color: #545b62;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark Mode Modal Buttons */
|
||||||
|
body.dark-mode .modal-footer .btn-primary {
|
||||||
|
background-color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-footer .btn-primary:hover {
|
||||||
|
background-color: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-footer .btn-secondary {
|
||||||
|
background-color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .modal-footer .btn-secondary:hover {
|
||||||
|
background-color: #545b62;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Date Range Modal Styles */
|
||||||
|
.date-range-container {
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-input-group {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-input-group label {
|
||||||
|
display: block;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #333;
|
||||||
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 15px;
|
||||||
|
border: 2px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1em;
|
||||||
|
background-color: #fff;
|
||||||
|
transition: border-color 0.3s ease;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #007bff;
|
||||||
|
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-help {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 5px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode styles for date range modal */
|
||||||
|
body.dark-mode .date-input-group label {
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .date-input {
|
||||||
|
background-color: #2d3748;
|
||||||
|
border-color: #4a5568;
|
||||||
|
color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .date-input:focus {
|
||||||
|
border-color: #63b3ed;
|
||||||
|
box-shadow: 0 0 0 3px rgba(99, 179, 237, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .date-help {
|
||||||
|
color: #a0aec0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calendar Styles */
|
/* Calendar Styles */
|
||||||
@@ -898,18 +1057,20 @@ body.dark-mode .export-description {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.calendar-nav {
|
.calendar-nav {
|
||||||
background: none;
|
background-color: #f4f4f9;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 5px 10px;
|
padding: 8px 12px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #333;
|
||||||
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-nav:hover {
|
.calendar-nav:hover {
|
||||||
background-color: #f0f0f0;
|
background-color: #007bff;
|
||||||
color: #333;
|
color: white;
|
||||||
|
border-color: #007bff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-grid {
|
.calendar-grid {
|
||||||
@@ -929,7 +1090,8 @@ body.dark-mode .export-description {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
color: #666;
|
color: #666;
|
||||||
background-color: #f8f9fa;
|
background-color: #f4f4f9;
|
||||||
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-days {
|
.calendar-days {
|
||||||
@@ -948,30 +1110,83 @@ body.dark-mode .export-description {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day:hover {
|
.calendar-day:hover {
|
||||||
background-color: #e9ecef;
|
background-color: #e9ecef;
|
||||||
|
border-color: #007bff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day.other-month {
|
.calendar-day.other-month {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
|
background-color: #f8f9fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day.today {
|
.calendar-day.today {
|
||||||
background-color: #007bff;
|
background-color: #007bff;
|
||||||
color: white;
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day.selected {
|
.calendar-day.selected {
|
||||||
background-color: #28a745;
|
background-color: #28a745;
|
||||||
color: white;
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-day.selected:hover {
|
.calendar-day.selected:hover {
|
||||||
background-color: #218838;
|
background-color: #218838;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark Mode Calendar Styles */
|
||||||
|
body.dark-mode .calendar-header h3 {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-nav {
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
border-color: #555;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-nav:hover {
|
||||||
|
background-color: #007bff;
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-weekdays div {
|
||||||
|
background-color: #3c3c3c;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-day {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-day:hover {
|
||||||
|
background-color: #444;
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-day.other-month {
|
||||||
|
color: #666;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-day.today {
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode .calendar-day.selected {
|
||||||
|
background-color: #28a745;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* Responsive Calendar */
|
/* Responsive Calendar */
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.modal-content {
|
.modal-content {
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
<label class="report-description">Select day for daily report will export all orders scanned at quality scanning points</label>
|
<label class="report-description">Select day for daily report will export all orders scanned at quality scanning points</label>
|
||||||
<button class="btn report-btn" id="select-day-report">Select Day Daily Report</button>
|
<button class="btn report-btn" id="select-day-report">Select Day Daily Report</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-centered">
|
||||||
|
<label class="report-description">Select date range for custom report - from start date 00:00 to end date 23:59</label>
|
||||||
|
<button class="btn report-btn" id="date-range-report">Date Range Report</button>
|
||||||
|
</div>
|
||||||
<div class="form-centered">
|
<div class="form-centered">
|
||||||
<label class="report-description">5-day report will export all orders scanned at quality scanning points</label>
|
<label class="report-description">5-day report will export all orders scanned at quality scanning points</label>
|
||||||
<button class="btn report-btn" data-report="2">5-Day Complete Orders Report</button>
|
<button class="btn report-btn" data-report="2">5-Day Complete Orders Report</button>
|
||||||
@@ -24,6 +28,10 @@
|
|||||||
<label class="report-description">Report on items with quality issues for the current day</label>
|
<label class="report-description">Report on items with quality issues for the current day</label>
|
||||||
<button class="btn report-btn" data-report="3">Report on Items with Defects for the Current Day</button>
|
<button class="btn report-btn" data-report="3">Report on Items with Defects for the Current Day</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-centered">
|
||||||
|
<label class="report-description">Select specific day for quality defects report - items with quality issues</label>
|
||||||
|
<button class="btn report-btn" id="select-day-defects-report">Select Day Quality Defects Report</button>
|
||||||
|
</div>
|
||||||
<div class="form-centered">
|
<div class="form-centered">
|
||||||
<label class="report-description">Report on items with quality issues for the last 5 days</label>
|
<label class="report-description">Report on items with quality issues for the last 5 days</label>
|
||||||
<button class="btn report-btn" data-report="4">Report on Items with Defects for the Last 5 Days</button>
|
<button class="btn report-btn" data-report="4">Report on Items with Defects for the Last 5 Days</button>
|
||||||
@@ -44,6 +52,7 @@
|
|||||||
<div class="button-row">
|
<div class="button-row">
|
||||||
<button class="btn export-btn" id="export-csv">Export CSV</button>
|
<button class="btn export-btn" id="export-csv">Export CSV</button>
|
||||||
<!-- <button class="btn export-btn" id="export-excel">Export excell</button> -->
|
<!-- <button class="btn export-btn" id="export-excel">Export excell</button> -->
|
||||||
|
<button class="btn export-btn test-db-btn" id="test-database">Test Database</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -104,5 +113,33 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Date Range Popup Modal -->
|
||||||
|
<div id="date-range-modal" class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4>Select Date Range for Report</h4>
|
||||||
|
<span class="close-modal" id="close-date-range">×</span>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="date-range-container">
|
||||||
|
<div class="date-input-group">
|
||||||
|
<label for="start-date">Start Date:</label>
|
||||||
|
<input type="date" id="start-date" class="date-input" />
|
||||||
|
<small class="date-help">Report will include data from 00:00:00</small>
|
||||||
|
</div>
|
||||||
|
<div class="date-input-group">
|
||||||
|
<label for="end-date">End Date:</label>
|
||||||
|
<input type="date" id="end-date" class="date-input" />
|
||||||
|
<small class="date-help">Report will include data until 23:59:59</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-secondary" id="cancel-date-range">Cancel</button>
|
||||||
|
<button class="btn btn-primary" id="confirm-date-range" disabled>Generate Report</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user