Compare commits
2 Commits
ff5da926f3
...
15b07b3d55
| Author | SHA1 | Date | |
|---|---|---|---|
| 15b07b3d55 | |||
| dd4b494435 |
@@ -1,13 +1,19 @@
|
||||
import pandas as pd
|
||||
import io
|
||||
from flask import Blueprint, render_template, request, send_file, flash
|
||||
from app.utils.helpers import login_required
|
||||
|
||||
from app.models.subcontractor_model import Subcontractor
|
||||
|
||||
from app.models.manhole_excavation_model import ManholeExcavation
|
||||
from app.models.trench_excavation_model import TrenchExcavation
|
||||
from app.models.manhole_domestic_chamber_model import ManholeDomesticChamber
|
||||
from app.models.laying_model import Laying
|
||||
|
||||
from app.models.mh_ex_client_model import ManholeExcavationClient
|
||||
from app.models.tr_ex_client_model import TrenchExcavationClient
|
||||
from app.models.mh_dc_client_model import ManholeDomesticChamberClient
|
||||
<<<<<<< HEAD
|
||||
from app.utils.helpers import login_required
|
||||
<<<<<<< HEAD
|
||||
|
||||
@@ -50,34 +56,39 @@ class SubcontractorBill:
|
||||
|
||||
# --- 3. DEFINE ROUTES ---
|
||||
=======
|
||||
=======
|
||||
from app.models.laying_client_model import LayingClient
|
||||
|
||||
>>>>>>> pankaj-dev
|
||||
|
||||
# --- BLUEPRINT DEFINITION ---
|
||||
file_report_bp = Blueprint("file_report", __name__, url_prefix="/file")
|
||||
|
||||
# --- DATA WRAPPERS ---
|
||||
# --- Client class ---
|
||||
class ClientBill:
|
||||
def __init__(self):
|
||||
self.df_tr = pd.DataFrame()
|
||||
self.df_mh = pd.DataFrame()
|
||||
self.df_dc = pd.DataFrame()
|
||||
self.df_laying = pd.DataFrame()
|
||||
|
||||
def Fetch(self, RA_Bill_No):
|
||||
trench = TrenchExcavationClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
|
||||
mh = ManholeExcavationClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
|
||||
dc = ManholeDomesticChamberClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
|
||||
lay = LayingClient.query.filter_by(RA_Bill_No=RA_Bill_No).all()
|
||||
|
||||
self.df_tr = pd.DataFrame([c.serialize() for c in trench])
|
||||
self.df_mh = pd.DataFrame([c.serialize() for c in mh])
|
||||
self.df_dc = pd.DataFrame([c.serialize() for c in dc])
|
||||
|
||||
if not self.df_dc.empty and "MH_NO" in self.df_dc.columns:
|
||||
self.df_dc.rename(columns={"MH_NO": "Node_No"}, inplace=True)
|
||||
|
||||
self.df_laying = pd.DataFrame([c.serialize() for c in lay])
|
||||
|
||||
drop_cols = ["id", "created_at", "_sa_instance_state"]
|
||||
for df in [self.df_tr, self.df_mh, self.df_dc]:
|
||||
for df in [self.df_tr, self.df_mh, self.df_dc, self.df_laying]:
|
||||
if not df.empty:
|
||||
df.drop(columns=drop_cols, errors="ignore", inplace=True)
|
||||
|
||||
# --- Subcontractor class ---
|
||||
class SubcontractorBill:
|
||||
def __init__(self):
|
||||
self.df_tr = pd.DataFrame()
|
||||
@@ -95,21 +106,19 @@ class SubcontractorBill:
|
||||
trench = TrenchExcavation.query.filter_by(**filters).all()
|
||||
mh = ManholeExcavation.query.filter_by(**filters).all()
|
||||
dc = ManholeDomesticChamber.query.filter_by(**filters).all()
|
||||
lay = ManholeDomesticChamber.query.filter_by(**filters).all()
|
||||
lay = Laying.query.filter_by(**filters).all()
|
||||
|
||||
self.df_tr = pd.DataFrame([c.serialize() for c in trench])
|
||||
self.df_mh = pd.DataFrame([c.serialize() for c in mh])
|
||||
self.df_dc = pd.DataFrame([c.serialize() for c in dc])
|
||||
self.df_laying = pd.DataFrame([c.serialize() for c in lay])
|
||||
|
||||
# if not self.df_dc.empty and "MH_NO" in self.df_dc.columns:
|
||||
# self.df_dc.rename(columns={"MH_NO": "Node_No"}, inplace=True)
|
||||
|
||||
|
||||
drop_cols = ["id", "created_at", "_sa_instance_state"]
|
||||
for df in [self.df_tr, self.df_mh, self.df_dc, self.df_laying]:
|
||||
if not df.empty:
|
||||
df.drop(columns=drop_cols, errors="ignore", inplace=True)
|
||||
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
# --- ROUTES ---
|
||||
|
||||
@@ -155,6 +164,9 @@ class SubcontractorBill:
|
||||
>>>>>>> pankaj-dev
|
||||
=======
|
||||
|
||||
>>>>>>> pankaj-dev
|
||||
=======
|
||||
# --- subcontractor report only ---
|
||||
>>>>>>> pankaj-dev
|
||||
@file_report_bp.route("/report", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@@ -252,7 +264,8 @@ def report_file():
|
||||
return send_file(output, download_name=file_name, as_attachment=True)
|
||||
|
||||
# We add bootstrap classes directly to the pandas output
|
||||
table_classes = "table table-hover table-bordered table-striped"
|
||||
# table_classes = "table table-hover table-bordered table-striped"
|
||||
table_classes = "table table-bordered table-striped table-hover table-sm mb-0"
|
||||
tables = {
|
||||
"tr": bill_gen.df_tr.to_html(classes=table_classes, index=False),
|
||||
"mh": bill_gen.df_mh.to_html(classes=table_classes, index=False),
|
||||
@@ -270,6 +283,10 @@ def report_file():
|
||||
download_all=download_all
|
||||
)
|
||||
|
||||
<<<<<<< HEAD
|
||||
>>>>>>> pankaj-dev
|
||||
=======
|
||||
# --- client comparison ---
|
||||
>>>>>>> pankaj-dev
|
||||
@file_report_bp.route("/client_vs_subcont", methods=["GET", "POST"])
|
||||
@login_required
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
body {
|
||||
background: #f5f7fa;
|
||||
font-family: Arial;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
form {
|
||||
width: 420px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
label {
|
||||
margin-top: 10px;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 20px;
|
||||
padding: 10px 20px;
|
||||
background: #0055ff;
|
||||
color: #fff;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
<body class="bg-light">
|
||||
|
||||
<!-- NAVBAR -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm">
|
||||
<!-- <nav class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm"> -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark shadow-sm fixed-top">
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Brand -->
|
||||
@@ -72,7 +74,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="/file/report">
|
||||
<i class="bi bi-download me-2"></i> Download Reports
|
||||
<i class="bi bi-download me-2"></i> Show Reports
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -92,7 +94,7 @@
|
||||
|
||||
<li>
|
||||
<a class="dropdown-item" href="/file/client_vs_subcont">
|
||||
<i class="bi bi-arrow-left-right me-2"></i> Comparison Report
|
||||
<i class="bi bi-arrow-left-right me-2"></i> Show Report
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -170,25 +172,32 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- FLASH MESSAGES -->
|
||||
<div class="container mt-3">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }} alert-dismissible fade show">
|
||||
{{ message }}
|
||||
<button class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<!-- PAGE CONTENT -->
|
||||
<div class="container mt-4">
|
||||
{% block content %}{% endblock %}
|
||||
<div class="container-fluid vh-100 pt-5 overflow-hidden">
|
||||
<!-- FLASH MESSAGES -->
|
||||
<div class="container mt-3">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="alert alert-{{ category }} alert-dismissible fade show">
|
||||
{{ message }}
|
||||
<button class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="overflow-auto h-100">
|
||||
<div class="container mt-4">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<<<<<<< HEAD
|
||||
<div class="container mt-4">
|
||||
<<<<<<< HEAD
|
||||
<h2 class="mb-4">Generate Subcontractor Report</h2>
|
||||
@@ -26,6 +27,16 @@
|
||||
=======
|
||||
<div class="card p-4 shadow-sm mx-auto" style="max-width: 600px;">
|
||||
<form method="POST" id="reportForm">
|
||||
>>>>>>> pankaj-dev
|
||||
=======
|
||||
<div class="container my-4">
|
||||
|
||||
<h2 class="text-center mb-4">Generate Subcontractor Report</h2>
|
||||
|
||||
<!-- FORM -->
|
||||
<div class="card shadow-sm p-3 p-md-4 mx-auto" style="max-width:600px;">
|
||||
<form method="POST">
|
||||
|
||||
>>>>>>> pankaj-dev
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Select Subcontractor</label>
|
||||
@@ -53,121 +64,125 @@
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" name="download_all" value="true" id="downloadAllSwitch"
|
||||
onchange="toggleRAInput(this)" {% if download_all %}checked{% endif %}>
|
||||
<label class="form-check-label fw-bold text-primary" for="downloadAllSwitch">
|
||||
Download All RA Bills for this Contractor
|
||||
<input class="form-check-input" type="checkbox" id="downloadAllSwitch" name="download_all" value="true"
|
||||
{% if download_all %}checked{% endif %}>
|
||||
<label class="form-check-label fw-bold text-primary">
|
||||
Download All RA Bills
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mb-4" id="ra_bill_container">
|
||||
<label class="form-label fw-semibold">RA Bill Number</label>
|
||||
<input type="text" name="ra_bill_no" id="ra_bill_input" class="form-control" placeholder="e.g. 01"
|
||||
<input type="text" name="ra_bill_no" id="ra_bill_input" class="form-control"
|
||||
value="{{ ra_bill_no or '' }}">
|
||||
<small class="text-muted">Required if "Download All" is off.</small>
|
||||
</div>
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6">
|
||||
<button type="submit" name="action" value="preview" class="btn btn-outline-primary w-100 py-2">
|
||||
<i class="fas fa-eye me-2"></i>Preview Data
|
||||
<div class="col-12 col-md-6">
|
||||
<button class="btn btn-outline-primary w-100" name="action" value="preview">
|
||||
Preview Data
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<button type="submit" name="action" value="download" class="btn btn-primary w-100 py-2">
|
||||
<i class="fas fa-download me-2"></i>Download Excel
|
||||
<div class="col-12 col-md-6">
|
||||
<button class="btn btn-primary w-100" name="action" value="download">
|
||||
Download Excel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<<<<<<< HEAD
|
||||
>>>>>>> pankaj-dev
|
||||
=======
|
||||
|
||||
>>>>>>> pankaj-dev
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if tables %}
|
||||
<div class="mt-5 mb-5">
|
||||
<hr>
|
||||
<h3 class="text-center mb-4">Report Preview</h3>
|
||||
<!-- REPORT PREVIEW -->
|
||||
<div class="mt-5">
|
||||
|
||||
<h3 class="text-center mb-3">Report Preview</h3>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<ul class="nav nav-tabs card-header-tabs" id="reportTabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active" id="tr-tab" data-bs-toggle="tab" data-bs-target="#tr"
|
||||
type="button">Tr.Ex.</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="mh-tab" data-bs-toggle="tab" data-bs-target="#mh"
|
||||
type="button">MH.Ex. </button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="dc-tab" data-bs-toggle="tab" data-bs-target="#dc" type="button">MH
|
||||
& DC</button>
|
||||
</li>
|
||||
|
||||
<!-- MOBILE SCROLLABLE TABS -->
|
||||
<div class="card-header p-0">
|
||||
<ul class="nav nav-tabs flex-nowrap overflow-auto">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="dc-tab" data-bs-toggle="tab" data-bs-target="#dc"
|
||||
type="button">Laying</button>
|
||||
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tr">
|
||||
Trench Excavation
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#mh">
|
||||
Manhole Excavation
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#dc">
|
||||
Manhole & Domestic Chambers
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#laying">
|
||||
Pipe Laying
|
||||
</button>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body tab-content" id="reportTabsContent">
|
||||
<div class="tab-pane fade show active" id="tr" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
|
||||
<!-- TAB CONTENT -->
|
||||
<div class="card-body tab-content">
|
||||
|
||||
<div class="tab-pane fade show active" id="tr">
|
||||
<div class="table-responsive overflow-auto">
|
||||
{{ tables.tr | safe }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="mh" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
|
||||
<div class="tab-pane fade" id="mh">
|
||||
<div class="table-responsive overflow-auto">
|
||||
{{ tables.mh | safe }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="dc" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
|
||||
<div class="tab-pane fade" id="dc">
|
||||
<div class="table-responsive overflow-auto">
|
||||
{{ tables.dc | safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="laying" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
<div class="tab-pane fade" id="laying">
|
||||
<div class="table-responsive overflow-auto">
|
||||
{{ tables.laying | safe }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Styling specifically for pandas output */
|
||||
.table-responsive .table {
|
||||
font-size: 0.9rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.table-responsive thead {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- BOOTSTRAP-ONLY JS -->
|
||||
<script>
|
||||
function toggleRAInput(checkbox) {
|
||||
const input = document.getElementById('ra_bill_input');
|
||||
const container = document.getElementById('ra_bill_container');
|
||||
function toggleRAInput() {
|
||||
const checkbox = document.getElementById("downloadAllSwitch");
|
||||
const input = document.getElementById("ra_bill_input");
|
||||
const container = document.getElementById("ra_bill_container");
|
||||
|
||||
if (checkbox.checked) {
|
||||
input.value = "";
|
||||
input.disabled = true;
|
||||
container.style.opacity = "0.5";
|
||||
container.classList.add("opacity-50");
|
||||
} else {
|
||||
input.disabled = false;
|
||||
container.style.opacity = "1";
|
||||
container.classList.remove("opacity-50");
|
||||
}
|
||||
}
|
||||
|
||||
// Check status on load to handle form persistence
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
toggleRAInput(document.getElementById('downloadAllSwitch'));
|
||||
});
|
||||
document.addEventListener("DOMContentLoaded", toggleRAInput);
|
||||
document.getElementById("downloadAllSwitch").addEventListener("change", toggleRAInput);
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user