3 Commits

Author SHA1 Message Date
82bedc3117 Update activity.log 2026-03-24 10:49:06 +00:00
cb68e454bc Update .env 2026-03-24 10:47:05 +00:00
675301df7f GST Release Display Chages 2026-03-24 16:08:37 +05:30
40 changed files with 431 additions and 509 deletions

Binary file not shown.

View File

@@ -1,8 +1,8 @@
from flask import Blueprint, render_template, request, redirect, url_for # routes/gst_release_routes.py
from flask import Blueprint, render_template, request, redirect, url_for, flash
from flask_login import login_required from flask_login import login_required
from model.gst_release import GSTRelease from model.gst_release import GSTRelease
from model.Log import LogHelper from model.Log import LogHelper
from flask import flash, current_app
gst_release_bp = Blueprint('gst_release_bp', __name__) gst_release_bp = Blueprint('gst_release_bp', __name__)
gst_service = GSTRelease() gst_service = GSTRelease()
@@ -13,7 +13,7 @@ gst_service = GSTRelease()
def add_gst_release(): def add_gst_release():
if request.method == 'POST': if request.method == 'POST':
gst_service.AddGSTRelease(request) gst_service.AddGSTRelease(request)
LogHelper.log_action("Add GST Release", f"User added GST release") LogHelper.log_action("Add GST Release", "User added GST release")
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error') flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
return redirect(url_for('gst_release_bp.add_gst_release')) return redirect(url_for('gst_release_bp.add_gst_release'))
@@ -30,7 +30,7 @@ def edit_gst_release(gst_release_id):
if request.method == 'POST': if request.method == 'POST':
gst_service.EditGSTRelease(request, gst_release_id) gst_service.EditGSTRelease(request, gst_release_id)
LogHelper.log_action("Edit GST Release", f"User edited GST release") LogHelper.log_action("Edit GST Release", "User edited GST release")
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error') flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
return redirect(url_for('gst_release_bp.add_gst_release')) return redirect(url_for('gst_release_bp.add_gst_release'))
@@ -40,7 +40,7 @@ def edit_gst_release(gst_release_id):
@gst_release_bp.route('/delete_gst_release/<int:gst_release_id>', methods=['GET', 'POST']) @gst_release_bp.route('/delete_gst_release/<int:gst_release_id>', methods=['GET', 'POST'])
@login_required @login_required
def delete_gst_release(gst_release_id): def delete_gst_release(gst_release_id):
gst_service.DeleteGSTRelease(gst_release_id) # remove request gst_service.DeleteGSTRelease(gst_release_id)
LogHelper.log_action("Delete GST Release", f"User deleted GST release") LogHelper.log_action("Delete GST Release", "User deleted GST release")
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error') flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
return redirect(url_for('gst_release_bp.add_gst_release')) return redirect(url_for('gst_release_bp.add_gst_release'))

View File

@@ -83,29 +83,17 @@ def check_village():
return village.CheckVillage(request=request) return village.CheckVillage(request=request)
# ------------------------- Delete Village -------------------------
@village_bp.route('/delete_village/<int:village_id>') @village_bp.route('/delete_village/<int:village_id>')
@login_required @login_required
def delete_village(village_id): def delete_village(village_id):
village = Village() village = Village()
village.DeleteVillage(request=request, village_id=village_id) village.DeleteVillage(request=request, village_id=village_id)
# ✅ Convert resultMessage to string if it's a Response or tuple flash(village.resultMessage, "success" if village.isSuccess else "error")
raw_msg = village.resultMessage return redirect(url_for('village.add_village'))
if isinstance(raw_msg, tuple):
# e.g., (<Response ...>, 200)
msg = "Village deleted successfully!"
elif hasattr(raw_msg, 'get_data'):
# Flask Response object
msg = raw_msg.get_data(as_text=True) # get raw text
else:
# fallback
msg = str(raw_msg) if raw_msg else "Village deleted successfully!"
return jsonify({
"status": "success" if village.isSuccess else "error",
"message": msg
})
# ------------------------- Edit Village ------------------------- # ------------------------- Edit Village -------------------------
@village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST']) @village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST'])

