from flask import render_template, request, send_file, jsonify 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 = "" # ========================= # Utility: Parse Year # ========================= def parse_year(self, year_value): 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_raw = request.args.get('year', '') stage = request.args.get('stage', '') year = self.parse_year(year_raw) dbconfig = DBConfig() connection = dbconfig.get_db_connection() if not connection: self.isSuccess = False return cursor = connection.cursor(dictionary=True) cursor.callproc("GetDocuments", [year, stage]) for result in cursor.stored_results(): self.documents = result.fetchall() break 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 not connection: return cursor = connection.cursor() files = request.files.getlist('documents') year_raw = request.form.get('year') stage = request.form.get('stage') year = self.parse_year(year_raw) if not year: self.resultMessage = "Invalid year selected." return for file in files: if '.' not in file.filename: continue extension = file.filename.rsplit('.', 1)[1].lower() 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]) connection.commit() cursor.close() connection.close() # ========================= # Summary Preview (JSON) # ========================= def Summary_preview(self, request): 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 = { "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() columns = [ 'gross_total_income', 'disallowance_14a', 'disallowance_37', 'gross_total_income'+'disallowance_14a'+'disallowance_37', 'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other', 'deduction_sec37_disallowance', 'deduction_80g', '-', 'net_taxable_income', '-', 'per_tax_a', 'tax_a_cal', 'per_surcharge_a', 'surcharge_a_cal', 'per_cess_a', 'edu_cess_a_cal', 'sum_of_a', '-', 'per_tax_b', 'tax_b_cal', 'per_surcharge_b', 'surcharge_b_cal', 'per_cess_b', 'edu_cess_b_cal', 'sum_of_b', '-', 'tax_payable', 'total_tax_payable', 'opening_balance', 'mat_credit_created', 'mat_credit_utilized', 'closing_balance', 'interest_234c', 'total_tax', '-', 'advance_tax', 'tds', 'tcs', 'sat', 'tax_on_assessment', 'refund', 'interest_244a_per143', 'refund_received', 'balance_receivable', '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", "-", "Per% Tax @(A)", "Tax cal(A)", "Per% surcharge @(A)", "Surcharge cal (A)", "Per% cess(A)", "Edu cess cal(A)", "Sum of tax_cal(A)", "-", "Per% Tax @(B)", "Tax cal(B)", "Per% surcharge @(B)", "Surcharge cal (B)", "Per% cess(B)", "Edu cess cal(B)", "Sum of tax_cal(B)", "-", "Tax Payable", "Total Tax Payable", "Opening Balance:", "Add: MAT Credit Created", "Less: MAT Credit Utilized", "Closing Balance", "Add: Interest u/s 234C", "Total Tax", "-", "Advance Tax", "TDS", "TCS", "SAT", "Tax on Regular Assessment", "Refund", "Add : Interest u/s 244A as per 143", "Less : Refund Received on:","Balance Receivable","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() 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", "-", "Per% Tax @(A)", "Tax cal(A)", "Per% surcharge @(A)", "Surcharge cal (A)", "Per% cess(A)", "Edu cess cal(A)", "Sum of tax_cal(A)", "-", "Per% Tax @(B)", "Tax cal(B)", "Per% surcharge @(B)", "Surcharge cal (B)", "Per% cess(B)", "Edu cess cal(B)", "Sum of tax_cal(B)", "-", "Tax Payable", "Total Tax Payable", "Opening Balance", "Add: MAT Credit Created", "Less: MAT Credit Utilized", "Closing Balance", "Add: Interest u/s 234C", "Total Tax", "-", "Advance Tax", "TDS", "TCS", "SAT", "Tax on Regular Assessment", "Refund", "Add : Interest u/s 244A as per 143", "Less : Refund Received on","Balance Receivable","Remarks" ] columns = [ 'gross_total_income', 'disallowance_14a', 'disallowance_37', 'gross_total_income'+'disallowance_14a'+'disallowance_37', 'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other', 'deduction_sec37_disallowance', 'deduction_80g', '-', 'net_taxable_income', '-', 'per_tax_a', 'tax_a_cal', 'per_surcharge_a', 'surcharge_a_cal', 'per_cess_a', 'edu_cess_a_cal', 'sum_of_a', '-', 'per_tax_b', 'tax_b_cal', 'per_surcharge_b', 'surcharge_b_cal', 'per_cess_b', 'edu_cess_b_cal', 'sum_of_b', '-', 'tax_payable', 'total_tax_payable', 'opening_balance', 'mat_credit_created', 'mat_credit_utilized', 'closing_balance', 'interest_234c', 'total_tax', '-', 'advance_tax', 'tds', 'tcs', 'sat', 'tax_on_assessment', 'refund', 'interest_244a_per143', 'refund_received', 'balance_receivable', '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) 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] title = workbook.add_format({'bold': True,'font_size': 14,'align': 'center'}) worksheet.merge_range(0, 0, 0, len(df.columns) - 1,"Laxmi Civil Engineering Services Pvt Ltd",title) header = workbook.add_format({'bold': True,'align': 'center', 'bg_color': '#007bff','font_color': 'white','border': 1 }) cell = workbook.add_format({'border': 1}) for col_num, col_name in enumerate(df.columns): worksheet.write(2, col_num, col_name, header) worksheet.set_column(col_num, col_num, 25) for row in range(len(df)): for col in range(len(df.columns)): worksheet.write(row + 3, col, df.iloc[row, 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()