From dd339070ab4f17471fe021a972380bdb0bf0a6e9 Mon Sep 17 00:00:00 2001 From: pjpatil12 Date: Wed, 3 Dec 2025 19:08:28 +0530 Subject: [PATCH] modify upload documents and filter store-proc commit --- AppCode/DocumentHandler.py | 54 +- .../DocumentHandler.cpython-313.pyc | Bin 8932 -> 8735 bytes main.py | 707 +----------------- static/uploads/AY_18-19_REfund_Working.xlsx | Bin 17345 -> 23934 bytes test.py | 223 ------ 5 files changed, 19 insertions(+), 965 deletions(-) delete mode 100644 test.py diff --git a/AppCode/DocumentHandler.py b/AppCode/DocumentHandler.py index 7e7b006..4524006 100644 --- a/AppCode/DocumentHandler.py +++ b/AppCode/DocumentHandler.py @@ -30,29 +30,20 @@ class DocumentHandler: return cursor = connection.cursor(dictionary=True) - # --- FILTER QUERY --- - query = "SELECT * FROM documents WHERE 1=1" - params = [] + cursor.callproc("GetDocuments", [year, stage]) - if year != "": - query += " AND year = %s" - params.append(year) - - if stage != "": - query += " AND stage = %s" - params.append(stage) - - - cursor.execute(query, params) - self.documents = cursor.fetchall() + # 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 # only first result set + break self.years = [row['year'] for row in year_rows] @@ -60,10 +51,8 @@ class DocumentHandler: connection.close() self.isSuccess = True - # UPLOAD DOCUMENTS + # Upload Documents def Upload(self, request): - """Log user actions with timestamp, user, action, and details.""" - dbconfig = DBConfig() connection = dbconfig.get_db_connection() @@ -72,25 +61,17 @@ class DocumentHandler: files = request.files.getlist('documents') year = request.form['year'] stage = request.form['stage'] - - for file in files: - if file is not FileHandler.ALLOWED_EXTENSIONS: - continue + 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) - extension = file.filename.rsplit('.', 1)[1] - # Need to Check whetehr all three items are required - file.save(filepath) - # cursor.execute(""" - # INSERT INTO documents (filename, filepath, filetype, year, stage) - # VALUES (%s, %s, %s, %s, %s) - # """, (filename, filepath, file.filename.rsplit('.', 1)[1], year, stage)) - - cursor.callproc('InsertDocument', [ filename, filepath, extension, year, stage ]) connection.commit() @@ -98,13 +79,11 @@ class DocumentHandler: connection.close() # return redirect(url_for('view_documents')) - + # Summary report def Summary_report(self, request): - dbconfig = DBConfig() connection = dbconfig.get_db_connection() - year = request.args.get('year') # if not year get all year in list. @@ -113,11 +92,7 @@ class DocumentHandler: allYears = yearGetter.get_year_by_model("AllYearsInAllModel") yearGetter.close() - return render_template( - 'summary_reports.html', - years=allYears, - message="Please select a year to download." - ) + return render_template('summary_reports.html', years=allYears,message="Please select a year to download.") # for excel try: @@ -132,7 +107,6 @@ class DocumentHandler: for stage_name, table_name in stages.items(): cursor = connection.cursor(dictionary=True) - cursor.callproc("sp_get_stage_data", [table_name, year]) for result in cursor.stored_results(): diff --git a/AppCode/__pycache__/DocumentHandler.cpython-313.pyc b/AppCode/__pycache__/DocumentHandler.cpython-313.pyc index 9be5c9a238aa05448a21af6101518f1bfe81f5d2..ebf3bd182aee492f6ebbd1f20b83475fb3109f49 100644 GIT binary patch delta 1512 zcmZ8hTWl0n7(O$dnVs34-EG<3Zui!mb`jW?c1xwTv<9$jkp?KZ+of$6Rk53I7Go_-YjH)Mp}{uDY01*MmdFwLzmaVKb9Rd#7B~2q7NOCOg4o~mY8%PR9eb1Jc<4w zyI(?xS~FQg%ArCvCz@AI$ONI{jdD4@M!-2f$V+*Yl;Bf75whi%H7i}3nJa3BW!esM zo6uC8lp!i?fuazK*Ye`X0R|z}gU}?+r+TtNPU>N6w1W1h$y@N@6Qbr}=en@R za88m|)=nl2>zo_pCx$c4aL^fWJ+xuCaw3$S{(+pUhd85$beqd0YV^}cCg!v8cXN&u z|5N~9kdDG{&ICtvHr9GrS0i3OhK`}6I8tj!oLIsN0h{UklR7#T${yFtif+uS1^uX! z*9)3rEtEB-U$H&IhNb!=NR9qknRV2Eb z$t5Y{5cyz{LI;IT3N#4ZN8w3c9QAHX+DS_@Oub~_0rFmpsjOPFuuJasyg*o{OwxY? z-StJ_tULiRcR0S{i+-~A_WHr)^@BHjgLnO*O1S5$e$&76jz4-o(gy#^8!6A)eP*tpViP|r0$+!6OfPuC1Fkbv=QM>kVKn@ntJ;R==zRnH z7ml{jI$^TsWZ`u3w=rwgp{2xa6xyLTGR2GoM81Kkk7!Q|&Bi=M2BcQg{zY*m5W5{nEeBFJ0$UcH zE3iGbqoI=6cD<>RnOpYFSLFFs;V?jKJF^16#-@Y-YTvdNzP7b_W1Xv;y4yqHE6BI> zw9!2}gVs2XSJpgnzIiRpH1Y9&`U?yn$1y6`Kp+{yJK(35_l0wm^ES-3#>3xHvMLcK dlr6qkEFGOIXxs6R@KNhluf;O)HAJy0^gov;dF%iH delta 1648 zcmZ8hO>7fK6rQ#B$Lrm!Z5+q3apDQYNt}>`q@)r_LkNi}l>8u@C4{8F%Go4V?X{WR zkdPkuQCkI3iNL7hM@UdqRjPU@6%wjcRqCNFtyHO@jat`m;LzSf+8)|VJ7Z&@?BUxt z?|tvR*|*=!jlthy${!UKPC%aKd+n)*HJ>U&w)!0d-IHTk^v2|%enL-Ya~a*RCifc2 zY(_tzEhJ8wmY%`qY-gDdux$SwCImxh2ZlqnC2ZaE0BBVJs6xWgS^I^cr(|!9mHiwFA@U1$zVlvY#gyjuhT+8x{ee9Mfh$J+XKUcJy{E zDzJZK5T4XE1bbn`Tyz!Jrlrm3MMpt+Rky}TII7@}xsEWe<#M_)RS@(AJvnFT1;?~* zC1J^F76A z!+p8oSv0aLLsCa{T~N*`%X6!aNInq05xyG!DbT#czN@V9xK%K?uUty30^bz;%o6@g z*v&xvuW+^ZCQ*Vzbxb@Raaq!yiW|dRk17`!&$6A=y+E2;(HEnqeML6XDMY%eO^;+ypHND%pbaT=&mZX zbLDyv4Bsk=MzzN`mqfzGBPGLLG6rUZ86oOe>>0|=z&TS#P)k~=tYO0Wlr;;jR7NK{ z$mF&ZgIk_N$=jHMQ@W+4(qJrwAG z5F}7wX<5`q&0>d~X3Z8veZkTVlYA6DBfae2Nus7m&i85XCl4w^_-kq0=k;HI^Otb% z{c!J(-rip;LnIPv!DDg*u9bsrRFb~S;zjXF)2e&(nj3ihmt7ZKD{$-WJ>QBe<40CH zkNxb{9!Ef+cC872C~so6-}z47Dl+)aKfdp6FC|D%bbx|N;UIx1SCIB=$Vw&W(i$?+ zixm8KwaRSAqk$f2iRQdT;cfh0;F?sNXgys=aCb0NM~8&SWkHTxirjW)X*6_>XbXjA zJRh874&&9}7+;zn?%24mwK%{|n#Q8+yop|?+@o|Yk;D0PV~45x2>xi}xVVj&W-S5i z2~}el;&C+8CCyOpDe|vR1NYEHhNu=TMN0$Wb_5Kin&3`bi9(uPR*tD9q1eU Qux^`c#Lk4*0mUNeKlP=K5C8xG diff --git a/main.py b/main.py index 1b193d3..b6c143d 100644 --- a/main.py +++ b/main.py @@ -5,22 +5,19 @@ import pymysql import io import mysql.connector from werkzeug.utils import secure_filename -from AppCode.FileHandler import FileHandler -from AppCode.DocumentHandler import DocumentHandler from config import db_config from AppCode.Config import DBConfig - +from AppCode.FileHandler import FileHandler +from AppCode.DocumentHandler import DocumentHandler from AppCode.ITRHandler import ITRHandler from AppCode.AOHandler import AOHandler from AppCode.CITHandler import CITHandler from AppCode.ITATHandler import ITATHandler - from AppCode.YearGet import YearGet - app = Flask(__name__) app.secret_key="secret1234" app.config['UPLOAD_FOLDER'] = FileHandler.UPLOAD_FOLDER @@ -49,7 +46,7 @@ def upload_file(): docHandler.Upload(request=request) return redirect(url_for('view_documents')) return render_template('upload.html') - + # View all documents with filters @app.route('/documents') @@ -84,42 +81,6 @@ def uploaded_file(filename): -# @app.route('/itr', methods=['GET', 'POST']) -# def itr_form(): -# if request.method == 'POST': -# data = {key: request.form.get(key, 0) for key in request.form} -# conn = mysql.connector.connect(**db_config) -# cursor = conn.cursor() -# query = """ -# INSERT INTO itr ( -# year, 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, tax_on_assessment, refund -# ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) -# """ -# values = tuple([ -# int(data.get('year', 0)) -# ] + [ -# float(data.get(col, 0)) for col in [ -# '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', 'tax_on_assessment', 'refund' -# ] -# ]) -# cursor.execute(query, values) -# conn.commit() -# flash("ITR record deleted successfully!", "success") -# cursor.close() -# conn.close() -# return redirect(url_for('index')) -# return render_template('itr_form.html') - ## =============================================== ## ITR (Income Tax Return) Routes ## =============================================== @@ -173,44 +134,6 @@ def update_itr(id): -## 3. UPDATE an existing ITR record -# @app.route('/itr/update/', methods=['GET', 'POST']) -# def update_itr(id): -# conn = get_db_connection() - -# if request.method == 'POST': -# cursor = conn.cursor() -# columns = [ -# 'year', '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', 'tax_on_assessment', 'refund' -# ] - -# # Create the "SET column = %s" part of the query -# set_clause = ', '.join([f"{col} = %s" for col in columns]) -# query = f"UPDATE itr SET {set_clause} WHERE id = %s" - -# values = [request.form.get(col, 0) for col in columns] -# values.append(id) # Add the ID for the WHERE clause at the end - -# cursor.execute(query, tuple(values)) -# conn.commit() -# cursor.close() -# conn.close() -# return redirect(url_for('display_itr')) - -# # For a GET request, fetch the existing data and show it in the form -# cursor = conn.cursor(dictionary=True) -# cursor.execute("SELECT * FROM itr WHERE id = %s", (id,)) -# record = cursor.fetchone() -# cursor.close() -# conn.close() -# return render_template('update_itr.html', record=record) - - ## =============================================== ## AO (Assessing Officer) Routes @@ -267,47 +190,6 @@ def delete_ao(id): - -# 3. UPDATE AO record -# @app.route('/ao/update/', methods=['GET', 'POST']) -# def update_ao(id): -# conn = get_db_connection() -# cursor = conn.cursor(dictionary=True) -# cursor.execute("SELECT * FROM ao WHERE id = %s", (id,)) -# ao_record = cursor.fetchone() - -# if not ao_record: -# cursor.close() -# conn.close() -# return "AO record not found", 404 - -# if request.method == 'POST': -# columns = [ -# 'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37', -# 'deduction_80ia_business', 'deduction_sec37_disallowance', 'deduction_80g', -# 'net_taxable_income', 'tax_30_percent', 'tax_book_profit_18_5', -# 'surcharge_12', 'edu_cess_3', 'total_tax_payable', 'mat_credit', -# 'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs', -# 'tax_on_assessment', 'refund' -# ] -# values = [request.form.get(col, 0) for col in columns] -# set_clause = ", ".join([f"{col}=%s" for col in columns]) -# query = f"UPDATE ao SET {set_clause} WHERE id=%s" -# cursor.execute(query, tuple(values) + (id,)) -# conn.commit() -# cursor.close() -# conn.close() -# flash("AO record updated successfully!", "success") -# return redirect(url_for('display_ao')) - -# cursor.close() -# conn.close() -# return render_template('update_ao.html', record=ao_record) - - - - - ## ======================================================= ## CIT (Commissioner of Income Tax) Routes ## ======================================================= @@ -360,94 +242,6 @@ def update_cit(id): return render_template('update_cit.html', record=record) - -# @app.route('/cit/update/', methods=['GET', 'POST']) -# def update_cit(id): - conn = get_db_connection() - cursor = conn.cursor(dictionary=True) - cursor.execute("SELECT * FROM cit WHERE id=%s", (id,)) - record = cursor.fetchone() - if not record: - cursor.close() - conn.close() - return "CIT record not found", 404 - - if request.method == 'POST': - columns = [ - "year", "gross_total_income", "deduction_80ia_business", "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", "tax_on_assessment", "refund" - ] - values = [request.form.get(col, 0) for col in columns] - set_clause = ", ".join([f"{col}=%s" for col in columns]) - query = f"UPDATE cit SET {set_clause} WHERE id=%s" - cursor.execute(query, tuple(values)+(id,)) - conn.commit() - cursor.close() - conn.close() - return redirect(url_for('display_cit')) - - cursor.close() - conn.close() - return render_template('add_cit.html', record=record) - -# DISPLAY all CIT records -# @app.route('/cit_records') -# def display_cit(): -# conn = get_db_connection() -# cursor = conn.cursor(dictionary=True) -# cursor.execute("SELECT * FROM cit ORDER BY year DESC, id DESC") -# cit_records = cursor.fetchall() -# cursor.close() -# conn.close() -# return render_template('display_cit.html', cit_records=cit_records) - - -# ADD a new CIT record -# @app.route('/cit/add', methods=['GET', 'POST']) -# def add_cit(): -# if request.method == 'POST': -# conn = get_db_connection() -# cursor = conn.cursor() - -# columns = [ -# "year", "gross_total_income", "deduction_80ia_business", "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", "tax_on_assessment", "refund" -# ] - -# values = [request.form.get(col, 0) for col in columns] -# query = f"INSERT INTO cit ({', '.join(columns)}) VALUES ({', '.join(['%s']*len(columns))})" -# cursor.execute(query, tuple(values)) -# conn.commit() -# flash("ITAT record added successfully!", "success") -# cursor.close() -# conn.close() -# return redirect(url_for('display_cit')) - -# return render_template('add_cit.html') - - - -# @app.route('/cit/delete/', methods=['POST']) -# def delete_cit(id): -# try: -# conn = get_db_connection() -# cursor = conn.cursor() -# cursor.execute("DELETE FROM cit WHERE id=%s", (id,)) -# conn.commit() -# flash("ITR record deleted successfully!", "success") -# except Exception as err: -# print(f"Error deleting CIT record: {err}") -# finally: -# cursor.close() -# conn.close() -# return redirect(url_for('display_cit')) - - - ## ======================================================= ## ITAT (Income Tax Appellate Tribunal) Routes ## ======================================================= @@ -460,32 +254,6 @@ def display_itat(): itat.close() return render_template('display_itat.html', records=records) -# ADD a new ITAT record -# @app.route('/itat/add', methods=['GET', 'POST']) -# def add_itat(): -# cit = CITHandler() -# cit_records = cit.get_all_cit() -# cit.close() - -# if request.method == 'POST': -# data = { -# "cit_id": request.form.get("cit_id"), -# "year": request.form.get("year"), -# "mat_tax_credit": request.form.get("mat_tax_credit"), -# "surcharge": request.form.get("surcharge"), -# "cess": request.form.get("cess"), -# "total_credit": request.form.get("total_credit") -# } - -# itat = ITATHandler() -# itat.add_itat(data) -# itat.close() - -# flash("ITAT Record Added Successfully!", "success") -# return redirect(url_for('display_itat')) - -# return render_template('add_itat.html', cit_records=cit_records) - @app.route('/itat/delete/', methods=['POST']) def delete_itat(id): @@ -523,56 +291,6 @@ def update_itat(id): return render_template('update_itat.html', record=record) - - -# DISPLAY all ITAT records -# @app.route('/itat_records') -# def display_itat(): -# conn = get_db_connection() -# cursor = conn.cursor(dictionary=True) -# # Querying the 'itat' table -# cursor.execute("SELECT * FROM itat ORDER BY year DESC, id DESC") -# records = cursor.fetchall() -# cursor.close() -# conn.close() -# # Rendering the 'display_itat.html' template -# return render_template('display_itat.html', records=records) - - -# ADD a new ITAT record -# @app.route('/itat/add', methods=['GET', 'POST']) -# def add_itat(): -# conn = get_db_connection() -# cursor = conn.cursor(dictionary=True) - -# # Fetch all CIT records to choose from -# cursor.execute("SELECT id, year FROM cit ORDER BY year DESC") -# cit_records = cursor.fetchall() - -# if request.method == 'POST': -# cit_id = request.form.get('cit_id') # selected parent CIT id -# columns = ['id', 'year','mat_tax_credit', 'surcharge', 'cess', 'total_credit'] -# values = [cit_id, -# request.form.get('year', 0), -# request.form.get('mat_tax_credit', 0), -# request.form.get('surcharge', 0), -# request.form.get('cess', 0), -# request.form.get('total_credit', 0)] -# query = f"INSERT INTO itat ({', '.join(columns)}) VALUES ({', '.join(['%s'] * len(columns))})" -# cursor.execute(query, tuple(values)) -# conn.commit() -# cursor.close() -# conn.close() -# flash("ITAT record added successfully!", "success") -# return redirect(url_for('display_itat')) - -# cursor.close() -# conn.close() -# return render_template('add_itat.html', cit_records=cit_records) - - - - @app.route('/itat/add', methods=['GET', 'POST']) def add_itat(): itat = ITATHandler() @@ -588,129 +306,7 @@ def add_itat(): return render_template('add_itat.html') -# @app.route('/itat/update/', methods=['GET', 'POST']) -# def update_itat(id): -# conn = get_db_connection() -# cursor = conn.cursor(dictionary=True) - -# # Fetch the existing record -# cursor.execute("SELECT * FROM itat WHERE id=%s", (id,)) -# record = cursor.fetchone() - -# if not record: -# cursor.close() -# conn.close() -# flash("ITAT record not found!", "danger") -# return redirect(url_for('display_itat')) - -# if request.method == 'POST': -# columns = ['year', 'mat_tax_credit', 'surcharge', 'cess', 'total_credit'] -# values = [request.form.get(col, 0) for col in columns] -# set_clause = ", ".join([f"{col}=%s" for col in columns]) -# query = f"UPDATE itat SET {set_clause} WHERE id=%s" -# cursor.execute(query, tuple(values) + (id,)) -# conn.commit() -# cursor.close() -# conn.close() -# flash("ITAT record updated successfully!", "success") -# return redirect(url_for('display_itat')) - -# cursor.close() -# conn.close() -# # Render a template with existing values filled in -# return render_template('update_itat.html', record=record) - - -# @app.route('/itat/delete/', methods=['POST']) -# def delete_itat(id): -# try: -# conn = get_db_connection() -# cursor = conn.cursor() -# cursor.execute("DELETE FROM itat WHERE id=%s", (id,)) -# conn.commit() -# flash("ITAT record deleted successfully!", "success") -# except Exception as err: -# flash(f"Error deleting ITAT: {err}", "danger") -# finally: -# cursor.close() -# conn.close() -# return redirect(url_for('display_itat')) - - -# -------------------- i dont use ------------------------- -# @app.route('/cit', methods=['GET', 'POST']) -# def cit_form(): - if request.method == 'POST': - data = {key: request.form.get(key, 0) for key in request.form} - conn = mysql.connector.connect(**db_config) - cursor = conn.cursor() - - query = """ - INSERT INTO cit ( - year, gross_total_income, deduction_80ia_business, 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, tax_on_assessment, refund - ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) - """ - - values = ( - data.get('year'), # Include 'year' as the first value - float(data.get('gross_total_income', 0)), - float(data.get('deduction_80ia_business', 0)), - float(data.get('deduction_sec37_disallowance', 0)), - float(data.get('deduction_80g', 0)), - float(data.get('net_taxable_income', 0)), - float(data.get('tax_30_percent', 0)), - float(data.get('tax_book_profit_18_5', 0)), - float(data.get('tax_payable', 0)), - float(data.get('surcharge_12', 0)), - float(data.get('edu_cess_3', 0)), - float(data.get('total_tax_payable', 0)), - float(data.get('mat_credit', 0)), - float(data.get('interest_234c', 0)), - float(data.get('total_tax', 0)), - float(data.get('advance_tax', 0)), - float(data.get('tds', 0)), - float(data.get('tcs', 0)), - float(data.get('tax_on_assessment', 0)), - float(data.get('refund', 0)) - ) - - cursor.execute(query, values) - conn.commit() - cursor.close() - conn.close() - return redirect(url_for('index')) - - return render_template('cit_form.html') - -# -------------------- i dont use ------------------------- -# @app.route('/itat', methods=['GET', 'POST']) -# def itat_form(): -# if request.method == 'POST': -# mat_tax_credit = request.form['mat_tax_credit'] -# surcharge = request.form['surcharge'] -# cess = request.form['cess'] -# total_credit = request.form['total_credit'] -# year=request.form['year'] -# conn = mysql.connector.connect(**db_config) -# cursor = conn.cursor() -# cursor.execute(""" -# INSERT INTO itat (year, mat_tax_credit, surcharge, cess, total_credit) -# VALUES (%s,%s, %s, %s, %s) -# """, (year,mat_tax_credit, surcharge, cess, total_credit)) -# conn.commit() -# cursor.close() -# conn.close() -# return redirect(url_for('index')) -# return render_template('itat_form.html') - - -# def get_db_connection(): -# connection = mysql.connector.connect(**db_config) -# return connection - +# report form @app.route('/reports') def reports(): return render_template("reports.html") @@ -796,6 +392,7 @@ def cit_report(): return render_template("cit_reports.html", years=years) + # Itat report download by year @app.route('/itat_report', methods=['GET']) def itat_report(): @@ -825,300 +422,6 @@ def itat_report(): return render_template("itat_reports.html", years=years) -# @app.route('/itr/reports', methods=['GET', 'POST']) -# def itr_reports(): -# yearGetter = YearGet() - -# if request.method == "POST": -# selected_year = request.form.get("year") -# itr=ITRHandler() - - -# yearGetter.close() -# return redirect(url_for("itr_report_result", year=selected_year)) - -# # GET method → fetch all distinct years through procedure -# years = yearGetter.get_year_by_model("GetITRYears") -# yearGetter.close() - -# print("---- year --",years) - -# return render_template("itr_reports.html", years=years) - - -# @app.route('/ao_report', methods=['GET']) -# def ao_report(): -# selected_year = request.args.get('year') -# connection = pymysql.connect(**db_config) - -# try: -# if selected_year: -# query = "SELECT * FROM ao WHERE year = %s" -# df = pd.read_sql(query, connection, params=[selected_year]) - -# if df.empty: -# return "No records found for the selected year." - -# # Transpose the DataFrame: rows → fields, columns → records -# df_transposed = df.transpose() -# df_transposed.insert(0, 'Field', df_transposed.index) - -# # Rename columns to "Record 1", "Record 2", ... -# for i in range(1, df_transposed.shape[1]): -# df_transposed.rename(columns={df_transposed.columns[i]: f"Record {i}"}, inplace=True) - -# df_transposed.reset_index(drop=True, inplace=True) - -# output = io.BytesIO() -# with pd.ExcelWriter(output, engine='xlsxwriter') as writer: -# df_transposed.to_excel(writer, index=False, sheet_name='AO_Vertical') - -# # Optional: Adjust formatting -# workbook = writer.book -# worksheet = writer.sheets['AO_Vertical'] -# worksheet.set_column(0, 0, 30) # Widen 'Field' column - -# output.seek(0) -# return send_file( -# output, -# mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', -# as_attachment=True, -# download_name=f"AO_Report_{selected_year}.xlsx" -# ) -# else: -# with connection.cursor() as cursor: -# cursor.execute("SELECT DISTINCT year FROM ao ORDER BY year DESC") -# years = [row[0] for row in cursor.fetchall()] -# return render_template("ao_reports.html", years=years) -# finally: -# connection.close() - - -# @app.route('/cit_report', methods=['GET']) -# def cit_report(): -# selected_year = request.args.get('year') -# connection = pymysql.connect(**db_config) - -# try: -# if selected_year: -# # Fetch data from the `cit` table for the selected year -# query = "SELECT * FROM cit WHERE year = %s" -# df = pd.read_sql(query, connection, params=[selected_year]) - -# output = io.BytesIO() -# with pd.ExcelWriter(output, engine='xlsxwriter') as writer: -# workbook = writer.book - -# # Write each row vertically on a separate sheet or below one another -# for i, (_, row) in enumerate(df.iterrows(), start=1): -# # Convert the row to vertical format -# vertical_df = pd.DataFrame(row).reset_index() -# vertical_df.columns = ['Field', 'Value'] - -# # Write each vertical entry below the previous (e.g., block by block) -# start_row = (i - 1) * (len(vertical_df) + 3) # 3-row gap between entries -# vertical_df.to_excel(writer, sheet_name='CIT_Report', index=False, startrow=start_row) - -# output.seek(0) - -# return send_file( -# output, -# mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', -# as_attachment=True, -# download_name=f"CIT_Report_{selected_year}_Vertical.xlsx" -# ) -# else: -# # Render dropdown for year selection -# with connection.cursor() as cursor: -# cursor.execute("SELECT DISTINCT year FROM cit ORDER BY year DESC") -# years = [row[0] for row in cursor.fetchall()] -# return render_template("cit_reports.html", years=years) -# finally: -# connection.close() - -# @app.route('/itat_report', methods=['GET']) -# def itat_report(): -# selected_year = request.args.get('year') -# connection = pymysql.connect(**db_config) - -# try: -# if selected_year: -# query = "SELECT * FROM itat WHERE year = %s" -# df = pd.read_sql(query, connection, params=[selected_year]) - -# output = io.BytesIO() -# with pd.ExcelWriter(output, engine='xlsxwriter') as writer: -# df.T.to_excel(writer, header=False, sheet_name='ITAT_Report') -# output.seek(0) - -# return send_file( -# output, -# mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', -# as_attachment=True, -# download_name=f"ITAT_Report_{selected_year}_Vertical.xlsx" -# ) -# else: -# with connection.cursor() as cursor: -# cursor.execute("SELECT DISTINCT year FROM itat ORDER BY year DESC") -# years = [row[0] for row in cursor.fetchall()] -# return render_template("itat_reports.html", years=years) -# finally: -# connection.close() - - -# @app.route('/itr_report_download', methods=['GET']) -# def itr_report_download(): -# connection = pymysql.connect(**db_config) -# try: -# selected_year = request.args.get('year') - -# if selected_year: -# query = "SELECT * FROM itr WHERE year = %s" -# df = pd.read_sql(query, connection, params=[selected_year]) - -# output = io.BytesIO() -# with pd.ExcelWriter(output, engine='xlsxwriter') as writer: -# df.to_excel(writer, index=False, sheet_name=f"ITR {selected_year}") -# output.seek(0) - -# return send_file( -# output, -# download_name=f"ITR_Report_{selected_year}.xlsx", -# as_attachment=True, -# mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' -# ) -# else: -# # If no year is selected, show dropdown -# with connection.cursor() as cursor: -# cursor.execute("SELECT DISTINCT year FROM itr ORDER BY year DESC") -# years = [row[0] for row in cursor.fetchall()] -# return render_template('itr_reports.html', years=years) -# finally: -# connection.close() - -# -------------------- i dont use ------------------------- -# @app.route('/download/') -# def download_report(doc_id): -# conn = get_db_connection() -# cursor = conn.cursor(dictionary=True) - -# cursor.execute("SELECT * FROM documents WHERE id = %s", (doc_id,)) -# document = cursor.fetchone() -# conn.close() - -# if not document: -# return "Document not found", 404 - -# file_path = os.path.join('static', 'uploads', document['filename']) # adjust as per your storage -# return send_from_directory(directory='static/uploads', path=document['filename'], as_attachment=True) - - -# @app.route('/summary_report', methods=['GET']) -# def summary_report(): -# year = request.args.get('year') - -# if not year: -# connection = pymysql.connect(**db_config) -# try: -# years = set() -# for table in ['itr', 'ao', 'cit', 'itat']: -# df = pd.read_sql(f"SELECT DISTINCT year FROM {table}", connection) -# years.update(int(y) for y in df['year'].dropna().tolist()) - -# return render_template('summary_reports.html', years=sorted(years), message="Please select a year to download.") - -# finally: -# connection.close() - -# connection = pymysql.connect(**db_config) -# try: -# stages = ['itr', 'ao', 'cit', 'itat'] -# stage_data = {} - -# for stage in stages: -# query = f"SELECT * FROM {stage} WHERE year = %s" -# df = pd.read_sql(query, connection, params=[year]) -# stage_data[stage.upper()] = df - -# 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", "Less: Deduction u/s 80G", "Net Taxable Income", "Tax @ 30%", -# "Tax @ 18.5% on Book Profit", "Surcharge @ 12%", "Education Cess @ 3%", "Total Tax Payable", -# "Less: MAT Credit", "Net Tax", "Add: Interest u/s 234C", "Total Tax", -# "Advance Tax", "TDS", "TCS", "SAT", "Tax on Regular Assessment", "Refund" -# ] - -# columns = [ -# 'gross_total_income', 'disallowance_14a', 'disallowance_37', 'gti', -# 'deduction_80ia', 'deduction_80g', 'net_taxable_income', 'tax_30', -# 'book_profit_tax', 'surcharge_12', 'education_cess', 'total_tax', -# 'mat_credit', 'net_tax', 'interest_234c', 'total_tax_payable', -# 'advance_tax', 'tds', 'tcs', 'sat', 'tax_regular', 'refund' -# ] - -# 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(A)": [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) - -# # Export to Excel with formatting -# output = io.BytesIO() -# with pd.ExcelWriter(output, engine='xlsxwriter') as writer: -# df.to_excel(writer, index=False, sheet_name=f'AY {year}') -# workbook = writer.book -# worksheet = writer.sheets[f'AY {year}'] - -# # Format definitions -# header_format = workbook.add_format({ -# 'bold': True, -# 'text_wrap': True, -# 'valign': 'middle', -# 'align': 'center', -# 'bg_color': '#007bff', -# 'font_color': 'white', -# 'border': 1 -# }) - -# cell_format = workbook.add_format({ -# 'border': 1, -# 'valign': 'top', -# 'align': 'center', -# }) - -# # Apply formats -# for col_num, value in enumerate(df.columns): -# worksheet.write(0, col_num, value, header_format) -# # Auto column width -# max_len = max(df[value].astype(str).map(len).max(), len(str(value))) + 2 -# worksheet.set_column(col_num, col_num, max_len) - -# # Format data rows -# for row_num in range(1, len(df) + 1): -# for col_num in range(len(df.columns)): -# worksheet.write(row_num, col_num, df.iloc[row_num - 1, col_num], cell_format) - -# output.seek(0) - -# return send_file( -# output, -# mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', -# as_attachment=True, -# download_name=f"Summary_Report_{year}.xlsx" -# ) - -# finally: -# connection.close() - - @app.route('/summary_report', methods=['GET']) def summary_report(): docHandler = DocumentHandler() diff --git a/static/uploads/AY_18-19_REfund_Working.xlsx b/static/uploads/AY_18-19_REfund_Working.xlsx index 920631b60b2107630bd4021f3dedea6e037b3f7b..41a6ff994c41edf22d03e1d1f4804a85c5af7e9f 100644 GIT binary patch delta 16833 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 diff --git a/test.py b/test.py deleted file mode 100644 index f9cd8a6..0000000 --- a/test.py +++ /dev/null @@ -1,223 +0,0 @@ -import os -from AppCode.Config import DBConfig -from AppCode.FileHandler import FileHandler -from werkzeug.utils import secure_filename - -class DocumentHandler: - - years = "" - documents = "" - isSuccess = False - resultMessage = "" - - 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() - - params = [] - query = "SELECT * FROM documents WHERE 1=1" - - if year: - query += " AND year = %s" - params.append(year) - if stage: - query += " AND stage = %s" - params.append(stage) - - - cursor.execute(query, params) - documentsdata = cursor.fetchall() - print("*************") - print(documentsdata) - cursor.callproc("GetYear") - - # records = [] - # for result in cursor.stored_results(): - # records = result.fetchall() - - yearsdata = "" - for res in cursor.stored_results(): - yearsdata = res.fetchall() - print(yearsdata) - - self.years = yearsdata - self.documents = documentsdata - self.isSuccess = True - - print("document --",documentsdata) - - cursor.close() - connection.close() - - - def Upload(self, request): - """Log user actions with timestamp, user, action, and details.""" - - 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: - if file is not FileHandler.ALLOWED_EXTENSIONS: - continue - - - filename = secure_filename(file.filename) - filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename) - extension = file.filename.rsplit('.', 1)[1] - # Need to Check whetehr all three items are required - - file.save(filepath) - - # cursor.execute(""" - # INSERT INTO documents (filename, filepath, filetype, year, stage) - # VALUES (%s, %s, %s, %s, %s) - # """, (filename, filepath, file.filename.rsplit('.', 1)[1], year, stage)) - - - cursor.callproc('InsertDocument', [ - filename, - filepath, - extension, - year, - stage - ]) - - connection.commit() - cursor.close() - connection.close() - # return redirect(url_for('view_documents')) - - #return render_template('upload.html') - - - - - - - -# old itr report code -@app.route('/itr_report', methods=['GET']) -def itr_report(): - yearGetter = YearGet() - - connection = pymysql.connect(**db_config) - try: - selected_year = request.args.get('year') - - if selected_year: - # Fetch ITR data for the selected year - query = "SELECT * FROM itr WHERE year = %s" - df = pd.read_sql(query, connection, params=[selected_year]) - - if df.empty: - return "No records found for the selected year." - - # Transpose DataFrame: vertical fields, horizontal records - df_transposed = df.transpose() - df_transposed.insert(0, 'Field', df_transposed.index) - - # Rename columns as Record 1, Record 2, etc. - record_cols = {i: f'Record {i}' for i in df_transposed.columns if isinstance(i, int)} - df_transposed.rename(columns=record_cols, inplace=True) - df_transposed.reset_index(drop=True, inplace=True) - - output = io.BytesIO() - with pd.ExcelWriter(output, engine='xlsxwriter') as writer: - df_transposed.to_excel(writer, index=False, sheet_name='ITR_Vertical') - - # Format for better readability (optional) - workbook = writer.book - worksheet = writer.sheets['ITR_Vertical'] - worksheet.set_column(0, 0, 30) # Field column wider - - output.seek(0) - return send_file( - output, - mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - as_attachment=True, - download_name=f"ITR_Report_{selected_year}.xlsx" - ) - - else: - # Render dropdown form with available years - with connection.cursor() as cursor: - cursor.execute("SELECT DISTINCT year FROM itr ORDER BY year DESC") - years = [row[0] for row in cursor.fetchall()] - return render_template("itr_reports.html", years=years) - - finally: - connection.close() - - - -# --------------\ - -@app.route('/itr_report', methods=['GET']) -def itr_report(): - yearGetter = YearGet() - - - selected_year = request.args.get('year') - - if selected_year: - # Fetch ITR data for the selected year - query = "SELECT * FROM itr WHERE year = %s" - df = pd.read_sql(query, connection, params=[selected_year]) - - if df.empty: - return "No records found for the selected year." - - - - # Transpose DataFrame: vertical fields, horizontal records - df_transposed = df.transpose() - df_transposed.insert(0, 'Field', df_transposed.index) - - # Rename columns as Record 1, Record 2, etc. - record_cols = {i: f'Record {i}' for i in df_transposed.columns if isinstance(i, int)} - df_transposed.rename(columns=record_cols, inplace=True) - df_transposed.reset_index(drop=True, inplace=True) - - output = io.BytesIO() - with pd.ExcelWriter(output, engine='xlsxwriter') as writer: - df_transposed.to_excel(writer, index=False, sheet_name='ITR_Vertical') - - # Format for better readability (optional) - workbook = writer.book - worksheet = writer.sheets['ITR_Vertical'] - worksheet.set_column(0, 0, 30) # Field column wider - - output.seek(0) - return send_file( - output, - mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - as_attachment=True, - download_name=f"ITR_Report_{selected_year}.xlsx" - ) - - else: - # Render dropdown form with available years - with connection.cursor() as cursor: - # cursor.execute("SELECT DISTINCT year FROM itr ORDER BY year DESC") - # years = [row[0] for row in cursor.fetchall()] - - years = yearGetter.get_year_by_model("GetITRYears") - yearGetter.close() - - print("---- year --",years) - - - return render_template("itr_reports.html", years=years)