View File

@@ -6,7 +6,6 @@ import config
import re import re
import mysql.connector import mysql.connector
# ---------------------------------------------------------- # ----------------------------------------------------------
# Mapping Class # Mapping Class
# ---------------------------------------------------------- # ----------------------------------------------------------
@@ -23,10 +22,11 @@ class itemCRUDMapping:
self.name = "Hold Type" self.name = "Hold Type"
elif itemType is ItemCRUDType.Subcontractor: elif itemType is ItemCRUDType.Subcontractor:
self.name = "Subcontractor" self.name = "Subcontractor"
elif itemType.name == "GSTRelease":
self.name = "GSTRelease"
else: else:
self.name = "Item" self.name = "Item"
# ---------------------------------------------------------- # ----------------------------------------------------------
# Generic CRUD Class # Generic CRUD Class
# ---------------------------------------------------------- # ----------------------------------------------------------
@@ -93,13 +93,47 @@ class ItemCRUD:
try: try:
# ====================================================== # ======================================================
# SUBCONTRACTOR (MULTI-FIELD) # GSTRelease MULTI-FIELD
# ====================================================== # ======================================================
if data: if self.itemCRUDType.name == "GSTRelease" and data:
# Duplicate check (PMC_No + Invoice_No)
if storedprocfetch:
cursor.callproc(storedprocfetch, (data['PMC_No'], data['Invoice_No']))
existing_item = None
for rs in cursor.stored_results():
existing_item = rs.fetchone()
if existing_item:
self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
)
return
# Insert GSTRelease
cursor.callproc(storedprocadd, (
data['PMC_No'],
data['Invoice_No'],
data['Basic_Amount'],
data['Final_Amount'],
data['Total_Amount'],
data['UTR'],
data['Contractor_ID']
))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
return
# ======================================================
# SUBCONTRACTOR MULTI-FIELD
# ======================================================
if self.itemCRUDType.name == "Subcontractor" and data:
# Duplicate check
cursor.callproc(storedprocfetch, (data['Contractor_Name'],)) cursor.callproc(storedprocfetch, (data['Contractor_Name'],))
existing_item = None existing_item = None
for rs in cursor.stored_results(): for rs in cursor.stored_results():
existing_item = rs.fetchone() existing_item = rs.fetchone()
@@ -111,7 +145,6 @@ class ItemCRUD:
) )
return return
# Insert
cursor.callproc(storedprocadd, ( cursor.callproc(storedprocadd, (
data['Contractor_Name'], data['Contractor_Name'],
data['Address'], data['Address'],
@@ -123,17 +156,16 @@ class ItemCRUD:
data['GST_No'], data['GST_No'],
data['Contractor_password'] data['Contractor_password']
)) ))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
ResponseHandler.add_success(self.itemCRUDMapping.name), 200 ResponseHandler.add_success(self.itemCRUDMapping.name), 200
) )
return return
# ====================================================== # ======================================================
# NORMAL (Village / Block / State) # NORMAL SINGLE-FIELD (Village / Block / State)
# ====================================================== # ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.patternAlphabetOnly, childname):
self.isSuccess = False self.isSuccess = False
@@ -142,7 +174,6 @@ class ItemCRUD:
) )
return return
# Duplicate check
if parentid is None: if parentid is None:
cursor.callproc(storedprocfetch, (childname,)) cursor.callproc(storedprocfetch, (childname,))
else: else:
@@ -159,17 +190,14 @@ class ItemCRUD:
) )
return return
# Insert
if parentid is None: if parentid is None:
cursor.callproc(storedprocadd, (childname,)) cursor.callproc(storedprocadd, (childname,))
else: else:
cursor.callproc(storedprocadd, (childname, parentid)) cursor.callproc(storedprocadd, (childname, parentid))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
ResponseHandler.add_success(self.itemCRUDMapping.name), 200 ResponseHandler.add_success(self.itemCRUDMapping.name), 200
) )
@@ -199,9 +227,33 @@ class ItemCRUD:
try: try:
# ====================================================== # ======================================================
# SUBCONTRACTOR (MULTI-FIELD) # GSTRelease MULTI-FIELD
# ====================================================== # ======================================================
if data: if self.itemCRUDType.name == "GSTRelease" and data:
cursor.callproc(storedprocupdate, (
childid,
data['PMC_No'],
data['Invoice_No'],
data['Basic_Amount'],
data['Final_Amount'],
data['Total_Amount'],
data['UTR'],
data['Contractor_ID']
))
connection.commit()
self.isSuccess = True
self.resultMessage = HtmlHelper.json_response(
ResponseHandler.update_success(self.itemCRUDMapping.name), 200
)
return
# ======================================================
# SUBCONTRACTOR MULTI-FIELD
# ======================================================
if self.itemCRUDType.name == "Subcontractor" and data:
cursor.callproc(storedprocupdate, ( cursor.callproc(storedprocupdate, (
childid, childid,
data['Contractor_Name'], data['Contractor_Name'],
@@ -214,9 +266,7 @@ class ItemCRUD:
data['GST_No'], data['GST_No'],
data['Contractor_password'] data['Contractor_password']
)) ))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.resultMessage = HtmlHelper.json_response(
ResponseHandler.update_success(self.itemCRUDMapping.name), 200 ResponseHandler.update_success(self.itemCRUDMapping.name), 200
@@ -224,7 +274,7 @@ class ItemCRUD:
return return
# ====================================================== # ======================================================
# NORMAL # NORMAL SINGLE-FIELD
# ====================================================== # ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.patternAlphabetOnly, childname):
self.isSuccess = False self.isSuccess = False
@@ -237,7 +287,6 @@ class ItemCRUD:
cursor.callproc(storedprocupdate, (childid, parentid, childname)) cursor.callproc(storedprocupdate, (childid, parentid, childname))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message'] self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message']
@@ -259,20 +308,15 @@ class ItemCRUD:
data = [] data = []
connection = config.get_db_connection() connection = config.get_db_connection()
if not connection: if not connection:
return [] return []
cursor = connection.cursor() cursor = connection.cursor()
try: try:
cursor.callproc(storedproc) cursor.callproc(storedproc)
for result in cursor.stored_results(): for result in cursor.stored_results():
data = result.fetchall() data = result.fetchall()
self.isSuccess = True self.isSuccess = True
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}") print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
@@ -280,7 +324,6 @@ class ItemCRUD:
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500 ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
) )
return [] return []
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()
@@ -298,13 +341,10 @@ class ItemCRUD:
try: try:
cursor.callproc(storedproc, (id,)) cursor.callproc(storedproc, (id,))
for rs in cursor.stored_results(): for rs in cursor.stored_results():
data = rs.fetchone() data = rs.fetchone()
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}") print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()
@@ -353,7 +393,6 @@ class ItemCRUD:
return HtmlHelper.json_response( return HtmlHelper.json_response(
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500 ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
) )
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()

