pankaj-dev #2

Merged
pjpatil12 merged 4 commits from pankaj-dev into main 2026-02-07 05:45:35 +00:00
47 changed files with 903 additions and 340 deletions

10
.gitignore vendored
View File

@@ -15,3 +15,13 @@ logs/
# Environment variables
.env
# Python cache
__pycache__/
*.pyc
# OS / Editor
.vscode/
.idea/

View File

@@ -32,6 +32,8 @@ class AOHandler:
# Add AO record # Add AO record
def add_ao(self, data): def add_ao(self, data):
try:
fields = [ fields = [
'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37', 'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37',
'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other', 'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other',
@@ -40,13 +42,18 @@ class AOHandler:
'tax_payable', 'surcharge', 'edu_cess', 'tax_payable', 'surcharge', 'edu_cess',
'total_tax_payable', 'mat_credit_created', 'mat_credit_utilized', 'total_tax_payable', 'mat_credit_created', 'mat_credit_utilized',
'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs', 'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs',
'sat', 'tax_on_assessment', 'refund', 'Remarks' 'sat', 'tax_on_assessment', 'refund', 'Remarks','created_at'
] ]
values = [data.get(f, 0) for f in fields] values = [data.get(f, 0) for f in fields]
self.cursor.callproc("InsertAO", values) self.cursor.callproc("InsertAO", values)
self.conn.commit() self.conn.commit()
except Exception as e:
self.conn.rollback()
raise e
finally:
self.cursor.close()
self.conn.close()
# UPDATE AO RECORD by AO id # UPDATE AO RECORD by AO id
def update_ao(self, id, data): def update_ao(self, id, data):

View File

@@ -43,7 +43,7 @@ class CITHandler:
'tax_payable', 'surcharge', 'edu_cess', 'tax_payable', 'surcharge', 'edu_cess',
'total_tax_payable', 'mat_credit_created', 'mat_credit_utilized', 'total_tax_payable', 'mat_credit_created', 'mat_credit_utilized',
'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs', 'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs',
'sat', 'tax_on_assessment', 'refund', 'Remarks' 'sat', 'tax_on_assessment', 'refund', 'Remarks','created_at'
] ]
values = [data.get(col, 0) for col in columns] values = [data.get(col, 0) for col in columns]

View File

