new fom of MAT credit add in table formate and update show

This commit is contained in:
2026-01-07 16:26:59 +05:30
parent 9c2486fdd6
commit 68511b7558
6 changed files with 595 additions and 6 deletions

123
AppCode/MatCreditHandler.py Normal file
View File

@@ -0,0 +1,123 @@
from AppCode.Config import DBConfig
import mysql.connector
class MatCreditHandler:
def __init__(self):
db = DBConfig()
self.conn = db.get_db_connection()
self.cursor = self.conn.cursor(dictionary=True)
@staticmethod
def fetch_all():
conn = DBConfig.get_db_connection()
cur = conn.cursor(dictionary=True)
try:
# Stored Procedure returns TWO result sets
cur.callproc("GetMatCedit")
result_sets = cur.stored_results()
mat_rows = next(result_sets).fetchall()
utilization_rows = next(result_sets).fetchall()
return mat_rows, utilization_rows
finally:
cur.close()
conn.close()
@staticmethod
def save_single(data):
conn = DBConfig.get_db_connection()
cur = conn.cursor()
try:
cur.execute(
"SELECT id FROM mat_credit WHERE financial_year=%s",
(data["financial_year"],)
)
row = cur.fetchone()
if row:
mat_id = row[0]
cur.execute("""
UPDATE mat_credit
SET mat_credit=%s, balance=%s
WHERE id=%s
""", (data["mat_credit"], data["balance"], mat_id))
cur.execute(
"DELETE FROM mat_utilization WHERE mat_credit_id=%s",
(mat_id,)
)
else:
cur.execute("""
INSERT INTO mat_credit (financial_year, mat_credit, balance)
VALUES (%s,%s,%s)
""", (data["financial_year"], data["mat_credit"], data["balance"]))
mat_id = cur.lastrowid
for u in data["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()
except Exception:
conn.rollback()
raise
finally:
cur.close()
conn.close()
@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
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()

58
main.py
View File

@@ -1,11 +1,11 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort, flash,send_file from flask import Flask, render_template, request, redirect, url_for, send_from_directory, abort, flash,send_file ,jsonify
import os import os
import pandas as pd import pandas as pd
import pymysql import pymysql
import io import io
import mysql.connector import mysql.connector
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from datetime import datetime
from AppCode.Config import DBConfig from AppCode.Config import DBConfig
from AppCode.FileHandler import FileHandler from AppCode.FileHandler import FileHandler
@@ -16,6 +16,8 @@ from AppCode.CITHandler import CITHandler
from AppCode.ITATHandler import ITATHandler from AppCode.ITATHandler import ITATHandler
from AppCode.YearGet import YearGet from AppCode.YearGet import YearGet
from AppCode.LoginAuth import LoginAuth from AppCode.LoginAuth import LoginAuth
from AppCode.MatCreditHandler import MatCreditHandler
# Server # Server
@@ -433,8 +435,8 @@ def check_year():
conn = DBConfig.get_db_connection() conn = DBConfig.get_db_connection()
cursor = conn.cursor() cursor = conn.cursor()
query = f"SELECT COUNT(*) FROM {table_name} WHERE year = %s" sqlstr = f"SELECT COUNT(*) FROM {table_name} WHERE year = %s"
cursor.execute(query, (year,)) cursor.execute(sqlstr, (year,))
result = cursor.fetchone()[0] result = cursor.fetchone()[0]
cursor.close() cursor.close()
@@ -442,6 +444,54 @@ def check_year():
return {"exists": result > 0} return {"exists": result > 0}
# new new
# Mat credit from
@app.route("/mat_credit", methods=["GET"])
def mat_credit():
mat= MatCreditHandler()
mat_rows, utilization_rows = mat.fetch_all()
utilization_map = {}
all_years = set()
for u in utilization_rows:
all_years.add(u["utilized_year"])
utilization_map.setdefault(
u["mat_credit_id"], {}
)[u["utilized_year"]] = u["utilized_amount"]
return render_template(
"mat_credit.html",
mat_rows=mat_rows,
utilization_map=utilization_map,
added_years=sorted(all_years)
)
# save mat credit row data
@app.route("/save_mat_row", methods=["POST"])
def save_mat_row():
mat= MatCreditHandler()
try:
mat.save_single(request.json)
return jsonify({"message": "Row saved successfully"})
except Exception as e:
return jsonify({"error": str(e)}), 500
# save mat credit bulk data
@app.route("/save_mat_all", methods=["POST"])
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 # run
if __name__ == '__main__': if __name__ == '__main__':

146
static/css/mat_credit.css Normal file
View File

@@ -0,0 +1,146 @@
/* ===== CONTAINER ===== */
.container {
max-width: 1200px;
margin: 30px auto;
padding: 25px;
background: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.08);
}
/* ===== TABLE ===== */
#matTable {
width: 100%;
border-collapse: collapse;
font-size: 14px;
text-align: center;
}
/* ===== HEADER ===== */
#matTable thead th {
background: linear-gradient(135deg, #0d6efd, #0a58ca);
color: #ffffff;
padding: 12px 8px;
border: 1px solid #0a58ca;
font-weight: 600;
white-space: nowrap;
}
/* ===== BODY CELLS ===== */
#matTable tbody td {
padding: 8px;
border: 1px solid #dcdcdc;
background-color: #ffffff;
}
/* ===== FY COLUMN ===== */
#matTable tbody td:first-child {
font-weight: 600;
background-color: #f5f8ff;
}
/* ===== INPUT FIELDS ===== */
#matTable input {
width: 100%;
padding: 6px 6px;
border: 1px solid #cfd8dc;
border-radius: 4px;
font-size: 13px;
text-align: right;
box-sizing: border-box;
}
/* TEXT INPUT (Unutilized) */
#matTable input[type="text"] {
text-align: center;
}
/* INPUT FOCUS */
#matTable input:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.15);
outline: none;
}
/* ===== ACTION BUTTON ===== */
#matTable button {
background-color: #198754;
border: none;
color: white;
padding: 6px 14px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
transition: 0.2s;
}
#matTable button:hover {
background-color: #157347;
}
/* ===== SAVE ALL BUTTON ===== */
button[onclick="saveAll()"] {
display: block;
width: 300px;
margin: 25px auto 0;
background-color: #28a745;
color: #fff;
font-size: 16px;
font-weight: 600;
padding: 12px;
border-radius: 8px;
border: none;
cursor: pointer;
}
button[onclick="saveAll()"]:hover {
background-color: #218838;
}
/* ===== ROW HOVER ===== */
#matTable tbody tr:hover {
background-color: #f1f6ff;
}
/* ===== ERROR HIGHLIGHT ===== */
.input-error {
border-color: #dc3545 !important;
background-color: #fff5f5;
}
/* ===== SUCCESS HIGHLIGHT ===== */
.row-saved {
background-color: #e9f7ef !important;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 768px) {
#matTable {
font-size: 12px;
}
#matTable thead {
display: none;
}
#matTable tbody tr {
display: block;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 6px;
padding: 10px;
}
#matTable tbody td {
display: flex;
justify-content: space-between;
padding: 6px 8px;
border: none;
}
#matTable tbody td::before {
content: attr(data-label);
font-weight: 600;
color: #0d6efd;
}
}

