Summary report UI improvements and JS preview logic
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort, flash,send_file
|
||||
from flask import (
|
||||
render_template, request, send_file, jsonify
|
||||
)
|
||||
from werkzeug.utils import secure_filename
|
||||
import pandas as pd
|
||||
import os
|
||||
@@ -17,11 +19,40 @@ class DocumentHandler:
|
||||
self.isSuccess = False
|
||||
self.resultMessage = ""
|
||||
|
||||
# VIEW DOCUMENTS
|
||||
# =========================
|
||||
# Utility: Parse Year
|
||||
# =========================
|
||||
def parse_year(self, year_value):
|
||||
"""
|
||||
Accepts:
|
||||
- '2026'
|
||||
- 'AY 2026-2027'
|
||||
Returns:
|
||||
- 2026 (int)
|
||||
"""
|
||||
if not year_value:
|
||||
return None
|
||||
|
||||
year_value = year_value.strip()
|
||||
|
||||
if year_value.isdigit():
|
||||
return int(year_value)
|
||||
|
||||
try:
|
||||
# "AY 2026-2027" → 2026
|
||||
return int(year_value.split()[1].split('-')[0])
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# =========================
|
||||
# View Documents
|
||||
# =========================
|
||||
def View(self, request):
|
||||
year = request.args.get('year', '')
|
||||
year_raw = request.args.get('year', '')
|
||||
stage = request.args.get('stage', '')
|
||||
|
||||
year = self.parse_year(year_raw)
|
||||
|
||||
dbconfig = DBConfig()
|
||||
connection = dbconfig.get_db_connection()
|
||||
|
||||
@@ -30,15 +61,13 @@ class DocumentHandler:
|
||||
return
|
||||
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
# --- FILTER QUERY ---
|
||||
|
||||
cursor.callproc("GetDocuments", [year, stage])
|
||||
|
||||
# fetch first result set
|
||||
for result in cursor.stored_results():
|
||||
self.documents = result.fetchall()
|
||||
break
|
||||
|
||||
# ---- GET YEARS FROM STORED PROCEDURE ----
|
||||
cursor.callproc("GetYear")
|
||||
|
||||
for result in cursor.stored_results():
|
||||
@@ -49,55 +78,72 @@ class DocumentHandler:
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
self.isSuccess = True
|
||||
|
||||
# =========================
|
||||
# Upload Documents
|
||||
# =========================
|
||||
def Upload(self, request):
|
||||
dbconfig = DBConfig()
|
||||
connection = dbconfig.get_db_connection()
|
||||
|
||||
if connection:
|
||||
cursor = connection.cursor()
|
||||
files = request.files.getlist('documents')
|
||||
year = request.form['year']
|
||||
stage = request.form['stage']
|
||||
if not connection:
|
||||
return
|
||||
|
||||
for file in files:
|
||||
extension = file.filename.rsplit('.', 1)[1]
|
||||
if extension not in FileHandler.ALLOWED_EXTENSIONS:
|
||||
print("Skip invalid file type : ",extension)
|
||||
continue
|
||||
cursor = connection.cursor()
|
||||
|
||||
filename = secure_filename(file.filename)
|
||||
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename)
|
||||
file.save(filepath)
|
||||
files = request.files.getlist('documents')
|
||||
year_raw = request.form.get('year')
|
||||
stage = request.form.get('stage')
|
||||
|
||||
cursor.callproc('InsertDocument', [ filename, filepath, extension, year, stage ])
|
||||
year = self.parse_year(year_raw)
|
||||
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
connection.close()
|
||||
# return redirect(url_for('view_documents'))
|
||||
if not year:
|
||||
self.resultMessage = "Invalid year selected."
|
||||
return
|
||||
|
||||
def Summary_report(self, request):
|
||||
dbconfig = DBConfig()
|
||||
connection = dbconfig.get_db_connection()
|
||||
for file in files:
|
||||
if '.' not in file.filename:
|
||||
continue
|
||||
|
||||
year_str = request.args.get('year')
|
||||
extension = file.filename.rsplit('.', 1)[1].lower()
|
||||
|
||||
# If year not selected
|
||||
if not year_str or not year_str.isdigit():
|
||||
yearGetter = YearGet()
|
||||
allYears = yearGetter.get_year_by_model("AllYearsInAllModel")
|
||||
yearGetter.close()
|
||||
return render_template(
|
||||
'summary_reports.html',
|
||||
years=allYears,
|
||||
message="Please select a valid year to download."
|
||||
if extension not in FileHandler.ALLOWED_EXTENSIONS:
|
||||
print("Skipping invalid file:", extension)
|
||||
continue
|
||||
|
||||
filename = secure_filename(file.filename)
|
||||
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename)
|
||||
|
||||
file.save(filepath)
|
||||
|
||||
cursor.callproc(
|
||||
'InsertDocument',
|
||||
[filename, filepath, extension, year, stage]
|
||||
)
|
||||
|
||||
# Convert year to int (IMPORTANT FIX)
|
||||
year = int(year_str)
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
# =========================
|
||||
# Summary Preview (JSON)
|
||||
# =========================
|
||||
def Summary_preview(self, request):
|
||||
"""
|
||||
Returns JSON preview of summary report for selected year.
|
||||
"""
|
||||
year_raw = request.args.get("year")
|
||||
year = self.parse_year(year_raw)
|
||||
|
||||
if not year:
|
||||
return jsonify([])
|
||||
|
||||
dbconfig = DBConfig()
|
||||
connection = dbconfig.get_db_connection()
|
||||
if not connection:
|
||||
return jsonify([])
|
||||
|
||||
try:
|
||||
stages = {
|
||||
@@ -112,11 +158,111 @@ class DocumentHandler:
|
||||
for stage_name, table_name in stages.items():
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
cursor.callproc("sp_get_stage_data", [table_name, year])
|
||||
|
||||
rows = []
|
||||
for result in cursor.stored_results():
|
||||
rows = result.fetchall()
|
||||
stage_data[stage_name] = pd.DataFrame(rows) if rows else pd.DataFrame()
|
||||
cursor.close()
|
||||
|
||||
columns = [
|
||||
'gross_total_income', 'disallowance_14a',
|
||||
'disallowance_37', '-',
|
||||
'deduction_80ia_business',
|
||||
'deduction_80ia_misc',
|
||||
'deduction_80ia_other',
|
||||
'deduction_sec37_disallowance',
|
||||
'deduction_80g', '-',
|
||||
'net_taxable_income',
|
||||
'tax_30_percent',
|
||||
'tax_book_profit_18_5',
|
||||
'tax_payable', 'surcharge',
|
||||
'edu_cess', 'total_tax_payable',
|
||||
'mat_credit_created',
|
||||
'mat_credit_utilized',
|
||||
'interest_234c', 'total_tax',
|
||||
'-', 'advance_tax', 'tds',
|
||||
'tcs', 'sat',
|
||||
'tax_on_assessment',
|
||||
'refund', 'Remarks'
|
||||
]
|
||||
|
||||
particulars = [
|
||||
"Gross Total Income", "Add: Disallowance u/s 14A",
|
||||
"Add: Disallowance u/s 37", "GTI as per",
|
||||
"Less: Deduction u/s 80IA - On Business Income",
|
||||
"- On Misc Receipts", "- On Other",
|
||||
"- On Sec 37 Disallowance",
|
||||
"Less: Deduction u/s 80G", " ",
|
||||
"Net Taxable Income", "Tax @ 30%",
|
||||
"Tax @ 18.5% on Book Profit",
|
||||
"Tax Payable", "Surcharge @ %",
|
||||
"Education Cess @ %", "Total Tax Payable",
|
||||
"Add: MAT Credit Created",
|
||||
"Less: MAT Credit Utilized",
|
||||
"Add: Interest u/s 234C",
|
||||
"Total Tax", " ",
|
||||
"Advance Tax", "TDS", "TCS", "SAT",
|
||||
"Tax on Regular Assessment",
|
||||
"Refund", "Remarks"
|
||||
]
|
||||
|
||||
def safe_get(df, col):
|
||||
return df[col].values[0] if col in df.columns and not df.empty else 0
|
||||
|
||||
preview = []
|
||||
for i, part in enumerate(particulars):
|
||||
preview.append({
|
||||
"Particular": part,
|
||||
"ITR": safe_get(stage_data['ITR'], columns[i]),
|
||||
"AO": safe_get(stage_data['AO'], columns[i]),
|
||||
"CIT": safe_get(stage_data['CIT'], columns[i]),
|
||||
"ITAT": safe_get(stage_data['ITAT'], columns[i]),
|
||||
})
|
||||
|
||||
return jsonify(preview)
|
||||
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
def Summary_report(self, request):
|
||||
dbconfig = DBConfig()
|
||||
connection = dbconfig.get_db_connection()
|
||||
|
||||
year_raw = request.args.get('year')
|
||||
|
||||
# Safely parse year to int
|
||||
try:
|
||||
year = int(year_raw)
|
||||
except (TypeError, ValueError):
|
||||
year = None
|
||||
|
||||
if not year:
|
||||
yearGetter = YearGet()
|
||||
allYears = yearGetter.get_year_by_model("AllYearsInAllModel")
|
||||
yearGetter.close()
|
||||
|
||||
return render_template(
|
||||
'summary_reports.html',
|
||||
years=allYears,
|
||||
message="Please select a valid year to download."
|
||||
)
|
||||
|
||||
try:
|
||||
stages = {
|
||||
"ITR": "itr",
|
||||
"AO": "ao",
|
||||
"CIT": "cit",
|
||||
"ITAT": "itat",
|
||||
}
|
||||
|
||||
stage_data = {}
|
||||
|
||||
for stage_name, table_name in stages.items():
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
cursor.callproc("sp_get_stage_data", [table_name, year])
|
||||
rows = []
|
||||
for result in cursor.stored_results():
|
||||
rows = result.fetchall()
|
||||
stage_data[stage_name] = pd.DataFrame(rows) if rows else pd.DataFrame()
|
||||
cursor.close()
|
||||
|
||||
@@ -124,25 +270,45 @@ class DocumentHandler:
|
||||
return df[col].values[0] if col in df.columns and not df.empty else "-"
|
||||
|
||||
particulars = [
|
||||
"Gross Total Income", "Add: Disallowance u/s 14A", "Add: Disallowance u/s 37",
|
||||
"GTI as per", "Less: Deduction u/s 80IA - On Business Income", "- On Misc Receipts",
|
||||
"- On Other", "- On Sec 37 Disallowance", "Less: Deduction u/s 80G", " ",
|
||||
"Net Taxable Income", "Tax @ 30%", "Tax @ 18.5% on Book Profit",
|
||||
"Tax Payable", "Surcharge @ %", "Education Cess @ %", "Total Tax Payable","Add: MAT Credit Created",
|
||||
"Less: MAT Credit Utilized", "Add: Interest u/s 234C", "Total Tax", " ",
|
||||
"Gross Total Income", "Add: Disallowance u/s 14A",
|
||||
"Add: Disallowance u/s 37", "GTI as per",
|
||||
"Less: Deduction u/s 80IA - On Business Income",
|
||||
"- On Misc Receipts", "- On Other",
|
||||
"- On Sec 37 Disallowance",
|
||||
"Less: Deduction u/s 80G", " ",
|
||||
"Net Taxable Income", "Tax @ 30%",
|
||||
"Tax @ 18.5% on Book Profit",
|
||||
"Tax Payable", "Surcharge @ %",
|
||||
"Education Cess @ %", "Total Tax Payable",
|
||||
"Add: MAT Credit Created",
|
||||
"Less: MAT Credit Utilized",
|
||||
"Add: Interest u/s 234C",
|
||||
"Total Tax", " ",
|
||||
"Advance Tax", "TDS", "TCS", "SAT",
|
||||
"Tax on Regular Assessment", "Refund" , "Remarks"
|
||||
"Tax on Regular Assessment",
|
||||
"Refund", "Remarks"
|
||||
]
|
||||
|
||||
columns = [
|
||||
'gross_total_income', 'disallowance_14a', 'disallowance_37',
|
||||
'-', 'deduction_80ia_business','deduction_80ia_misc',
|
||||
'deduction_80ia_other', 'deduction_sec37_disallowance','deduction_80g', '-',
|
||||
'net_taxable_income', 'tax_30_percent','tax_book_profit_18_5',
|
||||
'tax_payable','surcharge', 'edu_cess', 'total_tax_payable',
|
||||
'mat_credit_created','mat_credit_utilized' , 'interest_234c','total_tax', '-',
|
||||
'advance_tax', 'tds', 'tcs', 'sat',
|
||||
'tax_on_assessment', 'refund', 'Remarks'
|
||||
'gross_total_income', 'disallowance_14a',
|
||||
'disallowance_37', '-',
|
||||
'deduction_80ia_business',
|
||||
'deduction_80ia_misc',
|
||||
'deduction_80ia_other',
|
||||
'deduction_sec37_disallowance',
|
||||
'deduction_80g', '-',
|
||||
'net_taxable_income',
|
||||
'tax_30_percent',
|
||||
'tax_book_profit_18_5',
|
||||
'tax_payable', 'surcharge',
|
||||
'edu_cess', 'total_tax_payable',
|
||||
'mat_credit_created',
|
||||
'mat_credit_utilized',
|
||||
'interest_234c', 'total_tax',
|
||||
'-', 'advance_tax', 'tds',
|
||||
'tcs', 'sat',
|
||||
'tax_on_assessment',
|
||||
'refund', 'Remarks'
|
||||
]
|
||||
|
||||
data = {
|
||||
@@ -155,56 +321,44 @@ class DocumentHandler:
|
||||
|
||||
df = pd.DataFrame(data)
|
||||
|
||||
# ===== Excel Export =====
|
||||
output = io.BytesIO()
|
||||
|
||||
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
|
||||
sheet_name = f"AY {year} - {year + 1}"
|
||||
sheet_name = f"AY {year}-{year + 1}"
|
||||
df.to_excel(writer, index=False, sheet_name=sheet_name, startrow=2)
|
||||
|
||||
workbook = writer.book
|
||||
worksheet = writer.sheets[sheet_name]
|
||||
|
||||
# ===== Company Heading =====
|
||||
company_heading = workbook.add_format({
|
||||
title = workbook.add_format({
|
||||
'bold': True,
|
||||
'font_size': 14,
|
||||
'font_color': 'black',
|
||||
'align': 'center',
|
||||
'valign': 'middle'
|
||||
'align': 'center'
|
||||
})
|
||||
|
||||
worksheet.merge_range(
|
||||
0, 0, 0, len(df.columns) - 1,
|
||||
"Laxmi Civil Engineering Services Pvt Ltd",
|
||||
company_heading
|
||||
title
|
||||
)
|
||||
|
||||
# ===== Header Format =====
|
||||
header = workbook.add_format({
|
||||
'bold': True,
|
||||
'align': 'center',
|
||||
'valign': 'middle',
|
||||
'bg_color': '#007bff',
|
||||
'font_color': 'white',
|
||||
'border': 1
|
||||
})
|
||||
|
||||
cell = workbook.add_format({
|
||||
'border': 1,
|
||||
'align': 'left',
|
||||
'valign': 'middle'
|
||||
})
|
||||
cell = workbook.add_format({'border': 1})
|
||||
|
||||
# Write headers
|
||||
for col_num, col_name in enumerate(df.columns):
|
||||
worksheet.write(2, col_num, col_name, header)
|
||||
max_len = max(df[col_name].astype(str).map(len).max(), len(col_name)) + 2
|
||||
worksheet.set_column(col_num, col_num, max_len)
|
||||
worksheet.set_column(col_num, col_num, 25)
|
||||
|
||||
# Write data rows
|
||||
for row in range(3, len(df) + 3):
|
||||
for row in range(len(df)):
|
||||
for col in range(len(df.columns)):
|
||||
worksheet.write(row, col, df.iloc[row - 3, col], cell)
|
||||
worksheet.write(row + 3, col, df.iloc[row, col], cell)
|
||||
|
||||
worksheet.freeze_panes(3, 1)
|
||||
|
||||
@@ -219,3 +373,4 @@ class DocumentHandler:
|
||||
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user