3 Commits

Author SHA1 Message Date
Swapnil9693
38c5de14ce Merge branch 'swapnil-dev' of http://103.186.132.129:3001/pjpatil12/IncomeTaxSystem into swapnil-dev 2026-02-17 15:49:15 +05:30
Swapnil9693
684e41e5c3 log file added 2026-02-17 15:25:57 +05:30
Swapnil9693
b9a8b9c0a9 LDAP Config Added 2026-02-13 15:16:35 +05:30
33 changed files with 593 additions and 280 deletions

26
.gitignore vendored
View File

@@ -1,18 +1,30 @@
# Python # Python
*.__pycache__ *.__pycache__
*.pyc *.pyc
*.pyos *.pyo
*.pyd *.pyd
__pycache__ __pycache__
.vscode/
.idea/
# Ignore upload files # Ingnor upload files
static/uploads/ static/uploads/
# Ignore files
venv
# Ignore Log files ss
logs/
# Environment variables # Environment variables
.env .env
venv
# Ignore Log files # Python cache
logs/ __pycache__/
*.pyc
# OS / Editor
.vscode/
.idea/
__pycache__/
*.pyc

View File

@@ -108,7 +108,7 @@ class AOHandler:
"deduction_sec37_disallowance": "On Sec 37 Disallowance", "deduction_sec37_disallowance": "On Sec 37 Disallowance",
"deduction_80g": "Less: Deduction u/s 80G", "deduction_80g": "Less: Deduction u/s 80G",
"net_taxable_income": "Net Taxable Income", "net_taxable_income": "Net Taxable Income",
"--" : "-", "-" : "-",
"per_tax_a" : "Per% Tax @(A)", "per_tax_a" : "Per% Tax @(A)",
"tax_a_cal" : "Tax cal(A)", "tax_a_cal" : "Tax cal(A)",
"per_surcharge_a" : "Per% surcharge @(A)", "per_surcharge_a" : "Per% surcharge @(A)",
@@ -116,7 +116,7 @@ class AOHandler:
"per_cess_a" : "Per% cess(A)", "per_cess_a" : "Per% cess(A)",
"edu_cess_a_cal" : "Edu cess cal(A)", "edu_cess_a_cal" : "Edu cess cal(A)",
"sum_of_a" : "Sum of tax_cal(A)", "sum_of_a" : "Sum of tax_cal(A)",
"---" : "-", "-" : "-",
"per_tax_b" : "Per% Tax @(B)", "per_tax_b" : "Per% Tax @(B)",
"tax_b_cal" : "Tax cal(B)", "tax_b_cal" : "Tax cal(B)",
"per_surcharge_b" : "Per% surcharge @(B)", "per_surcharge_b" : "Per% surcharge @(B)",

View File

@@ -103,7 +103,7 @@ class CITHandler:
"deduction_sec37_disallowance": "On Sec 37 Disallowance", "deduction_sec37_disallowance": "On Sec 37 Disallowance",
"deduction_80g": "Less: Deduction u/s 80G", "deduction_80g": "Less: Deduction u/s 80G",
"net_taxable_income": "Net Taxable Income", "net_taxable_income": "Net Taxable Income",
"--" : "-", "-" : "-",
"per_tax_a" : "Per% Tax @(A)", "per_tax_a" : "Per% Tax @(A)",
"tax_a_cal" : "Tax cal(A)", "tax_a_cal" : "Tax cal(A)",
"per_surcharge_a" : "Per% surcharge @(A)", "per_surcharge_a" : "Per% surcharge @(A)",
@@ -111,7 +111,7 @@ class CITHandler:
"per_cess_a" : "Per% cess(A)", "per_cess_a" : "Per% cess(A)",
"edu_cess_a_cal" : "Edu cess cal(A)", "edu_cess_a_cal" : "Edu cess cal(A)",
"sum_of_a" : "Sum of tax_cal(A)", "sum_of_a" : "Sum of tax_cal(A)",
"---" : "-", "-" : "-",
"per_tax_b" : "Per% Tax @(B)", "per_tax_b" : "Per% Tax @(B)",
"tax_b_cal" : "Tax cal(B)", "tax_b_cal" : "Tax cal(B)",
"per_surcharge_b" : "Per% surcharge @(B)", "per_surcharge_b" : "Per% surcharge @(B)",

View File

@@ -1,4 +1,6 @@
from flask import render_template, request, send_file, jsonify from flask import (
render_template, request, send_file, jsonify
)
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
import pandas as pd import pandas as pd
import os import os
@@ -109,7 +111,10 @@ class DocumentHandler:
file.save(filepath) file.save(filepath)
cursor.callproc('InsertDocument',[filename, filepath, extension, year, stage]) cursor.callproc(
'InsertDocument',
[filename, filepath, extension, year, stage]
)
connection.commit() connection.commit()
cursor.close() cursor.close()
@@ -119,7 +124,9 @@ class DocumentHandler:
# Summary Preview (JSON) # Summary Preview (JSON)
# ========================= # =========================
def Summary_preview(self, request): def Summary_preview(self, request):
"""
Returns JSON preview of summary report for selected year.
"""
year_raw = request.args.get("year") year_raw = request.args.get("year")
year = self.parse_year(year_raw) year = self.parse_year(year_raw)
@@ -396,9 +403,26 @@ class DocumentHandler:
workbook = writer.book workbook = writer.book
worksheet = writer.sheets[sheet_name] worksheet = writer.sheets[sheet_name]
title = workbook.add_format({'bold': True,'font_size': 14,'align': 'center'}) title = workbook.add_format({
worksheet.merge_range(0, 0, 0, len(df.columns) - 1,"Laxmi Civil Engineering Services Pvt Ltd",title) 'bold': True,
header = workbook.add_format({'bold': True,'align': 'center', 'bg_color': '#007bff','font_color': 'white','border': 1 }) 'font_size': 14,
'align': 'center'
})
worksheet.merge_range(
0, 0, 0, len(df.columns) - 1,
"Laxmi Civil Engineering Services Pvt Ltd",
title
)
header = workbook.add_format({
'bold': True,
'align': 'center',
'bg_color': '#007bff',
'font_color': 'white',
'border': 1
})
cell = workbook.add_format({'border': 1}) cell = workbook.add_format({'border': 1})
for col_num, col_name in enumerate(df.columns): for col_num, col_name in enumerate(df.columns):