View File

@@ -8,7 +8,7 @@ class ItemCRUDType(Enum):
State = 4 State = 4
HoldType = 5 HoldType = 5
Subcontractor = 6 Subcontractor = 6
GSTRelease = 7
class RegEx: class RegEx:
patternAlphabetOnly = "^[A-Za-z ]+$" patternAlphabetOnly = "^[A-Za-z ]+$"

View File

@@ -1,109 +1,8 @@
# from flask import request # model/gst_release.py
# from model.ItemCRUD import ItemCRUD
# from model.Utilities import ItemCRUDType
# class GSTRelease:
# """CRUD operations for GST Release using ItemCRUD"""
# def __init__(self):
# self.isSuccess = False
# self.resultMessage = ""
# # ------------------- Add GST Release -------------------
# def AddGSTRelease(self, request):
# pmc_no = request.form.get('PMC_No', '').strip()
# invoice_no = request.form.get('invoice_No', '').strip()
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.AddItem(
# request=request,
# parentid=None,
# childname=f"{pmc_no}-{invoice_no}",
# storedprocfetch="CheckGSTReleaseExists",
# storedprocadd="AddGSTReleaseFromExcel" # your stored procedure handles extra fields
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# # ------------------- Get All GST Releases -------------------
# def GetAllGSTReleases(self):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# # Pass request=None for fetch
# rows = gst.GetAllData(request=None, storedproc="GetAllGSTReleases")
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# data = []
# for row in rows:
# data.append({
# "gst_release_id": row[0],
# "pmc_no": row[1],
# "invoice_no": row[2],
# "basic_amount": row[3],
# "final_amount": row[4],
# "total_amount": row[5],
# "utr": row[6],
# "contractor_id": row[7]
# })
# return data
# # ------------------- Get GST Release By ID -------------------
# def GetGSTReleaseByID(self, gst_release_id):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# row = gst.GetDataByID(gst_release_id, request=None, storedproc="GetGSTReleaseById")
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# if row:
# return {
# "gst_release_id": row[0],
# "pmc_no": row[1],
# "invoice_no": row[2],
# "basic_amount": row[3],
# "final_amount": row[4],
# "total_amount": row[5],
# "utr": row[6],
# "contractor_id": row[7]
# }
# return None
# # ------------------- Edit GST Release -------------------
# def EditGSTRelease(self, request, gst_release_id):
# pmc_no = request.form.get('PMC_No', '').strip()
# invoice_no = request.form.get('invoice_No', '').strip()
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.EditItem(
# request=request,
# childid=gst_release_id,
# parentid=None,
# childname=f"{pmc_no}-{invoice_no}",
# storedprocupdate="UpdateGSTRelease" # stored procedure handles extra fields
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# # ------------------- Delete GST Release -------------------
# def DeleteGSTRelease(self, gst_release_id):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.DeleteItem(
# itemID=gst_release_id,
# request=None,
# storedprocDelete="DeleteGSTReleaseById"
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
from flask import request, jsonify from flask import request, jsonify
from model.ItemCRUD import ItemCRUD from model.ItemCRUD import ItemCRUD
from model.Utilities import ItemCRUDType from model.Utilities import ItemCRUDType
class GSTRelease: class GSTRelease:
def __init__(self): def __init__(self):
@@ -125,6 +24,7 @@ class GSTRelease:
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0) "Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
} }
# Add GST Release
gst.AddItem( gst.AddItem(
request=request, request=request,
data=data, data=data,
@@ -132,6 +32,12 @@ class GSTRelease:
storedprocadd="AddGSTReleaseFromExcel" storedprocadd="AddGSTReleaseFromExcel"
) )
# Check if addition was successful
if gst.isSuccess:
print(f"GST Release Added: {data}")
else:
print(f"Failed to add GST Release: {gst.resultMessage}")
self.isSuccess = gst.isSuccess self.isSuccess = gst.isSuccess
self.resultMessage = str(gst.resultMessage) self.resultMessage = str(gst.resultMessage)
@@ -198,7 +104,6 @@ class GSTRelease:
def GetAllGSTReleases(self): def GetAllGSTReleases(self):
try: try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
rows = gst.GetAllData(None, "GetAllGSTReleases") rows = gst.GetAllData(None, "GetAllGSTReleases")
data = [] data = []
@@ -224,7 +129,6 @@ class GSTRelease:
def GetGSTReleaseByID(self, gst_release_id): def GetGSTReleaseByID(self, gst_release_id):
try: try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById") row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById")
if row: if row:

