update itr and ao from and auto save mat ceadit and utility

This commit is contained in:
2026-02-06 15:11:58 +05:30
parent a0f4568ba2
commit a9af2cde8a
43 changed files with 825 additions and 327 deletions

View File

@@ -32,6 +32,8 @@ class AOHandler:
# Add AO record
def add_ao(self, data):
try:
fields = [
'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37',
'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other',
@@ -40,13 +42,18 @@ class AOHandler:
'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'
'sat', 'tax_on_assessment', 'refund', 'Remarks','created_at'
]
values = [data.get(f, 0) for f in fields]
self.cursor.callproc("InsertAO", values)
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
def update_ao(self, id, data):

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
import pandas as pd
import os
@@ -17,11 +19,40 @@ class DocumentHandler:
self.isSuccess = False
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):
year = request.args.get('year', '')
year_raw = request.args.get('year', '')
stage = request.args.get('stage', '')
year = self.parse_year(year_raw)
dbconfig = DBConfig()
connection = dbconfig.get_db_connection()
@@ -30,15 +61,13 @@ class DocumentHandler:
return
cursor = connection.cursor(dictionary=True)
# --- FILTER QUERY ---
cursor.callproc("GetDocuments", [year, stage])
# fetch first result set
for result in cursor.stored_results():
self.documents = result.fetchall()
break
# ---- GET YEARS FROM STORED PROCEDURE ----
cursor.callproc("GetYear")
for result in cursor.stored_results():
@@ -49,55 +78,72 @@ class DocumentHandler:
cursor.close()
connection.close()
self.isSuccess = True
# =========================
# Upload Documents
# =========================
def Upload(self, request):
dbconfig = DBConfig()
connection = dbconfig.get_db_connection()
if connection:
cursor = connection.cursor()
files = request.files.getlist('documents')
year = request.form['year']
stage = request.form['stage']
if not connection:
return
for file in files:
extension = file.filename.rsplit('.', 1)[1]
if extension not in FileHandler.ALLOWED_EXTENSIONS:
print("Skip invalid file type : ",extension)
continue
cursor = connection.cursor()
filename = secure_filename(file.filename)
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename)
file.save(filepath)
files = request.files.getlist('documents')
year_raw = request.form.get('year')
stage = request.form.get('stage')
cursor.callproc('InsertDocument', [ filename, filepath, extension, year, stage ])
year = self.parse_year(year_raw)
connection.commit()
cursor.close()
connection.close()
# return redirect(url_for('view_documents'))
if not year:
self.resultMessage = "Invalid year selected."
return
def Summary_report(self, request):
dbconfig = DBConfig()
connection = dbconfig.get_db_connection()
for file in files:
if '.' not in file.filename:
continue
year_str = request.args.get('year')
extension = file.filename.rsplit('.', 1)[1].lower()
# If year not selected
if not year_str or not year_str.isdigit():
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."
if extension not in FileHandler.ALLOWED_EXTENSIONS:
print("Skipping invalid file:", extension)
continue
filename = secure_filename(file.filename)
filepath = os.path.join(FileHandler.UPLOAD_FOLDER, filename)
file.save(filepath)
cursor.callproc(
'InsertDocument',
[filename, filepath, extension, year, stage]
)
# Convert year to int (IMPORTANT FIX)
year = int(year_str)
connection.commit()
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:
stages = {
@@ -112,11 +158,111 @@ class DocumentHandler:
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()
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()
cursor.close()
@@ -124,25 +270,45 @@ class DocumentHandler:
return df[col].values[0] if col in df.columns and not df.empty else "-"
particulars = [
"Gross Total Income", "Add: Disallowance u/s 14A", "Add: Disallowance u/s 37",
"GTI as per", "Less: Deduction u/s 80IA - 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", " ",
"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"
"Tax on Regular Assessment",
"Refund", "Remarks"
]
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'
'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'
]
data = {
@@ -155,56 +321,44 @@ class DocumentHandler:
df = pd.DataFrame(data)
# ===== Excel Export =====
output = io.BytesIO()
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)
workbook = writer.book
worksheet = writer.sheets[sheet_name]
# ===== Company Heading =====
company_heading = workbook.add_format({
title = workbook.add_format({
'bold': True,
'font_size': 14,
'font_color': 'black',
'align': 'center',
'valign': 'middle'
'align': 'center'
})
worksheet.merge_range(
0, 0, 0, len(df.columns) - 1,
"Laxmi Civil Engineering Services Pvt Ltd",
company_heading
title
)
# ===== Header Format =====
header = workbook.add_format({
'bold': True,
'align': 'center',
'valign': 'middle',
'bg_color': '#007bff',
'font_color': 'white',
'border': 1
})
cell = workbook.add_format({
'border': 1,
'align': 'left',
'valign': 'middle'
})
cell = workbook.add_format({'border': 1})
# Write headers
for col_num, col_name in enumerate(df.columns):
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, max_len)
worksheet.set_column(col_num, col_num, 25)
# Write data rows
for row in range(3, len(df) + 3):
for row in range(len(df)):
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)
@@ -219,3 +373,4 @@ class DocumentHandler:
finally:
connection.close()

View File

@@ -41,21 +41,29 @@ class ITRHandler:
# INSERT ITR RECORD using procedure "add_itr"
def add_itr(self, data):
columns = [
'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37',
'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other',
'deduction_sec37_disallowance', 'deduction_80g',
'net_taxable_income', 'tax_30_percent', 'tax_book_profit_18_5',
'tax_payable', 'surcharge', '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','created_at'
]
values = [data.get(col, 0) for col in columns]
try:
columns = [
'year', 'gross_total_income', 'disallowance_14a', 'disallowance_37',
'deduction_80ia_business', 'deduction_80ia_misc', 'deduction_80ia_other',
'deduction_sec37_disallowance', 'deduction_80g',
'net_taxable_income', 'tax_30_percent', 'tax_book_profit_18_5',
'tax_payable', 'surcharge', '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','created_at'
]
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
def update(self, id, data):

View File

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