diff --git a/app/models/__pycache__/manhole_domestic_chamber_model.cpython-313.pyc b/app/models/__pycache__/manhole_domestic_chamber_model.cpython-313.pyc index 0482c1c..81afb3c 100644 Binary files a/app/models/__pycache__/manhole_domestic_chamber_model.cpython-313.pyc and b/app/models/__pycache__/manhole_domestic_chamber_model.cpython-313.pyc differ diff --git a/app/models/__pycache__/manhole_excavation_model.cpython-313.pyc b/app/models/__pycache__/manhole_excavation_model.cpython-313.pyc index b222504..fcfaf27 100644 Binary files a/app/models/__pycache__/manhole_excavation_model.cpython-313.pyc and b/app/models/__pycache__/manhole_excavation_model.cpython-313.pyc differ diff --git a/app/models/__pycache__/mh_dc_client_model.cpython-313.pyc b/app/models/__pycache__/mh_dc_client_model.cpython-313.pyc new file mode 100644 index 0000000..2c41e37 Binary files /dev/null and b/app/models/__pycache__/mh_dc_client_model.cpython-313.pyc differ diff --git a/app/models/__pycache__/mh_ex_client_model.cpython-313.pyc b/app/models/__pycache__/mh_ex_client_model.cpython-313.pyc index 960c1b8..1ea928a 100644 Binary files a/app/models/__pycache__/mh_ex_client_model.cpython-313.pyc and b/app/models/__pycache__/mh_ex_client_model.cpython-313.pyc differ diff --git a/app/models/mh_dc_client_model.py b/app/models/mh_dc_client_model.py index c9aa264..7ad73d1 100644 --- a/app/models/mh_dc_client_model.py +++ b/app/models/mh_dc_client_model.py @@ -13,29 +13,25 @@ class ManholeDomesticChamberClient(db.Model): # Basic Fields Location = db.Column(db.String(255)) Node_No = db.Column(db.String(100)) + MH_TOP_LEVEL = db.Column(db.Float) + MH_IL_LEVEL = db.Column(db.Float) Depth_of_MH = db.Column(db.Float) + # Excavation categories - d_0_to_0_75 = db.Column(db.Float) - d_1_06_to_1_65 = db.Column(db.Float) - d_1_06_to_1_65 = db.Column(db.Float) - d_1_66_to_2_15 = db.Column(db.Float) - d_2_16_to_2_65 = db.Column(db.Float) - d_2_66_to_3_15 = db.Column(db.Float) - d_3_16_to_3_65= db.Column(db.Float) - d_3_66_to_4_15 = db.Column(db.Float) - d_4_16_to_4_65 = db.Column(db.Float) - d_4_66_to_5_15 = db.Column(db.Float) - d_5_16_to_5_65 = db.Column(db.Float) + d_0_to_1_5 = db.Column(db.Float) + d_1_5_to_2_0 = db.Column(db.Float) + d_2_0_to_2_5 = db.Column(db.Float) + d_2_5_to_3_0 = db.Column(db.Float) - d_5_66_to_6_15 = db.Column(db.Float) - d_6_16_to_6_65 = db.Column(db.Float) - d_6_66_to_7_15 = db.Column(db.Float) - d_7_16_to_7_65 = db.Column(db.Float) - d_7_66_to_8_15 = db.Column(db.Float) - d_8_16_to_8_65 = db.Column(db.Float) - d_8_66_to_9_15 = db.Column(db.Float) - d_9_16_to_9_65 = db.Column(db.Float) + d_3_0_to_3_5 = db.Column(db.Float) + d_3_5_to_4_0 = db.Column(db.Float) + d_4_0_to_4_5= db.Column(db.Float) + d_4_5_to_5_0 = db.Column(db.Float) + + d_5_0_to_5_5 = db.Column(db.Float) + d_5_5_to_6_0 = db.Column(db.Float) + d_6_0_to_6_5 = db.Column(db.Float) Domestic_Chambers = db.Column(db.Float) diff --git a/app/models/mh_ex_client_model.py b/app/models/mh_ex_client_model.py index ce67abd..84d3fd6 100644 --- a/app/models/mh_ex_client_model.py +++ b/app/models/mh_ex_client_model.py @@ -14,25 +14,32 @@ class ManholeExcavationClient(db.Model): Location = db.Column(db.String(255)) MH_NO = db.Column(db.String(100)) GL_m = db.Column(db.Float) - - - - Upto_IL_Depth = db.Column(db.Float) + MH_Invert_Level = db.Column(db.Float) + MH_Top_Level = db.Column(db.Float) + Ex_Level = db.Column(db.Float) Cutting_Depth = db.Column(db.Float) + MH_Depth = db.Column(db.Float) ID_of_MH_m = db.Column(db.Float) - Ex_Dia_of_Manhole = db.Column(db.Float) + + Dia_of_MH_Cutting = db.Column(db.Float) Area_of_Manhole = db.Column(db.Float) # Excavation categories + Marshi_Muddy_Slushy_0_to_1_5 = db.Column(db.Float) + Marshi_Muddy_Slushy_1_5_to_3_0 = db.Column(db.Float) + Marshi_Muddy_Slushy_3_0_to_4_5 = db.Column(db.Float) + Soft_Murum_0_to_1_5 = db.Column(db.Float) Soft_Murum_1_5_to_3_0 = db.Column(db.Float) Soft_Murum_3_0_to_4_5 = db.Column(db.Float) Hard_Murum_0_to_1_5 = db.Column(db.Float) Hard_Murum_1_5_to_3_0 = db.Column(db.Float) + Hard_Murum_3_0_to_4_5 = db.Column(db.Float) Soft_Rock_0_to_1_5 = db.Column(db.Float) Soft_Rock_1_5_to_3_0 = db.Column(db.Float) + Soft_Murum_3_0_to_4_5 = db.Column(db.Float) Hard_Rock_0_to_1_5 = db.Column(db.Float) Hard_Rock_1_5_to_3_0 = db.Column(db.Float) @@ -41,18 +48,24 @@ class ManholeExcavationClient(db.Model): Hard_Rock_6_0_to_7_5 = db.Column(db.Float) # Totals + Marshi_Muddy_Slushy_0_to_1_5_total = db.Column(db.Float) + Marshi_Muddy_Slushy_1_5_to_3_0_total = db.Column(db.Float) + Marshi_Muddy_Slushy_3_0_to_4_5_total = db.Column(db.Float) + Soft_Murum_0_to_1_5_total = db.Column(db.Float) Soft_Murum_1_5_to_3_0_total = db.Column(db.Float) Soft_Murum_3_0_to_4_5_total = db.Column(db.Float) Hard_Murum_0_to_1_5_total = db.Column(db.Float) - Hard_Murum_1_5_and_above_total = db.Column(db.Float) + Hard_Murum_1_5_to_3_0_total = db.Column(db.Float) + Hard_Murum_3_0_to_4_5_total = db.Column(db.Float) Soft_Rock_0_to_1_5_total = db.Column(db.Float) - Soft_Rock_1_5_and_above_total = db.Column(db.Float) + Soft_Rock_1_5_to_3_0_total = db.Column(db.Float) + Soft_Rock_3_0_to_4_5_total = db.Column(db.Float) Hard_Rock_0_to_1_5_total = db.Column(db.Float) - Hard_Rock_1_5_and_above_total = db.Column(db.Float) + Hard_Rock_1_5_to_3_0_total = db.Column(db.Float) Hard_Rock_3_0_to_4_5_total = db.Column(db.Float) Hard_Rock_4_5_to_6_0_total = db.Column(db.Float) Hard_Rock_6_0_to_7_5_total = db.Column(db.Float) diff --git a/app/routes/__pycache__/generate_comparison_report.cpython-313.pyc b/app/routes/__pycache__/generate_comparison_report.cpython-313.pyc index 0458d92..fa5eaa9 100644 Binary files a/app/routes/__pycache__/generate_comparison_report.cpython-313.pyc and b/app/routes/__pycache__/generate_comparison_report.cpython-313.pyc differ diff --git a/app/routes/generate_comparison_report.py b/app/routes/generate_comparison_report.py index 254f83f..29c80cb 100644 --- a/app/routes/generate_comparison_report.py +++ b/app/routes/generate_comparison_report.py @@ -1,15 +1,18 @@ from flask import Blueprint, render_template, request, send_file, flash -from app.models.subcontractor_model import Subcontractor +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 import db import pandas as pd import io -generate_report_bp = Blueprint("generate_report", __name__, url_prefix="/report") +generate_report_bp = Blueprint("generate_report", __name__, url_prefix="/report") @generate_report_bp.route("/comparison_report", methods=["GET", "POST"]) @@ -21,21 +24,26 @@ def comparison_report(): if not subcontractor_id: flash("Please select a subcontractor.", "danger") - return render_template("generate_comparison_report.html", subcontractors=subcontractors) + return render_template( + "generate_comparison_report.html", + subcontractors=subcontractors + ) subcontractor = Subcontractor.query.get_or_404(subcontractor_id) - # Fetch data - contractor_rows = TrenchExcavation.query.filter_by(subcontractor_id=subcontractor_id).all() - client_rows = TrenchExcavationClient.query.filter_by(subcontractor_id=subcontractor_id).all() + contractor_tr_ex = TrenchExcavation.query.filter_by( + subcontractor_id=subcontractor_id + ).all() - + client_tr_ex = TrenchExcavationClient.query.filter_by( + subcontractor_id=subcontractor_id + ).all() - diff_rows = [] + combined_rows_tr_ex = [] - for row1, row2 in zip(client_rows, contractor_rows): - - total1 = ( + for row1, row2 in zip(client_tr_ex, contractor_tr_ex): + # -------- Tr.Ex CLIENT TOTAL ---------- + client_total = ( (row1.Marshi_Muddy_Slushy_0_to_1_5_total or 0) + (row1.Marshi_Muddy_Slushy_1_5_to_3_0_total or 0) + (row1.Marshi_Muddy_Slushy_3_0_to_4_5_total or 0) + @@ -55,7 +63,8 @@ def comparison_report(): (row1.Hard_Rock_6_0_to_7_5_total or 0) ) - total2 = ( + # -------- SUBCONTRACTOR TOTAL ---------- + contractor_total = ( (row2.Soft_Murum_0_to_1_5_total or 0) + (row2.Soft_Murum_1_5_to_3_0_total or 0) + (row2.Soft_Murum_3_0_to_4_5_total or 0) + @@ -69,54 +78,132 @@ def comparison_report(): (row2.Hard_Rock_6_0_to_7_5_total or 0) ) - diff = total1 - total2 + diff = client_total - contractor_total - # ---- store for excel ---- - diff_rows.append({ + # -------- COMBINED ROW ---------- + row_data = { "Location": row1.Location, - "Node No": row1.MH_NO, - "Client Sum": round(total1, 2), - "Subcontractor Sum": round(total2, 2), - "Diff": round(diff, 2) - }) + "MH No": row1.MH_NO, + } - # optional console print + # Client columns + for col, val in row1.__dict__.items(): + if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + continue + row_data[f"Client_{col}"] = val + + row_data["Client_Total"] = round(client_total, 2) + + # Subcontractor columns + for col, val in row2.__dict__.items(): + if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + continue + row_data[f"Sub_{col}"] = val + + row_data["Sub_Total"] = round(contractor_total, 2) + row_data["Diff"] = round(diff, 2) + + combined_rows_tr_ex.append(row_data) + + # Console log print( - f"Location : {row1.Location} | " - f"MH_NO : {row1.MH_NO} | " - f"Client : {total1} | " - f"Sub : {total2} | " - f"Diff : {diff}" + f"{row1.Location} | {row1.MH_NO} | " + f"Client={client_total} | Sub={contractor_total} | Diff={diff}" ) + # -------- Tr.Ex model ---------- + df_tr_ex = pd.DataFrame(combined_rows_tr_ex) + + # manhole ex + # contractor_mh_ex = ManholeExcavation.query.filter_by( + # subcontractor_id=subcontractor_id + # ).all() + + # client_mh_ex = ManholeExcavationClient.query.filter_by( + # subcontractor_id=subcontractor_id + # ).all() + + # combined_rows_mh_ex = [] + + # for row1, row2 in zip(client_mh_ex, contractor_mh_ex): + # # -------- Tr.Ex CLIENT TOTAL ---------- + # client_total = ( + # (row1.Marshi_Muddy_Slushy_0_to_1_5_total or 0) + + # (row1.Marshi_Muddy_Slushy_1_5_to_3_0_total or 0) + + # (row1.Marshi_Muddy_Slushy_3_0_to_4_5_total or 0) + + # (row1.Soft_Murum_0_to_1_5_total or 0) + + # (row1.Soft_Murum_1_5_to_3_0_total or 0) + + # (row1.Soft_Murum_3_0_to_4_5_total or 0) + + # (row1.Hard_Murum_0_to_1_5_total or 0) + + # (row1.Hard_Murum_1_5_to_3_0_total or 0) + + # (row1.Hard_Murum_3_0_to_4_5_total or 0) + + # (row1.Soft_Rock_0_to_1_5_total or 0) + + # (row1.Soft_Rock_1_5_to_3_0_total or 0) + + # (row1.Soft_Rock_3_0_to_4_5_total or 0) + + # (row1.Hard_Rock_0_to_1_5_total or 0) + + # (row1.Hard_Rock_1_5_to_3_0_total or 0) + + # (row1.Hard_Rock_3_0_to_4_5_total or 0) + + # (row1.Hard_Rock_4_5_to_6_0_total or 0) + + # (row1.Hard_Rock_6_0_to_7_5_total or 0) + # ) + + # # -------- SUBCONTRACTOR TOTAL ---------- + # contractor_total = ( + # (row2.Soft_Murum_0_to_1_5_total or 0) + + # (row2.Soft_Murum_1_5_to_3_0_total or 0) + + # (row2.Soft_Murum_3_0_to_4_5_total or 0) + + # (row2.Hard_Murum_0_to_1_5_total or 0) + + # (row2.Hard_Murum_1_5_and_above_total or 0) + + # (row2.Soft_Rock_0_to_1_5_total or 0) + + # (row2.Soft_Rock_1_5_and_above_total or 0) + + # (row2.Hard_Rock_0_to_1_5_total or 0) + + # (row2.Hard_Rock_1_5_and_above_total or 0) + + # (row2.Hard_Rock_4_5_to_6_0_total or 0) + + # (row2.Hard_Rock_6_0_to_7_5_total or 0) + # ) + + # diff = client_total - contractor_total + + # # -------- COMBINED ROW ---------- + # row_data = { + # "Location": row1.Location, + # "MH No": row1.MH_NO, + # } + + # # Client columns + # for col, val in row1.__dict__.items(): + # if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + # continue + # row_data[f"Client_{col}"] = val + + # row_data["Client_Total"] = round(client_total, 2) + + # # Subcontractor columns + # for col, val in row2.__dict__.items(): + # if col.startswith("_") or col in ["id", "created_at", "subcontractor_id"]: + # continue + # row_data[f"Sub_{col}"] = val + + # row_data["Sub_Total"] = round(contractor_total, 2) + # row_data["Diff"] = round(diff, 2) + + # combined_rows_tr_ex.append(row_data) + + # # Console log + # print( + # f"{row1.Location} | {row1.MH_NO} | " + # f"Client={client_total} | Sub={contractor_total} | Diff={diff}" + # ) - # Convert to DataFrame - df_contractor = pd.DataFrame([r.__dict__ for r in contractor_rows]) - df_client = pd.DataFrame([r.__dict__ for r in client_rows]) - df_diff = pd.DataFrame(diff_rows, columns=["Location", "Node No", "Client Sum", "Subcontractor Sum", "Diff"]) - # Drop unwanted columns - drop_cols = ["id", "subcontractor_id", "created_at", "_sa_instance_state", "Remarks"] - df_contractor.drop(columns=drop_cols, errors="ignore", inplace=True) - df_client.drop(columns=drop_cols, errors="ignore", inplace=True) - # Convert to numeric - df_contractor = df_contractor.apply(pd.to_numeric, errors="coerce").fillna(0) - df_client = df_client.apply(pd.to_numeric, errors="coerce").fillna(0) - - - # EXPORT EXCEL output = io.BytesIO() file_name = f"{subcontractor.subcontractor_name}_Comparison_Report.xlsx" with pd.ExcelWriter(output, engine="xlsxwriter") as writer: - df_contractor.to_excel(writer, index=False, sheet_name="Contractor_Data") - df_client.to_excel(writer, index=False, sheet_name="Client_Data") - df_diff.to_excel(writer, index=False, sheet_name="Diff") - - + df_tr_ex.to_excel(writer, index=False, sheet_name="Tr.Ex") output.seek(0) @@ -127,7 +214,7 @@ def comparison_report(): mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) - return render_template("generate_comparison_report.html", subcontractors=subcontractors) - - - + return render_template( + "generate_comparison_report.html", + subcontractors=subcontractors + ) diff --git a/app/services/__pycache__/file_service.cpython-313.pyc b/app/services/__pycache__/file_service.cpython-313.pyc index 9e0afbb..e46e567 100644 Binary files a/app/services/__pycache__/file_service.cpython-313.pyc and b/app/services/__pycache__/file_service.cpython-313.pyc differ diff --git a/app/services/file_service.py b/app/services/file_service.py index 0a2e911..628e205 100644 --- a/app/services/file_service.py +++ b/app/services/file_service.py @@ -6,8 +6,11 @@ from app import db from app.models.trench_excavation_model import TrenchExcavation from app.models.manhole_excavation_model import ManholeExcavation from app.models.manhole_domestic_chamber_model import ManholeDomesticChamber + from app.models.tr_ex_client_model import TrenchExcavationClient from app.models.mh_ex_client_model import ManholeExcavationClient +from app.models.mh_dc_client_model import ManholeDomesticChamberClient + from app.utils.file_utils import ensure_upload_folder @@ -56,14 +59,17 @@ class FileService: if file_type == "manhole_domestic_chamber": return self.process_manhole_domestic_chamber(df, subcontractor_id) - # Trench Excavation save (client) + # Tr Ex save (client) if file_type =="tr_ex_client": return self.client_trench_excavation(df, subcontractor_id) - # Manhole Excavation save (client) - # if file_type =="mh_ex_client": - # return self.client_manhole_excavation(df, subcontractor_id) + # Mh Ex save (client) + if file_type =="mh_ex_client": + return self.client_manhole_excavation(df, subcontractor_id) + # Mh and Dc save (client) + if file_type == "mh_dc_client": + return self.client_manhole_domestic_chamber(df, subcontractor_id) return True, "File uploaded successfully." @@ -212,7 +218,7 @@ class FileService: # ---------------------- client ---------------------------------- - # Trench Excavation save method (TrenchExcavationClient model) + # Tr Ex save method (TrenchExcavationClient model) def client_trench_excavation(self, df, subcontractor_id): df.columns = [str(c).strip() for c in df.columns] # If the sheet has merged cells -> forward fill Location @@ -256,49 +262,96 @@ class FileService: return False, f"Clinnt Tr Ex Save Failed: {e}" - # Manhole Excavation save method (ManholeExcavationClient model) - # def client_manhole_excavation(self, df, subcontractor_id): - # # Clean column names (strip whitespace) - # df.columns = [str(c).strip() for c in df.columns] - # # If the sheet has merged cells -> forward fill Location - # if "Location" in df.columns: - # df["Location"] = df["Location"].ffill() + # Mh Ex save method (ManholeExcavationClient model) + def client_manhole_excavation(self, df, subcontractor_id): + # Clean column names (strip whitespace) + df.columns = [str(c).strip() for c in df.columns] + # If the sheet has merged cells -> forward fill Location + if "Location" in df.columns: + df["Location"] = df["Location"].ffill() - # # REMOVE empty rows - # df = df.dropna(how="all") - # # Identify missing location rows before insert - # missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] - # if not missing_loc.empty: - # return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" + # REMOVE empty rows + df = df.dropna(how="all") + # Identify missing location rows before insert + missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] + if not missing_loc.empty: + return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" - # saved_count = 0 + saved_count = 0 - # try: - # for index, row in df.iterrows(): - # record_data = {} - # # Insert only fields that exist in model - # for col in df.columns: - # if hasattr(ManholeExcavationClient, col): - # value = row[col] + try: + for index, row in df.iterrows(): + record_data = {} + # Insert only fields that exist in model + for col in df.columns: + if hasattr(ManholeExcavationClient, col): + value = row[col] - # # Normalize empty values - # if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: - # value = None + # Normalize empty values + if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: + value = None - # record_data[col] = value + record_data[col] = value - # record = ManholeExcavationClient( - # subcontractor_id=subcontractor_id, - # **record_data - # ) + record = ManholeExcavationClient( + subcontractor_id=subcontractor_id, + **record_data + ) - # db.session.add(record) - # saved_count += 1 + db.session.add(record) + saved_count += 1 - # db.session.commit() - # return True, f" Client Mh Ex. data saved successfully. Total rows: {saved_count}" + db.session.commit() + return True, f" Client Mh Ex. data saved successfully. Total rows: {saved_count}" - # except Exception as e: - # db.session.rollback() - # return False, f"Client Mh Ex. Save Failed: {e}" + except Exception as e: + db.session.rollback() + return False, f"Client Mh Ex. Save Failed: {e}" + + # Mh and Dc save method (ManholeDomesticChamberClient model) + def client_manhole_domestic_chamber(self, df, subcontractor_id): + # Clean column names (strip whitespace) + df.columns = [str(c).strip() for c in df.columns] + # If the sheet has merged cells -> forward fill Location + if "Location" in df.columns: + df["Location"] = df["Location"].ffill() + + # REMOVE empty rows + df = df.dropna(how="all") + # Identify missing location rows before insert + missing_loc = df[df["Location"].isna() | (df["Location"].astype(str).str.strip() == "")] + if not missing_loc.empty: + return False, f"Error: Some rows have empty Location. Rows: {missing_loc.index.tolist()}" + + saved_count = 0 + + try: + for index, row in df.iterrows(): + record_data = {} + + # Insert only fields that exist in model + for col in df.columns: + if hasattr(ManholeDomesticChamberClient, col): + value = row[col] + # Normalize empty values + if pd.isna(value) or str(value).strip() in ["", "-", "—", "nan", "NaN"]: + value = None + + record_data[col] = value + + record = ManholeDomesticChamberClient( + subcontractor_id=subcontractor_id, + **record_data + ) + + db.session.add(record) + saved_count += 1 + + db.session.commit() + return True, f"Mh and Dc data saved successfully. Total rows: {saved_count}" + + except Exception as e: + db.session.rollback() + return False, f"Mh and Dc data Save Failed: {e}" + \ No newline at end of file