@@ -1,4 +1,6 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort, flash,send_file 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
@@ -17,11 +19,40 @@ class DocumentHandler:
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
# VIEW DOCUMENTS # =========================
# Utility: Parse Year
# =========================
def parse_year(self, year_value):
"""
Accepts:
- '2026'
- 'AY 2026-2027'
Returns:
- 2026 (int)
"""
if not year_value:
return None
year_value = year_value.strip()
if year_value.isdigit():
return int(year_value)
try:
# "AY 2026-2027" → 2026
return int(year_value.split()[1].split('-')[0])
except Exception:
return None
# =========================
# View Documents
# =========================
def View(self, request): def View(self, request):
year = request.args.get('year', '') year_raw = request.args.get('year', '')
stage = request.args.get('stage', '') stage = request.args.get('stage', '')
year = self.parse_year(year_raw)
dbconfig = DBConfig() dbconfig = DBConfig()
connection = dbconfig.get_db_connection() connection = dbconfig.get_db_connection()
@@ -30,15 +61,13 @@ class DocumentHandler:
return return
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
# --- FILTER QUERY ---
cursor.callproc("GetDocuments", [year, stage]) cursor.callproc("GetDocuments", [year, stage])
# fetch first result set
for result in cursor.stored_results(): for result in cursor.stored_results():
self.documents = result.fetchall() self.documents = result.fetchall()
break break
# ---- GET YEARS FROM STORED PROCEDURE ----
cursor.callproc("GetYear") cursor.callproc("GetYear")
for result in cursor.stored_results(): for result in cursor.stored_results():
@@ -49,55 +78,72 @@ class DocumentHandler:
cursor.close() cursor.close()
connection.close() connection.close()
self.isSuccess = True self.isSuccess = True
# =========================
# Upload Documents # Upload Documents
# =========================
def Upload(self, request): def Upload(self, request):
dbconfig = DBConfig() dbconfig = DBConfig()
connection = dbconfig.get_db_connection() connection = dbconfig.get_db_connection()
if connection: if not connection:
cursor = connection.cursor() return
files = request.files.getlist('documents')
year = request.form['year']
stage = request.form['stage']
for file in files: cursor = connection.cursor()
extension = file.filename.rsplit('.', 1)[1]
if extension not in FileHandler.ALLOWED_EXTENSIONS:
print("Skip invalid file type : ",extension)
continue
filename = secure_filename(file.filename) files = request.files.getlist('documents')
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename) year_raw = request.form.get('year')
file.save(filepath) stage = request.form.get('stage')
cursor.callproc('InsertDocument', [ filename, filepath, extension, year, stage ]) year = self.parse_year(year_raw)
connection.commit() if not year:
cursor.close() self.resultMessage = "Invalid year selected."
connection.close() return
# return redirect(url_for('view_documents'))
def Summary_report(self, request): for file in files:
dbconfig = DBConfig() if '.' not in file.filename:
connection = dbconfig.get_db_connection() continue
year_str = request.args.get('year') extension = file.filename.rsplit('.', 1)[1].lower()
# If year not selected if extension not in FileHandler.ALLOWED_EXTENSIONS:
if not year_str or not year_str.isdigit(): print("Skipping invalid file:", extension)
yearGetter = YearGet() continue
allYears = yearGetter.get_year_by_model("AllYearsInAllModel")
yearGetter.close() filename = secure_filename(file.filename)
return render_template( filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename)
'summary_reports.html',
years=allYears, file.save(filepath)
message="Please select a valid year to download."
cursor.callproc(
'InsertDocument',
[filename, filepath, extension, year, stage]
) )
# Convert year to int (IMPORTANT FIX) connection.commit()
year = int(year_str) cursor.close()
connection.close()
# =========================
# Summary Preview (JSON)
# =========================
def Summary_preview(self, request):
"""
Returns JSON preview of summary report for selected year.
"""
year_raw = request.args.get("year")
year = self.parse_year(year_raw)
if not year:
return jsonify([])
dbconfig = DBConfig()
connection = dbconfig.get_db_connection()
if not connection:
return jsonify([])
try: try:
stages = { stages = {
@@ -112,11 +158,111 @@ class DocumentHandler:
for stage_name, table_name in stages.items(): for stage_name, table_name in stages.items():
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
cursor.callproc("sp_get_stage_data", [table_name, year]) cursor.callproc("sp_get_stage_data", [table_name, year])
rows = [] rows = []
for result in cursor.stored_results(): for result in cursor.stored_results():
rows = result.fetchall() rows = result.fetchall()
stage_data[stage_name] = pd.DataFrame(rows) if rows else pd.DataFrame()
cursor.close()
columns = [
'gross_total_income', 'disallowance_14a',
'disallowance_37', '-',
'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',
'edu_cess', 'total_tax_payable',
'mat_credit_created',
'mat_credit_utilized',
'interest_234c', 'total_tax',
'-', 'advance_tax', 'tds',
'tcs', 'sat',
'tax_on_assessment',
'refund', 'Remarks'
]
particulars = [
"Gross Total Income", "Add: Disallowance u/s 14A",
"Add: Disallowance u/s 37", "GTI as per",
"Less: Deduction u/s 80IA - On Business Income",
"- On Misc Receipts", "- On Other",
"- On Sec 37 Disallowance",
"Less: Deduction u/s 80G", " ",
"Net Taxable Income", "Tax @ 30%",
"Tax @ 18.5% on Book Profit",
"Tax Payable", "Surcharge @ %",
"Education Cess @ %", "Total Tax Payable",
"Add: MAT Credit Created",
"Less: MAT Credit Utilized",
"Add: Interest u/s 234C",
"Total Tax", " ",
"Advance Tax", "TDS", "TCS", "SAT",
"Tax on Regular Assessment",
"Refund", "Remarks"
]
def safe_get(df, col):
return df[col].values[0] if col in df.columns and not df.empty else 0
preview = []
for i, part in enumerate(particulars):
preview.append({
"Particular": part,
"ITR": safe_get(stage_data['ITR'], columns[i]),
"AO": safe_get(stage_data['AO'], columns[i]),
"CIT": safe_get(stage_data['CIT'], columns[i]),
"ITAT": safe_get(stage_data['ITAT'], columns[i]),
})
return jsonify(preview)
finally:
connection.close()
def Summary_report(self, request):
dbconfig = DBConfig()
connection = dbconfig.get_db_connection()
year_raw = request.args.get('year')
# Safely parse year to int
try:
year = int(year_raw)
except (TypeError, ValueError):
year = None
if not year:
yearGetter = YearGet()
allYears = yearGetter.get_year_by_model("AllYearsInAllModel")
yearGetter.close()
return render_template(
'summary_reports.html',
years=allYears,
message="Please select a valid year to download."
)
try:
stages = {
"ITR": "itr",
"AO": "ao",
"CIT": "cit",
"ITAT": "itat",
}
stage_data = {}
for stage_name, table_name in stages.items():
cursor = connection.cursor(dictionary=True)
cursor.callproc("sp_get_stage_data", [table_name, year])
rows = []
for result in cursor.stored_results():
rows = result.fetchall()
stage_data[stage_name] = pd.DataFrame(rows) if rows else pd.DataFrame() stage_data[stage_name] = pd.DataFrame(rows) if rows else pd.DataFrame()
cursor.close() cursor.close()
@@ -124,25 +270,45 @@ class DocumentHandler:
return df[col].values[0] if col in df.columns and not df.empty else "-" return df[col].values[0] if col in df.columns and not df.empty else "-"
particulars = [ particulars = [
"Gross Total Income", "Add: Disallowance u/s 14A", "Add: Disallowance u/s 37", "Gross Total Income", "Add: Disallowance u/s 14A",
"GTI as per", "Less: Deduction u/s 80IA - On Business Income", "- On Misc Receipts", "Add: Disallowance u/s 37", "GTI as per",
"- On Other", "- On Sec 37 Disallowance", "Less: Deduction u/s 80G", " ", "Less: Deduction u/s 80IA - On Business Income",
"Net Taxable Income", "Tax @ 30%", "Tax @ 18.5% on Book Profit", "- On Misc Receipts", "- On Other",
"Tax Payable", "Surcharge @ %", "Education Cess @ %", "Total Tax Payable","Add: MAT Credit Created", "- On Sec 37 Disallowance",
"Less: MAT Credit Utilized", "Add: Interest u/s 234C", "Total Tax", " ", "Less: Deduction u/s 80G", " ",
"Net Taxable Income", "Tax @ 30%",
"Tax @ 18.5% on Book Profit",
"Tax Payable", "Surcharge @ %",
"Education Cess @ %", "Total Tax Payable",
"Add: MAT Credit Created",
"Less: MAT Credit Utilized",
"Add: Interest u/s 234C",
"Total Tax", " ",
"Advance Tax", "TDS", "TCS", "SAT", "Advance Tax", "TDS", "TCS", "SAT",
"Tax on Regular Assessment", "Refund" , "Remarks" "Tax on Regular Assessment",
"Refund", "Remarks"
] ]
columns = [ columns = [
'gross_total_income', 'disallowance_14a', 'disallowance_37', 'gross_total_income', 'disallowance_14a',
'-', 'deduction_80ia_business','deduction_80ia_misc', 'disallowance_37', '-',
'deduction_80ia_other', 'deduction_sec37_disallowance','deduction_80g', '-', 'deduction_80ia_business',
'net_taxable_income', 'tax_30_percent','tax_book_profit_18_5', 'deduction_80ia_misc',
'tax_payable','surcharge', 'edu_cess', 'total_tax_payable', 'deduction_80ia_other',
'mat_credit_created','mat_credit_utilized' , 'interest_234c','total_tax', '-', 'deduction_sec37_disallowance',
'advance_tax', 'tds', 'tcs', 'sat', 'deduction_80g', '-',
'tax_on_assessment', 'refund', 'Remarks' 'net_taxable_income',
'tax_30_percent',
'tax_book_profit_18_5',
'tax_payable', 'surcharge',
'edu_cess', 'total_tax_payable',
'mat_credit_created',
'mat_credit_utilized',
'interest_234c', 'total_tax',
'-', 'advance_tax', 'tds',
'tcs', 'sat',
'tax_on_assessment',
'refund', 'Remarks'
] ]
data = { data = {
@@ -155,56 +321,44 @@ class DocumentHandler:
df = pd.DataFrame(data) df = pd.DataFrame(data)
# ===== Excel Export =====
output = io.BytesIO() output = io.BytesIO()
with pd.ExcelWriter(output, engine='xlsxwriter') as writer: with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
sheet_name = f"AY {year} - {year + 1}" sheet_name = f"AY {year}-{year + 1}"
df.to_excel(writer, index=False, sheet_name=sheet_name, startrow=2) df.to_excel(writer, index=False, sheet_name=sheet_name, startrow=2)
workbook = writer.book workbook = writer.book
worksheet = writer.sheets[sheet_name] worksheet = writer.sheets[sheet_name]
# ===== Company Heading ===== title = workbook.add_format({
company_heading = workbook.add_format({
'bold': True, 'bold': True,
'font_size': 14, 'font_size': 14,
'font_color': 'black', 'align': 'center'
'align': 'center',
'valign': 'middle'
}) })
worksheet.merge_range( worksheet.merge_range(
0, 0, 0, len(df.columns) - 1, 0, 0, 0, len(df.columns) - 1,
"Laxmi Civil Engineering Services Pvt Ltd", "Laxmi Civil Engineering Services Pvt Ltd",
company_heading title
) )
# ===== Header Format =====
header = workbook.add_format({ header = workbook.add_format({
'bold': True, 'bold': True,
'align': 'center', 'align': 'center',
'valign': 'middle',
'bg_color': '#007bff', 'bg_color': '#007bff',
'font_color': 'white', 'font_color': 'white',
'border': 1 'border': 1
}) })
cell = workbook.add_format({ cell = workbook.add_format({'border': 1})
'border': 1,
'align': 'left',
'valign': 'middle'
})
# Write headers
for col_num, col_name in enumerate(df.columns): for col_num, col_name in enumerate(df.columns):
worksheet.write(2, col_num, col_name, header) worksheet.write(2, col_num, col_name, header)
max_len = max(df[col_name].astype(str).map(len).max(), len(col_name)) + 2 worksheet.set_column(col_num, col_num, 25)
worksheet.set_column(col_num, col_num, max_len)
# Write data rows for row in range(len(df)):
for row in range(3, len(df) + 3):
for col in range(len(df.columns)): for col in range(len(df.columns)):
worksheet.write(row, col, df.iloc[row - 3, col], cell) worksheet.write(row + 3, col, df.iloc[row, col], cell)
worksheet.freeze_panes(3, 1) worksheet.freeze_panes(3, 1)
@@ -219,3 +373,4 @@ class DocumentHandler:
finally: finally:
connection.close() connection.close()

View File

@@ -41,21 +41,29 @@ class ITRHandler:
# INSERT ITR RECORD using procedure "add_itr" # INSERT ITR RECORD using procedure "add_itr"
def add_itr(self, data): def add_itr(self, data):
columns = [ try:
'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37', columns = [
'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other', 'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37',
'deduction_sec37_disallowance', 'deduction_80g', 'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other',
'net_taxable_income', 'tax_30_percent', 'tax_book_profit_18_5', 'deduction_sec37_disallowance', 'deduction_80g',
'tax_payable', 'surcharge', 'edu_cess', 'net_taxable_income', 'tax_30_percent', 'tax_book_profit_18_5',
'total_tax_payable', 'mat_credit_created', 'mat_credit_utilized', 'tax_payable', 'surcharge', 'edu_cess',
'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs', 'total_tax_payable', 'mat_credit_created', 'mat_credit_utilized',
'sat', 'tax_on_assessment', 'refund', 'Remarks','created_at' 'interest_234c', 'total_tax', 'advance_tax', 'tds', 'tcs',
] 'sat', 'tax_on_assessment', 'refund', 'Remarks','created_at'
values = [data.get(col, 0) for col in columns] ]
values = [data.get(col, 0) for col in columns]
# Call your stored procedure
self.cursor.callproc("InsertITR", values)
self.conn.commit()
except Exception as e:
self.conn.rollback()
raise e
finally:
self.cursor.close()
self.conn.close()
# Call your stored procedure
self.cursor.callproc("InsertITR", values)
self.conn.commit()
# update itr by id # update itr by id
def update(self, id, data): def update(self, id, data):

View File

@@ -1,15 +1,18 @@
from AppCode.Config import DBConfig from AppCode.Config import DBConfig
class MatCreditHandler: class MatCreditHandler:
def __init__(self): def __init__(self):
# db = DBConfig()
self.conn = DBConfig.get_db_connection() self.conn = DBConfig.get_db_connection()
self.cursor = self.conn.cursor(dictionary=True) self.cursor = self.conn.cursor(dictionary=True)
# get all Mat credit data # --------------------------------------------------
# FETCH ALL MAT CREDIT + UTILIZATION (For UI Display)
# --------------------------------------------------
def fetch_all(self): def fetch_all(self):
try: try:
self.cursor.callproc("GetMatCedit") 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()
@@ -18,30 +21,78 @@ class MatCreditHandler:
return mat_rows, utilization_rows return mat_rows, utilization_rows
finally: finally:
self.cursor.close() self.cursor.close()
self.conn.close()
# Save Mat credit data single row # --------------------------------------------------
# SAVE / UPDATE SINGLE MAT ROW (FROM MANUAL UI)
# --------------------------------------------------
@staticmethod @staticmethod
def save_single(data): def save_single(data):
conn = DBConfig.get_db_connection() conn = DBConfig.get_db_connection()
cur = conn.cursor(dictionary=True) cur = conn.cursor(dictionary=True)
try: try:
# Save / Update MAT Credit
cur.callproc(
"SaveOrUpdateMatCredit",
(
data["financial_year"],
data["mat_credit"],
data["balance"],
data.get("remarks", "")
)
)
cur.callproc("SaveOrUpdateMatCredit",( mat_id = None
data["financial_year"], for result in cur.stored_results():
data["mat_credit"], mat_id = result.fetchone()["mat_id"]
data["balance"]
))
result = next(cur.stored_results()).fetchone()
mat_id = result["mat_id"]
if not mat_id:
raise Exception("mat_id not returned from procedure")
# Save utilization rows
for u in data.get("utilization", []): for u in data.get("utilization", []):
if float(u["amount"]) > 0:
cur.callproc(
"InsertMatUtilization",
(mat_id, u["year"], u["amount"])
)
conn.commit()
except Exception as e:
conn.rollback()
raise e
finally:
cur.close()
conn.close()
# --------------------------------------------------
# AUTO SAVE MAT FROM ITR (MAIN LOGIC)
# --------------------------------------------------
@staticmethod
def save_from_itr(year, mat_created, mat_utilized, remarks="Auto from"):
conn = DBConfig.get_db_connection()
cur = conn.cursor(dictionary=True)
try:
mat_created = float(mat_created or 0)
mat_utilized = float(mat_utilized or 0)
balance = mat_created - mat_utilized
# Save / Update MAT Credit
cur.callproc(
"SaveOrUpdateMatCredit",
(year, mat_created, balance, remarks)
)
mat_id = None
for result in cur.stored_results():
mat_id = result.fetchone()["mat_id"]
# Save utilization only if used
if mat_utilized > 0:
cur.callproc( cur.callproc(
"InsertMatUtilization", "InsertMatUtilization",
(mat_id, u["year"], u["amount"]) (mat_id, year, mat_utilized)
) )
conn.commit() conn.commit()
@@ -49,56 +100,29 @@ class MatCreditHandler:
except Exception as e: except Exception as e:
conn.rollback() conn.rollback()
raise e raise e
finally: finally:
cur.close() cur.close()
conn.close() conn.close()
# save all Mat credit data # --------------------------------------------------
# @staticmethod # DELETE MAT CREDIT SAFELY (OPTIONAL)
# def save_bulk(rows): # --------------------------------------------------
# conn = DBConfig.get_db_connection() def delete_by_year(self, financial_year):
# cur = conn.cursor() try:
# skipped = [] self.cursor.execute(
"DELETE FROM mat_credit WHERE financial_year=%s",
(financial_year,)
)
self.conn.commit()
finally:
self.cursor.close()
self.conn.close()
# try: # --------------------------------------------------
# for row in rows: # CLOSE CONNECTION (MANUAL USE)
# cur.execute( # --------------------------------------------------
# "SELECT id FROM mat_credit WHERE financial_year=%s",
# (row["financial_year"],)
# )
# if cur.fetchone():
# skipped.append(row["financial_year"])
# continue
# cur.execute("""
# INSERT INTO mat_credit (financial_year, mat_credit, balance)
# VALUES (%s,%s,%s)
# """, (row["financial_year"], row["mat_credit"], row["balance"]))
# mat_id = cur.lastrowid
# for u in row["utilization"]:
# cur.execute("""
# INSERT INTO mat_utilization
# (mat_credit_id, utilized_year, utilized_amount)
# VALUES (%s,%s,%s)
# """, (mat_id, u["year"], u["amount"]))
# conn.commit()
# return skipped
# except Exception:
# conn.rollback()
# raise
# finally:
# cur.close()
# conn.close()
# CLOSE CONNECTION
def close(self): def close(self):
self.cursor.close() if self.cursor:
self.conn.close() self.cursor.close()
if self.conn:
self.conn.close()

92
main.py
View File

@@ -15,6 +15,7 @@ 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 subprocess
@@ -59,7 +60,6 @@ def view_documents():
docHandler.View(request=request) docHandler.View(request=request)
return render_template('view_docs.html', documents=docHandler.documents, years=docHandler.years) return render_template('view_docs.html', documents=docHandler.documents, years=docHandler.years)
# Upload file documents # Upload file documents
@app.route('/uploads/<filename>') @app.route('/uploads/<filename>')
@auth.login_required @auth.login_required
@@ -68,20 +68,26 @@ def uploaded_file(filename):
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, secure_filename(filename)) filepath = os.path.join(FileHandler.UPLOAD_FOLDER, secure_filename(filename))
if not os.path.exists(filepath): if not os.path.exists(filepath):
abort(404) flash("Unsupported file type for viewing", "warning")
return redirect(url_for('view_documents'))
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
if file_ext == 'pdf': if file_ext == 'pdf':
return send_file(filepath, mimetype='application/pdf') return send_file(filepath, mimetype='application/pdf')
# Word
elif file_ext in ['doc', 'docx']:
return send_file(filepath, as_attachment=True)
# Excel
elif file_ext in ['xls', 'xlsx']: 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') return send_file(filepath, as_attachment=False, download_name=filename, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
else: else:
return abort(415) # Unsupported type for viewing flash("Unsupported file type for viewing", "warning")
return redirect(url_for('view_documents'))
return send_file(filepath, as_attachment=True) return send_file(filepath, as_attachment=True, download_name=filename)
@@ -105,20 +111,28 @@ def display_itr():
def add_itr(): def add_itr():
if request.method == 'POST': if request.method == 'POST':
itr = ITRHandler() itr = ITRHandler()
mat = MatCreditHandler()
itr.add_itr(request.form) itr.add_itr(request.form)
itr.close() itr.close()
if 'documents' in request.files: if 'documents' in request.files:
doc = DocumentHandler() doc = DocumentHandler()
doc.Upload(request) doc.Upload(request)
# AUTO SAVE MAT FROM ITR
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ITR"
)
# 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'))
return render_template('add_itr.html',current_date=date.today().isoformat()) return render_template('add_itr.html',current_date=date.today().isoformat())
## 4. DELETE an ITR record ## 4. DELETE an ITR records
@app.route('/itr/delete/<int:id>', methods=['POST']) @app.route('/itr/delete/<int:id>', methods=['POST'])
@auth.login_required @auth.login_required
def delete_itr(id): def delete_itr(id):
@@ -166,11 +180,25 @@ def display_ao():
def add_ao(): def add_ao():
if request.method == 'POST': if request.method == 'POST':
ao = AOHandler() ao = AOHandler()
mat = MatCreditHandler()
ao.add_ao(request.form) ao.add_ao(request.form)
ao.close() ao.close()
if 'documents' in request.files:
doc = DocumentHandler()
doc.Upload(request)
# AUTO SAVE MAT FROM ITR
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ao"
)
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') return render_template('add_ao.html',current_date=date.today().isoformat())
# 3. UPDATE AO record # 3. UPDATE AO record
@app.route('/ao/update/<int:id>', methods=['GET', 'POST']) @app.route('/ao/update/<int:id>', methods=['GET', 'POST'])
@@ -224,12 +252,25 @@ def display_cit():
def add_cit(): def add_cit():
if request.method == 'POST': if request.method == 'POST':
cit = CITHandler() cit = CITHandler()
mat = MatCreditHandler()
cit.add_cit(request.form) cit.add_cit(request.form)
cit.close() cit.close()
if 'documents' in request.files:
doc = DocumentHandler()
doc.Upload(request)
# AUTO SAVE MAT FROM ITR
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via cit"
)
flash("CIT record added successfully!", "success") flash("CIT record added successfully!", "success")
return redirect(url_for('display_cit')) return redirect(url_for('display_cit'))
return render_template('add_cit.html') return render_template('add_cit.html', current_date=date.today().isoformat())
# 3 delete CIT records by id # 3 delete CIT records by id
@app.route('/cit/delete/<int:id>', methods=['POST']) @app.route('/cit/delete/<int:id>', methods=['POST'])
@@ -281,13 +322,27 @@ def display_itat():
def add_itat(): def add_itat():
if request.method == 'POST': if request.method == 'POST':
itat = ITATHandler() itat = ITATHandler()
mat = MatCreditHandler()
data = {k: request.form.get(k, 0) for k in request.form} data = {k: request.form.get(k, 0) for k in request.form}
itat.add_itat(data) itat.add_itat(data)
itat.close() itat.close()
if 'documents' in request.files:
doc = DocumentHandler()
doc.Upload(request)
# AUTO SAVE MAT FROM ITR
mat.save_from_itr(
year=request.form["year"],
mat_created=float(request.form.get("mat_credit_created", 0)),
mat_utilized=float(request.form.get("mat_credit_utilized", 0)),
remarks="Created via ITR"
)
flash("ITAT record added successfully!", "success") flash("ITAT record added successfully!", "success")
return redirect(url_for('display_itat')) return redirect(url_for('display_itat'))
return render_template('add_itat.html') return render_template('add_itat.html',current_date=date.today().isoformat())
# 3.Update ITAT records by id # 3.Update ITAT records by id
@app.route('/itat/update/<int:id>', methods=['GET', 'POST']) @app.route('/itat/update/<int:id>', methods=['GET', 'POST'])
@@ -449,6 +504,17 @@ def summary_report():
docHandler = DocumentHandler() docHandler = DocumentHandler()
return docHandler.Summary_report(request=request) return docHandler.Summary_report(request=request)
@app.route('/summary/download', methods=['GET'])
@auth.login_required
def download_summary():
year_raw = request.args.get('year')
if not year_raw:
return "Year parameter is required", 400
docHandler = DocumentHandler()
# reuse your existing Summary_report method
return docHandler.Summary_report(request=request)
# check year in table existe or not by using ajax calling. # check year in table existe or not by using ajax calling.
# @app.route('/check_year', methods=['POST']) # @app.route('/check_year', methods=['POST'])
@@ -519,6 +585,12 @@ def save_mat_row():
finally: finally:
mat.close() mat.close()
@app.route("/summary/preview")
def summary_preview_route():
handler = DocumentHandler()
return handler.Summary_preview(request)
# save mat credit bulk data # save mat credit bulk data
# @app.route("/save_mat_all", methods=["POST"]) # @app.route("/save_mat_all", methods=["POST"])
# @auth.login_required # @auth.login_required

