2025-11-30 16:24:49 +05:30
|
|
|
from AppCode.Config import DBConfig
|
|
|
|
|
import mysql.connector
|
2025-12-02 00:36:46 +05:30
|
|
|
import pandas as pd
|
|
|
|
|
import io
|
|
|
|
|
|
2025-11-30 16:24:49 +05:30
|
|
|
class AOHandler:
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.conn = DBConfig.get_db_connection()
|
|
|
|
|
self.cursor = self.conn.cursor(dictionary=True)
|
|
|
|
|
|
|
|
|
|
# GET ALL AO RECORDS using stored procedure "GetAllItr"
|
|
|
|
|
def get_all_ao(self):
|
|
|
|
|
self.cursor.callproc("GetAllAO")
|
|
|
|
|
records = []
|
|
|
|
|
|
|
|
|
|
for result in self.cursor.stored_results():
|
|
|
|
|
records = result.fetchall()
|
|
|
|
|
|
|
|
|
|
return records
|
|
|
|
|
|
2026-01-07 00:49:42 +05:30
|
|
|
# get ao recourd
|
2025-11-30 16:24:49 +05:30
|
|
|
def get_ao_by_id(self, id):
|
2025-12-01 12:04:07 +05:30
|
|
|
self.cursor.callproc('GetAOById', [id])
|
2025-11-30 16:24:49 +05:30
|
|
|
records = []
|
|
|
|
|
for result in self.cursor.stored_results():
|
|
|
|
|
records = result.fetchall()
|
|
|
|
|
|
|
|
|
|
if records:
|
2026-01-07 00:49:42 +05:30
|
|
|
return records[0]
|
2025-11-30 16:24:49 +05:30
|
|
|
return None
|
|
|
|
|
|
2026-01-07 00:49:42 +05:30
|
|
|
# Add AO record
|
2025-11-30 20:38:41 +05:30
|
|
|
def add_ao(self, data):
|
2026-02-06 15:11:58 +05:30
|
|
|
|
|
|
|
|
try:
|
2025-11-30 20:38:41 +05:30
|
|
|
fields = [
|
2026-01-29 18:19:49 +05:30
|
|
|
'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',
|
2026-02-06 15:11:58 +05:30
|
|
|
'sat', 'tax_on_assessment', 'refund', 'Remarks','created_at'
|
2025-11-30 20:38:41 +05:30
|
|
|
]
|
2025-11-30 16:24:49 +05:30
|
|
|
|
2025-11-30 20:38:41 +05:30
|
|
|
values = [data.get(f, 0) for f in fields]
|
2026-01-24 16:29:04 +05:30
|
|
|
self.cursor.callproc("InsertAO", values)
|
2025-11-30 20:38:41 +05:30
|
|
|
self.conn.commit()
|
2026-02-06 15:11:58 +05:30
|
|
|
except Exception as e:
|
|
|
|
|
self.conn.rollback()
|
|
|
|
|
raise e
|
|
|
|
|
finally:
|
|
|
|
|
self.cursor.close()
|
|
|
|
|
self.conn.close()
|
2025-11-30 16:24:49 +05:30
|
|
|
|
2026-01-07 00:49:42 +05:30
|
|
|
# UPDATE AO RECORD by AO id
|
2025-12-01 17:45:16 +05:30
|
|
|
def update_ao(self, id, data):
|
|
|
|
|
fields = [
|
2026-01-29 18:19:49 +05:30
|
|
|
'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'
|
|
|
|
|
]
|
2025-11-30 16:24:49 +05:30
|
|
|
|
2025-12-01 17:45:16 +05:30
|
|
|
values = [id] + [data.get(f, 0) for f in fields]
|
2025-11-30 16:24:49 +05:30
|
|
|
|
2025-12-01 17:45:16 +05:30
|
|
|
self.cursor.callproc("UpdateAOById", values)
|
|
|
|
|
self.conn.commit()
|
2025-11-30 16:24:49 +05:30
|
|
|
|
|
|
|
|
|
2025-11-30 20:38:41 +05:30
|
|
|
# DELETE RECORD by AO id
|
|
|
|
|
def delete_ao_by_id(self, id):
|
|
|
|
|
self.cursor.callproc('DeleteAOById', [id])
|
|
|
|
|
self.conn.commit()
|
2025-11-30 16:24:49 +05:30
|
|
|
|
2026-01-24 18:22:28 +05:30
|
|
|
# report download by year
|
|
|
|
|
def ao_report_download(self, selected_year):
|
|
|
|
|
try:
|
|
|
|
|
# AY calculation (2020 -> AY 2020-2021)
|
|
|
|
|
ay_start = int(selected_year)
|
|
|
|
|
ay_end = ay_start + 1
|
|
|
|
|
assessment_year = f"AY {ay_start}-{ay_end}"
|
|
|
|
|
|
|
|
|
|
# Fetch AO records
|
|
|
|
|
self.cursor.callproc("GetAOByYear", [selected_year])
|
|
|
|
|
|
|
|
|
|
rows = []
|
|
|
|
|
for result in self.cursor.stored_results():
|
|
|
|
|
rows = result.fetchall()
|
|
|
|
|
|
|
|
|
|
if not rows:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
# Remove id column if exists
|
|
|
|
|
for row in rows:
|
|
|
|
|
row.pop("id", None)
|
|
|
|
|
|
|
|
|
|
# Mapping DB fields → readable Excel labels
|
|
|
|
|
field_mapping = {
|
|
|
|
|
"gross_total_income": "Gross Total Income",
|
|
|
|
|
"disallowance_14a": "Add: Disallowance u/s 14A",
|
|
|
|
|
"disallowance_37": "Add: Disallowance u/s 37",
|
|
|
|
|
"deduction_80ia_business": "Less: Deduction u/s 80IA - On Business Income",
|
|
|
|
|
"deduction_80ia_misc": "On Misc Receipts",
|
|
|
|
|
"deduction_80ia_other": "On Other",
|
|
|
|
|
"deduction_sec37_disallowance": "On Sec 37 Disallowance",
|
|
|
|
|
"deduction_80g": "Less: Deduction u/s 80G",
|
|
|
|
|
"net_taxable_income": "Net Taxable Income",
|
|
|
|
|
"tax_30_percent": "Tax @ 30%",
|
|
|
|
|
"tax_book_profit_18_5": "Tax @ 18.5% on Book Profit",
|
|
|
|
|
"tax_payable": "Tax Payable",
|
2026-01-29 18:19:49 +05:30
|
|
|
"surcharge": "Surcharge",
|
|
|
|
|
"edu_cess": "Education Cess",
|
2026-01-24 18:22:28 +05:30
|
|
|
"total_tax_payable": "Total Tax Payable",
|
2026-01-29 18:19:49 +05:30
|
|
|
"mat_credit_created": "Add: MAT Credit Created",
|
|
|
|
|
"mat_credit_utilized": "Less: MAT Credit Utilized",
|
2026-01-24 18:22:28 +05:30
|
|
|
"interest_234c": "Add: Interest u/s 234C",
|
|
|
|
|
"total_tax": "Total Tax",
|
|
|
|
|
"advance_tax": "Advance Tax",
|
|
|
|
|
"tds": "TDS",
|
|
|
|
|
"tcs": "TCS",
|
|
|
|
|
"sat": "SAT",
|
|
|
|
|
"tax_on_assessment": "Tax on Regular Assessment",
|
|
|
|
|
"refund": "Refund",
|
|
|
|
|
"Remarks": "Remarks"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Vertical AO structure
|
|
|
|
|
data = []
|
|
|
|
|
for key, label in field_mapping.items():
|
|
|
|
|
value = rows[0].get(key, 0)
|
|
|
|
|
data.append([label, value])
|
|
|
|
|
|
|
|
|
|
df = pd.DataFrame(data, columns=["Particulars", "AO"])
|
|
|
|
|
|
|
|
|
|
# Excel output
|
|
|
|
|
output = io.BytesIO()
|
|
|
|
|
with pd.ExcelWriter(output, engine="xlsxwriter") as writer:
|
|
|
|
|
workbook = writer.book
|
|
|
|
|
worksheet = workbook.add_worksheet("AO Report")
|
|
|
|
|
writer.sheets["AO Report"] = worksheet
|
|
|
|
|
|
|
|
|
|
# Formats
|
|
|
|
|
title_fmt = workbook.add_format({
|
|
|
|
|
"bold": True,
|
|
|
|
|
"align": "center",
|
|
|
|
|
"font_size": 14
|
|
|
|
|
})
|
|
|
|
|
header_fmt = workbook.add_format({
|
|
|
|
|
"bold": True,
|
|
|
|
|
"border": 1,
|
|
|
|
|
"align": "center"
|
|
|
|
|
})
|
|
|
|
|
text_fmt = workbook.add_format({"border": 1})
|
|
|
|
|
num_fmt = workbook.add_format({
|
|
|
|
|
"border": 1,
|
|
|
|
|
"num_format": "#,##0.00"
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
# Company Name
|
|
|
|
|
worksheet.merge_range(
|
|
|
|
|
"A1:B1",
|
|
|
|
|
"Laxmi Civil Engineering Services Pvt Ltd",
|
|
|
|
|
title_fmt
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Assessment Year
|
|
|
|
|
worksheet.merge_range(
|
|
|
|
|
"A2:B2",
|
|
|
|
|
f"Assessment Year : {assessment_year}",
|
|
|
|
|
workbook.add_format({"bold": True, "align": "center"})
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Header
|
|
|
|
|
worksheet.write_row("A4", ["Particulars", "AO"], header_fmt)
|
|
|
|
|
|
|
|
|
|
# Data rows
|
|
|
|
|
row_no = 4
|
|
|
|
|
for _, row in df.iterrows():
|
|
|
|
|
worksheet.write(row_no, 0, row["Particulars"], text_fmt)
|
|
|
|
|
worksheet.write(row_no, 1, row["AO"], num_fmt)
|
|
|
|
|
row_no += 1
|
|
|
|
|
|
|
|
|
|
# Column width
|
|
|
|
|
worksheet.set_column("A:A", 45)
|
|
|
|
|
worksheet.set_column("B:B", 20)
|
|
|
|
|
|
|
|
|
|
output.seek(0)
|
|
|
|
|
return output
|
|
|
|
|
|
|
|
|
|
except mysql.connector.Error as e:
|
|
|
|
|
print("MySQL Error →", e)
|
|
|
|
|
return None
|
|
|
|
|
|
2025-11-30 16:24:49 +05:30
|
|
|
# CLOSE CONNECTION
|
|
|
|
|
def close(self):
|
|
|
|
|
self.cursor.close()
|
2026-01-24 18:22:28 +05:30
|
|
|
self.conn.close()
|