Files
Comparison_Project/app/routes/generate_comparison_report.py

225 lines
6.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import Blueprint, render_template, request, send_file, flash
import pandas as pd
import io
import re
from app.models.subcontractor_model import Subcontractor
from app.models.trench_excavation_model import TrenchExcavation
from app.models.tr_ex_client_model import TrenchExcavationClient
from app.models.manhole_excavation_model import ManholeExcavation
from app.models.mh_ex_client_model import ManholeExcavationClient
from app.models.manhole_domestic_chamber_model import ManholeDomesticChamber
from app.models.mh_dc_client_model import ManholeDomesticChamberClient
generate_report_bp = Blueprint("generate_report", __name__, url_prefix="/report")
# HEADER FORMATTER
def format_header(header):
# Handle Client- / Subcontractor-
if "-" in header:
prefix, rest = header.split("-", 1)
prefix = prefix.title()
else:
prefix, rest = None, header
parts = rest.split("_")
result = []
i = 0
while i < len(parts):
# Detect num_num → num.num
if i + 1 < len(parts) and parts[i].isdigit() and parts[i + 1].isdigit():
result.append(f"{parts[i]}.{parts[i + 1]}")
i += 2
else:
result.append(parts[i].title())
i += 1
final_text = " ".join(result)
return f"{prefix}-{final_text}" if prefix else final_text
# LOOKUP CREATOR
def make_lookup(rows, key_field):
return {
(r.get("Location"), r.get(key_field)): r
for r in rows
if r.get("Location") and r.get(key_field)
}
# GENERIC COMPARISON BUILDER
def build_comparison(client_rows, contractor_rows, key_field):
contractor_lookup = make_lookup(contractor_rows, key_field)
output = []
for c in client_rows:
s = contractor_lookup.get((c.get("Location"), c.get(key_field)))
if not s:
continue
client_total = sum(v or 0 for k, v in c.items() if k.endswith("_total"))
sub_total = sum(v or 0 for k, v in s.items() if k.endswith("_total"))
diff = client_total - sub_total
row = {
"Location": c.get("Location"),
key_field.replace("_", " "): c.get(key_field)
}
# CLIENT DATA
for k, v in c.items():
if k in ["id", "created_at"]:
continue
row[f"Client-{k}"] = v
row["Client-Total"] = round(client_total, 2)
row[" "] = ""
# SUBCONTRACTOR DATA
for k, v in s.items():
if k in ["id", "created_at", "subcontractor_id"]:
continue
row[f"Subcontractor-{k}"] = v
row["Subcontractor-Total"] = round(sub_total, 2)
row["Diff"] = round(diff, 2)
output.append(row)
df = pd.DataFrame(output)
df.columns = [format_header(col) for col in df.columns]
return df
# EXCEL SHEET WRITER (SEPARATED)
def write_sheet(writer, df, sheet_name, subcontractor_name):
workbook = writer.book
df.to_excel(writer, sheet_name=sheet_name, index=False, startrow=3)
ws = writer.sheets[sheet_name]
title_fmt = workbook.add_format({
"bold": True,
"font_size": 14
})
client_fmt = workbook.add_format({
"bold": True,
"border": 1,
"bg_color": "#D9EDF7"
})
sub_fmt = workbook.add_format({
"bold": True,
"border": 1,
"bg_color": "#F7E1D9"
})
total_fmt = workbook.add_format({
"bold": True,
"border": 1,
"bg_color": "#FFF2CC"
})
diff_fmt = workbook.add_format({
"bold": True,
"border": 1,
"bg_color": "#E2EFDA"
})
# MAIN HEADING
ws.merge_range(
0, 0, 0, len(df.columns) - 1,
f"CLIENT vs SUBCONTRACTOR {subcontractor_name}",
title_fmt
)
# COLUMN HEADERS
for col_num, col_name in enumerate(df.columns):
if col_name.startswith("Client-"):
ws.write(3, col_num, col_name, client_fmt)
elif col_name.startswith("Subcontractor-"):
ws.write(3, col_num, col_name, sub_fmt)
elif col_name.endswith("Total"):
ws.write(3, col_num, col_name, total_fmt)
elif col_name == "Diff":
ws.write(3, col_num, col_name, diff_fmt)
else:
ws.write(3, col_num, col_name)
ws.set_column(col_num, col_num, 20)
# old report generate ROUTE
@generate_report_bp.route("/comparison_report", methods=["GET", "POST"])
def comparison_report():
subcontractors = Subcontractor.query.all()
if request.method == "POST":
subcontractor_id = request.form.get("subcontractor_id")
if not subcontractor_id:
flash("Please select subcontractor", "danger")
return render_template(
"generate_comparison_report.html",
subcontractors=subcontractors
)
subcontractor = Subcontractor.query.get_or_404(subcontractor_id)
# ===================== DATA =====================
tr_client = [r.serialize() for r in TrenchExcavationClient.query.all()]
tr_sub = [r.serialize() for r in TrenchExcavation.query.filter_by(
subcontractor_id=subcontractor_id
).all()]
df_tr = build_comparison(tr_client, tr_sub, "MH_NO")
print("-- tr clint --:",tr_client )
print("-- tr sub --:",tr_sub )
mh_client = [r.serialize() for r in ManholeExcavationClient.query.all()]
mh_sub = [r.serialize() for r in ManholeExcavation.query.filter_by(
subcontractor_id=subcontractor_id
).all()]
df_mh = build_comparison(mh_client, mh_sub, "MH_NO")
# print("-- mh clint --:",mh_client)
# print("-- mh sub --:",mh_sub )
dc_client = [r.serialize() for r in ManholeDomesticChamberClient.query.all()]
dc_sub = [r.serialize() for r in ManholeDomesticChamber.query.filter_by(
subcontractor_id=subcontractor_id
).all()]
df_dc = build_comparison(dc_client, dc_sub, "MH_NO")
# print("-- mh dc clint --:",dc_client )
# print("-- mh dc sub --:", dc_sub)
# ===================== EXCEL =====================
output = io.BytesIO()
filename = f"{subcontractor.subcontractor_name}_Comparison_Report.xlsx"
with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
write_sheet(writer, df_tr, "Tr.Ex", subcontractor.subcontractor_name)
write_sheet(writer, df_mh, "Mh.Ex", subcontractor.subcontractor_name)
write_sheet(writer, df_dc, "MH & DC", subcontractor.subcontractor_name)
output.seek(0)
return send_file(
output,
as_attachment=True,
download_name=filename,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
return render_template(
"generate_comparison_report.html",
subcontractors=subcontractors
)