View File

@@ -1,153 +1,278 @@
/* ================= GLOBAL FORM ELEMENTS ================= */ /* ================= PAGE WRAPPER ================= */
.main {
margin-left: 260px;
width: calc(100% - 260px);
margin-top: 80px;
padding: 20px;
transition: all 0.3s ease;
}
/* ================= CONTAINER ================= */
.container {
width: 100%;
max-width: none;
margin: 0;
padding: 25px 30px;
background: #ffffff;
border-radius: 12px;
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.08);
}
/* ================= PAGE TITLE ================= */
.container h2 {
text-align: center;
color: #007bff;
font-size: 22px;
font-weight: 700;
margin-bottom: 20px;
}
h3 {
text-align: center;
margin-top: 10px;
}
/* ================= FORM ================= */
form {
width: 100%;
}
form label { form label {
display: block; display: block;
margin-top: 10px; margin-top: 10px;
font-weight: bold; font-weight: 600;
color: #333; color: #333;
} }
select { /* ================= INPUTS ================= */
width: 100%; form input,
max-width: 300px; form select {
/* restrict width on desktop/laptop */ width: 100%;
padding: 10px 12px; padding: 10px 12px;
border: 1px solid #ccc; margin-top: 6px;
border-radius: 6px; border: 1px solid #ccc;
margin-top: 6px; border-radius: 6px;
font-size: 15px; background-color: #f8f9ff;
background-color: white; font-size: 14px;
cursor: pointer;
transition: 0.2s;
} }
select:focus { form input:focus,
border-color: #007bff; form select:focus {
box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); outline: none;
outline: none; border-color: #007bff;
box-shadow: 0 0 6px rgba(0, 123, 255, 0.35);
}
/* ================= AUTO FIELDS ================= */
.auto {
background-color: #d5edd7;
font-weight: 600;
}
/* ================= FORM GROUP ================= */
.form-group {
margin-bottom: 16px;
display: flex;
flex-direction: column;
font-weight: 600;
}
/* Inline two columns */
.form-group.inline-2 {
flex-direction: row;
gap: 16px;
}
.form-group.inline-2 > div {
flex: 1;
} }
/* ================= BUTTONS ================= */ /* ================= BUTTONS ================= */
button { button {
margin-top: 20px; display: block;
padding: 10px 18px; width: 60%;
background-color: #007bff; margin: 25px auto 0;
color: white; padding: 12px 20px;
border: none; background-color: #28a745;
cursor: pointer; color: #fff;
border-radius: 6px; border: none;
font-size: 15px; border-radius: 6px;
font-weight: 600; font-size: 15px;
transition: 0.3s; font-weight: 600;
cursor: pointer;
transition: 0.3s;
} }
button:hover { button:hover {
background-color: #0069d9; background-color: #218838;
} box-shadow: 0 4px 10px rgba(40, 167, 69, 0.35);
/* ================= MAIN CONTAINER ================= */
.main {
margin-left: 260px;
/* sidebar width if exists */
padding: 70px 30px 40px 30px;
/* top padding for navbar */
margin-top: 50px;
/* extra top spacing */
width: auto;
transition: 0.3s;
}
.container {
max-width: 800px;
margin: 0 auto;
background: #ffffff;
padding: 35px 40px;
border-radius: 12px;
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.08);
} }
/* ================= BACK BUTTON ================= */ /* ================= BACK BUTTON ================= */
.back-btn { .back-btn {
display: inline-block; display: inline-block;
margin-top: 20px; margin-top: 20px;
padding: 10px 18px; padding: 10px 18px;
background-color: #007bff; background-color: #007bff;
color: white; color: #fff;
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
border-radius: 6px; border-radius: 6px;
text-decoration: none; text-decoration: none;
transition: 0.3s; transition: 0.3s;
} }
.back-btn:hover { .back-btn:hover {
background-color: #006ae6; background-color: #006ae6;
} }
/* ================= MESSAGES ================= */ /* ================= STICKY FILTER BAR ================= */
.head {
position: sticky;
top: 60px;
background: #fff;
z-index: 1000;
padding: 15px 0;
border-bottom: 1px solid #ccc;
}
/* ================= SELECT + DOWNLOAD ================= */
.select-download-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.select-download-wrapper select {
max-width: 300px;
}
select {
width: 100%;
max-width: 300px;
padding: 10px 12px;
border: 1px solid #ccc;
border-radius: 6px;
margin-top: 6px;
font-size: 15px;
background-color: white;
cursor: pointer;
transition: 0.2s;
}
select:focus {
border-color: #007bff;
box-shadow: 0 0 5px rgba(0,123,255,0.5);
outline: none;
}
/* ================= DOWNLOAD BUTTON ================= */
#downloadBtn {
display: none;
padding: 10px 20px;
font-size: 16px;
background-color: #28a745;
color: #fff;
text-decoration: none;
border-radius: 4px;
white-space: nowrap;
transition: 0.3s;
}
#downloadBtn:hover {
background-color: #218838;
}
/* ================= TABLE PREVIEW ================= */
#previewContent {
max-height: 60vh;
overflow-y: auto;
overflow-x: auto;
width: 100%;
margin-top: 15px;
}
#previewContent table {
width: 100%;
min-width: 600px;
border-collapse: collapse;
}
#previewContent th,
#previewContent td {
padding: 10px;
border: 1px solid #ccc;
white-space: nowrap;
}
/* Sticky table header */
#previewContent th {
position: sticky;
top: 0;
background-color: #007bff;
color: #fff;
z-index: 10;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* ================= MESSAGE ================= */
.message { .message {
margin-top: 15px; margin-top: 15px;
color: #555; color: #555;
font-size: 14px; font-size: 14px;
} }
/* ================= RESPONSIVE ================= */ /* ================= RESPONSIVE ================= */
/* Tablets (<= 992px) */
@media (max-width: 992px) { @media (max-width: 992px) {
.main { .main {
margin-left: 0; margin-left: 0;
/* remove sidebar spacing */ width: 100%;
padding: 50px 20px 20px 20px; padding: 20px;
} }
.container { button {
padding: 25px 20px; width: 100%;
} }
}
select {
max-width: 100%; @media (max-width: 768px) {
/* full width */ .container {
} padding: 18px;
}
button {
width: 100%; .container h2 {
/* full width */ font-size: 18px;
padding: 12px 0; }
}
.form-group.inline-2 {
flex-direction: column;
gap: 10px;
}
} }
/* Mobile (<= 576px) */
@media (max-width: 576px) { @media (max-width: 576px) {
.main { .main {
padding: 40px 15px 15px 15px; padding: 15px;
} margin-top: 70px;
}
.container { #previewContent table {
padding: 20px; min-width: 500px;
} }
h2 { #previewContent th,
font-size: 22px; #previewContent td {
text-align: center; font-size: 13px;
} padding: 8px;
}
select { }
font-size: 14px;
padding: 10px; @media (max-width: 420px) {
} form input,
form select {
button { font-size: 13px;
font-size: 14px; padding: 9px;
padding: 12px 0; }
}
.back-btn {
width: 100%;
text-align: center;
padding: 12px 0;
}
.message {
font-size: 13px;
}
} }