View File

@@ -1,250 +1,264 @@
window.onload = function () { window.onload = function () {
if (document.getElementById('Village_Name')) { document.getElementById('Village_Name').focus();
document.getElementById('Village_Name').focus();
}
}; };
$(document).ready(function () { $(document).ready(function () {
// RUN ONLY IF THIS PAGE HAS FORM/TABLE // 🔥 RESTORE VIEW MODE AFTER RELOAD
if ($('#addForm').length && $('#addTable').length) { var viewMode = localStorage.getItem("viewMode");
// ✅ DEFAULT VIEW → SHOW FORM if (viewMode === "table") {
$('#addForm').hide();
$('#addTable').show();
} else {
$('#addForm').show();
$('#addTable').hide();
}
// 🔥 BUTTON TOGGLE LOGIC
$('#addButton').click(function () {
$('#addForm').show(); $('#addForm').show();
$('#addTable').hide(); $('#addTable').hide();
localStorage.setItem("viewMode", "form");
});
// 🔥 BUTTON TOGGLE $('#displayButton').click(function () {
$('#addButton').click(function () { $('#addForm').hide();
$('#addForm').show(); $('#addTable').show();
$('#addTable').hide();
});
$('#displayButton').click(function () { localStorage.setItem("viewMode", "table");
$('#addForm').hide(); });
$('#addTable').show();
});
}
// ===============================
// STATE → DISTRICT // STATE → DISTRICT
// =============================== $('#state_Id').change(function () {
if ($('#state_Id').length) {
$('#state_Id').change(function () { var stateId = $(this).val();
var stateId = $(this).val(); if (stateId) {
if (stateId) {
$.ajax({
url: '/get_districts/' + stateId,
type: 'GET',
success: function (data) {
var districtDropdown = $('#district_Id');
districtDropdown.empty();
districtDropdown.append('<option value="" disabled selected>Select District</option>');
data.forEach(function (district) {
districtDropdown.append(
'<option value="' + district.id + '">' + district.name + '</option>'
);
});
districtDropdown.prop('disabled', false);
}
});
}
});
}
// ===============================
// DISTRICT → BLOCK
// ===============================
if ($('#district_Id').length) {
$('#district_Id').change(function () {
var districtId = $(this).val();
if (districtId) {
$.ajax({
url: '/get_blocks/' + districtId,
type: 'GET',
success: function (data) {
var blockDropdown = $('#block_Id');
blockDropdown.empty();
blockDropdown.append('<option value="" disabled selected>Select Block</option>');
data.forEach(function (block) {
blockDropdown.append(
'<option value="' + block.id + '">' + block.name + '</option>'
);
});
blockDropdown.prop('disabled', false);
}
});
}
});
}
// ===============================
// VILLAGE NAME VALIDATION
// ===============================
if ($('#Village_Name').length) {
$('#Village_Name').on('input', function () {
var villageName = $(this).val();
var validPattern = /^[A-Za-z ]*$/;
if (!validPattern.test(villageName)) {
$('#villageMessage')
.text('Only letters and spaces are allowed!')
.css('color', 'red');
$('#submitVillage').prop('disabled', true);
} else {
$('#villageMessage').text('');
$('#submitVillage').prop('disabled', false);
}
});
}
// ===============================
// CHECK DUPLICATE VILLAGE
// ===============================
if ($('#Village_Name').length && $('#block_Id').length) {
$('#Village_Name, #block_Id').on('change keyup', function () {
var blockId = $('#block_Id').val();
var villageName = $('#Village_Name').val().trim();
if (blockId && villageName) {
$.ajax({
url: '/check_village',
type: 'POST',
data: {
block_Id: blockId,
Village_Name: villageName
},
success: function (response) {
if (response.status === 'exists') {
$('#villageMessage')
.text(response.message)
.css('color', 'red');
$('#submitVillage').prop('disabled', true);
} else {
$('#villageMessage')
.text(response.message)
.css('color', 'green');
$('#submitVillage').prop('disabled', false);
}
},
error: function () {
$('#villageMessage')
.text('Error checking village name')
.css('color', 'red');
$('#submitVillage').prop('disabled', true);
}
});
}
});
}
// ===============================
// ADD VILLAGE (SAFE SCOPE FIX)
// ===============================
if ($('#villageForm').length) {
$('#villageForm').submit(function (event) {
event.preventDefault();
$.ajax({ $.ajax({
url: '/add_village', url: '/get_districts/' + stateId,
type: 'GET',
success: function (data) {
var districtDropdown = $('#district_Id');
districtDropdown.empty();
districtDropdown.append('<option value="" disabled selected>Select District</option>');
data.forEach(function (district) {
districtDropdown.append(
'<option value="' + district.id + '">' + district.name + '</option>'
);
});
districtDropdown.prop('disabled', false);
}
});
}
});
// DISTRICT → BLOCK
$('#district_Id').change(function () {
var districtId = $(this).val();
if (districtId) {
$.ajax({
url: '/get_blocks/' + districtId,
type: 'GET',
success: function (data) {
var blockDropdown = $('#block_Id');
blockDropdown.empty();
blockDropdown.append('<option value="" disabled selected>Select Block</option>');
data.forEach(function (block) {
blockDropdown.append(
'<option value="' + block.id + '">' + block.name + '</option>'
);
});
blockDropdown.prop('disabled', false);
}
});
}
});
// VILLAGE NAME VALIDATION
$('#Village_Name').on('input', function () {
var villageName = $(this).val();
var validPattern = /^[A-Za-z ]*$/;
if (!validPattern.test(villageName)) {
$('#villageMessage')
.text('Only letters and spaces are allowed!')
.css('color', 'red');
$('#submitVillage').prop('disabled', true);
} else {
$('#villageMessage').text('');
$('#submitVillage').prop('disabled', false);
}
});
// CHECK DUPLICATE VILLAGE
$('#Village_Name, #block_Id').on('change keyup', function () {
var blockId = $('#block_Id').val();
var villageName = $('#Village_Name').val().trim();
if (blockId && villageName) {
$.ajax({
url: '/check_village',
type: 'POST', type: 'POST',
data: $(this).serialize(),
data: {
block_Id: blockId,
Village_Name: villageName
},
success: function (response) { success: function (response) {
if (response && response.status === 'success') { if (response.status === 'exists') {
alert(response.message || 'Village added successfully!'); $('#villageMessage')
.text(response.message)
.css('color', 'red');
// ✅ clear form $('#submitVillage').prop('disabled', true);
$('#villageForm')[0].reset();
// ✅ switch to table
$('#addForm').hide();
$('#addTable').show();
// optional refresh
location.reload();
} else { } else {
alert(response.message || 'Error adding village. Please try again.');
$('#villageMessage')
.text(response.message)
.css('color', 'green');
$('#submitVillage').prop('disabled', false);
} }
}, },
error: function () { error: function () {
alert('An error occurred. Please try again.');
$('#villageMessage')
.text('Error checking village name')
.css('color', 'red');
$('#submitVillage').prop('disabled', true);
} }
}); });
}
});
// ADD VILLAGE
$('#villageForm').submit(function (event) {
event.preventDefault();
$.ajax({
url: '/add_village',
type: 'POST',
data: $(this).serialize(),
success: function (response) {
if (response.status === 'success') {
alert('Village added successfully!');
location.reload();
} else {
alert(response.message || 'Error adding village. Please try again.');
}
},
error: function () {
alert('An error occurred. Please try again.');
}
}); });
}
});
}); });
// 🔥 DELETE FUNCTION (UPDATED)
function deleteVillage(villageId) {
if (!confirm("Are you sure you want to delete this village?")) {
return;
}
// =============================== // ✅ save that user is on table
// DELETE FUNCTION (SAFE) localStorage.setItem("viewMode", "table");
// ===============================
function deleteVillage(villageId, element) {
if (!confirm("Are you sure you want to delete this village?")) return;
$.ajax({ $.ajax({
url: '/delete_village/' + villageId, url: '/delete_village/' + villageId,
type: 'GET', type: 'GET',
dataType: 'json',
success: function (response) { success: function () {
alert(response.message); // ✅ now shows "Village deleted successfully!"
if (element) $(element).closest("tr").remove(); setTimeout(function () {
alert("Village deleted successfully!");
// reload but stay on table
location.reload();
}, 1000);
}, },
error: function () { error: function () {
alert("Error deleting village. Please try again."); alert("Error deleting village. Please try again.");
} }
}); });
} }

