commit 602c87148d39e2f4b4088e791aa15052097d28c8 Author: admin Date: Thu Sep 18 11:33:28 2025 +0530 Initial commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/New folder.iml b/.idea/New folder.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/New folder.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..99e1656 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..228e855 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ed380a0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/__pycache__/config.cpython-313.pyc b/__pycache__/config.cpython-313.pyc new file mode 100644 index 0000000..f6387b5 Binary files /dev/null and b/__pycache__/config.cpython-313.pyc differ diff --git a/config.py b/config.py new file mode 100644 index 0000000..e80fc75 --- /dev/null +++ b/config.py @@ -0,0 +1,7 @@ +db_config = { + 'host': 'localhost', + 'user': 'root', + 'password': 'admin', + 'database': 'income_tax', + 'port': 3306 +} diff --git a/js/App.js b/js/App.js new file mode 100644 index 0000000..5908412 --- /dev/null +++ b/js/App.js @@ -0,0 +1,13 @@ +import React from 'react'; +import FormPage from './components/FormPage'; + +function App() { + return ( +
+

Income Tax Entry Form

+ +
+ ); +} + +export default App; diff --git a/js/FormPage.js b/js/FormPage.js new file mode 100644 index 0000000..ca680bd --- /dev/null +++ b/js/FormPage.js @@ -0,0 +1,50 @@ +import React, { useState } from 'react'; +import axios from 'axios'; + +const FormPage = ({ table }) => { + const [formData, setFormData] = useState({ + gross_total_income: '', + net_taxable_income: '', + tax_payable: '', + total_tax_payable: '', + refund: '' + }); + + const handleChange = e => { + setFormData({ ...formData, [e.target.name]: e.target.value }); + }; + + const handleSubmit = async e => { + e.preventDefault(); + await axios.post(`http://localhost:5000/add/${table}`, formData); + alert('Entry saved'); + setFormData({ + gross_total_income: '', + net_taxable_income: '', + tax_payable: '', + total_tax_payable: '', + refund: '' + }); + }; + + return ( +
+ {Object.keys(formData).map(key => ( +
+ + +
+ ))} + +
+ ); +}; + +export default FormPage; diff --git a/main.py b/main.py new file mode 100644 index 0000000..a85fc47 --- /dev/null +++ b/main.py @@ -0,0 +1,877 @@ +from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort +import os +import mysql.connector +from werkzeug.utils import secure_filename +from config import db_config + + +app = Flask(__name__) +app.config['UPLOAD_FOLDER'] = os.path.join('static', 'uploads') +ALLOWED_EXTENSIONS = {'pdf', 'docx', 'doc', 'xlsx', 'xls'} + +@app.route('/') +def welcome(): + return render_template('welcome.html') + +@app.route('/dashboard') +def index(): + return render_template('index.html') # Your dashboard page + +# Ensure folder exists +os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) + + +def allowed_file(filename): + return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + + +# Upload route +@app.route('/upload', methods=['GET', 'POST']) +def upload_file(): + if request.method == 'POST': + files = request.files.getlist('documents') + year = request.form['year'] + stage = request.form['stage'] + + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor() + + for file in files: + if file and allowed_file(file.filename): + filename = secure_filename(file.filename) + filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename) + 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)) + + conn.commit() + cursor.close() + conn.close() + return redirect(url_for('view_documents')) + + return render_template('upload.html') + + +# View all documents with filters +@app.route('/documents') +def view_documents(): + year = request.args.get('year') + stage = request.args.get('stage') + + conn = mysql.connector.connect(**db_config) + cursor = conn.cursor(dictionary=True) + + query = "SELECT * FROM documents WHERE 1=1" + params = [] + + if year: + query += " AND year = %s" + params.append(year) + if stage: + query += " AND stage = %s" + params.append(stage) + + cursor.execute(query, params) + documents = cursor.fetchall() + + cursor.execute("SELECT DISTINCT year FROM documents ORDER BY year DESC") + years = [row['year'] for row in cursor.fetchall()] + + cursor.close() + conn.close() + + return render_template('view_docs.html', documents=documents, years=years) + + +# Serve uploaded file +from flask import send_file + +@app.route('/uploads/') +def uploaded_file(filename): + mode = request.args.get('mode', 'view') + filepath = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(filename)) + + 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 + + # --- Download Mode --- + return send_file(filepath, as_attachment=True) + + +# (Keep all your other routes and imports as they are) + +## 1. READ/DISPLAY all ITR records +# This page will show all records in a table with Edit and Delete buttons. +@app.route('/itr_records') +def display_itr(): + conn = get_db_connection() + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT * FROM itr ORDER BY year DESC, id DESC") + records = cursor.fetchall() + cursor.close() + conn.close() + return render_template('display_itr.html', records=records) + + +## 2. CREATE/ADD a new ITR record +# This route handles both showing the blank form and saving the new data. +@app.route('/itr/add', methods=['GET', 'POST']) +def add_itr(): + if request.method == 'POST': + conn = get_db_connection() + cursor = conn.cursor() + + # A list of all columns in your form and database table + 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' + ] + + query = f"INSERT INTO itr ({', '.join(columns)}) VALUES ({', '.join(['%s'] * len(columns))})" + values = [request.form.get(col, 0) for col in columns] + + cursor.execute(query, tuple(values)) + conn.commit() + cursor.close() + conn.close() + # After adding, redirect to the page that shows all records + return redirect(url_for('display_itr')) + + # If it's a GET request, just show the blank form to add a record + return render_template('add_itr.html') + + +## 3. UPDATE an existing ITR record +# This route needs an ID to know which record to edit. +@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) + + +## 4. DELETE an ITR record +# This route also needs an ID to know which record to delete. +@app.route('/itr/delete/', methods=['POST']) +def delete_itr(id): + conn = get_db_connection() + cursor = conn.cursor() + cursor.execute("DELETE FROM itr WHERE id = %s", (id,)) + conn.commit() + cursor.close() + conn.close() + # After deleting, redirect back to the display page + return redirect(url_for('display_itr')) + + +@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() + cursor.close() + conn.close() + return redirect(url_for('index')) + return render_template('itr_form.html') + + +# +# ADD THESE NEW FUNCTIONS TO YOUR APP.PY FILE +# + +## =============================================== +## AO (Assessing Officer) Routes +## =============================================== + +# DISPLAY all AO records +@app.route('/ao_records') +def display_ao(): + conn = get_db_connection() + cursor = conn.cursor(dictionary=True) + # Note: Querying the 'ao' table + cursor.execute("SELECT * FROM ao ORDER BY year DESC, id DESC") + records = cursor.fetchall() + cursor.close() + conn.close() + # Note: Rendering the 'display_ao.html' template + return render_template('display_ao.html', records=records) + + +# ADD a new AO record +@app.route('/ao/add', methods=['GET', 'POST']) +def add_ao(): + if request.method == 'POST': + conn = get_db_connection() + cursor = conn.cursor() + + # Define the columns for the 'ao' table + 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' + ] # Make sure these match your 'ao' table columns! + + # Note: Inserting into the 'ao' table + query = f"INSERT INTO ao ({', '.join(columns)}) VALUES ({', '.join(['%s'] * len(columns))})" + values = [request.form.get(col, 0) for col in columns] + + cursor.execute(query, tuple(values)) + conn.commit() + cursor.close() + conn.close() + # Note: Redirecting to the 'display_ao' function + return redirect(url_for('display_ao')) + + # Note: Rendering the 'add_ao.html' template + return render_template('add_ao.html') + + +# (You will also need to add update_ao and delete_ao functions later) + + +@app.route('/ao', methods=['GET', 'POST']) +def ao_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 ao ( + 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 (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """ + + values = tuple([ + data.get('year'), + float(data.get('gross_total_income', 0)), + float(data.get('disallowance_14a', 0)), + float(data.get('disallowance_37', 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('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('ao_form.html') + + +# +# ADD THESE NEW CIT FUNCTIONS TO YOUR APP.PY FILE +# + +## ======================================================= +## CIT (Commissioner of Income Tax) Routes +## ======================================================= + +# DISPLAY all CIT records +@app.route('/cit_records') +def display_cit(): + conn = get_db_connection() + cursor = conn.cursor(dictionary=True) + # Querying the 'cit' table + cursor.execute("SELECT * FROM cit ORDER BY year DESC, id DESC") + records = cursor.fetchall() + cursor.close() + conn.close() + # Rendering the 'display_cit.html' template + return render_template('display_cit.html', records=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() + + # IMPORTANT: These columns match your 'cit' table structure + 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' + ] + + # Inserting into the 'cit' table + query = f"INSERT INTO cit ({', '.join(columns)}) VALUES ({', '.join(['%s'] * len(columns))})" + values = [request.form.get(col, 0) for col in columns] + + cursor.execute(query, tuple(values)) + conn.commit() + cursor.close() + conn.close() + # Redirecting to the 'display_cit' function + return redirect(url_for('display_cit')) + + # Rendering the 'add_cit.html' template + return render_template('add_cit.html') + + +# (You will also need to add update_cit and delete_cit functions later) + + +# +# ADD THESE FINAL FUNCTIONS FOR ITAT TO YOUR APP.PY FILE +# + +## ======================================================= +## ITAT (Income Tax Appellate Tribunal) Routes +## ======================================================= + +# 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(): + if request.method == 'POST': + conn = get_db_connection() + cursor = conn.cursor() + + # NOTE: These are the specific columns for your 'itat' table + columns = [ + 'year', 'mat_tax_credit', 'surcharge', 'cess', 'total_credit' + ] + + # Inserting into the 'itat' table + query = f"INSERT INTO itat ({', '.join(columns)}) VALUES ({', '.join(['%s'] * len(columns))})" + values = [request.form.get(col, 0) for col in columns] + + cursor.execute(query, tuple(values)) + conn.commit() + cursor.close() + conn.close() + # Redirecting to the 'display_itat' function + return redirect(url_for('display_itat')) + + # Rendering the 'add_itat.html' template + return render_template('add_itat.html') + + +# (You will also need to add update_itat and delete_itat functions later) + +@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') + + +@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 + +import pandas as pd +import pymysql +import io +@app.route('/reports') +def reports(): + return render_template("reports.html") + + + +@app.route('/itr_report', methods=['GET']) +def itr_report(): + 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('/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() + + +@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) + +# main.py +from flask import Flask, send_file +import pandas as pd +import io +import pymysql # or use mysql.connector if preferred +from config import db_config +@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() + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5003, debug=True) + \ No newline at end of file diff --git a/static/index.css b/static/index.css new file mode 100644 index 0000000..6c66df2 --- /dev/null +++ b/static/index.css @@ -0,0 +1,54 @@ +body { + font-family: Arial, sans-serif; + background-color: #f2f6fc; + margin: 0; + padding: 0; +} + +.container { + max-width: 800px; + margin: 40px auto; + padding: 30px; + background-color: #ffffff; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0,0,0,0.1); +} + +h2 { + text-align: center; + color: #333; + margin-bottom: 20px; +} + +form label { + display: block; + margin-top: 15px; + font-weight: 500; + color: #444; +} + +form input[type="number"] { + width: 100%; + padding: 8px 10px; + margin-top: 5px; + border: 1px solid #ccc; + border-radius: 6px; + font-size: 14px; +} + +form button { + margin-top: 25px; + background-color: #007BFF; + color: white; + padding: 12px 20px; + border: none; + border-radius: 6px; + font-size: 16px; + cursor: pointer; + width: 100%; + transition: background-color 0.3s ease; +} + +form button:hover { + background-color: #0056b3; +} diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..e69de29 diff --git a/static/uploads/Contractor_Report_194.xlsx b/static/uploads/Contractor_Report_194.xlsx new file mode 100644 index 0000000..5c88582 Binary files /dev/null and b/static/uploads/Contractor_Report_194.xlsx differ diff --git a/static/uploads/Feedback_Report_Form.pdf b/static/uploads/Feedback_Report_Form.pdf new file mode 100644 index 0000000..6332c81 Binary files /dev/null and b/static/uploads/Feedback_Report_Form.pdf differ diff --git a/static/uploads/Rakesh_Kumar1.xlsx b/static/uploads/Rakesh_Kumar1.xlsx new file mode 100644 index 0000000..8d83dcc Binary files /dev/null and b/static/uploads/Rakesh_Kumar1.xlsx differ diff --git a/templates/add_itr.html b/templates/add_itr.html new file mode 100644 index 0000000..983fa9c --- /dev/null +++ b/templates/add_itr.html @@ -0,0 +1,19 @@ +
+