184
static/js/mat_credit.js Normal file
View File

@@ -0,0 +1,184 @@
/* =====================================================
GLOBAL STATE
===================================================== */
let addedYears = [];
/* =====================================================
INITIALIZE YEARS FROM DATABASE HEADERS
===================================================== */
document.addEventListener("DOMContentLoaded", () => {
const headers = document.querySelectorAll("#tableHeader th");
headers.forEach(th => {
if (th.innerText.startsWith("Utilized")) {
const year = th.innerText.replace("Utilized", "").trim();
if (!addedYears.includes(year)) {
addedYears.push(year);
}
}
});
});
/* =====================================================
ADD YEAR COLUMN (DYNAMIC)
===================================================== */
function addYearColumn() {
const yearSelect = document.getElementById("yearSelect");
const year = yearSelect.value;
if (!year) {
alert("Please select AY");
return;
}
if (addedYears.includes(year)) {
alert("This AY is already added");
return;
}
addedYears.push(year);
// Add header column
const headerRow = document.getElementById("tableHeader");
const th = document.createElement("th");
th.innerText = "Utilized " + year;
// Insert before Balance column
headerRow.insertBefore(th, headerRow.children[headerRow.children.length - 2]);
// Add input cells to all existing rows
document.querySelectorAll("#matTable tbody tr").forEach(tr => {
const td = document.createElement("td");
td.innerHTML = `<input type="number">`;
tr.insertBefore(td, tr.children[tr.children.length - 2]);
});
}
/* =====================================================
ADD NEW ROW
===================================================== */
function addRow() {
const tbody = document.querySelector("#matTable tbody");
const tr = document.createElement("tr");
let utilizedCols = "";
addedYears.forEach(() => {
utilizedCols += `<td><input type="number"></td>`;
});
tr.innerHTML = `
<td contenteditable="true"></td>
<td><input></td>
${utilizedCols}
<td><input></td>
<td>
<button onclick="saveRow(this)">Save</button>
</td>
`;
tbody.appendChild(tr);
}
/* =====================================================
SAVE SINGLE ROW
===================================================== */
function saveRow(btn) {
const tr = btn.closest("tr");
const inputs = tr.querySelectorAll("input");
const financialYear = tr.children[0].innerText.trim();
if (!financialYear) {
alert("AY is required");
return;
}
let payload = {
financial_year: financialYear,
mat_credit: inputs[0].value || 0,
balance: inputs[inputs.length - 1].value || 0,
utilization: []
};
addedYears.forEach((year, i) => {
const value = inputs[i + 1].value;
if (value) {
payload.utilization.push({
year: year,
amount: value
});
}
});
fetch("/save_mat_row", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload)
})
.then(res => res.json().then(j => ({ ok: res.ok, data: j })))
.then(res => {
if (res.ok) {
alert("✅ " + res.data.message);
} else {
alert("⚠️ " + res.data.error);
}
})
.catch(() => {
alert("Server error");
});
}
/* =====================================================
SAVE ALL ROWS
===================================================== */
function saveAll() {
let rows = [];
document.querySelectorAll("#matTable tbody tr").forEach(tr => {
const inputs = tr.querySelectorAll("input");
const financialYear = tr.children[0].innerText.trim();
if (!financialYear) return;
let row = {
financial_year: financialYear,
mat_credit: inputs[0].value || 0,
balance: inputs[inputs.length - 1].value || 0,
utilization: []
};
addedYears.forEach((year, i) => {
const value = inputs[i + 1].value;
if (value) {
row.utilization.push({
year: year,
amount: value
});
}
});
rows.push(row);
});
if (!rows.length) {
alert("No data to save");
return;
}
fetch("/save_mat_all", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(rows)
})
.then(res => res.json())
.then(res => {
let msg = "✅ " + res.message;
if (res.skipped && res.skipped.length) {
msg += "\n\nSkipped AY:\n" + res.skipped.join(", ");
}
alert(msg);
})
.catch(() => {
alert("Server error");
});
}

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>{% block title %}Income Tax Utilities{% endblock %}</title> <title>{% block title %}Income Tax Utilities{% endblock %}</title>
@@ -23,7 +24,9 @@
<!-- SIDEBAR --> <!-- SIDEBAR -->
<div class="sidebar hide" id="sidebar"> <div class="sidebar hide" id="sidebar">
<a href="{{ url_for('index') }}"><h2>Dashboard</h2></a> <a href="{{ url_for('index') }}">
<h2>Dashboard</h2>
</a>
<div class="menu-btn" onclick="toggleMenu('itrMenu')">ITR ▼</div> <div class="menu-btn" onclick="toggleMenu('itrMenu')">ITR ▼</div>
<div class="submenu" id="itrMenu"> <div class="submenu" id="itrMenu">
@@ -57,6 +60,14 @@
<a href="{{ url_for('summary_report') }}">📝 Summary Report</a> <a href="{{ url_for('summary_report') }}">📝 Summary Report</a>
</div> </div>
<div class="menu-btn" onclick="toggleMenu('matCredit')">Mat Credit ▼</div>
<div class="submenu" id="matCredit">
<a href="{{ url_for('mat_credit') }}">📄 Mat Credit from</a>
<!-- <a href="{{ url_for('view_documents') }}">📄 Documents</a> -->
</div>
<!-- Logout at bottom --> <!-- Logout at bottom -->
<a href="{{ url_for('auth.logout') }}" class="sidebar-logout"> <a href="{{ url_for('auth.logout') }}" class="sidebar-logout">
<img src="{{ url_for('static', filename='images/logout_icon.png') }}" class="logout-icon" alt="Logout" /> <img src="{{ url_for('static', filename='images/logout_icon.png') }}" class="logout-icon" alt="Logout" />
@@ -74,4 +85,5 @@
<!-- Extra JS for child pages --> <!-- Extra JS for child pages -->
{% block extra_js %}{% endblock %} {% block extra_js %}{% endblock %}
</body> </body>
</html> </html>

