from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort, flash,send_file from werkzeug.utils import secure_filename import pandas as pd import os import io from AppCode.Config import DBConfig from AppCode.FileHandler import FileHandler from AppCode.YearGet import YearGet class DocumentHandler: def __init__(self): self.years = [] self.documents = [] self.isSuccess = False self.resultMessage = "" # VIEW DOCUMENTS def View(self, request): year = request.args.get('year', '') stage = request.args.get('stage', '') dbconfig = DBConfig() connection = dbconfig.get_db_connection() if not connection: self.isSuccess = False 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(): year_rows = result.fetchall() break self.years = [row['year'] for row in year_rows] 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'] for file in files: extension = file.filename.rsplit('.', 1)[1] if extension not in FileHandler.ALLOWED_EXTENSIONS: print("Skip invalid file type : ",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 ]) connection.commit() cursor.close() connection.close() # return redirect(url_for('view_documents')) def Summary_report(self, request): dbconfig = DBConfig() connection = dbconfig.get_db_connection() year_str = request.args.get('year') # 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." ) # Convert year to int (IMPORTANT FIX) year = int(year_str) 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() def safe_get(df, col): 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 @ 3%", "Total Tax Payable", "Less: MAT Credit Utilized", "Add: Interest u/s 234C", "Total Tax", " ", "Advance Tax", "TDS", "TCS", "SAT", "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_12', 'edu_cess_3', 'total_tax_payable', 'mat_credit' , 'interest_234c','total_tax', '-', 'advance_tax', 'tds', 'tcs', 'sat', 'tax_on_assessment', 'refund', 'Remarks' ] data = { "Particulars": particulars, "ITR": [safe_get(stage_data['ITR'], col) for col in columns], "AO": [safe_get(stage_data['AO'], col) for col in columns], "CIT": [safe_get(stage_data['CIT'], col) for col in columns], "ITAT": [safe_get(stage_data['ITAT'], col) for col in columns], } df = pd.DataFrame(data) # ===== Excel Export ===== output = io.BytesIO() with pd.ExcelWriter(output, engine='xlsxwriter') as writer: 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({ 'bold': True, 'font_size': 14, 'font_color': 'black', 'align': 'center', 'valign': 'middle' }) worksheet.merge_range( 0, 0, 0, len(df.columns) - 1, "Laxmi Civil Engineering Services Pvt Ltd", company_heading ) # ===== 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' }) # 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) # Write data rows for row in range(3, len(df) + 3): for col in range(len(df.columns)): worksheet.write(row, col, df.iloc[row - 3, col], cell) worksheet.freeze_panes(3, 1) output.seek(0) return send_file( output, download_name=f"AY{year}-{year + 1}_Summary_Report.xlsx", as_attachment=True, mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) finally: connection.close()