Add New Income Tax Return Record

+
+ + + {% for field 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" + ] %} + + + {% endfor %} + +
+
\ No newline at end of file diff --git a/templates/ao_form.html b/templates/ao_form.html new file mode 100644 index 0000000..af1e681 --- /dev/null +++ b/templates/ao_form.html @@ -0,0 +1,127 @@ + + + + AO Form Entry + + + + +
+

AO Form Entry

+
+ + + {% for field in [ + "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" + ] %} + + + {% endfor %} + +
+
+ + + + + diff --git a/templates/ao_reports.html b/templates/ao_reports.html new file mode 100644 index 0000000..4447d7d --- /dev/null +++ b/templates/ao_reports.html @@ -0,0 +1,74 @@ + + + + Download AO Reports + + + + +
+

Download AO Report

+
+ + +
+ +

+ +
+
+ + diff --git a/templates/cit_form.html b/templates/cit_form.html new file mode 100644 index 0000000..17553a9 --- /dev/null +++ b/templates/cit_form.html @@ -0,0 +1,123 @@ + + + + CIT Form Entry + + + + +
+

CIT Form Entry

+
+ + + + {% for field in [ + "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" + ] %} + + + {% endfor %} + +
+
+ + + + diff --git a/templates/cit_reports.html b/templates/cit_reports.html new file mode 100644 index 0000000..3047463 --- /dev/null +++ b/templates/cit_reports.html @@ -0,0 +1,74 @@ + + + + Download CIT Reports + + + + +
+

Download CIT Report

+
+ + +
+ +

+ +
+
+ + diff --git a/templates/display_itr.html b/templates/display_itr.html new file mode 100644 index 0000000..bd3d85f --- /dev/null +++ b/templates/display_itr.html @@ -0,0 +1,66 @@ + + + + + ITR Records + + + +
+

Income Tax Return Records ๐Ÿงพ

+ โž• Add New Record + + {% if records %} +
+ + + + + + + + + + + + + {% for record in records %} + + + + + + + + + {% endfor %} + +
YearGross Total IncomeNet Taxable IncomeTotal Tax PayableRefundActions
{{ record.year }}{{ "{:,.2f}".format(record.gross_total_income) }}{{ "{:,.2f}".format(record.net_taxable_income) }}{{ "{:,.2f}".format(record.total_tax_payable) }}{{ "{:,.2f}".format(record.refund) }} + Edit + +
+ +
+
+
+ {% else %} +

No records found. Click the button above to add one!

+ {% endif %} +
+ + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..8eb3a00 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,129 @@ + + + + + Dashboard | Income Tax Utilities + + + + +
+

Dashboard ๐Ÿ›๏ธ

+ + + + + +
+

CIT (Commissioner of Income Tax)

+ +
+ +
+

ITAT (Income Tax Appellate Tribunal)

+ +
+ + +
+ + \ No newline at end of file diff --git a/templates/itat_form.html b/templates/itat_form.html new file mode 100644 index 0000000..4d56bc0 --- /dev/null +++ b/templates/itat_form.html @@ -0,0 +1,126 @@ + + + + ITAT Form Entry + + + + +
+

ITAT Form Entry

+
+ + + + + + + + + + + + + + + + +
+
+ + + + diff --git a/templates/itat_reports.html b/templates/itat_reports.html new file mode 100644 index 0000000..548b457 --- /dev/null +++ b/templates/itat_reports.html @@ -0,0 +1,74 @@ + + + + Download ITAT Reports + + + + +
+

Download ITAT Report

+
+ + +
+ +

+ +
+
+ + diff --git a/templates/itr_form.html b/templates/itr_form.html new file mode 100644 index 0000000..f6b6d9d --- /dev/null +++ b/templates/itr_form.html @@ -0,0 +1,251 @@ + + + + + + +ITR Form Entry + + + + + + + + + +
+ +

Income Tax Return Form

+ +
+ + + + + + + +{% for field 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" + +] %} + + + + + +{% endfor %} + + + +
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/templates/itr_reports.html b/templates/itr_reports.html new file mode 100644 index 0000000..321d3fe --- /dev/null +++ b/templates/itr_reports.html @@ -0,0 +1,74 @@ + + + + Download ITR Reports + + + + +
+

Download ITR Report

+
+ + +
+ +

+ +
+
+ + diff --git a/templates/reports.html b/templates/reports.html new file mode 100644 index 0000000..2e2fa8a --- /dev/null +++ b/templates/reports.html @@ -0,0 +1,130 @@ + + + + Reports Of Stages + + + + + + + diff --git a/templates/stage_reports.html b/templates/stage_reports.html new file mode 100644 index 0000000..34247f1 --- /dev/null +++ b/templates/stage_reports.html @@ -0,0 +1,146 @@ + + + + {{ stage }} Reports + + + + +
+

{{ stage }} Reports

+ +
+ + + +
+ + {% if documents %} + + + + + + + + + {% for doc in documents %} + + + + + {% endfor %} + +
YearAction
{{ doc.year }} + Download +
+ {% else %} +

No reports found for this selection.

+ {% endif %} +
+ + diff --git a/templates/summary_reports.html b/templates/summary_reports.html new file mode 100644 index 0000000..3067cec --- /dev/null +++ b/templates/summary_reports.html @@ -0,0 +1,83 @@ + + + + Download Summary Report + + + +
+

Download Year-wise Summary Report

+ + {% if message %} +

{{ message }}

+ {% endif %} + +
+ + + +
+
+ + \ No newline at end of file diff --git a/templates/update_itr.html b/templates/update_itr.html new file mode 100644 index 0000000..62a48de --- /dev/null +++ b/templates/update_itr.html @@ -0,0 +1,21 @@ + + + + + Update ITR Record + + + + +
+

Update ITR Record for Year {{ record.year }}

+
+ {% for field in record.keys() if field != 'id' %} + + + {% endfor %} + +
+
+ + \ No newline at end of file diff --git a/templates/upload.html b/templates/upload.html new file mode 100644 index 0000000..c41eec7 --- /dev/null +++ b/templates/upload.html @@ -0,0 +1,123 @@ + + + + Upload Documents + + + + +
+

Upload Income Tax Documents

+
+ + + + + + + + + + +
+
+ + diff --git a/templates/view_docs.html b/templates/view_docs.html new file mode 100644 index 0000000..7fdec5f --- /dev/null +++ b/templates/view_docs.html @@ -0,0 +1,164 @@ + + + + View Documents + + + +
+

Document Records

+ +
+ + + + + + + +
+ + + + + + + + + + + + + + + {% for doc in documents %} + + + + + + + + + + {% endfor %} + +
FileTypeStageYearUploaded AtDownloadView
{{ doc.filename }}{{ doc.filetype }}{{ doc.stage }}{{ doc.year }}{{ doc.uploaded_at }}DownloadView
+
+ + diff --git a/templates/welcome.html b/templates/welcome.html new file mode 100644 index 0000000..b7e5b4f --- /dev/null +++ b/templates/welcome.html @@ -0,0 +1,55 @@ + + + + + + Welcome - Laxmi Civil Engineering Pvt. Ltd + + + + + +

Welcome to Laxmi Civil Engineering Pvt. Ltd

+

Income Tax Filing and Compliance

+ Go To Dashboard + + + +