View File

@@ -7,12 +7,7 @@ class FileHandler:
@staticmethod @staticmethod
def CHeckExistingOrCreateNewUploadFolder(): def CHeckExistingOrCreateNewUploadFolder():
# Whether path exists #Wheteher path exists
os.makedirs(FileHandler.UPLOAD_FOLDER, exist_ok=True) os.makedirs(FileHandler.UPLOAD_FOLDER, exist_ok=True)
return return
@staticmethod
def CheckExistingOrCreateNewLoggerFolder():
if not os.path.exists("logs"):
os.mkdir("logs")
return

View File

@@ -98,7 +98,7 @@ class ITATHandler:
"deduction_sec37_disallowance": "On Sec 37 Disallowance", "deduction_sec37_disallowance": "On Sec 37 Disallowance",
"deduction_80g": "Less: Deduction u/s 80G", "deduction_80g": "Less: Deduction u/s 80G",
"net_taxable_income": "Net Taxable Income", "net_taxable_income": "Net Taxable Income",
"--" : "-", "-" : "-",
"per_tax_a" : "Per% Tax @(A)", "per_tax_a" : "Per% Tax @(A)",
"tax_a_cal" : "Tax cal(A)", "tax_a_cal" : "Tax cal(A)",
"per_surcharge_a" : "Per% surcharge @(A)", "per_surcharge_a" : "Per% surcharge @(A)",
@@ -106,7 +106,7 @@ class ITATHandler:
"per_cess_a" : "Per% cess(A)", "per_cess_a" : "Per% cess(A)",
"edu_cess_a_cal" : "Edu cess cal(A)", "edu_cess_a_cal" : "Edu cess cal(A)",
"sum_of_a" : "Sum of tax_cal(A)", "sum_of_a" : "Sum of tax_cal(A)",
"---" : "-", "-" : "-",
"per_tax_b" : "Per% Tax @(B)", "per_tax_b" : "Per% Tax @(B)",
"tax_b_cal" : "Tax cal(B)", "tax_b_cal" : "Tax cal(B)",
"per_surcharge_b" : "Per% surcharge @(B)", "per_surcharge_b" : "Per% surcharge @(B)",

View File

@@ -1,8 +1,11 @@
import mysql.connector import mysql.connector
import pandas as pd import pandas as pd
import io import io
from flask import send_file, render_template, request
from AppCode.Config import DBConfig from AppCode.Config import DBConfig
class ITRHandler: class ITRHandler:
def __init__(self): def __init__(self):
@@ -22,13 +25,16 @@ class ITRHandler:
def get_itr_by_id(self, id): def get_itr_by_id(self, id):
# Call stored procedure # Call stored procedure
self.cursor.callproc('GetITRById', [id]) self.cursor.callproc('GetITRById', [id])
# Fetch result # Fetch result
records = [] records = []
for result in self.cursor.stored_results(): for result in self.cursor.stored_results():
records = result.fetchall() records = result.fetchall()
if records: if records:
print(records[0]) print(records[0])
return records[0] # return single record return records[0] # return single record
return None return None
@@ -45,10 +51,10 @@ class ITRHandler:
] ]
values = [data.get(col, 0) for col in columns] values = [data.get(col, 0) for col in columns]
# Call your stored procedure # Call your stored procedure
self.cursor.callproc("InsertITR", values) self.cursor.callproc("InsertITR", values)
self.conn.commit() self.conn.commit()
except Exception as e: except Exception as e:
self.conn.rollback() self.conn.rollback()
raise e raise e
@@ -106,7 +112,7 @@ class ITRHandler:
"deduction_sec37_disallowance": "On Sec 37 Disallowance", "deduction_sec37_disallowance": "On Sec 37 Disallowance",
"deduction_80g": "Less: Deduction u/s 80G", "deduction_80g": "Less: Deduction u/s 80G",
"net_taxable_income": "Net Taxable Income", "net_taxable_income": "Net Taxable Income",
"--" : "-", "-" : "-",
"per_tax_a" : "Per% Tax @(A)", "per_tax_a" : "Per% Tax @(A)",
"tax_a_cal" : "Tax cal(A)", "tax_a_cal" : "Tax cal(A)",
"per_surcharge_a" : "Per% surcharge @(A)", "per_surcharge_a" : "Per% surcharge @(A)",
@@ -114,7 +120,7 @@ class ITRHandler:
"per_cess_a" : "Per% cess(A)", "per_cess_a" : "Per% cess(A)",
"edu_cess_a_cal" : "Edu cess cal(A)", "edu_cess_a_cal" : "Edu cess cal(A)",
"sum_of_a" : "Sum of tax_cal(A)", "sum_of_a" : "Sum of tax_cal(A)",
"---" : "-", "-" : "-",
"per_tax_b" : "Per% Tax @(B)", "per_tax_b" : "Per% Tax @(B)",
"tax_b_cal" : "Tax cal(B)", "tax_b_cal" : "Tax cal(B)",
"per_surcharge_b" : "Per% surcharge @(B)", "per_surcharge_b" : "Per% surcharge @(B)",
@@ -139,7 +145,7 @@ class ITRHandler:
"interest_244a_per143" : "Add : Interest u/s 244A as per 143", "interest_244a_per143" : "Add : Interest u/s 244A as per 143",
"refund_received" : "Less : Refund Received on", "refund_received" : "Less : Refund Received on",
"balance_receivable" : "Balance Receivable", "balance_receivable" : "Balance Receivable",
"remarks" : "Remarks" "Remarks" : "Remarks"
} }
# Convert to vertical structures # Convert to vertical structures
@@ -158,8 +164,13 @@ class ITRHandler:
writer.sheets["ITR Report"] = worksheet writer.sheets["ITR Report"] = worksheet
# Formats # Formats
title_fmt = workbook.add_format({"bold": True, "align": "center", "valign": "vcenter","font_size": 14}) title_fmt = workbook.add_format({
header_fmt = workbook.add_format({"bold": True, "border": 1, "align": "center"}) "bold": True, "align": "center", "valign": "vcenter",
"font_size": 14
})
header_fmt = workbook.add_format({
"bold": True, "border": 1, "align": "center"
})
cell_fmt = workbook.add_format({"border": 1}) cell_fmt = workbook.add_format({"border": 1})
num_fmt = workbook.add_format({"border": 1, "num_format": "#,##0.00"}) num_fmt = workbook.add_format({"border": 1, "num_format": "#,##0.00"})

