new fom of MAT credit add in table formate and update show
This commit is contained in:
123
AppCode/MatCreditHandler.py
Normal file
123
AppCode/MatCreditHandler.py
Normal 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
58
main.py
@@ -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
146
static/css/mat_credit.css
Normal 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
184
static/js/mat_credit.js
Normal 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");
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -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
74
templates/mat_credit.html
Normal 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 %}
|
||||||
Reference in New Issue
Block a user