View File

@@ -68,50 +68,49 @@
{% endwith %} {% endwith %}
</div> </div>
<!-- GST Release History Table -->
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none;">
<div class="search-container"> <div class="search-container">
<h2>GST Release History</h2> <h2>GST Release History</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()"> <input type="text" id="searchBar" placeholder="Search..." onkeyup="searchTable()">
</div> </div>
<table id="sortableTable" border="1"> <table id="sortableTable" border="1">
<thead> <thead>
<tr> <tr>
<th class="sortable-header">GST_Release_Id</th> <th class="sortable-header">GST_Release_Id</th>
<th class="sortable-header">PMC_No</th> <th class="sortable-header">PMC_No</th>
<th>Invoice_No</th> <th>Invoice_No</th>
<th>Basic_Amount</th> <th>Basic_Amount</th>
<th>Final_Amount</th> <th>Final_Amount</th>
<th>Total_Amount</th> <th>Total_Amount</th>
<th>UTR</th> <th>UTR</th>
<th>Update</th> <th>Update</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for gst_rel in gst_releases %} {% for gst_rel in gst_releases %}
<tr> <tr>
<td>{{ gst_rel[0] }}</td> <td>{{ gst_rel.gst_release_id }}</td>
<td>{{ gst_rel[1] }}</td> <td>{{ gst_rel.pmc_no }}</td>
<td>{{ gst_rel[2] }}</td> <td>{{ gst_rel.invoice_no }}</td>
<td>{{ gst_rel[3] }}</td> <td>{{ gst_rel.basic_amount }}</td>
<td>{{ gst_rel[4] }}</td> <td>{{ gst_rel.final_amount }}</td>
<td>{{ gst_rel[5] }}</td> <td>{{ gst_rel.total_amount }}</td>
<td>{{ gst_rel[6] }}</td> <td>{{ gst_rel.utr }}</td>
<td> <td>
<a href="/edit_gst_release/{{ gst_rel[0] }}"> <a href="{{ url_for('gst_release_bp.edit_gst_release', gst_release_id=gst_rel.gst_release_id) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" <img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
class="icon"> </a>
</a> </td>
</td> <td>
<td> <a href="{{ url_for('gst_release_bp.delete_gst_release', gst_release_id=gst_rel.gst_release_id) }}"
<a href="/delete_gst_release/{{ gst_rel[0] }}" onclick="return confirm('Are you sure you want to delete this GST Release?')">
onclick="return confirm('Are you sure you want to delete this GST Release?')"> <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" </a>
class="icon"> </td>
</a> </tr>
</td> {% endfor %}
</tr>
{% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@@ -1,129 +1,99 @@
{% extends 'base.html' %} {% block content %} {% extends 'base.html' %}
{% block content %}
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Village Management</title> <title>Village Management</title>
<link <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
rel="stylesheet" <script src="{{ url_for('static', filename='js/village.js') }}"></script>
type="text/css" <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
href="{{ url_for('static', filename='css/style.css') }}"
/>
<script src="{{ url_for('static', filename='js/village.js') }}"></script>
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
<!-- Button Container to Center Buttons -->
<div class="button-container"> <!-- Button Container to Center Buttons -->
<div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm" style="display: none"> <div id="addForm" style="display: none;">
<div class="container"> <div class="container">
<div class="form-block"> <div class="form-block">
<h2>Add a New Village</h2> <h2>Add a New Village</h2>
<form id="villageForm" method="POST"> <form id="villageForm" method="POST">
<label for="state_Id">State:</label> <label for="state_Id">State:</label>
<select id="state_Id" name="state_Id" required> <select id="state_Id" name="state_Id" required>
<option value="" disabled selected>Select State</option> <option value="" disabled selected>Select State</option>
{% for state in states %} {% for state in states %}
<option value="{{ state[0] }}">{{ state[1] }}</option> <option value="{{ state[0] }}">{{ state[1] }}</option>
{% endfor %} {% endfor %}
</select> </select>
<label for="district_Id">District:</label> <label for="district_Id">District:</label>
<select id="district_Id" name="district_Id" required disabled> <select id="district_Id" name="district_Id" required disabled>
<option value="" disabled selected>Select District</option> <option value="" disabled selected>Select District</option>
</select> </select>
<label for="block_Id">Block:</label> <label for="block_Id">Block:</label>
<select id="block_Id" name="block_Id" required disabled> <select id="block_Id" name="block_Id" required disabled>
<option value="" disabled selected>Select Block</option> <option value="" disabled selected>Select Block</option>
</select> </select>
<label for="Village_Name">Village Name:</label> <label for="Village_Name">Village Name:</label>
<input <input type="text" id="Village_Name" name="Village_Name" placeholder="Enter Village Name" required>
type="text" <span id="villageMessage"></span>
id="Village_Name"
name="Village_Name"
placeholder="Enter Village Name"
required
/>
<span id="villageMessage"></span>
<button type="submit" id="submitVillage" disabled>Add Village</button> <button type="submit" id="submitVillage" disabled>Add Village</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
<div id="addTable" style="display: none"> <div id="addTable" style="display: none;">
<div class="search-container"> <div class="search-container">
<h2>Display Villages</h2> <h2>Display Villages</h2>
<input <input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
type="text"
id="searchBar"
placeholder="Searching..."
onkeyup="searchTable()"
/>
</div> </div>
<table id="sortableTable" border="1"> <table id="sortableTable" border="1">
<tr> <tr>
<th>Village Sr No</th> <th>Village Sr No</th>
<th class="sortable-header"> <th class="sortable-header">
Village Name Village Name
<span class="sort-buttons"> <span class="sort-buttons">
<span class="sort-asc">⬆️</span> <span class="sort-asc">⬆️</span>
<span class="sort-desc">⬇️</span> <span class="sort-desc">⬇️</span>
</span> </span></th>
</th> <th class="sortable-header">Block Name
<th class="sortable-header"> <span class="sort-buttons">
Block Name <span class="sort-asc">⬆️</span>
<span class="sort-buttons"> <span class="sort-desc">⬇️</span>
<span class="sort-asc">⬆️</span> </span></th>
<span class="sort-desc">⬇️</span> <th>Update</th>
</span> <th>Delete</th>
</th> </tr>
<th>Update</th> {% for village in villages %}
<th>Delete</th> <tr>
</tr> <td>{{ village[0] }}</td>
{% for village in villages %} <td>{{ village[1] }}</td>
<tr> <td>{{ village[2] }}</td>
<td>{{ village[0] }}</td> <td>
<td>{{ village[1] }}</td> <a href="{{ url_for('village.edit_village', village_id=village[0]) }}">
<td>{{ village[2] }}</td> <img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
<td> class="icon">
<a </a>
href="{{ url_for('village.edit_village', village_id=village[0]) }}" </td>
> <td>
<img <a href="#"
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" onclick="deleteVillage({{ village[0] }}); return false;">
alt="Edit"
class="icon"
/>
</a>
</td>
<td>
<a href="javascript:void(0);"
onclick="deleteVillage({{ village[0] }}, this)">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
class="icon"> alt="Delete" class="icon">
</a> </a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</table> </table>
</div> </div>
<!-- Flash Alerts -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<script>
{% for category, message in messages %}
alert("{{ message }}");
{% endfor %}
</script>
{% endif %}
{% endwith %}
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -28,17 +28,25 @@
<button type="submit">Update Village</button> <button type="submit">Update Village</button>
</form> </form>
<!-- Flash Messages (hidden, used for JS popup) --> </div>
<div id="flash-messages-container" style="display:none;">
<!-- Flash Message (Hidden, used for JS popup) -->
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %} {% if messages %}
{% for category, message in messages %} {% for category, message in messages %}
<div class="flash-message" data-category="{{ category }}">{{ message }}</div> <div id="flash-message" data-category="{{ category }}" style="display:none;">{{ message }}</div>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endwith %} {% endwith %}
</div> </div>
<script>
window.onload = function () {
const flash = document.getElementById('flash-message');
if (flash && flash.innerText.trim() !== "") {
alert(flash.innerText);
}
};
</script>
</body> </body>
{% endblock %} {% endblock %}