View File

@@ -1,49 +1,22 @@
import os import os
import logging from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json
from flask import current_app
from datetime import datetime from datetime import datetime
from flask import session, request, current_app from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
class LogHelper: class LogHelper:
@staticmethod
def setup_logger(app):
if not os.path.exists("logs"):
os.makedirs("logs")
formatter = logging.Formatter("%(asctime)s | %(levelname)s | User:%(user)s | IP:%(ip)s | %(message)s")
file_handler = logging.FileHandler("logs/app.log")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)
app.logger.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.addHandler(stream_handler)
# ---------------------------------------
# Log User Activity
# ---------------------------------------
@staticmethod
def log_request():
if request.endpoint and "static" not in request.endpoint:
user = session.get("user", "Anonymous")
ip = request.remote_addr
current_app.logger.info(
f"{request.method} {request.path}",
extra={"user": user, "ip": ip}
)
# ---------------------------------------
# Custom Action Logging
# ---------------------------------------
@staticmethod @staticmethod
def log_action(action, details=""): def log_action(action, details=""):
user = session.get("user", "Anonymous") """Log user actions with timestamp, user, action, and details."""
ip = request.remote_addr logData = LogData()
current_app.logger.info(f"{action} | {details}",extra={"user": user, "ip": ip}) logData.WriteLog(action, details="")
class LogData:
filepath = ""
timestamp = None
def __init__(self):
self.filepath = os.path.join(current_app.root_path, 'activity.log')
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

View File

@@ -1,5 +1,8 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash, session from flask import Blueprint, render_template, request, redirect, url_for, flash, session
<<<<<<< HEAD
import os import os
=======
>>>>>>> b9a8b9c0a9c322c129ac50b3dec0ffb3c6d82a83
from functools import wraps from functools import wraps
from ldap3 import Server, Connection, ALL from ldap3 import Server, Connection, ALL
from ldap3.core.exceptions import LDAPException from ldap3.core.exceptions import LDAPException
@@ -10,51 +13,105 @@ class LoginAuth:
# Create Blueprint # Create Blueprint
self.bp = Blueprint("auth", __name__) self.bp = Blueprint("auth", __name__)
# LDAP CONFIG # -------------------------------
self.LDAP_SERVER = os.getenv("LDAP_SERVER", "ldap://host.docker.internal:389") # LDAP CONFIGURATION
self.BASE_DN = "ou=users,dc=lcepl,dc=org" # -------------------------------
<<<<<<< HEAD
self.LDAP_SERVER = os.getenv(
"LDAP_SERVER",
"ldap://host.docker.internal:389"
)
=======
self.LDAP_SERVER = "ldap://localhost:389"
>>>>>>> b9a8b9c0a9c322c129ac50b3dec0ffb3c6d82a83
self.BASE_DN = "ou=users,dc=lcepl,dc=org" # LDAP Users DN
# Register Routes # -------------------------------
self.bp.add_url_rule("/login", view_func=self.login, methods=["GET", "POST"]) # LOGIN ROUTE
self.bp.add_url_rule("/logout", view_func=self.logout) # -------------------------------
@self.bp.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get("username")
password = request.form.get("password")
<<<<<<< HEAD
if not username or not password:
flash("Username and password are required!", "danger")
return render_template("login.html")
user_dn = f"uid={username},{self.BASE_DN}"
server = Server(self.LDAP_SERVER, get_info=ALL)
=======
# ================= LOGIN ================= if not username or not password:
def login(self): flash("Username and password are required!", "danger")
if request.method == "POST": return render_template("login.html")
username = request.form.get("username")
password = request.form.get("password")
if not username or not password: user_dn = f"uid={username},{self.BASE_DN}"
flash("Username and password are required!", "danger") server = Server(self.LDAP_SERVER, get_info=ALL)
return render_template("login.html")
user_dn = f"uid={username},{self.BASE_DN}" >>>>>>> b9a8b9c0a9c322c129ac50b3dec0ffb3c6d82a83
server = Server(self.LDAP_SERVER, get_info=ALL) try:
# Attempt LDAP bind
conn = Connection(server, user=user_dn, password=password, auto_bind=True)
if conn.bound:
<<<<<<< HEAD
=======
>>>>>>> b9a8b9c0a9c322c129ac50b3dec0ffb3c6d82a83
session['user'] = username
flash(f"Login successful! Welcome {username}", "success")
return redirect(url_for('welcome'))
else:
flash("Invalid username or password!", "danger")
except LDAPException as e:
flash(f"LDAP login failed: {str(e)}", "danger")
finally:
if 'conn' in locals():
conn.unbind()
<<<<<<< HEAD
# GET request: show login form
return render_template("login.html")
try:
conn = Connection(server, user=user_dn, password=password, auto_bind=True)
if conn.bound: # LOGIN ROUTE
session["user"] = username # @self.bp.route('/login', methods=['GET', 'POST'])
flash(f"Login successful! Welcome {username}", "success") # def login():
conn.unbind() # if request.method == 'POST':
return redirect(url_for("welcome")) # username = request.form.get("username")
else: # password = request.form.get("password")
flash("Invalid username or password!", "danger") # # Dummy validation — REPLACE with DB check later
# if username == "admin" and password == "admin123":
# session['user'] = username
# flash("Login successful!", "success")
# return redirect(url_for('welcome'))
# else:
# flash("Invalid username or password!", "danger")
# return render_template("login.html")
=======
except LDAPException as e: # GET request: show login form
flash(f"LDAP login failed: {str(e)}", "danger") return render_template("login.html")
return render_template("login.html") >>>>>>> b9a8b9c0a9c322c129ac50b3dec0ffb3c6d82a83
# -------------------------------
# LOGOUT ROUTE
# -------------------------------
@self.bp.route('/logout')
def logout():
session.clear()
flash("Logged out successfully!", "success")
return redirect(url_for('auth.login'))
# ================= LOGOUT ================= # ===================================================
def logout(self): # LOGIN REQUIRED DECORATOR INSIDE CLASS
session.clear() # ===================================================
flash("Logged out successfully!", "success")
return redirect(url_for("auth.login"))
# ================= LOGIN REQUIRED =================
def login_required(self, f): def login_required(self, f):
"""
Protect routes: redirect to login if user not authenticated.
"""
@wraps(f) @wraps(f)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
if "user" not in session: if "user" not in session:

