Files
IncomeTaxSystem/main.py

550 lines
15 KiB
Python
Raw Normal View History

from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort, flash,send_file ,jsonify
2025-09-18 11:33:28 +05:30
import os
2026-01-21 22:59:36 +05:30
from dotenv import load_dotenv
load_dotenv()
import pandas as pd
2025-09-18 11:33:28 +05:30
from werkzeug.utils import secure_filename
from AppCode.Config import DBConfig
from AppCode.LoginAuth import LoginAuth
from AppCode.FileHandler import FileHandler
from AppCode.YearGet import YearGet
from AppCode.DocumentHandler import DocumentHandler
2025-11-30 16:24:49 +05:30
from AppCode.ITRHandler import ITRHandler
from AppCode.AOHandler import AOHandler
2025-12-01 12:04:07 +05:30
from AppCode.CITHandler import CITHandler
from AppCode.ITATHandler import ITATHandler
from AppCode.MatCreditHandler import MatCreditHandler
# Server
2025-09-18 11:33:28 +05:30
app = Flask(__name__)
2026-01-21 22:59:36 +05:30
app.secret_key=os.getenv("SECRET_KEY")
auth = LoginAuth()
app.register_blueprint(auth.bp)
2025-09-18 11:33:28 +05:30
2025-11-30 20:38:41 +05:30
# welcome page
2025-09-18 11:33:28 +05:30
@app.route('/')
@auth.login_required
2025-09-18 11:33:28 +05:30
def welcome():
return render_template('index.html')
2025-11-30 20:38:41 +05:30
# Dashboard page
2025-09-18 11:33:28 +05:30
@app.route('/dashboard')
@auth.login_required
2025-09-18 11:33:28 +05:30
def index():
2025-11-30 20:38:41 +05:30
return render_template('index.html')
2025-09-18 11:33:28 +05:30
2026-01-21 22:59:36 +05:30
2025-11-30 20:38:41 +05:30
# Upload File route
2025-09-18 11:33:28 +05:30
@app.route('/upload', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def upload_file():
if request.method == 'POST':
2025-11-30 16:24:49 +05:30
FileHandler.CHeckExistingOrCreateNewUploadFolder()
docHandler = DocumentHandler()
docHandler.Upload(request=request)
2025-09-18 11:33:28 +05:30
return redirect(url_for('view_documents'))
return render_template('upload.html')
# View all documents with filters
2025-09-18 11:33:28 +05:30
@app.route('/documents')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def view_documents():
2025-11-30 16:24:49 +05:30
docHandler = DocumentHandler()
docHandler.View(request=request)
return render_template('view_docs.html', documents=docHandler.documents, years=docHandler.years)
2025-09-18 11:33:28 +05:30
2025-11-30 16:24:49 +05:30
# Upload file documents
2025-09-18 11:33:28 +05:30
@app.route('/uploads/<filename>')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def uploaded_file(filename):
mode = request.args.get('mode', 'view')
2026-01-21 22:59:36 +05:30
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, secure_filename(filename))
2025-09-18 11:33:28 +05:30
if not os.path.exists(filepath):
abort(404)
file_ext = filename.rsplit('.', 1)[-1].lower()
# --- View Mode ---
if mode == 'view':
if file_ext == 'pdf':
return send_file(filepath, mimetype='application/pdf')
elif file_ext in ['xls', 'xlsx']:
# Excel cannot be rendered in-browser by Flask; trigger download instead
return send_file(filepath, as_attachment=False, download_name=filename, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
else:
return abort(415) # Unsupported type for viewing
return send_file(filepath, as_attachment=True)
2025-11-30 20:38:41 +05:30
## ===============================================
## ITR (Income Tax Return) Routes
## ===============================================
## 1. READ/DISPLAY all ITR records
2025-11-30 16:24:49 +05:30
@app.route('/itr_records')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-11-30 16:24:49 +05:30
def display_itr():
itr = ITRHandler()
records = itr.get_all_itr()
itr.close()
return render_template('display_itr.html', records=records)
2025-11-30 20:38:41 +05:30
## 2. CREATE/ADD a new ITR record
2025-11-30 16:24:49 +05:30
@app.route('/itr/add', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-11-30 16:24:49 +05:30
def add_itr():
if request.method == 'POST':
itr = ITRHandler()
itr.add_itr(request.form)
itr.close()
flash("ITR record added successfully!", "success")
return redirect(url_for('display_itr'))
return render_template('add_itr.html')
2025-11-30 20:38:41 +05:30
## 4. DELETE an ITR record
2025-09-18 11:33:28 +05:30
@app.route('/itr/delete/<int:id>', methods=['POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def delete_itr(id):
2025-11-30 16:24:49 +05:30
itr = ITRHandler()
itr.delete_itr_by_id(id=id)
itr.close()
2025-09-18 11:33:28 +05:30
return redirect(url_for('display_itr'))
## 3. UPDATE an existing ITR record
@app.route('/itr/update/<int:id>', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def update_itr(id):
itr = ITRHandler()
if request.method == 'POST':
2026-01-22 13:39:14 +05:30
data = {k: request.form.get(k, 0) for k in request.form}
itr.update(id, data)
itr.close()
return redirect(url_for('display_itr'))
record = itr.get_itr_by_id(id)
itr.close()
return render_template('update_itr.html', record=record)
2025-09-18 11:33:28 +05:30
## ===============================================
## AO (Assessing Officer) Routes
## ===============================================
2025-11-30 20:38:41 +05:30
# 1. DISPLAY all AO records
2025-09-18 11:33:28 +05:30
@app.route('/ao_records')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def display_ao():
2025-11-30 16:24:49 +05:30
ao = AOHandler()
ao_records = ao.get_all_ao()
ao.close()
return render_template('display_ao.html', ao_records=ao_records)
2025-11-30 20:38:41 +05:30
# 2. ADD a new AO record
2025-09-18 11:33:28 +05:30
@app.route('/ao/add', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def add_ao():
if request.method == 'POST':
2025-11-30 20:38:41 +05:30
ao = AOHandler()
ao.add_ao(request.form)
ao.close()
2025-11-30 16:24:49 +05:30
flash("AO record added successfully!", "success")
2025-09-18 11:33:28 +05:30
return redirect(url_for('display_ao'))
return render_template('add_ao.html')
# 3. UPDATE AO record
@app.route('/ao/update/<int:id>', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def update_ao(id):
ao = AOHandler()
record = ao.get_ao_by_id(id)
if not record:
return "AO record not found", 404
if request.method == 'POST':
data = request.form.to_dict()
ao.update_ao(id, data)
ao.close()
flash("AO record updated successfully!", "success")
return redirect(url_for('display_ao'))
ao.close()
return render_template("update_ao.html", record=record)
2025-09-18 11:33:28 +05:30
2025-11-30 20:38:41 +05:30
# 4. DELETE AO record safely
@app.route('/ao/delete/<int:id>', methods=['POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-11-30 20:38:41 +05:30
def delete_ao(id):
ao = AOHandler()
ao.delete_ao_by_id(id=id)
ao.close()
flash("AO deleted successfully!", "success")
return redirect(url_for('display_ao'))
2025-11-30 16:24:49 +05:30
2025-11-30 20:38:41 +05:30
2025-09-18 11:33:28 +05:30
## =======================================================
## CIT (Commissioner of Income Tax) Routes
## =======================================================
# 1 DISPLAY all CIT records
2025-09-18 11:33:28 +05:30
@app.route('/cit_records')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def display_cit():
2025-12-01 12:04:07 +05:30
cit = CITHandler()
cit_records = cit.get_all_cit()
cit.close()
2025-11-30 16:24:49 +05:30
return render_template('display_cit.html', cit_records=cit_records)
# 2 new CIT records add
2025-09-18 11:33:28 +05:30
@app.route('/cit/add', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def add_cit():
if request.method == 'POST':
2025-12-01 12:04:07 +05:30
cit = CITHandler()
cit.add_cit(request.form)
cit.close()
flash("CIT record added successfully!", "success")
2025-09-18 11:33:28 +05:30
return redirect(url_for('display_cit'))
return render_template('add_cit.html')
# 3 delete CIT records by id
2025-12-01 12:04:07 +05:30
@app.route('/cit/delete/<int:id>', methods=['POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-12-01 12:04:07 +05:30
def delete_cit(id):
cit = CITHandler()
cit.delete_cit(id)
cit.close()
flash("CIT record deleted successfully!", "success")
return redirect(url_for('display_cit'))
# 4 update CIT records by id
@app.route('/cit/update/<int:id>', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def update_cit(id):
cit = CITHandler()
record = cit.get_cit_by_id(id)
2025-12-01 12:04:07 +05:30
if not record:
cit.close()
return "CIT record not found", 404
2025-12-01 12:04:07 +05:30
if request.method == 'POST':
2026-01-22 13:39:14 +05:30
data = {k: request.form.get(k, 0) for k in request.form}
cit.update_cit(id, data)
cit.close()
return redirect(url_for('display_cit'))
2025-12-01 12:04:07 +05:30
cit.close()
return render_template('update_cit.html', record=record)
2025-12-01 12:04:07 +05:30
2025-09-18 11:33:28 +05:30
## =======================================================
## ITAT (Income Tax Appellate Tribunal) Routes
## =======================================================
# 1.DISPLAY all ITAT records
2025-09-18 11:33:28 +05:30
@app.route('/itat_records')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def display_itat():
2025-12-01 12:04:07 +05:30
itat = ITATHandler()
records = itat.get_all_itat()
itat.close()
2025-09-18 11:33:28 +05:30
return render_template('display_itat.html', records=records)
# 2.Add new ITAT records
@app.route('/itat/add', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def add_itat():
if request.method == 'POST':
itat = ITATHandler()
2026-01-22 13:39:14 +05:30
data = {k: request.form.get(k, 0) for k in request.form}
itat.add_itat(data)
itat.close()
flash("ITAT record added successfully!", "success")
return redirect(url_for('display_itat'))
2025-12-01 12:04:07 +05:30
return render_template('add_itat.html')
# 3.Update ITAT records by id
2025-12-01 12:04:07 +05:30
@app.route('/itat/update/<int:id>', methods=['GET', 'POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-12-01 12:04:07 +05:30
def update_itat(id):
itat = ITATHandler()
record = itat.get_itat_by_id(id)
if not record:
flash("Record Not Found!", "danger")
return redirect(url_for('display_itat'))
if request.method == 'POST':
itat.update_itat(id, request.form)
2025-12-01 12:04:07 +05:30
itat.close()
flash("ITAT Record Updated!", "success")
return redirect(url_for('display_itat'))
itat.close()
return render_template('update_itat.html', record=record)
# 3.delete ITAT records by id
@app.route('/itat/delete/<int:id>', methods=['POST'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def delete_itat(id):
itat = ITATHandler()
itat.delete_itat_by_id(id)
itat.close()
flash("ITAT Record Deleted!", "success")
return redirect(url_for('display_itat'))
2025-09-18 11:33:28 +05:30
2025-11-30 16:24:49 +05:30
## =======================================================
## All Report Routes
## =======================================================
# report page
2025-09-18 11:33:28 +05:30
@app.route('/reports')
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def reports():
return render_template("reports.html")
# Itr report download by year
2025-09-18 11:33:28 +05:30
@app.route('/itr_report', methods=['GET'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-09-18 11:33:28 +05:30
def itr_report():
yearGetter = YearGet()
selected_year = request.args.get('year')
2025-09-18 11:33:28 +05:30
if selected_year:
itr = ITRHandler()
output = itr.itr_report_download(selected_year)
itr.close()
2025-09-18 11:33:28 +05:30
if output is None:
return "No records found for the selected year."
2025-09-18 11:33:28 +05:30
return send_file(
output,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
as_attachment=True,
download_name=f"ITR_Report_{selected_year}.xlsx"
)
2025-09-18 11:33:28 +05:30
else:
years = yearGetter.get_year_by_model("GetITRYears")
yearGetter.close()
return render_template("itr_reports.html", years=years)
2025-09-18 11:33:28 +05:30
# Ao report download by year
@app.route('/ao_report', methods=['GET'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def ao_report():
yearGetter = YearGet()
selected_year = request.args.get('year')
if selected_year:
ao = AOHandler()
output = ao.ao_report_download(selected_year)
ao.close()
if output is None:
return "No records found for the selected year."
return send_file(
output,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
as_attachment=True,
download_name=f"AO_Report_{selected_year}.xlsx"
)
else:
years = yearGetter.get_year_by_model("GetAOYears")
yearGetter.close()
return render_template("ao_reports.html", years=years)
# Cit report download by year
@app.route('/cit_report', methods=['GET'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def cit_report():
selected_year = request.args.get('year')
yearGetter = YearGet()
if selected_year:
cit = CITHandler()
output = cit.cit_report_download(selected_year)
cit.close()
if output is None:
return "No records found for the selected year."
return send_file(
output,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
as_attachment=True,
download_name=f"CIT_Report_{selected_year}_Vertical.xlsx"
)
else:
years = yearGetter.get_year_by_model("GetCITYears")
yearGetter.close()
return render_template("cit_reports.html", years=years)
# Itat report download by year
@app.route('/itat_report', methods=['GET'])
2026-01-21 22:59:36 +05:30
@auth.login_required
def itat_report():
selected_year = request.args.get('year')
yearGetter = YearGet()
if selected_year:
itat = ITATHandler()
output = itat.itat_report_download(selected_year)
itat.close()
if output is None:
return "No records found for the selected year."
return send_file(
output,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
as_attachment=True,
download_name=f"ITAT_Report_{selected_year}_Vertical.xlsx"
)
else:
# Use stored procedure for years
years = yearGetter.get_year_by_model("GetITATYears")
yearGetter.close()
return render_template("itat_reports.html", years=years)
# summary report
2025-12-02 15:38:19 +05:30
@app.route('/summary_report', methods=['GET'])
2026-01-21 22:59:36 +05:30
@auth.login_required
2025-12-02 15:38:19 +05:30
def summary_report():
docHandler = DocumentHandler()
return docHandler.Summary_report(request=request)
2025-09-18 11:33:28 +05:30
@app.route('/summary/download', methods=['GET'])
@auth.login_required
def download_summary():
year_raw = request.args.get('year')
if not year_raw:
return "Year parameter is required", 400
docHandler = DocumentHandler()
# reuse your existing Summary_report method
return docHandler.Summary_report(request=request)
2025-09-18 11:33:28 +05:30
2026-01-21 22:59:36 +05:30
# check year in table existe or not by using ajax calling.
# @app.route('/check_year', methods=['POST'])
# @auth.login_required
# def check_year():
# data = request.get_json()
# table_name = data.get("table")
# year = data.get("year")
2026-01-21 22:59:36 +05:30
# check_year_obj = YearGet()
# result = check_year_obj.CheckYearExists(table_name, year)
# check_year_obj.close()
2026-01-22 13:39:14 +05:30
# return result
2026-01-22 13:39:14 +05:30
@app.route('/check_year', methods=['POST'])
def check_year():
table_name = request.json.get("table")
year = request.json.get("year")
conn = DBConfig.get_db_connection()
cursor = conn.cursor()
sqlstr = f"SELECT COUNT(*) FROM {table_name} WHERE year = %s"
cursor.execute(sqlstr, (year,))
result = cursor.fetchone()[0]
cursor.close()
conn.close()
return {"exists": result > 0}
# Mat credit from
@app.route("/mat_credit", methods=["GET"])
2026-01-21 22:59:36 +05:30
@auth.login_required
def mat_credit():
mat = MatCreditHandler()
try:
mat_rows, utilization_rows = mat.fetch_all()
finally:
mat.close()
utilization_map = {}
all_years = set()
for u in utilization_rows:
all_years.add(u["utilized_year"])
utilization_map.setdefault(
u["mat_credit_id"], {}
)[u["utilized_year"]] = u["utilized_amount"]
return render_template(
"mat_credit.html",
mat_rows=mat_rows,
utilization_map=utilization_map,
added_years=sorted(all_years)
)
# save mat credit row data
@app.route("/save_mat_row", methods=["POST"])
2026-01-21 22:59:36 +05:30
@auth.login_required
def save_mat_row():
mat = MatCreditHandler()
try:
mat.save_single(request.json)
return jsonify({"message": "Row saved successfully"})
except Exception as e:
return jsonify({"error": str(e)}), 500
finally:
mat.close()
@app.route("/summary/preview")
def summary_preview_route():
handler = DocumentHandler()
return handler.Summary_preview(request)
# save mat credit bulk data
# @app.route("/save_mat_all", methods=["POST"])
# @auth.login_required
# def save_mat_all():
# mat= MatCreditHandler()
# try:
# skipped = mat.save_bulk(request.json)
# return jsonify({"message": "Saved successfully", "skipped": skipped})
# except Exception as e:
# return jsonify({"error": str(e)}), 500
2026-01-21 22:59:36 +05:30
# run server
2025-09-18 11:33:28 +05:30
if __name__ == '__main__':
2026-01-21 22:59:36 +05:30
app.run(
host=os.getenv("FLASK_HOST"),
port=int(os.getenv("FLASK_PORT")),
debug=os.getenv("FLASK_DEBUG") == "true"
)