Add Daily Mirror interactive dashboard with charts and pivot tables
- Created comprehensive dashboard with Chart.js visualizations - Added API endpoint /api/dashboard_data for aggregated data - Implemented weekly tracking for orders, production, and deliveries - Added interactive pivot table for customer × week analysis - Fixed collation issues in database joins - Includes 4 summary cards with key metrics - Charts display orders, production finished, and deliveries by week - Click-to-expand data tables for detailed view - Time range filter (4-52 weeks) - Data sources: scanfg_orders (finished), dm_orders, dm_deliveries
This commit is contained in:
@@ -568,6 +568,175 @@ def api_daily_mirror_history_data():
|
|||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
|
@daily_mirror_bp.route('/api/dashboard_data', methods=['GET'])
|
||||||
|
def api_dashboard_data():
|
||||||
|
"""API endpoint to get aggregated dashboard data for pivot table view"""
|
||||||
|
access_check = check_daily_mirror_api_access()
|
||||||
|
if access_check:
|
||||||
|
return access_check
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"DEBUG: dashboard_data API called")
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
# Get date range parameters
|
||||||
|
weeks_back = int(request.args.get('weeks_back', 12))
|
||||||
|
end_date = datetime.now()
|
||||||
|
start_date = end_date - timedelta(weeks=weeks_back)
|
||||||
|
|
||||||
|
dm_db = DailyMirrorDatabase()
|
||||||
|
if not dm_db.connect():
|
||||||
|
return jsonify({'error': 'Database connection failed'}), 500
|
||||||
|
|
||||||
|
cursor = dm_db.connection.cursor()
|
||||||
|
|
||||||
|
# 1. Get finished orders from scanfg_orders (production finished)
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
DATE_FORMAT(date, '%%Y%%u') as week_number,
|
||||||
|
DATE_FORMAT(date, '%%Y-W%%u') as week_display,
|
||||||
|
COUNT(*) as finished_count,
|
||||||
|
SUM(approved_quantity) as approved_qty,
|
||||||
|
SUM(rejected_quantity) as rejected_qty
|
||||||
|
FROM scanfg_orders
|
||||||
|
WHERE date >= %s AND date <= %s
|
||||||
|
GROUP BY week_number, week_display
|
||||||
|
ORDER BY week_number
|
||||||
|
""", (start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')))
|
||||||
|
finished_orders_raw = cursor.fetchall()
|
||||||
|
finished_orders = [
|
||||||
|
{
|
||||||
|
'week_number': row[0],
|
||||||
|
'week_display': row[1],
|
||||||
|
'finished_count': row[2],
|
||||||
|
'approved_qty': row[3],
|
||||||
|
'rejected_qty': row[4]
|
||||||
|
}
|
||||||
|
for row in finished_orders_raw
|
||||||
|
]
|
||||||
|
|
||||||
|
# 2. Get customer orders from dm_orders by customer and week
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
c.customer_name,
|
||||||
|
DATE_FORMAT(o.order_date, '%%Y%%u') as week_number,
|
||||||
|
DATE_FORMAT(o.order_date, '%%Y-W%%u') as week_display,
|
||||||
|
COUNT(*) as order_count,
|
||||||
|
SUM(o.quantity_requested) as total_quantity,
|
||||||
|
SUM(CASE WHEN o.order_status = 'OPEN' THEN o.quantity_requested ELSE 0 END) as open_quantity,
|
||||||
|
SUM(CASE WHEN o.order_status = 'COMPLETED' THEN o.quantity_requested ELSE 0 END) as completed_quantity
|
||||||
|
FROM dm_orders o
|
||||||
|
LEFT JOIN dm_customers c ON o.customer_code COLLATE utf8mb4_unicode_ci = c.customer_code COLLATE utf8mb4_unicode_ci
|
||||||
|
WHERE o.order_date >= %s AND o.order_date <= %s
|
||||||
|
GROUP BY c.customer_name, week_number, week_display
|
||||||
|
ORDER BY c.customer_name, week_number
|
||||||
|
""", (start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')))
|
||||||
|
customer_orders_raw = cursor.fetchall()
|
||||||
|
customer_orders = [
|
||||||
|
{
|
||||||
|
'customer_name': row[0],
|
||||||
|
'week_number': row[1],
|
||||||
|
'week_display': row[2],
|
||||||
|
'order_count': row[3],
|
||||||
|
'total_quantity': row[4],
|
||||||
|
'open_quantity': row[5],
|
||||||
|
'completed_quantity': row[6]
|
||||||
|
}
|
||||||
|
for row in customer_orders_raw
|
||||||
|
]
|
||||||
|
|
||||||
|
# 3. Get deliveries from dm_deliveries by customer and week
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
c.customer_name,
|
||||||
|
DATE_FORMAT(d.delivery_date, '%%Y%%u') as week_number,
|
||||||
|
DATE_FORMAT(d.delivery_date, '%%Y-W%%u') as week_display,
|
||||||
|
COUNT(*) as delivery_count,
|
||||||
|
SUM(d.quantity_delivered) as total_delivered
|
||||||
|
FROM dm_deliveries d
|
||||||
|
LEFT JOIN dm_customers c ON d.customer_code COLLATE utf8mb4_unicode_ci = c.customer_code COLLATE utf8mb4_unicode_ci
|
||||||
|
WHERE d.delivery_date >= %s AND d.delivery_date <= %s
|
||||||
|
GROUP BY c.customer_name, week_number, week_display
|
||||||
|
ORDER BY c.customer_name, week_number
|
||||||
|
""", (start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')))
|
||||||
|
deliveries_raw = cursor.fetchall()
|
||||||
|
deliveries = [
|
||||||
|
{
|
||||||
|
'customer_name': row[0],
|
||||||
|
'week_number': row[1],
|
||||||
|
'week_display': row[2],
|
||||||
|
'delivery_count': row[3],
|
||||||
|
'total_delivered': row[4]
|
||||||
|
}
|
||||||
|
for row in deliveries_raw
|
||||||
|
]
|
||||||
|
|
||||||
|
# 4. Get summary metrics
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_orders,
|
||||||
|
SUM(quantity_requested) as total_quantity,
|
||||||
|
COUNT(DISTINCT customer_code) as unique_customers
|
||||||
|
FROM dm_orders
|
||||||
|
WHERE order_date >= %s AND order_date <= %s
|
||||||
|
""", (start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')))
|
||||||
|
order_summary_row = cursor.fetchone()
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_finished,
|
||||||
|
SUM(approved_quantity) as total_approved,
|
||||||
|
SUM(rejected_quantity) as total_rejected
|
||||||
|
FROM scanfg_orders
|
||||||
|
WHERE date >= %s AND date <= %s
|
||||||
|
""", (start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')))
|
||||||
|
production_summary_row = cursor.fetchone()
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_deliveries,
|
||||||
|
SUM(quantity_delivered) as total_delivered
|
||||||
|
FROM dm_deliveries
|
||||||
|
WHERE delivery_date >= %s AND delivery_date <= %s
|
||||||
|
""", (start_date.strftime('%Y-%m-%d'), end_date.strftime('%Y-%m-%d')))
|
||||||
|
delivery_summary_row = cursor.fetchone()
|
||||||
|
|
||||||
|
dm_db.disconnect()
|
||||||
|
|
||||||
|
print(f"DEBUG: Data aggregation successful. Orders: {len(customer_orders)}, Production: {len(finished_orders)}, Deliveries: {len(deliveries)}")
|
||||||
|
|
||||||
|
# Build response
|
||||||
|
response_data = {
|
||||||
|
'date_range': {
|
||||||
|
'start': start_date.strftime('%Y-%m-%d'),
|
||||||
|
'end': end_date.strftime('%Y-%m-%d'),
|
||||||
|
'weeks_back': weeks_back
|
||||||
|
},
|
||||||
|
'summary': {
|
||||||
|
'total_orders': order_summary_row[0] or 0,
|
||||||
|
'total_quantity': int(order_summary_row[1] or 0),
|
||||||
|
'unique_customers': order_summary_row[2] or 0,
|
||||||
|
'total_finished': production_summary_row[0] or 0,
|
||||||
|
'total_approved': int(production_summary_row[1] or 0),
|
||||||
|
'total_rejected': int(production_summary_row[2] or 0),
|
||||||
|
'total_deliveries': delivery_summary_row[0] or 0,
|
||||||
|
'total_delivered': int(delivery_summary_row[1] or 0)
|
||||||
|
},
|
||||||
|
'finished_orders_by_week': finished_orders,
|
||||||
|
'customer_orders_by_week': customer_orders,
|
||||||
|
'deliveries_by_week': deliveries
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"DEBUG: Returning response data successfully")
|
||||||
|
return jsonify(response_data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR getting dashboard data: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
|
|
||||||
# =============================================
|
# =============================================
|
||||||
# TUNE DATABASE ROUTES
|
# TUNE DATABASE ROUTES
|
||||||
# =============================================
|
# =============================================
|
||||||
@@ -1174,4 +1343,4 @@ def clear_delivery():
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error clearing delivery records: {e}")
|
print(f"Error clearing delivery records: {e}")
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user