View File

@@ -13,7 +13,7 @@ class MatCreditHandler:
def fetch_all(self): def fetch_all(self):
try: try:
self.cursor.callproc("GetMatCredit") self.cursor.callproc("GetMatCedit")
result_sets = self.cursor.stored_results() result_sets = self.cursor.stored_results()
mat_rows = next(result_sets).fetchall() mat_rows = next(result_sets).fetchall()
utilization_rows = next(result_sets).fetchall() utilization_rows = next(result_sets).fetchall()
@@ -38,9 +38,8 @@ class MatCreditHandler:
( (
data["financial_year"], data["financial_year"],
data["mat_credit"], data["mat_credit"],
data["opening_balance"],
data["balance"], data["balance"],
data.get("remarks", "update on manually on mat credit from ui") data.get("remarks", "")
) )
) )
@@ -69,21 +68,20 @@ class MatCreditHandler:
# AUTO SAVE MAT FROM ITR (MAIN LOGIC) # AUTO SAVE MAT FROM ITR (MAIN LOGIC)
# -------------------------------------------------- # --------------------------------------------------
@staticmethod @staticmethod
def save_from_itr(year, mat_created, opening_balance, mat_utilized, remarks): def save_from_itr(year, mat_created, mat_utilized, remarks="Auto from"):
conn = DBConfig.get_db_connection() conn = DBConfig.get_db_connection()
cur = conn.cursor(dictionary=True) cur = conn.cursor(dictionary=True)
try: try:
mat_created = float(mat_created or 0) mat_created = float(mat_created or 0)
opening_balance = float(mat_created or 0)
mat_utilized = float(mat_utilized or 0) mat_utilized = float(mat_utilized or 0)
balance = opening_balance + mat_created - mat_utilized balance = mat_created - mat_utilized
# Save / Update MAT Credit # Save / Update MAT Credit
cur.callproc( cur.callproc(
"SaveOrUpdateMatCredit", "SaveOrUpdateMatCredit",
(year, mat_created, opening_balance, balance, remarks) (year, mat_created, balance, remarks)
) )
mat_id = None mat_id = None

View File

@@ -1,26 +1,3 @@
# -------------- development's Dockerfile ----------------
# FROM python:3.11-slim
# # Prevent Python buffering
# ENV PYTHONDONTWRITEBYTECODE=1
# ENV PYTHONUNBUFFERED=1
# WORKDIR /app
# # Install system deps (if needed later)
# RUN apt-get update && apt-get install -y \
# build-essential \
# && rm -rf /var/lib/apt/lists/*
# COPY requirements.txt .
# RUN pip install --no-cache-dir -r requirements.txt
# COPY . .
# EXPOSE 5000
# CMD ["python", "main.py"]
# -------------- Production Dockerfile ----------------
FROM python:3.11-slim FROM python:3.11-slim
WORKDIR /app WORKDIR /app
@@ -33,4 +10,3 @@ COPY . .
EXPOSE 5010 EXPOSE 5010
CMD ["gunicorn", "--bind", "0.0.0.0:5010", "main:app"] CMD ["gunicorn", "--bind", "0.0.0.0:5010", "main:app"]
# end

0
db/income_tax.sql Normal file
View File

View File

@@ -2,7 +2,6 @@ version: "3.9"
services: services:
# Database connection
db: db:
image: mysql:8 image: mysql:8
container_name: tax-mysql container_name: tax-mysql
@@ -13,7 +12,6 @@ services:
volumes: volumes:
- mysql_data:/var/lib/mysql - mysql_data:/var/lib/mysql
# Application config
flaskapp: flaskapp:
build: . build: .
container_name: tax-flask container_name: tax-flask
@@ -32,11 +30,11 @@ services:
FLASK_PORT: 5010 FLASK_PORT: 5010
FLASK_DEBUG: "false" FLASK_DEBUG: "false"
SECRET_KEY: secret1234 SECRET_KEY: secret1234
LDAP_SERVER: ldap://host.docker.internal:389 LDAP_SERVER: ldap://host.docker.internal:389 # 👈 ADD THIS
LOG_VIEW_SECRET: super-log-2026 LOG_VIEW_SECRET: super-log-2026
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
- ./logs:/app/logs - ./logs:/app/logs
volumes: volumes:
mysql_data: mysql_data:

160
main.py
View File

