Compare commits
5 Commits
91b078a0c3
...
laxmi-dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 82bedc3117 | |||
| cb68e454bc | |||
| 675301df7f | |||
| 7146391c18 | |||
| 94b5563d15 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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 model.gst_release import GSTRelease
|
||||
from model.Log import LogHelper
|
||||
from flask import flash, current_app
|
||||
|
||||
gst_release_bp = Blueprint('gst_release_bp', __name__)
|
||||
gst_service = GSTRelease()
|
||||
@@ -13,7 +13,7 @@ gst_service = GSTRelease()
|
||||
def add_gst_release():
|
||||
if request.method == 'POST':
|
||||
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')
|
||||
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':
|
||||
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')
|
||||
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'])
|
||||
@login_required
|
||||
def delete_gst_release(gst_release_id):
|
||||
gst_service.DeleteGSTRelease(gst_release_id) # remove request
|
||||
LogHelper.log_action("Delete GST Release", f"User deleted GST release")
|
||||
gst_service.DeleteGSTRelease(gst_release_id)
|
||||
LogHelper.log_action("Delete GST Release", "User deleted GST release")
|
||||
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
|
||||
return redirect(url_for('gst_release_bp.add_gst_release'))
|
||||
@@ -86,12 +86,12 @@ def edit_payment(payment_id):
|
||||
|
||||
return render_template('edit_payment.html', payment_data=payment_data)
|
||||
|
||||
|
||||
# ------------------- Delete Payment -------------------
|
||||
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['POST'])
|
||||
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET'])
|
||||
@login_required
|
||||
def delete_payment(payment_id):
|
||||
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
|
||||
|
||||
if not success:
|
||||
flash("Payment not found or failed to delete", "error")
|
||||
else:
|
||||
|
||||
@@ -83,29 +83,17 @@ def check_village():
|
||||
return village.CheckVillage(request=request)
|
||||
|
||||
|
||||
# ------------------------- Delete Village -------------------------
|
||||
@village_bp.route('/delete_village/<int:village_id>')
|
||||
@login_required
|
||||
def delete_village(village_id):
|
||||
|
||||
village = Village()
|
||||
village.DeleteVillage(request=request, village_id=village_id)
|
||||
|
||||
# ✅ Convert resultMessage to string if it's a Response or tuple
|
||||
raw_msg = village.resultMessage
|
||||
flash(village.resultMessage, "success" if village.isSuccess else "error")
|
||||
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 -------------------------
|
||||
@village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST'])
|
||||
|
||||
@@ -6,7 +6,6 @@ import config
|
||||
import re
|
||||
import mysql.connector
|
||||
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Mapping Class
|
||||
# ----------------------------------------------------------
|
||||
@@ -23,10 +22,11 @@ class itemCRUDMapping:
|
||||
self.name = "Hold Type"
|
||||
elif itemType is ItemCRUDType.Subcontractor:
|
||||
self.name = "Subcontractor"
|
||||
elif itemType.name == "GSTRelease":
|
||||
self.name = "GSTRelease"
|
||||
else:
|
||||
self.name = "Item"
|
||||
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Generic CRUD Class
|
||||
# ----------------------------------------------------------
|
||||
@@ -93,13 +93,47 @@ class ItemCRUD:
|
||||
|
||||
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'],))
|
||||
|
||||
existing_item = None
|
||||
for rs in cursor.stored_results():
|
||||
existing_item = rs.fetchone()
|
||||
@@ -111,7 +145,6 @@ class ItemCRUD:
|
||||
)
|
||||
return
|
||||
|
||||
# Insert
|
||||
cursor.callproc(storedprocadd, (
|
||||
data['Contractor_Name'],
|
||||
data['Address'],
|
||||
@@ -123,17 +156,16 @@ class ItemCRUD:
|
||||
data['GST_No'],
|
||||
data['Contractor_password']
|
||||
))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
# ======================================================
|
||||
# NORMAL (Village / Block / State)
|
||||
# NORMAL SINGLE-FIELD (Village / Block / State)
|
||||
# ======================================================
|
||||
if not re.match(RegEx.patternAlphabetOnly, childname):
|
||||
self.isSuccess = False
|
||||
@@ -142,7 +174,6 @@ class ItemCRUD:
|
||||
)
|
||||
return
|
||||
|
||||
# Duplicate check
|
||||
if parentid is None:
|
||||
cursor.callproc(storedprocfetch, (childname,))
|
||||
else:
|
||||
@@ -159,17 +190,14 @@ class ItemCRUD:
|
||||
)
|
||||
return
|
||||
|
||||
# Insert
|
||||
if parentid is None:
|
||||
cursor.callproc(storedprocadd, (childname,))
|
||||
else:
|
||||
cursor.callproc(storedprocadd, (childname, parentid))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
|
||||
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
|
||||
)
|
||||
|
||||
@@ -199,9 +227,33 @@ class ItemCRUD:
|
||||
|
||||
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, (
|
||||
childid,
|
||||
data['Contractor_Name'],
|
||||
@@ -214,9 +266,7 @@ class ItemCRUD:
|
||||
data['GST_No'],
|
||||
data['Contractor_password']
|
||||
))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.update_success(self.itemCRUDMapping.name), 200
|
||||
@@ -224,7 +274,7 @@ class ItemCRUD:
|
||||
return
|
||||
|
||||
# ======================================================
|
||||
# NORMAL
|
||||
# NORMAL SINGLE-FIELD
|
||||
# ======================================================
|
||||
if not re.match(RegEx.patternAlphabetOnly, childname):
|
||||
self.isSuccess = False
|
||||
@@ -237,7 +287,6 @@ class ItemCRUD:
|
||||
cursor.callproc(storedprocupdate, (childid, parentid, childname))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message']
|
||||
|
||||
@@ -259,20 +308,15 @@ class ItemCRUD:
|
||||
|
||||
data = []
|
||||
connection = config.get_db_connection()
|
||||
|
||||
if not connection:
|
||||
return []
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
try:
|
||||
cursor.callproc(storedproc)
|
||||
|
||||
for result in cursor.stored_results():
|
||||
data = result.fetchall()
|
||||
|
||||
self.isSuccess = True
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
|
||||
self.isSuccess = False
|
||||
@@ -280,7 +324,6 @@ class ItemCRUD:
|
||||
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
return []
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
@@ -298,13 +341,10 @@ class ItemCRUD:
|
||||
|
||||
try:
|
||||
cursor.callproc(storedproc, (id,))
|
||||
|
||||
for rs in cursor.stored_results():
|
||||
data = rs.fetchone()
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
@@ -353,7 +393,6 @@ class ItemCRUD:
|
||||
return HtmlHelper.json_response(
|
||||
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
@@ -8,7 +8,7 @@ class ItemCRUDType(Enum):
|
||||
State = 4
|
||||
HoldType = 5
|
||||
Subcontractor = 6
|
||||
|
||||
GSTRelease = 7
|
||||
|
||||
class RegEx:
|
||||
patternAlphabetOnly = "^[A-Za-z ]+$"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,109 +1,8 @@
|
||||
# from flask import request
|
||||
# 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)
|
||||
|
||||
# model/gst_release.py
|
||||
from flask import request, jsonify
|
||||
from model.ItemCRUD import ItemCRUD
|
||||
from model.Utilities import ItemCRUDType
|
||||
|
||||
|
||||
class GSTRelease:
|
||||
|
||||
def __init__(self):
|
||||
@@ -125,6 +24,7 @@ class GSTRelease:
|
||||
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
|
||||
}
|
||||
|
||||
# Add GST Release
|
||||
gst.AddItem(
|
||||
request=request,
|
||||
data=data,
|
||||
@@ -132,6 +32,12 @@ class GSTRelease:
|
||||
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.resultMessage = str(gst.resultMessage)
|
||||
|
||||
@@ -198,7 +104,6 @@ class GSTRelease:
|
||||
def GetAllGSTReleases(self):
|
||||
try:
|
||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
|
||||
rows = gst.GetAllData(None, "GetAllGSTReleases")
|
||||
|
||||
data = []
|
||||
@@ -224,7 +129,6 @@ class GSTRelease:
|
||||
def GetGSTReleaseByID(self, gst_release_id):
|
||||
try:
|
||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
|
||||
row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById")
|
||||
|
||||
if row:
|
||||
|
||||
@@ -1,160 +1,5 @@
|
||||
// $(document).ready(function () {
|
||||
// // ===============================
|
||||
// // FORM / TABLE TOGGLE
|
||||
// // ===============================
|
||||
// if ($('#addForm').length && $('#addTable').length) {
|
||||
// $('#addForm').show();
|
||||
// $('#addTable').hide();
|
||||
|
||||
// $('#addButton').click(function () {
|
||||
// $('#addForm').show();
|
||||
// $('#addTable').hide();
|
||||
// });
|
||||
|
||||
// $('#displayButton').click(function () {
|
||||
// $('#addForm').hide();
|
||||
// $('#addTable').show();
|
||||
// });
|
||||
// }
|
||||
|
||||
// // ===============================
|
||||
// // Subcontractor autocomplete
|
||||
// // ===============================
|
||||
// $("#subcontractor").keyup(function () {
|
||||
// let query = $(this).val();
|
||||
// if (query !== "") {
|
||||
// $.ajax({
|
||||
// url: "/search_subcontractor",
|
||||
// method: "POST",
|
||||
// data: { query: query },
|
||||
// success: function (data) {
|
||||
// $("#subcontractor_list").fadeIn().html(data);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// $("#subcontractor_list").fadeOut();
|
||||
// }
|
||||
// });
|
||||
|
||||
// $(document).on("click", "li", function () {
|
||||
// $("#subcontractor").val($(this).text());
|
||||
// $("#subcontractor_id").val($(this).attr("data-id"));
|
||||
// $("#subcontractor_list").fadeOut();
|
||||
// });
|
||||
|
||||
// // Focus
|
||||
// if (document.getElementById('subcontractor')) {
|
||||
// document.getElementById('subcontractor').focus();
|
||||
// }
|
||||
|
||||
// // ===============================
|
||||
// // ADD INVOICE
|
||||
// // ===============================
|
||||
// if ($('#invoiceForm').length && window.location.href.includes('add_invoice')) {
|
||||
// $("#invoiceForm").on("submit", function (e) {
|
||||
// e.preventDefault();
|
||||
// let formData = $(this).serialize();
|
||||
|
||||
// $.ajax({
|
||||
// url: '/add_invoice',
|
||||
// method: 'POST',
|
||||
// data: formData,
|
||||
// dataType: 'json',
|
||||
// success: function (response) {
|
||||
// if (response.status === "success") {
|
||||
// alert(response.message || "Invoice added successfully!");
|
||||
// $('#invoiceForm')[0].reset(); // clear form
|
||||
// $('#addForm').hide();
|
||||
// $('#addTable').show(); // switch to table
|
||||
// location.reload(); // optional refresh
|
||||
// } else {
|
||||
// alert(response.message || "Error adding invoice.");
|
||||
// }
|
||||
// },
|
||||
// error: function (xhr) {
|
||||
// alert(xhr.responseJSON?.message || "Submission failed. Please try again.");
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// }
|
||||
// // Example AJAX update function
|
||||
// function updateInvoice(invoiceId, formElement) {
|
||||
// const formData = $(formElement).serialize();
|
||||
|
||||
// $.ajax({
|
||||
// url: '/update_invoice/' + invoiceId,
|
||||
// method: 'POST',
|
||||
// data: formData,
|
||||
// dataType: 'json',
|
||||
// success: function(response) {
|
||||
// if(response.status === "success") {
|
||||
// alert(response.message || "Invoice updated successfully!");
|
||||
|
||||
// // ✅ Hide Add Form, Show Table
|
||||
// $('#addForm').hide();
|
||||
// $('#addTable').show();
|
||||
|
||||
// // Optional: reload table or refresh page
|
||||
// location.reload();
|
||||
// } else {
|
||||
// alert(response.message || "Update failed. Please try again.");
|
||||
// }
|
||||
// },
|
||||
// error: function(xhr) {
|
||||
// alert(xhr.responseJSON?.message || "Error updating invoice.");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// // ===============================
|
||||
// // DELETE INVOICE
|
||||
// // ===============================
|
||||
// function deleteInvoice(invoiceId, element) {
|
||||
// if (!confirm("Are you sure you want to delete this invoice?")) return;
|
||||
|
||||
// $.ajax({
|
||||
// url: '/delete_invoice/' + invoiceId,
|
||||
// method: 'GET',
|
||||
// dataType: 'json',
|
||||
// success: function (response) {
|
||||
// alert(response.message || "Invoice deleted successfully!");
|
||||
// if (element) $(element).closest("tr").remove();
|
||||
// },
|
||||
// error: function (xhr) {
|
||||
// alert(xhr.responseJSON?.message || "Error deleting invoice. Please try again.");
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// Subcontractor autocomplete functionality
|
||||
$(document).ready(function () {
|
||||
// ===============================
|
||||
// FORM / TABLE TOGGLE
|
||||
// ===============================
|
||||
if ($('#addForm').length && $('#addTable').length) {
|
||||
// Default: show form, hide table
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
|
||||
// ✅ Check URL hash to show table instead
|
||||
if (window.location.hash === "#addTable") {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
}
|
||||
|
||||
$('#addButton').click(function () {
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
});
|
||||
|
||||
$('#displayButton').click(function () {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
});
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// Subcontractor autocomplete
|
||||
// ===============================
|
||||
$("#subcontractor").keyup(function () {
|
||||
let query = $(this).val();
|
||||
if (query !== "") {
|
||||
@@ -176,96 +21,42 @@ $(document).ready(function () {
|
||||
$("#subcontractor_id").val($(this).attr("data-id"));
|
||||
$("#subcontractor_list").fadeOut();
|
||||
});
|
||||
});
|
||||
|
||||
// Focus
|
||||
if (document.getElementById('subcontractor')) {
|
||||
document.getElementById('subcontractor').focus();
|
||||
// Success Alert: show alert and reload after 3 seconds
|
||||
function showSuccessAlert() {
|
||||
const alertBox = document.getElementById("invoiceSuccessAlert");
|
||||
alertBox.classList.add("show");
|
||||
setTimeout(() => {
|
||||
alertBox.classList.remove("show");
|
||||
// Reload page or redirect after alert hides
|
||||
window.location.href = '/add_invoice';
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// ADD INVOICE
|
||||
// ===============================
|
||||
if ($('#invoiceForm').length && window.location.href.includes('add_invoice')) {
|
||||
// Submit form via AJAX
|
||||
$("#invoiceForm").on("submit", function (e) {
|
||||
e.preventDefault();
|
||||
let formData = $(this).serialize();
|
||||
|
||||
$.ajax({
|
||||
url: '/add_invoice',
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
if(response.status === "success") {
|
||||
alert(response.message || "Invoice added successfully!");
|
||||
$('#invoiceForm')[0].reset(); // clear form
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show(); // switch to table
|
||||
location.reload(); // optional refresh
|
||||
showSuccessAlert();
|
||||
} else {
|
||||
alert(response.message || "Error adding invoice.");
|
||||
alert(response.message);
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
let msg = xhr.responseJSON?.message || "Submission failed. Please try again.";
|
||||
alert(msg);
|
||||
error: function (xhr, status, error) {
|
||||
alert("Submission failed: " + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// UPDATE INVOICE
|
||||
// ===============================
|
||||
function updateInvoice(invoiceId, formElement) {
|
||||
const formData = $(formElement).serialize();
|
||||
|
||||
$.ajax({
|
||||
url: '/update_invoice/' + invoiceId,
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if(response.status === "success") {
|
||||
alert(response.message || "Invoice updated successfully!");
|
||||
|
||||
// Redirect to Add Invoice page's table part
|
||||
window.location.href = "/add_invoice#addTable";
|
||||
} else {
|
||||
alert(response.message || "Update failed. Please try again.");
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
let msg = xhr.responseJSON?.message || "Error updating invoice.";
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
window.updateInvoice = updateInvoice; // make globally accessible
|
||||
|
||||
// ===============================
|
||||
// DELETE INVOICE
|
||||
// ===============================
|
||||
function deleteInvoice(invoiceId, element) {
|
||||
if (!confirm("Are you sure you want to delete this invoice?")) return;
|
||||
|
||||
$.ajax({
|
||||
url: '/delete_invoice/' + invoiceId,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
if (response.status === "success") {
|
||||
alert(response.message || "Invoice deleted successfully!");
|
||||
if (element) $(element).closest("tr").remove();
|
||||
} else {
|
||||
alert(response.message || "Error deleting invoice.");
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
let msg = xhr.responseJSON?.message || "Error deleting invoice. Please try again.";
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
window.deleteInvoice = deleteInvoice; // make globally accessible
|
||||
});
|
||||
window.onload = function () {
|
||||
document.getElementById('subcontractor').focus();
|
||||
};
|
||||
@@ -1,37 +1,41 @@
|
||||
|
||||
|
||||
window.onload = function () {
|
||||
if (document.getElementById('Village_Name')) {
|
||||
document.getElementById('Village_Name').focus();
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// ✅ RUN ONLY IF THIS PAGE HAS FORM/TABLE
|
||||
if ($('#addForm').length && $('#addTable').length) {
|
||||
// 🔥 RESTORE VIEW MODE AFTER RELOAD
|
||||
var viewMode = localStorage.getItem("viewMode");
|
||||
|
||||
// ✅ DEFAULT VIEW → SHOW FORM
|
||||
if (viewMode === "table") {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
} else {
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
}
|
||||
|
||||
|
||||
// 🔥 BUTTON TOGGLE
|
||||
// 🔥 BUTTON TOGGLE LOGIC
|
||||
|
||||
$('#addButton').click(function () {
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
|
||||
localStorage.setItem("viewMode", "form");
|
||||
});
|
||||
|
||||
$('#displayButton').click(function () {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
|
||||
localStorage.setItem("viewMode", "table");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// STATE → DISTRICT
|
||||
// ===============================
|
||||
if ($('#state_Id').length) {
|
||||
|
||||
$('#state_Id').change(function () {
|
||||
|
||||
var stateId = $(this).val();
|
||||
@@ -50,24 +54,25 @@ $(document).ready(function () {
|
||||
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();
|
||||
@@ -86,24 +91,25 @@ $(document).ready(function () {
|
||||
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();
|
||||
@@ -121,16 +127,13 @@ $(document).ready(function () {
|
||||
|
||||
$('#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();
|
||||
@@ -139,6 +142,7 @@ $(document).ready(function () {
|
||||
if (blockId && villageName) {
|
||||
|
||||
$.ajax({
|
||||
|
||||
url: '/check_village',
|
||||
type: 'POST',
|
||||
|
||||
@@ -164,7 +168,9 @@ $(document).ready(function () {
|
||||
.css('color', 'green');
|
||||
|
||||
$('#submitVillage').prop('disabled', false);
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
error: function () {
|
||||
@@ -174,77 +180,85 @@ $(document).ready(function () {
|
||||
.css('color', 'red');
|
||||
|
||||
$('#submitVillage').prop('disabled', true);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// ADD VILLAGE (SAFE SCOPE FIX)
|
||||
// ===============================
|
||||
if ($('#villageForm').length) {
|
||||
|
||||
// ADD VILLAGE
|
||||
$('#villageForm').submit(function (event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
|
||||
url: '/add_village',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
|
||||
success: function (response) {
|
||||
|
||||
if (response && response.status === 'success') {
|
||||
if (response.status === 'success') {
|
||||
|
||||
alert(response.message || 'Village added successfully!');
|
||||
|
||||
// ✅ clear form
|
||||
$('#villageForm')[0].reset();
|
||||
|
||||
// ✅ switch to table
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
|
||||
// optional refresh
|
||||
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) {
|
||||
|
||||
// ===============================
|
||||
// DELETE FUNCTION (SAFE)
|
||||
// ===============================
|
||||
function deleteVillage(villageId, element) {
|
||||
if (!confirm("Are you sure you want to delete this village?")) return;
|
||||
if (!confirm("Are you sure you want to delete this village?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ save that user is on table
|
||||
localStorage.setItem("viewMode", "table");
|
||||
|
||||
$.ajax({
|
||||
url: '/delete_village/' + villageId,
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
alert(response.message); // ✅ now shows "Village deleted successfully!"
|
||||
if (element) $(element).closest("tr").remove();
|
||||
|
||||
success: function () {
|
||||
|
||||
setTimeout(function () {
|
||||
|
||||
alert("Village deleted successfully!");
|
||||
|
||||
// reload but stay on table
|
||||
location.reload();
|
||||
|
||||
}, 1000);
|
||||
|
||||
},
|
||||
|
||||
error: function () {
|
||||
alert("Error deleting village. Please try again.");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
@@ -68,10 +68,11 @@
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<!-- GST Release History Table -->
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>GST Release History</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
<input type="text" id="searchBar" placeholder="Search..." onkeyup="searchTable()">
|
||||
</div>
|
||||
<table id="sortableTable" border="1">
|
||||
<thead>
|
||||
@@ -90,24 +91,22 @@
|
||||
<tbody>
|
||||
{% for gst_rel in gst_releases %}
|
||||
<tr>
|
||||
<td>{{ gst_rel[0] }}</td>
|
||||
<td>{{ gst_rel[1] }}</td>
|
||||
<td>{{ gst_rel[2] }}</td>
|
||||
<td>{{ gst_rel[3] }}</td>
|
||||
<td>{{ gst_rel[4] }}</td>
|
||||
<td>{{ gst_rel[5] }}</td>
|
||||
<td>{{ gst_rel[6] }}</td>
|
||||
<td>{{ gst_rel.gst_release_id }}</td>
|
||||
<td>{{ gst_rel.pmc_no }}</td>
|
||||
<td>{{ gst_rel.invoice_no }}</td>
|
||||
<td>{{ gst_rel.basic_amount }}</td>
|
||||
<td>{{ gst_rel.final_amount }}</td>
|
||||
<td>{{ gst_rel.total_amount }}</td>
|
||||
<td>{{ gst_rel.utr }}</td>
|
||||
<td>
|
||||
<a href="/edit_gst_release/{{ gst_rel[0] }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||
class="icon">
|
||||
<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" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/delete_gst_release/{{ gst_rel[0] }}"
|
||||
<a href="{{ url_for('gst_release_bp.delete_gst_release', gst_release_id=gst_rel.gst_release_id) }}"
|
||||
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" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -1,66 +1,47 @@
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
<head xmlns="http://www.w3.org/1999/html">
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Add Invoice</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='css/invoice.css') }}"
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% if success == 'true' %}
|
||||
<div
|
||||
class="alert alert-success alert-dismissible fade show mt-3"
|
||||
role="alert"
|
||||
>
|
||||
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert">
|
||||
✅ Invoice added successfully!
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="alert"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<!-- Flash Messages -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %} {% if
|
||||
messages %}
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="flash-messages">
|
||||
{% for category, message in messages %}
|
||||
<div class="alert {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %} {% endwith %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
|
||||
<div id="addForm" style="display: none">
|
||||
<div id="addForm" style="display: none;">
|
||||
<h2>Add Invoice</h2>
|
||||
|
||||
<form
|
||||
id="invoiceForm"
|
||||
action="{{ url_for('invoice.add_invoice') }}"
|
||||
method="POST"
|
||||
>
|
||||
<form id="invoiceForm" action="{{ url_for('invoice.add_invoice') }}" method="POST">
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="subcontractor"
|
||||
name="subcontractor"
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
|
||||
<div id="subcontractor_list"></div>
|
||||
</div>
|
||||
@@ -72,9 +53,7 @@
|
||||
<select id="village" name="village" required>
|
||||
<option value="">-- Select Village --</option>
|
||||
{% for village in villages %}
|
||||
<option value="{{ village.Village_Name }}">
|
||||
{{ village.Village_Name }}
|
||||
</option>
|
||||
<option value="{{ village.Village_Name }}">{{ village.Village_Name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
@@ -92,11 +71,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_details">Invoice Details:</label>
|
||||
<textarea
|
||||
id="invoice_details"
|
||||
name="invoice_details"
|
||||
required
|
||||
></textarea>
|
||||
<textarea id="invoice_details" name="invoice_details" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -114,161 +89,59 @@
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="basic_amount">Basic Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="basic_amount"
|
||||
name="basic_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="debit_amount">Debit Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="debit_amount"
|
||||
name="debit_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="debit_amount" name="debit_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="after_debit_amount">After Debit Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="after_debit_amount"
|
||||
name="after_debit_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div class="percentage-field">
|
||||
<label for="gst_percentage">GST %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="gst_percentage"
|
||||
name="gst_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<input type="number" step="0.01" id="gst_percentage" name="gst_percentage" placeholder="%"/>
|
||||
<label for="gst_amount">GST Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="gst_amount"
|
||||
name="gst_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="gst_amount" name="gst_amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="amount">Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="amount"
|
||||
name="amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="amount" name="amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="tds_percentage">TDS %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="tds_percentage"
|
||||
name="tds_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<input type="number" step="0.01" id="tds_percentage" name="tds_percentage" placeholder="%"/>
|
||||
<label for="tds_amount">TDS Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="tds_amount"
|
||||
name="tds_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="tds_amount" name="tds_amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div class="percentage-field">
|
||||
<label for="sd_percentage">SD %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="sd_percentage"
|
||||
name="sd_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<input type="number" step="0.01" id="sd_percentage" name="sd_percentage" placeholder="%"/>
|
||||
<label for="sd_amount">SD Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="sd_amount"
|
||||
name="sd_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="sd_amount" name="sd_amount" placeholder="₹ - 00.00" readonly required>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="commission_percentage">On Commission %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="commission_percentage"
|
||||
name="commission_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<input type="number" step="0.01" id="commission_percentage" name="commission_percentage" placeholder="%"/>
|
||||
<label for="on_commission">On Commission:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="on_commission"
|
||||
name="on_commission"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="on_commission" name="on_commission" placeholder="₹ - 00.00" readonly required>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="hydro_percentage">Hydro Testing %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="hydro_percentage"
|
||||
name="hydro_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<input type="number" step="0.01" id="hydro_percentage" name="hydro_percentage" placeholder="%"/>
|
||||
<label for="hydro_testing">Hydro Testing:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="hydro_testing"
|
||||
name="hydro_testing"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" placeholder="₹ - 00.00" readonly required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hold-row">
|
||||
<button type="button" id="add_hold_amount" class="button">
|
||||
+ Add Hold Amount
|
||||
</button>
|
||||
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button>
|
||||
</div>
|
||||
|
||||
<!-- Dynamically added hold amount fields -->
|
||||
@@ -277,25 +150,11 @@
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="gst_sd_amount"
|
||||
name="gst_sd_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="final_amount">Final Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="final_amount"
|
||||
name="final_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -303,16 +162,11 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none">
|
||||
<div id="addTable" style="display: none;">
|
||||
<!-- Invoice Table Section -->
|
||||
<div class="search-container">
|
||||
<h2>Invoice List</h2>
|
||||
<input
|
||||
type="text"
|
||||
id="searchBar"
|
||||
placeholder="Searching..."
|
||||
onkeyup="searchTable()"
|
||||
/>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
{% if invoices %}
|
||||
<table class="invoice-table">
|
||||
<thead>
|
||||
@@ -364,27 +218,14 @@
|
||||
<td>{{ invoice.Final_Amount }}</td>
|
||||
<td>
|
||||
<!-- Edit -->
|
||||
<a
|
||||
href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
|
||||
>
|
||||
<img
|
||||
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
|
||||
alt="Edit"
|
||||
class="icon edit-btn"
|
||||
data-id="{{ invoice.Invoice_Id }}"
|
||||
/>
|
||||
<a href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
href="javascript:void(0);"
|
||||
onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
|
||||
>
|
||||
<img
|
||||
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||
alt="Delete"
|
||||
class="icon"
|
||||
/>
|
||||
<!-- Delete -->
|
||||
<a href="{{ url_for('invoice.delete_invoice_route', invoice_id=invoice.Invoice_Id) }}" onclick="return confirm('Are you sure?')">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -397,28 +238,26 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get all the input fields
|
||||
const basicAmount = document.getElementById("basic_amount");
|
||||
const debitAmount = document.getElementById("debit_amount");
|
||||
const afterDebitAmount = document.getElementById("after_debit_amount");
|
||||
const amount = document.getElementById("amount");
|
||||
const basicAmount = document.getElementById('basic_amount');
|
||||
const debitAmount = document.getElementById('debit_amount');
|
||||
const afterDebitAmount = document.getElementById('after_debit_amount');
|
||||
const amount = document.getElementById('amount');
|
||||
|
||||
// Percentage fields
|
||||
const gstPercentage = document.getElementById("gst_percentage");
|
||||
const gstAmount = document.getElementById("gst_amount");
|
||||
const tdsPercentage = document.getElementById("tds_percentage");
|
||||
const tdsAmount = document.getElementById("tds_amount");
|
||||
const sdPercentage = document.getElementById("sd_percentage");
|
||||
const sdAmountInput = document.getElementById("sd_amount");
|
||||
const commissionPercentage = document.getElementById(
|
||||
"commission_percentage",
|
||||
);
|
||||
const onCommission = document.getElementById("on_commission");
|
||||
const hydroPercentage = document.getElementById("hydro_percentage");
|
||||
const hydroTesting = document.getElementById("hydro_testing");
|
||||
const gstSdAmount = document.getElementById("gst_sd_amount");
|
||||
const finalAmount = document.getElementById("final_amount");
|
||||
const gstPercentage = document.getElementById('gst_percentage');
|
||||
const gstAmount = document.getElementById('gst_amount');
|
||||
const tdsPercentage = document.getElementById('tds_percentage');
|
||||
const tdsAmount = document.getElementById('tds_amount');
|
||||
const sdPercentage = document.getElementById('sd_percentage');
|
||||
const sdAmountInput = document.getElementById('sd_amount');
|
||||
const commissionPercentage = document.getElementById('commission_percentage');
|
||||
const onCommission = document.getElementById('on_commission');
|
||||
const hydroPercentage = document.getElementById('hydro_percentage');
|
||||
const hydroTesting = document.getElementById('hydro_testing');
|
||||
const gstSdAmount = document.getElementById('gst_sd_amount');
|
||||
const finalAmount = document.getElementById('final_amount');
|
||||
|
||||
// Calculate after debit amount when basic or debit amount changes
|
||||
function calculateAfterDebitAmount() {
|
||||
@@ -494,9 +333,7 @@
|
||||
|
||||
// Get hold amounts
|
||||
let totalHold = 0;
|
||||
document
|
||||
.querySelectorAll('input[name="hold_amount[]"]')
|
||||
.forEach((input) => {
|
||||
document.querySelectorAll('input[name="hold_amount[]"]').forEach(input => {
|
||||
totalHold += parseFloat(input.value) || 0;
|
||||
});
|
||||
|
||||
@@ -506,30 +343,27 @@
|
||||
}
|
||||
|
||||
// Add event listeners
|
||||
basicAmount.addEventListener("input", calculateAfterDebitAmount);
|
||||
debitAmount.addEventListener("input", calculateAfterDebitAmount);
|
||||
basicAmount.addEventListener('input', calculateAfterDebitAmount);
|
||||
debitAmount.addEventListener('input', calculateAfterDebitAmount);
|
||||
|
||||
// Percentage fields
|
||||
gstPercentage.addEventListener("input", calculateGST);
|
||||
tdsPercentage.addEventListener("input", calculateOtherDeductions);
|
||||
sdPercentage.addEventListener("input", calculateOtherDeductions);
|
||||
commissionPercentage.addEventListener(
|
||||
"input",
|
||||
calculateOtherDeductions,
|
||||
);
|
||||
hydroPercentage.addEventListener("input", calculateOtherDeductions);
|
||||
gstPercentage.addEventListener('input', calculateGST);
|
||||
tdsPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
sdPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
commissionPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
hydroPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
|
||||
// Listen for changes in hold amounts
|
||||
document.addEventListener("holdAmountChanged", calculateFinalAmount);
|
||||
document.addEventListener('holdAmountChanged', calculateFinalAmount);
|
||||
});
|
||||
|
||||
// Optional JS for auto-hiding flash
|
||||
setTimeout(() => {
|
||||
document
|
||||
.querySelectorAll(".alert")
|
||||
.forEach((el) => (el.style.display = "none"));
|
||||
document.querySelectorAll('.alert').forEach(el => el.style.display = 'none');
|
||||
}, 5000);
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -97,15 +97,13 @@
|
||||
<td><a href="/edit_payment/{{ payment[0] }}"><img
|
||||
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||
class="icon"></a></td>
|
||||
|
||||
<td>
|
||||
<form action="{{ url_for('payment_bp.delete_payment', payment_id=payment[0]) }}" method="POST"
|
||||
style="display:inline;">
|
||||
<button type="submit"
|
||||
onclick="return confirm('Are you sure you want to delete this payment?')">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||
alt="Delete" class="icon">
|
||||
</button>
|
||||
</form>
|
||||
<a href="{{ url_for('payment_bp.delete_payment', payment_id=payment[0]) }}"
|
||||
onclick="return confirm('Are you sure you want to delete this Payment?')">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
|
||||
class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- <tr>
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Village Management</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='css/style.css') }}"
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css" 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>
|
||||
<body>
|
||||
|
||||
<!-- Button Container to Center Buttons -->
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
|
||||
<div id="addForm" style="display: none">
|
||||
<div id="addForm" style="display: none;">
|
||||
<div class="container">
|
||||
<div class="form-block">
|
||||
<h2>Add a New Village</h2>
|
||||
@@ -42,13 +40,7 @@
|
||||
</select>
|
||||
|
||||
<label for="Village_Name">Village Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="Village_Name"
|
||||
name="Village_Name"
|
||||
placeholder="Enter Village Name"
|
||||
required
|
||||
/>
|
||||
<input type="text" id="Village_Name" name="Village_Name" placeholder="Enter Village Name" required>
|
||||
<span id="villageMessage"></span>
|
||||
|
||||
<button type="submit" id="submitVillage" disabled>Add Village</button>
|
||||
@@ -57,15 +49,10 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none">
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>Display Villages</h2>
|
||||
<input
|
||||
type="text"
|
||||
id="searchBar"
|
||||
placeholder="Searching..."
|
||||
onkeyup="searchTable()"
|
||||
/>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
</div>
|
||||
|
||||
<table id="sortableTable" border="1">
|
||||
@@ -76,15 +63,12 @@
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span>
|
||||
</th>
|
||||
<th class="sortable-header">
|
||||
Block Name
|
||||
</span></th>
|
||||
<th class="sortable-header">Block Name
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span>
|
||||
</th>
|
||||
</span></th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
@@ -94,36 +78,22 @@
|
||||
<td>{{ village[1] }}</td>
|
||||
<td>{{ village[2] }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="{{ url_for('village.edit_village', village_id=village[0]) }}"
|
||||
>
|
||||
<img
|
||||
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
|
||||
alt="Edit"
|
||||
class="icon"
|
||||
/>
|
||||
<a href="{{ url_for('village.edit_village', village_id=village[0]) }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||
class="icon">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="javascript:void(0);"
|
||||
onclick="deleteVillage({{ village[0] }}, this)">
|
||||
<a href="#"
|
||||
onclick="deleteVillage({{ village[0] }}); return false;">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||
class="icon">
|
||||
alt="Delete" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</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>
|
||||
{% endblock %}
|
||||
|
||||
@@ -28,17 +28,25 @@
|
||||
|
||||
<button type="submit">Update Village</button>
|
||||
</form>
|
||||
<!-- Flash Messages (hidden, used for JS popup) -->
|
||||
<div id="flash-messages-container" style="display:none;">
|
||||
</div>
|
||||
|
||||
<!-- Flash Message (Hidden, used for JS popup) -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if 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 %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
const flash = document.getElementById('flash-message');
|
||||
if (flash && flash.innerText.trim() !== "") {
|
||||
alert(flash.innerText);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user