View File

@@ -46,16 +46,6 @@ document.addEventListener("DOMContentLoaded", function () {
var tax_payable = (tax30 > tax185) ? tax30 : tax185; var tax_payable = (tax30 > tax185) ? tax30 : tax185;
setValue("tax_payable", tax_payable); setValue("tax_payable", tax_payable);
// // --- SURCHARGE ---
// var percent = getValue("persentage");
// var surcharge = tax_payable * (percent / 100);
// setValue("surcharge", surcharge);
// // --- edu_cess ---
// var per_cess = getValue("persentage_cess")
// var edu_cess = (tax_payable + surcharge) * (per_cess / 100);
// setValue("edu_cess", edu_cess);
// --- SURCHARGE --- // --- SURCHARGE ---
var percent = getValue("persentage"); var percent = getValue("persentage");
var surcharge = tax_payable * (percent / 100); var surcharge = tax_payable * (percent / 100);
@@ -70,11 +60,37 @@ document.addEventListener("DOMContentLoaded", function () {
var total_tax_payable = tax_payable + surcharge + edu_cess; var total_tax_payable = tax_payable + surcharge + edu_cess;
setValue("total_tax_payable", total_tax_payable); setValue("total_tax_payable", total_tax_payable);
// // --- mat_credit_created --- new
// setValue("mat_credit_created", Math.max(tax185 - total_tax_payable, 0));
// // --- mat credit_utilized --- new
// setValue("mat_credit_utilized", Math.max(total_tax_payable - tax185, 0));
// --- MAT credit and utilized ---
var a = tax185
var b = total_tax_payable
var result = 0
if (a > b) {
result = a - b
setValue("mat_credit_created", result);
}
else {
setValue("mat_credit_created", result);
}
if (b > a) {
result = b - a
setValue("mat_credit_utilized", result);
}
else {
setValue("mat_credit_utilized", result);
}
// --- FINAL TAX --- // --- FINAL TAX ---
var mat_credit = getValue("mat_credit_utilized"); var mat_credit = getValue("mat_credit_utilized");
var interest_234c = getValue("interest_234c"); var interest_234c = getValue("interest_234c");
var total_tax = total_tax_payable + mat_credit + interest_234c; // var total_tax = total_tax_payable + mat_credit + interest_234c;
var total_tax = total_tax_payable - mat_credit + interest_234c;
setValue("total_tax", total_tax); setValue("total_tax", total_tax);
// --- ASSESSMENT --- // --- ASSESSMENT ---

View File

@@ -68,6 +68,28 @@ document.addEventListener("DOMContentLoaded", function () {
var total_tax_payable = tax_payable + surcharge + edu_cess; var total_tax_payable = tax_payable + surcharge + edu_cess;
setValue("total_tax_payable", total_tax_payable); setValue("total_tax_payable", total_tax_payable);
// --- mat credit_utilized ---
var a = tax185
var b = total_tax_payable
var result = 0
if (a > b) {
result = a - b
setValue("mat_credit_created", result);
}
else {
setValue("mat_credit_created", result);
}
if (b > a) {
result = b - a
setValue("mat_credit_utilized", result);
}
else {
setValue("mat_credit_utilized", result);
}
// --- FINAL TAX --- // --- FINAL TAX ---
var mat_credit = getValue("mat_credit_utilized"); var mat_credit = getValue("mat_credit_utilized");
var interest_234c = getValue("interest_234c"); var interest_234c = getValue("interest_234c");

View File

@@ -61,16 +61,36 @@ document.addEventListener("DOMContentLoaded", function () {
setValue("total_tax_payable", total_tax_payable); setValue("total_tax_payable", total_tax_payable);
// --- mat_credit_created --- new // --- mat_credit_created --- new
setValue("mat_credit_created", Math.max(tax185 - total_tax_payable, 0)); // setValue("mat_credit_created", Math.max(tax185 - total_tax_payable, 0));
// --- mat credit_utilized --- new // // --- mat credit_utilized --- new
setValue("mat_credit_utilized", Math.max(total_tax_payable - tax185, 0)); // setValue("mat_credit_utilized", Math.max(total_tax_payable - tax185, 0));
// --- mat credit_utilized ---
var a = tax185
var b = total_tax_payable
var result = 0
if (a > b) {
result = a - b
setValue("mat_credit_created", result);
}
else {
setValue("mat_credit_created", result);
}
if (b > a) {
result = b - a
setValue("mat_credit_utilized", result);
}
else {
setValue("mat_credit_utilized", result);
}
// --- FINAL TAX --- // --- FINAL TAX ---
var mat_credit = getValue("mat_credit_utilized"); var mat_credit = getValue("mat_credit_utilized");
var interest_234c = getValue("interest_234c"); var interest_234c = getValue("interest_234c");
// var total_tax = total_tax_payable + mat_credit + interest_234c; // var total_tax = total_tax_payable + mat_credit + interest_234c;
var total_tax = total_tax_payable + mat_credit + interest_234c; var total_tax = total_tax_payable + interest_234c;
setValue("total_tax", total_tax); setValue("total_tax", total_tax);
// --- ASSESSMENT --- // --- ASSESSMENT ---

View File

@@ -0,0 +1,50 @@
document.getElementById("year").addEventListener("change", function () {
const year = this.value;
const downloadBtn = document.getElementById("downloadBtn");
const previewDiv = document.getElementById("preview");
const contentDiv = document.getElementById("previewContent");
if (!year) {
downloadBtn.style.display = "none";
previewDiv.style.display = "none";
contentDiv.innerHTML = "";
return;
}
downloadBtn.href = `/summary/download?year=${year}`;
downloadBtn.style.display = "inline-block";
fetch(`/summary/preview?year=${year}`)
.then(res => res.json())
.then(data => {
let html = `<table>
<thead>
<tr>
<th>Particular</th>
<th>ITR</th>
<th>AO</th>
<th>CIT</th>
<th>ITAT</th>
</tr>
</thead>
<tbody>`;
data.forEach(row => {
html += `<tr>
<td>${row.Particular}</td>
<td>${row.ITR}</td>
<td>${row.AO}</td>
<td>${row.CIT}</td>
<td>${row.ITAT}</td>
</tr>`;
});
html += `</tbody></table>`;
contentDiv.innerHTML = html;
// Show preview
previewDiv.style.display = "block";
})
.catch(err => console.error("Preview load error:", err));
});

View File

@@ -10,7 +10,8 @@
<div class="container"> <div class="container">
<h2 style="text-align:center;">New Assessing Officer Form</h2> <h2 style="text-align:center;">New Assessing Officer Form</h2>
<form id="ao" method="POST"> <form id="ao" method="POST" enctype="multipart/form-data">
<input type="hidden" name="stage" value="ao">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>
<label>Assessment Year:</label> <label>Assessment Year:</label>
@@ -19,11 +20,12 @@
-- Please select Assessment Year -- -- Please select Assessment Year --
</option> </option>
</select> </select>
<div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div> <div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div>
</div> </div>
<div>
<label>Record Created Date:</label>
<input type="date" name="created_at" value="{{ current_date }}" required>
</div>
</div> </div>
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
@@ -170,9 +172,15 @@
<input type="number" name="refund" class="auto" step="any" value="0.00" readonly> <input type="number" name="refund" class="auto" step="any" value="0.00" readonly>
</div> </div>
<div class="form-group"> <div class="form-group full-width inline-2">
<label>Remarks:</label> <div>
<input type="text" name="Remarks"> <label>Select Documents:</label>
<input type="file" name="documents" multiple>
</div>
<div>
<label>Remarks:</label>
<input type="text" name="Remarks">
</div>
</div> </div>

View File

@@ -9,7 +9,8 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2 style="text-align:center;">New CIT Form </h2> <h2 style="text-align:center;">New CIT Form </h2>
<form id="cit" method="POST"> <form id="cit" method="POST" enctype="multipart/form-data">
<input type="hidden" name="stage" value="cit">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>
<label>Assessment Year:</label> <label>Assessment Year:</label>
@@ -20,6 +21,10 @@
</select> </select>
<div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div> <div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div>
</div> </div>
<div>
<label>Record Created Date:</label>
<input type="date" name="created_at" value="{{ current_date }}" required>
</div>
</div> </div>
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
@@ -166,9 +171,15 @@
<input type="number" name="refund" class="auto" step="any" value="0.00" readonly> <input type="number" name="refund" class="auto" step="any" value="0.00" readonly>
</div> </div>
<div class="form-group"> <div class="form-group full-width inline-2">
<label>Remarks:</label> <div>
<input type="text" name="Remarks"> <label>Select Documents:</label>
<input type="file" name="documents" multiple>
</div>
<div>
<label>Remarks:</label>
<input type="text" name="Remarks">
</div>
</div> </div>
<button type="submit">Submit</button> <button type="submit">Submit</button>

View File

@@ -10,8 +10,8 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2 style="text-align:center;">New Income Tax Appellate Tribunal Form</h2> <h2 style="text-align:center;">New Income Tax Appellate Tribunal Form</h2>
<form id="itat" method="POST" onsubmit="return showSuccessMessage()"> <form id="itat" method="POST" enctype="multipart/form-data" onsubmit="return showSuccessMessage()">
<input type="hidden" name="stage" value="itr">
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
<div> <div>
<label>Assessment Year:</label> <label>Assessment Year:</label>
@@ -22,6 +22,10 @@
</select> </select>
<div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div> <div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div>
</div> </div>
<div>
<label>Record Created Date:</label>
<input type="date" name="created_at" value="{{ current_date }}" required>
</div>
</div> </div>
<div class="form-group full-width inline-2"> <div class="form-group full-width inline-2">
@@ -172,9 +176,15 @@
<input type="number" name="refund" class="auto" step="any" value="0.00" readonly> <input type="number" name="refund" class="auto" step="any" value="0.00" readonly>
</div> </div>
<div class="form-group"> <div class="form-group full-width inline-2">
<label>Remarks:</label> <div>
<input type="text" name="Remarks"> <label>Select Documents:</label>
<input type="file" name="documents" multiple>
</div>
<div>
<label>Remarks:</label>
<input type="text" name="Remarks">
</div>
</div> </div>
<button type="submit">Submit</button> <button type="submit">Submit</button>

View File

@@ -23,7 +23,7 @@
<div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div> <div id="yearError" style="color:red; display:none; margin-bottom:10px;"></div>
</div> </div>
<div> <div>
<label>Created Date:</label> <label>Record Created Date:</label>
<input type="date" name="created_at" value="{{ current_date }}" required> <input type="date" name="created_at" value="{{ current_date }}" required>
</div> </div>
</div> </div>

View File

@@ -22,6 +22,7 @@
<th>Gross Total Income</th> <th>Gross Total Income</th>
<th>Net Taxable Income</th> <th>Net Taxable Income</th>
<th>Total Tax</th> <th>Total Tax</th>
<th>Created Record Date</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
@@ -32,6 +33,7 @@
<td>{{ ao.gross_total_income }}</td> <td>{{ ao.gross_total_income }}</td>
<td>{{ ao.net_taxable_income }}</td> <td>{{ ao.net_taxable_income }}</td>
<td>{{ ao.total_tax }}</td> <td>{{ ao.total_tax }}</td>
<td>{{ ao.created_at.strftime('%Y-%m-%d') }}</td>
<td> <td>
<a href="{{ url_for('update_ao', id=ao.id) }}" class="btn btn-update">Edit</a> <a href="{{ url_for('update_ao', id=ao.id) }}" class="btn btn-update">Edit</a>

View File

@@ -42,7 +42,7 @@
<tbody> <tbody>
{% for row in mat_rows %} {% for row in mat_rows %}
<tr> <tr>
<td contenteditable="true">{{ row.financial_year }}</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>
{% for y in added_years %} {% for y in added_years %}

View File

@@ -1,32 +1,34 @@
{% extends "base.html" %} {% extends "base.html" %} {% block title %}Download Summary Report{% endblock %}
{% block title %}Download Summary Report{% endblock %}
{% block extra_css %} {% block extra_css %}
<!-- Optional: Add page-specific CSS --> <link rel="stylesheet" href="{{ url_for('static', filename='css/summary.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/summary.css') }}"> {% endblock %} {% block content %}
{% endblock %}
{% block content %}
<div class="container"> <div class="container">
<div class="head">
<h2>Download Year-wise Summary Report</h2> <h2>Download Year-wise Summary Report</h2>
{% if message %} {% if message %}
<p class="message">{{ message }}</p> <p class="message">{{ message }}</p>
{% endif %} {% endif %}
<form method="GET" action="{{ url_for('summary_report') }}"> <div class="select-download-wrapper">
<label>Select Year:</label> <select name="year" id="year" required>
<select name="year" id="year" required> <option value="">-- Select Year --</option>
<option value="">-- Select Year --</option> {% for year in years %}
{% for year in years %} <option value="{{ year }}">AY {{ year }}-{{ year + 1 }}</option>
<option value="{{ year }}">AY {{ year }}-{{ year + 1 }}</option> {% endfor %}
{% endfor %} </select>
</select>
<button type="submit">Download Summary Report</button> <a id="downloadBtn" href="#">Download Summary Report</a>
</form> </div>
</div>
<!-- Preview Section -->
<div id="preview" style="display: none">
<h3>Summary Preview</h3>
<div id="previewContent"></div>
</div>
</div> </div>
{% endblock %} {% block extra_js %}
<script src="{{ url_for('static', filename='js/summary_preview.js') }}"></script>
{% endblock %} {% endblock %}

View File

@@ -8,7 +8,7 @@
{% block content %} {% block content %}
<div class="container"> <div class="container">
<h2>Update 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>
@@ -169,6 +169,23 @@
<input type="text" name="Remarks" value="{{ record.remarks}}"> <input type="text" name="Remarks" value="{{ record.remarks}}">
</div> </div>
<div class="form-group full-width inline-2">
<div>
<label>Created Date:</label>
<input type="date" name="created_at"
value="{{ record.created_at.strftime('%Y-%m-%d') if record.created_at else current_date }}"
readonly>
</div>
<div>
<label>Last Updated:</label>
<input type="date" name="updated_at"
value="{{ record.updated_at.strftime('%Y-%m-%d') if record.updated_at else current_date }}"
readonly>
</div>
</div>
<button type="submit">Update Record</button> <button type="submit">Update Record</button>
</form> </form>

View File

@@ -27,7 +27,11 @@
</select> </select>
<button type="submit">Apply</button> <button type="submit">Apply</button>
</form> </form>
{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endwith %}
<!-- DOCUMENT TABLE --> <!-- DOCUMENT TABLE -->
<div class="table-responsive"> <div class="table-responsive">
<table> <table>