74
templates/mat_credit.html Normal file
View File

@@ -0,0 +1,74 @@
{% extends "base.html" %}
{% block title %}MAT Credit{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/mat_credit.css') }}">
{% endblock %}
{% block content %}
<div class="container">
<div class="container">
<!-- YEAR ADD CONTROLS -->
<div class="year-controls">
<select id="yearSelect">
<option value="">-- Select AY --</option>
{% for y in range(2001, 2026) %}
<option value="{{ y }}-{{ y+1 }}">{{ y }}-{{ y+1 }}</option>
{% endfor %}
</select>
<button onclick="addYearColumn()"> Add Year</button>
</div>
<!-- SCROLL WRAPPER -->
<div class="table-wrapper">
<table id="matTable">
<thead>
<tr id="tableHeader">
<th>AY</th>
<th>MAT Credit</th>
{% for y in added_years %}
<th>Utilized {{ y }}</th>
{% endfor %}
<th>Balance</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for row in mat_rows %}
<tr>
<td contenteditable="true">{{ row.financial_year }}</td>
<td><input value="{{ row.mat_credit }}"></td>
{% for y in added_years %}
<td>
<input value="{{ utilization_map.get(row.id, {}).get(y, '') }}">
</td>
{% endfor %}
<td><input value="{{ row.balance }}"></td>
<td><button onclick="saveRow(this)">Save</button></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<br>
<button onclick="addRow()"> Add Row</button>
<button onclick="saveAll()">💾 Save All</button>
</div>
</div>
{% block extra_js %}
<script src="{{ url_for('static', filename='js/mat_credit.js') }}"></script>
{% endblock %}
{% endblock %}