@@ -1,6 +1,7 @@
from flask import Flask, render_template, request, redirect, url_for, flash,send_file ,jsonify, session from flask import Flask, render_template, request, redirect, url_for, flash,send_file ,jsonify, session
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv()
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from datetime import date from datetime import date
from AppCode.Config import DBConfig from AppCode.Config import DBConfig
@@ -13,27 +14,56 @@ from AppCode.AOHandler import AOHandler
from AppCode.CITHandler import CITHandler from AppCode.CITHandler import CITHandler
from AppCode.ITATHandler import ITATHandler from AppCode.ITATHandler import ITATHandler
from AppCode.MatCreditHandler import MatCreditHandler from AppCode.MatCreditHandler import MatCreditHandler
import logging
import sys
from AppCode.Log import LogHelper
# Loading env file
load_dotenv()
# Server # Server
app = Flask(__name__) app = Flask(__name__)
app.secret_key=os.getenv("SECRET_KEY") app.secret_key=os.getenv("SECRET_KEY")
# login auth
import logging
import sys
# Remove default handlers
if not os.path.exists("logs"):
os.mkdir("logs")
file_handler = logging.FileHandler("logs/app.log")
file_handler.setLevel(logging.INFO)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
formatter = logging.Formatter(
"%(asctime)s | %(levelname)s | User:%(user)s | %(message)s"
)
file_handler.setFormatter(formatter)
stream_handler.setFormatter(formatter)
app.logger.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.addHandler(stream_handler)
auth = LoginAuth() auth = LoginAuth()
app.register_blueprint(auth.bp) app.register_blueprint(auth.bp)
# LOGGING SETUP
LogHelper.setup_logger(app)
@app.before_request @app.before_request
def log_all_requests(): def log_user_activity():
LogHelper.log_request() if request.endpoint and "static" not in request.endpoint:
user = session.get("user", "Anonymous")
ip = request.remote_addr
app.logger.info(
f"Accessed: {request.method} {request.path}",
extra={"user": user}
)
# welcome page # welcome page
@@ -57,7 +87,6 @@ def upload_file():
FileHandler.CHeckExistingOrCreateNewUploadFolder() FileHandler.CHeckExistingOrCreateNewUploadFolder()
docHandler = DocumentHandler() docHandler = DocumentHandler()
docHandler.Upload(request=request) docHandler.Upload(request=request)
LogHelper.log_action("UPLOAD", "Document uploaded")
return redirect(url_for('view_documents')) return redirect(url_for('view_documents'))
return render_template('upload.html') return render_template('upload.html')
@@ -80,14 +109,14 @@ def uploaded_file(filename):
if not os.path.exists(filepath): if not os.path.exists(filepath):
flash("Unsupported file type for viewing", "warning") flash("Unsupported file type for viewing", "warning")
return redirect(url_for('view_documents')) return redirect(url_for('view_documents'))
LogHelper.log_action("VIEW FILE", filename)
file_ext = filename.rsplit('.', 1)[-1].lower() file_ext = filename.rsplit('.', 1)[-1].lower()
# --- View Mode --- # --- View Mode ---
if mode == 'view': if mode == 'view':
# pdf # pdf
if file_ext == 'pdf': if file_ext == 'pdf':
return send_file(filepath, mimetype='application/pdf') return send_file(filepath, mimetype='application/pdf')
# Word # Word
elif file_ext in ['doc', 'docx']: elif file_ext in ['doc', 'docx']:
return send_file(filepath, as_attachment=True) return send_file(filepath, as_attachment=True)
# Excel # Excel
@@ -132,11 +161,10 @@ def add_itr():
mat.save_from_itr( mat.save_from_itr(
year=request.form["year"], year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)), mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)), mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ITR" remarks="Created via ITR"
) )
LogHelper.log_action("ADD ITR Record", f"Year: {request.form['year']}")
# flash("ITR record added successfully!", "success") # flash("ITR record added successfully!", "success")
flash("ITR record and documents uploaded successfully!", "success") flash("ITR record and documents uploaded successfully!", "success")
return redirect(url_for('display_itr')) return redirect(url_for('display_itr'))
@@ -150,7 +178,6 @@ def delete_itr(id):
itr = ITRHandler() itr = ITRHandler()
itr.delete_itr_by_id(id=id) itr.delete_itr_by_id(id=id)
itr.close() itr.close()
LogHelper.log_action("ITR record deleted successfully!", id)
return redirect(url_for('display_itr')) return redirect(url_for('display_itr'))
## 3. UPDATE an existing ITR record ## 3. UPDATE an existing ITR record
@@ -163,24 +190,15 @@ def update_itr(id):
data = {k: request.form.get(k, 0) for k in request.form} data = {k: request.form.get(k, 0) for k in request.form}
itr.update(id, data) itr.update(id, data)
itr.close() itr.close()
mat = MatCreditHandler()
# AUTO SAVE MAT FROM ITR
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Updated via ITR"
)
LogHelper.log_action("ITR record updated successfully!", data)
return redirect(url_for('display_itr')) return redirect(url_for('display_itr'))
record = itr.get_itr_by_id(id) record = itr.get_itr_by_id(id)
itr.close() itr.close()
return render_template('update_itr.html', record=record, current_date=date.today().isoformat()) return render_template('update_itr.html', record=record, current_date=date.today().isoformat())
## =============================================== ## ===============================================
## AO (Assessing Officer) Routes ## AO (Assessing Officer) Routes
## =============================================== ## ===============================================
@@ -213,11 +231,10 @@ def add_ao():
mat.save_from_itr( mat.save_from_itr(
year=request.form["year"], year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)), mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)), mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ao" remarks="Created via ao"
) )
LogHelper.log_action("AO record added successfully!", "")
flash("AO record added successfully!", "success") flash("AO record added successfully!", "success")
return redirect(url_for('display_ao')) return redirect(url_for('display_ao'))
return render_template('add_ao.html',current_date=date.today().isoformat()) return render_template('add_ao.html',current_date=date.today().isoformat())
@@ -236,15 +253,6 @@ def update_ao(id):
data = request.form.to_dict() data = request.form.to_dict()
ao.update_ao(id, data) ao.update_ao(id, data)
ao.close() ao.close()
mat = MatCreditHandler()
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ao"
)
LogHelper.log_action("AO record updated successfully!", data)
flash("AO record updated successfully!", "success") flash("AO record updated successfully!", "success")
return redirect(url_for('display_ao')) return redirect(url_for('display_ao'))
@@ -259,7 +267,6 @@ def delete_ao(id):
ao = AOHandler() ao = AOHandler()
ao.delete_ao_by_id(id=id) ao.delete_ao_by_id(id=id)
ao.close() ao.close()
LogHelper.log_action("AO deleted successfully!", id)
flash("AO deleted successfully!", "success") flash("AO deleted successfully!", "success")
return redirect(url_for('display_ao')) return redirect(url_for('display_ao'))
@@ -296,11 +303,9 @@ def add_cit():
mat.save_from_itr( mat.save_from_itr(
year=request.form["year"], year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)), mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)), mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via cit" remarks="Created via cit"
) )
LogHelper.log_action("CIT record added successfully!", "")
flash("CIT record added successfully!", "success") flash("CIT record added successfully!", "success")
return redirect(url_for('display_cit')) return redirect(url_for('display_cit'))
@@ -313,7 +318,6 @@ def delete_cit(id):
cit = CITHandler() cit = CITHandler()
cit.delete_cit(id) cit.delete_cit(id)
cit.close() cit.close()
LogHelper.log_action("CIT record deleted successfully!", id)
flash("CIT record deleted successfully!", "success") flash("CIT record deleted successfully!", "success")
return redirect(url_for('display_cit')) return redirect(url_for('display_cit'))
@@ -332,16 +336,6 @@ def update_cit(id):
data = {k: request.form.get(k, 0) for k in request.form} data = {k: request.form.get(k, 0) for k in request.form}
cit.update_cit(id, data) cit.update_cit(id, data)
cit.close() cit.close()
mat = MatCreditHandler()
# AUTO SAVE MAT FROM ITR
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Updated via cit"
)
LogHelper.log_action("CIT record updated successfully!", data)
return redirect(url_for('display_cit')) return redirect(url_for('display_cit'))
cit.close() cit.close()
@@ -380,11 +374,10 @@ def add_itat():
mat.save_from_itr( mat.save_from_itr(
year=request.form["year"], year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)), mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)), mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ITAT" remarks="Created via ITR"
) )
LogHelper.log_action("ITAT record added successfully!", data)
flash("ITAT record added successfully!", "success") flash("ITAT record added successfully!", "success")
return redirect(url_for('display_itat')) return redirect(url_for('display_itat'))
@@ -404,16 +397,6 @@ def update_itat(id):
if request.method == 'POST': if request.method == 'POST':
itat.update_itat(id, request.form) itat.update_itat(id, request.form)
itat.close() itat.close()
mat = MatCreditHandler()
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
opening_balance=float(request.form.get("opening_balance", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Updated via ITAT"
)
LogHelper.log_action("ITAT Record Updated!", id)
flash("ITAT Record Updated!", "success") flash("ITAT Record Updated!", "success")
return redirect(url_for('display_itat')) return redirect(url_for('display_itat'))
@@ -426,7 +409,6 @@ def update_itat(id):
def delete_itat(id): def delete_itat(id):
itat = ITATHandler() itat = ITATHandler()
itat.delete_itat_by_id(id) itat.delete_itat_by_id(id)
LogHelper.log_action("itat record of by id:", id)
itat.close() itat.close()
flash("ITAT Record Deleted!", "success") flash("ITAT Record Deleted!", "success")
return redirect(url_for('display_itat')) return redirect(url_for('display_itat'))
@@ -455,7 +437,7 @@ def itr_report():
if output is None: if output is None:
return "No records found for the selected year." return "No records found for the selected year."
LogHelper.log_action("itr report download", selected_year)
return send_file( return send_file(
output, output,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
@@ -482,7 +464,7 @@ def ao_report():
if output is None: if output is None:
return "No records found for the selected year." return "No records found for the selected year."
LogHelper.log_action("ao report download", selected_year)
return send_file( return send_file(
output, output,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
@@ -510,7 +492,7 @@ def cit_report():
if output is None: if output is None:
return "No records found for the selected year." return "No records found for the selected year."
LogHelper.log_action("cit report download", selected_year)
return send_file( return send_file(
output, output,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
@@ -539,7 +521,7 @@ def itat_report():
if output is None: if output is None:
return "No records found for the selected year." return "No records found for the selected year."
LogHelper.log_action("itat report download", selected_year)
return send_file( return send_file(
output, output,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
@@ -569,7 +551,7 @@ def download_summary():
return "Year parameter is required", 400 return "Year parameter is required", 400
docHandler = DocumentHandler() docHandler = DocumentHandler()
LogHelper.log_action("/summary/download | download summary sheet !",year_raw) # reuse your existing Summary_report method
return docHandler.Summary_report(request=request) return docHandler.Summary_report(request=request)
@@ -581,7 +563,7 @@ def download_summary():
# table_name = data.get("table") # table_name = data.get("table")
# year = data.get("year") # year = data.get("year")
# check_year_obj = YearGet()ss # check_year_obj = YearGet()
# result = check_year_obj.CheckYearExists(table_name, year) # result = check_year_obj.CheckYearExists(table_name, year)
# check_year_obj.close() # check_year_obj.close()
# return result # return result
@@ -619,9 +601,8 @@ def mat_credit():
for u in utilization_rows: for u in utilization_rows:
all_years.add(u["utilized_year"]) all_years.add(u["utilized_year"])
utilization_map.setdefault( utilization_map.setdefault(
u["mat_credit_id"], {} u["mat_credit_id"], {}
)[u["utilized_year"]] = u["utilized_amount"] )[u["utilized_year"]] = u["utilized_amount"]
LogHelper.log_action("/mat_credit| Save mat credit !",all_years)
return render_template( return render_template(
"mat_credit.html", "mat_credit.html",
@@ -637,7 +618,6 @@ def save_mat_row():
mat = MatCreditHandler() mat = MatCreditHandler()
try: try:
mat.save_single(request.json) mat.save_single(request.json)
LogHelper.log_action("/save_mat_row", "Save Mat row!")
return jsonify({"message": "Row saved successfully"}) return jsonify({"message": "Row saved successfully"})
except Exception as e: except Exception as e:
return jsonify({"error": str(e)}), 500 return jsonify({"error": str(e)}), 500
@@ -649,19 +629,6 @@ def summary_preview_route():
handler = DocumentHandler() handler = DocumentHandler()
return handler.Summary_preview(request) 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
@app.route("/view_logs", methods=["GET", "POST"]) @app.route("/view_logs", methods=["GET", "POST"])
@auth.login_required @auth.login_required
def view_logs(): def view_logs():
@@ -673,17 +640,28 @@ def view_logs():
if entered != secret: if entered != secret:
flash("Invalid secret!", "danger") flash("Invalid secret!", "danger")
return render_template("view_logs_auth.html") return render_template("view_logs_auth.html")
try: try:
with open("logs/app.log", "r") as f: with open("logs/app.log", "r") as f:
logs = f.readlines() logs = f.readlines()
except FileNotFoundError: except FileNotFoundError:
logs = ["Log file not found"] logs = ["Log file not found"]
return render_template("view_logs.html", logs=logs) return render_template("view_logs.html", logs=logs)
return render_template("view_logs_auth.html") return render_template("view_logs_auth.html")
# 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
# run server # run server
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -12,6 +12,4 @@ xlrd==2.0.1
gunicorn==21.2.0 gunicorn==21.2.0
XlsxWriter==3.2.0
ldap3 ldap3

View File

@@ -1,3 +1,132 @@
/* ================= RESET ================= */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* ================= BODY ================= */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background-color: #f4f7f9;
height: 100vh;
overflow: hidden;
/* no scroll desktop */
}
/* ================= LINKS ================= */
a {
text-decoration: none !important;
color: #007bff;
}
/* ================= NAVBAR ================= */
.navbar {
width: 100%;
height: 60px;
background-color: #007bff;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
position: fixed;
top: 0;
left: 0;
color: white;
z-index: 1000;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.nav-left {
display: flex;
align-items: center;
gap: 15px;
}
.nav-logo {
height: 70px;
filter: brightness(0) invert(1);
}
.toggle-btn {
font-size: 26px;
cursor: pointer;
}
/* ================= SIDEBAR ================= */
.sidebar {
width: 250px;
background: white;
height: calc(100vh - 60px);
position: fixed;
top: 60px;
left: 0;
padding-top: 20px;
border-right: 1px solid #d6d6d6;
display: flex;
flex-direction: column;
}
.sidebar.hide {
left: -250px;
}
.menu-items {
flex: 1;
display: flex;
flex-direction: column;
}
.menu-btn {
padding: 14px 20px;
font-size: 16px;
color: #007bff;
font-weight: 600;
cursor: pointer;
border-bottom: 1px solid #e5e5e5;
}
.menu-btn:hover {
background: #e9f3ff;
}
.submenu {
display: none;
background: #f4faff;
}
.submenu a {
padding: 12px 35px;
display: block;
color: #0056b3;
}
/* ================= MAIN ================= */
.main {
margin-left: 250px;
margin-top: 60px;
width: calc(100% - 250px);
height: calc(100vh - 60px);
display: flex;
align-items: center;
/* ✅ vertical center */
justify-content: center;
/* ✅ horizontal center */
padding: 30px;
}
/* ================= CONTAINER ================= */
.container {
width: 100%;
max-width: 680px;
/* 🔥 laptop & desktop size */
background: #ffffff;
padding: 45px 55px;
border-radius: 14px;
box-shadow: 0 14px 40px rgba(0, 0, 0, 0.12);
text-align: center;
}
/* ================= HEADING ================= */ /* ================= HEADING ================= */
.container h2 { .container h2 {
font-size: 28px; font-size: 28px;

View File

@@ -62,7 +62,6 @@ function addRow() {
tr.innerHTML = ` tr.innerHTML = `
<td contenteditable="true"></td> <td contenteditable="true"></td>
<td><input></td> <td><input></td>
<td><input></td>
${utilizedCols} ${utilizedCols}
<td><input></td> <td><input></td>
<td> <td>
@@ -89,7 +88,6 @@ function saveRow(btn) {
let payload = { let payload = {
financial_year: financialYear, financial_year: financialYear,
mat_credit: inputs[0].value || 0, mat_credit: inputs[0].value || 0,
opening_balance: inputs[1].value || 0,
balance: inputs[inputs.length - 1].value || 0, balance: inputs[inputs.length - 1].value || 0,
utilization: [] utilization: []
}; };

View File

@@ -9,7 +9,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2 style="text-align:center;">New Assessing Officer(AO) Form</h2> <h2 style="text-align:center;">New AO Form</h2>
<form id="ao" method="POST" enctype="multipart/form-data"> <form id="ao" method="POST" enctype="multipart/form-data">
<input type="hidden" name="stage" value="ao"> <input type="hidden" name="stage" value="ao">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">

View File

@@ -9,7 +9,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2 style="text-align:center;">New Income Tax Appellate Tribunal(ITAT) Form</h2> <h2 style="text-align:center;">New Income Tax Appellate Tribunal Form</h2>
<form id="itat" method="POST" enctype="multipart/form-data" onsubmit="return showSuccessMessage()"> <form id="itat" method="POST" enctype="multipart/form-data" onsubmit="return showSuccessMessage()">
<input type="hidden" name="stage" value="itr"> <input type="hidden" name="stage" value="itr">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">

View File

@@ -172,7 +172,7 @@
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>
<label>Add :Mat Credit Created:</label> <label>Less :Mat Credit Created:</label>
<input type="number" name="mat_credit_created" step="any" value="0.00" oninput="calculate()" required> <input type="number" name="mat_credit_created" step="any" value="0.00" oninput="calculate()" required>
</div> </div>
<div> <div>

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Download Assessing Officer(AO) Report</h2> <h2>Download AO Report</h2>
<form method="GET" action="{{ url_for('ao_report') }}" target="_blank"> <form method="GET" action="{{ url_for('ao_report') }}" target="_blank">
<label for="year">Select Year:</label><br> <label for="year">Select Year:</label><br>
<select name="year" id="year" required> <select name="year" id="year" required>

View File

@@ -7,7 +7,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2 style="text-align: center;">Assessing Officer(AO) Records 👨‍💼</h2> <h2 style="text-align: center;">Assessing Officer Records 👨‍💼</h2>
<!-- Add AO Record Button --> <!-- Add AO Record Button -->
<div style="text-align: right; margin-bottom: 10px;"> <div style="text-align: right; margin-bottom: 10px;">
<a href="{{ url_for('add_ao') }}" class="btn btn-add"> Add AO Record</a> <a href="{{ url_for('add_ao') }}" class="btn btn-add"> Add AO Record</a>

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2 style="text-align: center;">Income Income Tax Appellate Tribunal(ITAT) Records 📄</h2> <h2 style="text-align: center;">Income Tax Appellate Tribunal Records 📄</h2>
<div style="text-align: right; margin-bottom: 10px;"> <div style="text-align: right; margin-bottom: 10px;">
<a href="{{ url_for('add_itat') }}" class="btn btn-add"> Add New Record</a> <a href="{{ url_for('add_itat') }}" class="btn btn-add"> Add New Record</a>

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Download Income Tax Appellate Tribunal(ITAT) Report</h2> <h2>Download ITAT Report</h2>
<form method="GET" action="{{ url_for('itat_report') }}" target="_blank"> <form method="GET" action="{{ url_for('itat_report') }}" target="_blank">
<label for="year">Select Year:</label><br> <label for="year">Select Year:</label><br>
<select name="year" id="year" required> <select name="year" id="year" required>

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Download Income Tax Return(ITR) Report</h2> <h2>Download ITR Report</h2>
<form method="GET" action="{{ url_for('itr_report') }}" target="_blank"> <form method="GET" action="{{ url_for('itr_report') }}" target="_blank">
<label for="year">Select Year:</label><br> <label for="year">Select Year:</label><br>
<select name="year" id="year" required> <select name="year" id="year" required>

View File

@@ -29,7 +29,6 @@
<tr id="tableHeader"> <tr id="tableHeader">
<th>AY</th> <th>AY</th>
<th>MAT Credit</th> <th>MAT Credit</th>
<th>Opening balance</th>
{% for y in added_years %} {% for y in added_years %}
<th>Utilized {{ y }}</th> <th>Utilized {{ y }}</th>
@@ -45,7 +44,6 @@
<tr> <tr>
<td contenteditable="false">{{ row.financial_year }}-{{ row.financial_year | int + 1 }}</td> <td contenteditable="false">{{ row.financial_year }}-{{ row.financial_year | int + 1 }}</td>
<td><input value="{{ row.mat_credit }}"></td> <td><input value="{{ row.mat_credit }}"></td>
<td><input value="{{ row.opening_balance }}"></td>
{% for y in added_years %} {% for y in added_years %}
<td> <td>

View File

@@ -8,10 +8,10 @@
<div class="container"> <div class="container">
<h2>Reports</h2> <h2>Reports</h2>
<ul> <ul>
<li><a href="{{ url_for('itr_report') }}">→ View Income Tax Return(ITR) Reports</a></li> <li><a href="{{ url_for('itr_report') }}">→ View ITR Reports</a></li>
<li><a href="{{ url_for('ao_report') }}">→ View Assessing Officer(AO) Reports</a></li> <li><a href="{{ url_for('ao_report') }}">→ View AO Reports</a></li>
<li><a href="{{ url_for('cit_report') }}">→ View CIT Reports</a></li> <li><a href="{{ url_for('cit_report') }}">→ View CIT Reports</a></li>
<li><a href="{{ url_for('itat_report') }}">→ View Income Tax Appellate Tribunal(ITAT) Reports</a></li> <li><a href="{{ url_for('itat_report') }}">→ View ITAT Reports</a></li>
</ul> </ul>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ stage }} Reports</title>
<link rel="stylesheet" href="{{ url_for('static', filename='index.css') }}">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f0f2f5;
margin: 0;
padding: 0;
}
.container {
max-width: 960px;
margin: 40px auto;
padding: 30px;
background-color: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
h2 {
color: #333;
text-align: center;
margin-bottom: 30px;
font-size: 28px;
}
form {
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
margin-bottom: 30px;
flex-wrap: wrap;
}
label {
font-weight: 600;
font-size: 16px;
}
select {
padding: 8px 14px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 6px;
outline: none;
transition: border 0.2s;
}
select:focus {
border-color: #007bff;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
font-size: 15px;
}
th,
td {
padding: 12px;
border: 1px solid #ddd;
text-align: left;
}
th {
background-color: #007bff;
color: white;
}
tr:nth-child(even) td {
background-color: #f9fbfc;
}
tr:hover td {
background-color: #eef5ff;
}
.btn-download {
background-color: #28a745;
color: white;
border: none;
padding: 7px 14px;
border-radius: 5px;
text-decoration: none;
font-size: 14px;
cursor: pointer;
transition: background-color 0.2s;
}
.btn-download:hover {
background-color: #218838;
}
.no-data {
text-align: center;
color: #777;
font-size: 16px;
margin-top: 20px;
}
/* Back button styling */
.back-btn {
display: inline-block;
margin-bottom: 20px;
padding: 10px 18px;
background: #6c757d;
color: white;
font-size: 15px;
font-weight: 600;
border-radius: 6px;
text-decoration: none;
transition: background 0.3s ease;
}
.back-btn:hover {
background: #5a6268;
}
</style>
</head>
<body>
<div class="container">
<h2>{{ stage }} Reports</h2>
<form method="GET">
<input type="hidden" name="stage" value="{{ stage }}">
<label for="year">Select Year:</label>
<select name="year" id="year" onchange="this.form.submit()">
<option value="">-- All Years --</option>
{% for y in years %}
<option value="{{ y }}" {% if y==request.args.get('year') %}selected{% endif %}>{{ y }}</option>
{% endfor %}
</select>
</form>
{% if documents %}
<table>
<thead>
<tr>
<th>Year</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for doc in documents %}
<tr>
<td>{{ doc.year }}</td>
<td>
<a class="btn-download" href="{{ url_for('download_report', doc_id=doc.id) }}">Download</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="no-data">No reports found for this selection.</p>
{% endif %}
</div>
</body>
</html>

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Update Assessing Officer(AO) Record for Year {{ record.year }} - {{ record.year + 1 }}</h2> <h2>Update AO Record for Year {{ record.year }} - {{ record.year + 1 }}</h2>
<form method="POST" action="{{ url_for('update_ao', id=record.id) }}"> <form method="POST" action="{{ url_for('update_ao', id=record.id) }}">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>

View File

@@ -7,7 +7,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Update Income Tax Appellate Tribunal(ITAT) Record for Year {{ record.year }}</h2> <h2>Update ITAT Record for Year {{ record.year }}</h2>
<form method="POST" action="{{ url_for('update_itat', id=record.id) }}"> <form method="POST" action="{{ url_for('update_itat', id=record.id) }}">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Update Income Tax Return (ITR) Record for Year {{record.year}} - {{record.year+1}}</h2> <h2>Update ITR Record for Year {{record.year}} - {{record.year+1}}</h2>
<form method="POST" action="{{ url_for('update_itr', id=record.id) }}"> <form method="POST" action="{{ url_for('update_itr', id=record.id) }}">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>

View File

@@ -1,28 +1,24 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title> <title>Document</title>
<style> <style>
body { body {
background: black; background: black;
color: #00ff00; color: #00ff00;
font-family: monospace; font-family: monospace;
} }
.log-box {
.log-box { white-space: pre-wrap;
white-space: pre-wrap; height: 90vh;
height: 90vh; overflow-y: scroll;
overflow-y: scroll; }
}
</style> </style>
</head> </head>
<body>
<body>
<h2>Application Logs</h2> <h2>Application Logs</h2>
<div class="log-box">{% for line in logs %} {{ line }} {% endfor %}</div> <div class="log-box">{% for line in logs %} {{ line }} {% endfor %}</div>
</body> </body>
</html>
</html>

View File

@@ -1,10 +1,10 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>View Logs - Authorization</title> <title>View Logs - Authorization</title>
<style> <style>
body { body {
margin: 0; margin: 0;
@@ -70,18 +70,21 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h2>Enter Secret to View Logs</h2> <h2>Enter Secret to View Logs</h2>
<form method="POST"> <form method="POST">
<input type="password" name="secret" placeholder="Enter Secret Password" required> <input type="password" name="secret" placeholder="Enter Secret Password" required>
<button type="submit">Open Logs</button> <button type="submit">Open Logs</button>
</form> </form>
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %} {% for category, message in messages %}
<div class="flash-message">{{ message }}</div> <div class="flash-message">{{ message }}</div>
{% endfor %} {% endfor %}
{% endwith %} {% endwith %}
</div> </div>
</body>
</html> </body>
</html>