import matplotlib matplotlib.use("Agg") from flask import Blueprint, render_template, session, redirect, url_for, jsonify, request import matplotlib.pyplot as plt import io import base64 from app.utils.plot_utils import plot_to_base64 from app.services.dashboard_service import DashboardService from sqlalchemy import func from app import db from app.models.trench_excavation_model import TrenchExcavation from app.models.manhole_excavation_model import ManholeExcavation from app.models.laying_model import Laying from app.models.subcontractor_model import Subcontractor dashboard_bp = Blueprint("dashboard", __name__, url_prefix="/dashboard") @dashboard_bp.route("/") def dashboard(): if not session.get("user_id"): return redirect(url_for("auth.login")) return render_template("dashboard.html", title="Business Intelligence Dashboard") @dashboard_bp.route("/api/live-stats") def live_stats(): try: # 1. Overall Volume t_count = TrenchExcavation.query.count() m_count = ManholeExcavation.query.count() l_count = Laying.query.count() # 2. Location Distribution (Business reach) loc_results = db.session.query( TrenchExcavation.Location, func.count(TrenchExcavation.id) ).group_by(TrenchExcavation.Location).all() # 3. Work Timeline (Business productivity trend) # Assuming your models have a 'created_at' field timeline_results = db.session.query( func.date(TrenchExcavation.created_at), func.count(TrenchExcavation.id) ).group_by(func.date(TrenchExcavation.created_at)).order_by(func.date(TrenchExcavation.created_at)).all() return jsonify({ "summary": { "trench": t_count, "manhole": m_count, "laying": l_count, "total": t_count + m_count + l_count }, "locations": {row[0]: row[1] for row in loc_results if row[0]}, "timeline": {str(row[0]): row[1] for row in timeline_results} }) except Exception as e: return jsonify({"error": str(e)}), 500 # subcontractor dashboard @dashboard_bp.route("/subcontractor_dashboard") def subcontractor_dashboard(): if not session.get("user_id"): return redirect(url_for("auth.login")) subcontractors = Subcontractor.query.all() return render_template( "subcontractor_dashboard.html", subcontractors=subcontractors ) # ✅ API: Get Unique RA Bills @dashboard_bp.route("/api/get-ra-bills") def get_ra_bills(): subcontractor_id = request.args.get("subcontractor") category = request.args.get("category") if not subcontractor_id or not category: return {"ra_bills": []} match category: case "trench_excavation": results = db.session.query( TrenchExcavation.RA_Bill_No ).filter( TrenchExcavation.subcontractor_id == subcontractor_id ).distinct().order_by(TrenchExcavation.RA_Bill_No).all() # (Add others same pattern later) case _: results = [] ra_bills = [r[0] for r in results if r[0]] return {"ra_bills": ra_bills} # API FOR CHART DATA # @dashboard_bp.route("/api/subcontractor-chart") # def subcontractor_chart(): # subcontractor_id = request.args.get("subcontractor") # category = request.args.get("category") # ra_bill = request.args.get("ra_bill") # labels = [] # values = [] # match category: # # ✅ Trench # case "trench_excavation": # query = db.session.query( # TrenchExcavation.excavation_category, # func.sum(TrenchExcavation.Total) # ) # if subcontractor_id: # query = query.filter(TrenchExcavation.subcontractor_id == subcontractor_id) # if ra_bill: # query = query.filter(TrenchExcavation.RA_Bill_No == ra_bill) # results = query.group_by(TrenchExcavation.excavation_category).all() # # ✅ Manhole # case "manhole_excavation": # query = db.session.query( # ManholeExcavation.excavation_category, # func.sum(ManholeExcavation.Total) # ) # if subcontractor_id: # query = query.filter(ManholeExcavation.subcontractor_id == subcontractor_id) # if ra_bill: # query = query.filter(ManholeExcavation.RA_Bill_No == ra_bill) # results = query.group_by(ManholeExcavation.excavation_category).all() # case _: # results = [] # for r in results: # labels.append(r[0]) # values.append(float(r[1] or 0)) # return jsonify({ # "labels": labels, # "values": values # }) @dashboard_bp.route("/api/trench-analysis") def trench_analysis(): subcontractor_id = request.args.get("subcontractor") ra_bill = request.args.get("ra_bill") query = TrenchExcavation.query if subcontractor_id: query = query.filter(TrenchExcavation.subcontractor_id == subcontractor_id) if ra_bill: query = query.filter(TrenchExcavation.RA_Bill_No == ra_bill) data = query.all() result = { "Soft Murum": {"depth": 0, "qty": 0}, "Hard Murum": {"depth": 0, "qty": 0}, "Soft Rock": {"depth": 0, "qty": 0}, "Hard Rock": {"depth": 0, "qty": 0}, } for r in data: # Soft Murum result["Soft Murum"]["depth"] += ( (r.Soft_Murum_0_to_1_5 or 0) + (r.Soft_Murum_1_5_to_3_0 or 0) + (r.Soft_Murum_3_0_to_4_5 or 0) ) result["Soft Murum"]["qty"] += ( (r.Soft_Murum_0_to_1_5_total or 0) + (r.Soft_Murum_1_5_to_3_0_total or 0) + (r.Soft_Murum_3_0_to_4_5_total or 0) ) # Hard Murum result["Hard Murum"]["depth"] += ( (r.Hard_Murum_0_to_1_5 or 0) + (r.Hard_Murum_1_5_to_3_0 or 0) ) result["Hard Murum"]["qty"] += ( (r.Hard_Murum_0_to_1_5_total or 0) + (r.Hard_Murum_1_5_and_above_total or 0) ) # Soft Rock result["Soft Rock"]["depth"] += ( (r.Soft_Rock_0_to_1_5 or 0) + (r.Soft_Rock_1_5_to_3_0 or 0) ) result["Soft Rock"]["qty"] += ( (r.Soft_Rock_0_to_1_5_total or 0) + (r.Soft_Rock_1_5_and_above_total or 0) ) # Hard Rock result["Hard Rock"]["depth"] += ( (r.Hard_Rock_0_to_1_5 or 0) + (r.Hard_Rock_1_5_to_3_0 or 0) + (r.Hard_Rock_3_0_to_4_5 or 0) + (r.Hard_Rock_4_5_to_6_0 or 0) + (r.Hard_Rock_6_0_to_7_5 or 0) ) result["Hard Rock"]["qty"] += ( (r.Hard_Rock_0_to_1_5_total or 0) + (r.Hard_Rock_1_5_to_3_0_total or 0) + (r.Hard_Rock_3_0_to_4_5_total or 0) + (r.Hard_Rock_4_5_to_6_0_total or 0) + (r.Hard_Rock_6_0_to_7_5_total or 0) ) labels = list(result.keys()) depth = [result[k]["depth"] for k in labels] qty = [result[k]["qty"] for k in labels] return jsonify({ "labels": labels, "depth": depth, "qty": qty })