Compare commits
29 Commits
2679554e98
...
swapnil-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d84ba520cf | ||
| 0aeaf775dd | |||
| 88e8771b51 | |||
| 6c74b5d3bf | |||
| 47ba78d72c | |||
| 1946a98d59 | |||
| 8f35e08429 | |||
| 82bedc3117 | |||
| cb68e454bc | |||
|
|
91b078a0c3 | ||
|
|
eb46929893 | ||
| 675301df7f | |||
|
|
14e799a1d4 | ||
| 8ab1b69033 | |||
| dbeec9962d | |||
| 8750f268db | |||
|
|
b78526ad9f | ||
| 7146391c18 | |||
| 94b5563d15 | |||
| 937018dc16 | |||
| eda238c235 | |||
| f184d6cecc | |||
| e7646eee76 | |||
| 64ca39944b | |||
|
|
6b4beb5af8 | ||
|
|
d092eb0527 | ||
|
|
f9e9612df5 | ||
|
|
46ec2c0276 | ||
|
|
630ee1744f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ __pycache__/
|
|||||||
|
|
||||||
static/downloads/
|
static/downloads/
|
||||||
static/uploads/
|
static/uploads/
|
||||||
|
|
||||||
|
|||||||
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,5 +1,5 @@
|
|||||||
import config
|
import config
|
||||||
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
|
from flask import Blueprint, render_template, request, redirect, url_for, jsonify, flash
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
|
|
||||||
from model.State import State
|
from model.State import State
|
||||||
@@ -74,7 +74,14 @@ def edit_block(block_id):
|
|||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
block.EditBlock(request, block_id)
|
block.EditBlock(request, block_id)
|
||||||
return block.resultMessage
|
block.resultMessage
|
||||||
|
|
||||||
|
if block.resultMessage:
|
||||||
|
flash("Block updated successfully!", "success")
|
||||||
|
return redirect(url_for('block.add_block'))
|
||||||
|
else:
|
||||||
|
flash(block.resultMessage, "error")
|
||||||
|
|
||||||
|
|
||||||
connection = config.get_db_connection()
|
connection = config.get_db_connection()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|||||||
@@ -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'))
|
||||||
@@ -10,21 +10,21 @@ hold_bp = Blueprint("hold_types", __name__)
|
|||||||
@hold_bp.route('/add_hold_type', methods=['GET','POST'])
|
@hold_bp.route('/add_hold_type', methods=['GET','POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def add_hold_type():
|
def add_hold_type():
|
||||||
|
|
||||||
hold = HoldTypes()
|
hold = HoldTypes()
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
hold.AddHoldType(request) # ✅
|
hold.AddHoldType(request)
|
||||||
return hold.resultMessage
|
# ✅ Always redirect to same page (NO JSON)
|
||||||
|
return redirect(url_for("hold_types.add_hold_type"))
|
||||||
|
|
||||||
hold_types = hold.GetAllHoldTypes() # ✅
|
# GET request → show data
|
||||||
|
hold_types = hold.GetAllHoldTypes()
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"add_hold_type.html",
|
"add_hold_type.html",
|
||||||
Hold_Types_data=hold_types
|
Hold_Types_data=hold_types
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ----------------
|
# ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ----------------
|
||||||
@hold_bp.route('/check_hold_type', methods=['POST'])
|
@hold_bp.route('/check_hold_type', methods=['POST'])
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ def activity_log():
|
|||||||
end_date,
|
end_date,
|
||||||
user_name
|
user_name
|
||||||
)
|
)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"activity_log.html",
|
"activity_log.html",
|
||||||
logs=filtered_logs,
|
logs=filtered_logs,
|
||||||
|
|||||||
@@ -86,12 +86,12 @@ def edit_payment(payment_id):
|
|||||||
|
|
||||||
return render_template('edit_payment.html', payment_data=payment_data)
|
return render_template('edit_payment.html', payment_data=payment_data)
|
||||||
|
|
||||||
|
|
||||||
# ------------------- Delete Payment -------------------
|
# ------------------- Delete Payment -------------------
|
||||||
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['POST'])
|
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def delete_payment(payment_id):
|
def delete_payment(payment_id):
|
||||||
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
|
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
flash("Payment not found or failed to delete", "error")
|
flash("Payment not found or failed to delete", "error")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -83,17 +83,29 @@ 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)
|
||||||
|
|
||||||
flash(village.resultMessage, "success" if village.isSuccess else "error")
|
# ✅ Convert resultMessage to string if it's a Response or tuple
|
||||||
return redirect(url_for('village.add_village'))
|
raw_msg = village.resultMessage
|
||||||
|
|
||||||
|
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'])
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
|
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
|
||||||
|
|
||||||
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
|
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
|
||||||
from model.Log import LogData, LogHelper
|
from model.Log import LogData, LogHelper
|
||||||
@@ -147,7 +147,7 @@ class Block:
|
|||||||
|
|
||||||
self.isSuccess = block.isSuccess
|
self.isSuccess = block.isSuccess
|
||||||
self.resultMessage = block.resultMessage
|
self.resultMessage = block.resultMessage
|
||||||
return render_template('add_block.html')
|
return
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
# ----------------------------------------------------------
|
||||||
# Delete Block
|
# Delete Block
|
||||||
|
|||||||
@@ -27,13 +27,27 @@ class FolderAndFile:
|
|||||||
os.makedirs(folder, exist_ok=True)
|
os.makedirs(folder, exist_ok=True)
|
||||||
return folder
|
return folder
|
||||||
|
|
||||||
# -----------------------------
|
@staticmethod
|
||||||
# FILE PATH METHODS
|
def get_logs_folder():
|
||||||
# -----------------------------
|
folder = os.path.join(current_app.root_path, "logs")
|
||||||
|
|
||||||
|
if not os.path.exists(folder):
|
||||||
|
os.makedirs(folder)
|
||||||
|
|
||||||
|
os.makedirs(folder, exist_ok=True)
|
||||||
|
return folder
|
||||||
|
|
||||||
|
# FILE PATH METHODS - download
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_download_path(filename):
|
def get_download_path(filename):
|
||||||
return os.path.join(FolderAndFile.get_download_folder(), filename)
|
return os.path.join(FolderAndFile.get_download_folder(), filename)
|
||||||
|
|
||||||
|
# FILE PATH METHODS - upload file
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_upload_path(filename):
|
def get_upload_path(filename):
|
||||||
return os.path.join(FolderAndFile.get_upload_folder(), filename)
|
return os.path.join(FolderAndFile.get_upload_folder(), filename)
|
||||||
|
|
||||||
|
# FILE PATH METHODS - activity log file
|
||||||
|
@staticmethod
|
||||||
|
def get_activity_log_path(filename):
|
||||||
|
return os.path.join(FolderAndFile.get_logs_folder(), filename)
|
||||||
@@ -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,26 +156,24 @@ 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.allPattern, childname):
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = HtmlHelper.json_response(
|
self.resultMessage = HtmlHelper.json_response(
|
||||||
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
|
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
|
||||||
)
|
)
|
||||||
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,32 @@ class ItemCRUD:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# ======================================================
|
# ======================================================
|
||||||
# SUBCONTRACTOR (MULTI-FIELD)
|
# GSTRelease MULTI-FIELD
|
||||||
# ======================================================
|
# ======================================================
|
||||||
if data:
|
if self.itemCRUDType.name == "GSTRelease" and data:
|
||||||
|
|
||||||
|
cursor.callproc(storedprocupdate, (
|
||||||
|
data['p_pmc_no'], # PMC_No
|
||||||
|
data['p_invoice_no'], # Invoice_No
|
||||||
|
data['p_basic_amount'], # Basic_Amount
|
||||||
|
data['p_final_amount'], # Final_Amount
|
||||||
|
data['p_total_amount'], # Total_Amount
|
||||||
|
data['p_utr'], # UTR
|
||||||
|
data['p_gst_release_id']# GST_Release_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 +265,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,9 +273,9 @@ class ItemCRUD:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# ======================================================
|
# ======================================================
|
||||||
# NORMAL
|
# NORMAL SINGLE-FIELD
|
||||||
# ======================================================
|
# ======================================================
|
||||||
if not re.match(RegEx.patternAlphabetOnly, childname):
|
if not re.match(RegEx.allPattern, childname):
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
|
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
|
||||||
return
|
return
|
||||||
@@ -237,7 +286,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 +307,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 +323,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 +340,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()
|
||||||
@@ -324,7 +363,7 @@ class ItemCRUD:
|
|||||||
f"User {current_user.id} checked '{childname}'"
|
f"User {current_user.id} checked '{childname}'"
|
||||||
)
|
)
|
||||||
|
|
||||||
if not re.match(RegEx.patternAlphabetOnly, childname):
|
if not re.match(RegEx.allPattern, childname):
|
||||||
return HtmlHelper.json_response(
|
return HtmlHelper.json_response(
|
||||||
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
|
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
|
||||||
)
|
)
|
||||||
@@ -353,7 +392,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()
|
||||||
114
model/Log.py
114
model/Log.py
@@ -1,29 +1,41 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from flask_login import current_user
|
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from model.FolderAndFile import FolderAndFile
|
||||||
|
|
||||||
class LogHelper:
|
class LogHelper:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def log_action(action, details=""):
|
def log_action(action, details=""):
|
||||||
"""Add a log entry."""
|
"""Log user actions with timestamp, user, action, and details."""
|
||||||
log_data = LogData()
|
logData = LogData()
|
||||||
log_data.add_log(action, details)
|
logData.WriteLog(action, details="")
|
||||||
|
|
||||||
|
|
||||||
class LogData:
|
class LogData:
|
||||||
|
filepath = ""
|
||||||
|
timestamp = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.filepath = os.path.join(current_app.root_path, 'activity.log')
|
self.filepath = FolderAndFile.get_activity_log_path('activity.log')
|
||||||
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
self.user = getattr(current_user, "cn", None) \
|
self.user = LogData.get_current_user()
|
||||||
or getattr(current_user, "username", None) \
|
|
||||||
or getattr(current_user, "sAMAccountName", "Unknown")
|
|
||||||
|
|
||||||
|
|
||||||
def add_log(self, action, details=""):
|
@staticmethod
|
||||||
"""Create/Add a log entry."""
|
def get_current_user():
|
||||||
|
if hasattr(current_user, "cn") and current_user.cn:
|
||||||
|
return current_user.cn
|
||||||
|
elif hasattr(current_user, "username") and current_user.username:
|
||||||
|
return current_user.username
|
||||||
|
elif hasattr(current_user, "sAMAccountName") and current_user.sAMAccountName:
|
||||||
|
return current_user.sAMAccountName
|
||||||
|
return "Unknown"
|
||||||
|
|
||||||
|
def WriteLog(self, action, details=""):
|
||||||
|
"""Log user actions with timestamp, user, action, and details."""
|
||||||
|
|
||||||
with open(self.filepath, "a", encoding="utf-8") as f:
|
with open(self.filepath, "a", encoding="utf-8") as f:
|
||||||
f.write(
|
f.write(
|
||||||
f"Timestamp: {self.timestamp} | "
|
f"Timestamp: {self.timestamp} | "
|
||||||
@@ -32,73 +44,41 @@ class LogData:
|
|||||||
f"Details: {details}\n"
|
f"Details: {details}\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_all_logs(self):
|
def GetActivitiesLog(self):
|
||||||
"""Read all logs."""
|
|
||||||
logs = []
|
logs = []
|
||||||
|
|
||||||
if os.path.exists(self.filepath):
|
if os.path.exists(self.filepath):
|
||||||
with open(self.filepath, 'r', encoding="utf-8") as f:
|
with open(self.filepath, 'r') as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
parts = line.strip().split(" | ")
|
parts = line.strip().split(" | ")
|
||||||
if len(parts) == 4:
|
if len(parts) == 4:
|
||||||
logs.append({
|
logs.append({
|
||||||
"timestamp": parts[0].split(":", 1)[1].strip(),
|
"timestamp": parts[0].replace("Timestamp:", "").strip(),
|
||||||
"user": parts[1].split(":", 1)[1].strip(),
|
"user": parts[1].replace("User:", "").strip(),
|
||||||
"action": parts[2].split(":", 1)[1].strip(),
|
"action": parts[2].replace("Action:", "").strip(),
|
||||||
"details": parts[3].split(":", 1)[1].strip()
|
"details": parts[3].replace("Details:", "").strip()
|
||||||
})
|
})
|
||||||
return logs
|
return logs
|
||||||
|
|
||||||
def get_filtered_logs(self, start_date=None, end_date=None, user_name=None):
|
def GetFilteredActivitiesLog(self, startDate, endDate, userName):
|
||||||
"""Filter logs by date and/or user."""
|
filtered_logs = self.GetActivitiesLog()
|
||||||
logs = self.get_all_logs()
|
|
||||||
|
|
||||||
# Filter by date
|
# Date filter
|
||||||
if start_date or end_date:
|
if startDate or endDate:
|
||||||
start_dt = datetime.strptime(start_date, "%Y-%m-%d") if start_date else datetime.min
|
try:
|
||||||
end_dt = datetime.strptime(end_date, "%Y-%m-%d") if end_date else datetime.max
|
start_dt = datetime.strptime(startDate, "%Y-%m-%d") if startDate else datetime.min
|
||||||
logs = [
|
end_dt = datetime.strptime(endDate, "%Y-%m-%d") if endDate else datetime.max
|
||||||
log for log in logs
|
|
||||||
|
filtered_logs = [
|
||||||
|
log for log in filtered_logs
|
||||||
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
|
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
|
||||||
]
|
]
|
||||||
|
|
||||||
# Filter by username
|
except Exception as e:
|
||||||
if user_name:
|
print("Date filter error:", e)
|
||||||
logs = [log for log in logs if user_name.lower() in log.get("user", "").lower()]
|
|
||||||
|
|
||||||
return logs
|
|
||||||
|
|
||||||
def update_log(self, index, action=None, details=None):
|
|
||||||
"""Update a specific log entry by index (0-based)."""
|
|
||||||
logs = self.get_all_logs()
|
|
||||||
if 0 <= index < len(logs):
|
|
||||||
if action:
|
|
||||||
logs[index]["action"] = action
|
|
||||||
if details:
|
|
||||||
logs[index]["details"] = details
|
|
||||||
self._rewrite_logs_file(logs)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def delete_log(self, index):
|
|
||||||
"""Delete a specific log entry by index (0-based)."""
|
|
||||||
logs = self.get_all_logs()
|
|
||||||
if 0 <= index < len(logs):
|
|
||||||
logs.pop(index)
|
|
||||||
self._rewrite_logs_file(logs)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
# ------------------- INTERNAL HELPER -------------------
|
|
||||||
|
|
||||||
def _rewrite_logs_file(self, logs):
|
|
||||||
"""Overwrite the log file with current logs."""
|
|
||||||
with open(self.filepath, "w", encoding="utf-8") as f:
|
|
||||||
for log in logs:
|
|
||||||
f.write(
|
|
||||||
f"Timestamp: {log['timestamp']} | "
|
|
||||||
f"User: {log['user']} | "
|
|
||||||
f"Action: {log['action']} | "
|
|
||||||
f"Details: {log['details']}\n"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Username filter
|
||||||
|
if userName:
|
||||||
|
filtered_logs = [log for log in filtered_logs if userName.lower() in log["user"].lower()]
|
||||||
|
|
||||||
|
return filtered_logs
|
||||||
@@ -8,10 +8,11 @@ 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 ]+$"
|
||||||
|
allPattern = "^(?!\s*$).+"
|
||||||
|
|
||||||
|
|
||||||
class ResponseHandler:
|
class ResponseHandler:
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
|
from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
|
||||||
import config
|
import config
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
@@ -11,11 +13,18 @@ class Village:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = ""
|
self.resultMessage = ""
|
||||||
|
self.response = {} # ✅ ADDED
|
||||||
self.village = ItemCRUD(itemType=ItemCRUDType.Village)
|
self.village = ItemCRUD(itemType=ItemCRUDType.Village)
|
||||||
|
|
||||||
# 🔹 Helper: sync status
|
# 🔹 Helper: sync status
|
||||||
def _set_status(self, village):
|
def _set_status(self, village):
|
||||||
self.isSuccess = village.isSuccess
|
self.isSuccess = village.isSuccess
|
||||||
|
|
||||||
|
# ✅ UPDATED (safe handling)
|
||||||
|
if hasattr(village, "response"):
|
||||||
|
self.response = village.response
|
||||||
|
self.resultMessage = village.response.get("message", "")
|
||||||
|
else:
|
||||||
self.resultMessage = village.resultMessage
|
self.resultMessage = village.resultMessage
|
||||||
|
|
||||||
# 🔹 Helper: get request data
|
# 🔹 Helper: get request data
|
||||||
@@ -28,8 +37,9 @@ class Village:
|
|||||||
block_id, village_name = self._get_form_data(request)
|
block_id, village_name = self._get_form_data(request)
|
||||||
|
|
||||||
if not village_name:
|
if not village_name:
|
||||||
|
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
|
||||||
|
self.resultMessage = self.response["message"]
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = "Village name cannot be empty"
|
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -65,8 +75,9 @@ class Village:
|
|||||||
block_id, village_name = self._get_form_data(request)
|
block_id, village_name = self._get_form_data(request)
|
||||||
|
|
||||||
if not village_name:
|
if not village_name:
|
||||||
|
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
|
||||||
|
self.resultMessage = self.response["message"]
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = "Village name cannot be empty"
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -102,8 +113,9 @@ class Village:
|
|||||||
block_id, village_name = self._get_form_data(request)
|
block_id, village_name = self._get_form_data(request)
|
||||||
|
|
||||||
if not village_name:
|
if not village_name:
|
||||||
|
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
|
||||||
|
self.resultMessage = self.response["message"]
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = "Village name cannot be empty"
|
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -163,9 +175,11 @@ class Village:
|
|||||||
except mysql.connector.Error as e:
|
except mysql.connector.Error as e:
|
||||||
print(f"Error fetching blocks: {e}")
|
print(f"Error fetching blocks: {e}")
|
||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = HtmlHelper.json_response(
|
|
||||||
ResponseHandler.fetch_failure("block"), 500
|
# ✅ FIXED (removed jsonify response)
|
||||||
)
|
self.response = ResponseHandler.fetch_failure("block")
|
||||||
|
self.resultMessage = self.response["message"]
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|||||||
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
|
# 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):
|
||||||
@@ -115,6 +14,12 @@ class GSTRelease:
|
|||||||
try:
|
try:
|
||||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||||
|
|
||||||
|
# Print the full form data
|
||||||
|
print("===== DEBUG: FORM DATA =====")
|
||||||
|
for key, value in request.form.items():
|
||||||
|
print(f"{key} : {value}")
|
||||||
|
print("=============================")
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"PMC_No": request.form.get("PMC_No", "").strip(),
|
"PMC_No": request.form.get("PMC_No", "").strip(),
|
||||||
"Invoice_No": request.form.get("Invoice_No", "").strip(),
|
"Invoice_No": request.form.get("Invoice_No", "").strip(),
|
||||||
@@ -125,6 +30,11 @@ class GSTRelease:
|
|||||||
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
|
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("===== DEBUG: PARSED DATA =====")
|
||||||
|
print(data)
|
||||||
|
print("==============================")
|
||||||
|
|
||||||
|
# Add GST Release
|
||||||
gst.AddItem(
|
gst.AddItem(
|
||||||
request=request,
|
request=request,
|
||||||
data=data,
|
data=data,
|
||||||
@@ -132,6 +42,8 @@ class GSTRelease:
|
|||||||
storedprocadd="AddGSTReleaseFromExcel"
|
storedprocadd="AddGSTReleaseFromExcel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print(f"AddItem result: isSuccess={gst.isSuccess}, message={gst.resultMessage}")
|
||||||
|
|
||||||
self.isSuccess = gst.isSuccess
|
self.isSuccess = gst.isSuccess
|
||||||
self.resultMessage = str(gst.resultMessage)
|
self.resultMessage = str(gst.resultMessage)
|
||||||
|
|
||||||
@@ -142,20 +54,26 @@ class GSTRelease:
|
|||||||
|
|
||||||
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
|
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
|
||||||
|
|
||||||
# ------------------- Edit GST Release -------------------
|
|
||||||
def EditGSTRelease(self, request, gst_release_id):
|
def EditGSTRelease(self, request, gst_release_id):
|
||||||
try:
|
try:
|
||||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||||
|
|
||||||
|
# Map form inputs to stored procedure parameters
|
||||||
data = {
|
data = {
|
||||||
"PMC_No": request.form.get("PMC_No", "").strip(),
|
"p_pmc_no": request.form.get("PMC_No", "").strip(),
|
||||||
"Invoice_No": request.form.get("Invoice_No", "").strip(),
|
"p_invoice_no": request.form.get("invoice_no", "").strip(),
|
||||||
"Basic_Amount": float(request.form.get("Basic_Amount", 0) or 0),
|
"p_basic_amount": float(request.form.get("Basic_Amount", 0) or 0),
|
||||||
"Final_Amount": float(request.form.get("Final_Amount", 0) or 0),
|
"p_final_amount": float(request.form.get("Final_Amount", 0) or 0),
|
||||||
"Total_Amount": float(request.form.get("Total_Amount", 0) or 0),
|
"p_total_amount": float(request.form.get("Total_Amount", 0) or 0),
|
||||||
"UTR": request.form.get("UTR", "").strip()
|
"p_utr": request.form.get("UTR", "").strip(),
|
||||||
|
"p_gst_release_id": gst_release_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print("===== DEBUG: UPDATE DATA =====")
|
||||||
|
print(data)
|
||||||
|
print("==============================")
|
||||||
|
|
||||||
|
# Call your stored procedure
|
||||||
gst.EditItem(
|
gst.EditItem(
|
||||||
request=request,
|
request=request,
|
||||||
childid=gst_release_id,
|
childid=gst_release_id,
|
||||||
@@ -171,8 +89,6 @@ class GSTRelease:
|
|||||||
self.isSuccess = False
|
self.isSuccess = False
|
||||||
self.resultMessage = str(e)
|
self.resultMessage = str(e)
|
||||||
|
|
||||||
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
|
|
||||||
|
|
||||||
# ------------------- Delete GST Release -------------------
|
# ------------------- Delete GST Release -------------------
|
||||||
def DeleteGSTRelease(self, gst_release_id):
|
def DeleteGSTRelease(self, gst_release_id):
|
||||||
try:
|
try:
|
||||||
@@ -198,7 +114,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 +139,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:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ $(document).ready(function () {
|
|||||||
let holdType = $(this).val().replace(/^\s+/, "");
|
let holdType = $(this).val().replace(/^\s+/, "");
|
||||||
$(this).val(holdType);
|
$(this).val(holdType);
|
||||||
|
|
||||||
let reg = /^[A-Za-z]/;
|
let reg = /^.+$/; // all pattern allow
|
||||||
|
|
||||||
if (!reg.test(holdType)) {
|
if (!reg.test(holdType)) {
|
||||||
$("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red");
|
$("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red");
|
||||||
|
|||||||
@@ -1,5 +1,160 @@
|
|||||||
// Subcontractor autocomplete functionality
|
// $(document).ready(function () {
|
||||||
$(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.");
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
$(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 () {
|
$("#subcontractor").keyup(function () {
|
||||||
let query = $(this).val();
|
let query = $(this).val();
|
||||||
if (query !== "") {
|
if (query !== "") {
|
||||||
@@ -21,42 +176,96 @@
|
|||||||
$("#subcontractor_id").val($(this).attr("data-id"));
|
$("#subcontractor_id").val($(this).attr("data-id"));
|
||||||
$("#subcontractor_list").fadeOut();
|
$("#subcontractor_list").fadeOut();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Success Alert: show alert and reload after 3 seconds
|
// Focus
|
||||||
function showSuccessAlert() {
|
if (document.getElementById('subcontractor')) {
|
||||||
const alertBox = document.getElementById("invoiceSuccessAlert");
|
document.getElementById('subcontractor').focus();
|
||||||
alertBox.classList.add("show");
|
|
||||||
setTimeout(() => {
|
|
||||||
alertBox.classList.remove("show");
|
|
||||||
// Reload page or redirect after alert hides
|
|
||||||
window.location.href = '/add_invoice';
|
|
||||||
}, 3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit form via AJAX
|
// ===============================
|
||||||
|
// ADD INVOICE
|
||||||
|
// ===============================
|
||||||
|
if ($('#invoiceForm').length && window.location.href.includes('add_invoice')) {
|
||||||
$("#invoiceForm").on("submit", function (e) {
|
$("#invoiceForm").on("submit", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let formData = $(this).serialize();
|
let formData = $(this).serialize();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/add_invoice',
|
url: '/add_invoice',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: formData,
|
data: formData,
|
||||||
|
dataType: 'json',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
if(response.status === "success") {
|
if (response.status === "success") {
|
||||||
showSuccessAlert();
|
alert(response.message || "Invoice added successfully!");
|
||||||
|
$('#invoiceForm')[0].reset(); // clear form
|
||||||
|
$('#addForm').hide();
|
||||||
|
$('#addTable').show(); // switch to table
|
||||||
|
location.reload(); // optional refresh
|
||||||
} else {
|
} else {
|
||||||
alert(response.message);
|
alert(response.message || "Error adding invoice.");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr, status, error) {
|
error: function (xhr) {
|
||||||
alert("Submission failed: " + error);
|
let msg = xhr.responseJSON?.message || "Submission failed. Please try again.";
|
||||||
|
alert(msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// 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!");
|
||||||
|
|
||||||
window.onload = function () {
|
// Redirect to Add Invoice page's table part
|
||||||
document.getElementById('subcontractor').focus();
|
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
|
||||||
|
});
|
||||||
@@ -1,26 +1,23 @@
|
|||||||
|
|
||||||
// Search on table using search inpute options
|
// Search on table using search inpute options
|
||||||
function searchTable() {
|
function searchTable() {
|
||||||
let input = document.getElementById("searchBar").value.toLowerCase();
|
let input = document.getElementById("searchBar").value.toLowerCase();
|
||||||
let rows = document.querySelectorAll("table tbody tr");
|
let tables = document.querySelectorAll("table");
|
||||||
|
|
||||||
rows.forEach(row => {
|
tables.forEach(table => {
|
||||||
let blockName = row.cells[1].textContent.toLowerCase();
|
let rows = table.querySelectorAll("tr");
|
||||||
let districtName = row.cells[2].textContent.toLowerCase();
|
|
||||||
let villageName = row.cells[3].textContent.toLowerCase();
|
|
||||||
|
|
||||||
if (blockName.includes(input) || districtName.includes(input)|| villageName.includes(input)) {
|
rows.forEach((row, index) => {
|
||||||
row.style.display = "";
|
if (index === 0) return; // header skip
|
||||||
} else {
|
|
||||||
row.style.display = "none";
|
let text = row.textContent.toLowerCase();
|
||||||
}
|
|
||||||
|
row.style.display = text.includes(input) ? "" : "none";
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Common Sorting Script for Tables
|
// Common Sorting Script for Tables
|
||||||
function sortTable(n, dir) {
|
function sortTable(n, dir) {
|
||||||
var table, rows, switching, i, x, y, shouldSwitch;
|
var table, rows, switching, i, x, y, shouldSwitch;
|
||||||
@@ -57,14 +54,14 @@ function sortTable(n, dir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Attach sorting functionality to all sortable tables
|
// Attach sorting functionality to all sortable tables
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
// Find all elements with the class "sortable-header"
|
// Find all elements with the class "sortable-header"
|
||||||
var sortableHeaders = document.querySelectorAll(".sortable-header");
|
var sortableHeaders = document.querySelectorAll(".sortable-header");
|
||||||
|
|
||||||
sortableHeaders.forEach(function(header) {
|
sortableHeaders.forEach(function (header) {
|
||||||
// Attach click event for ascending sort
|
// Attach click event for ascending sort
|
||||||
if (header.querySelector(".sort-asc")) {
|
if (header.querySelector(".sort-asc")) {
|
||||||
header.querySelector(".sort-asc").addEventListener("click", function() {
|
header.querySelector(".sort-asc").addEventListener("click", function () {
|
||||||
var columnIndex = Array.from(header.parentNode.children).indexOf(header);
|
var columnIndex = Array.from(header.parentNode.children).indexOf(header);
|
||||||
sortTable(columnIndex, "asc");
|
sortTable(columnIndex, "asc");
|
||||||
});
|
});
|
||||||
@@ -72,7 +69,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
|
|
||||||
// Attach click event for descending sort
|
// Attach click event for descending sort
|
||||||
if (header.querySelector(".sort-desc")) {
|
if (header.querySelector(".sort-desc")) {
|
||||||
header.querySelector(".sort-desc").addEventListener("click", function() {
|
header.querySelector(".sort-desc").addEventListener("click", function () {
|
||||||
var columnIndex = Array.from(header.parentNode.children).indexOf(header);
|
var columnIndex = Array.from(header.parentNode.children).indexOf(header);
|
||||||
sortTable(columnIndex, "desc");
|
sortTable(columnIndex, "desc");
|
||||||
});
|
});
|
||||||
@@ -106,3 +103,30 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
addButton.classList.remove("active-button");
|
addButton.classList.remove("active-button");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
|
||||||
|
let tables = document.querySelectorAll("table");
|
||||||
|
|
||||||
|
tables.forEach(table => {
|
||||||
|
let header = table.querySelector("tr:first-child");
|
||||||
|
|
||||||
|
if (header) {
|
||||||
|
header.style.position = "sticky";
|
||||||
|
header.style.top = "0";
|
||||||
|
header.style.background = "#fff";
|
||||||
|
header.style.zIndex = "2";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!table.parentElement.classList.contains("table-wrapper")) {
|
||||||
|
let wrapper = document.createElement("div");
|
||||||
|
wrapper.classList.add("table-wrapper");
|
||||||
|
wrapper.style.maxHeight = "65vh"
|
||||||
|
wrapper.style.overflowY = "auto";
|
||||||
|
|
||||||
|
table.parentNode.insertBefore(wrapper, table);
|
||||||
|
wrapper.appendChild(table);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,10 +1,37 @@
|
|||||||
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
|
||||||
|
if ($('#addForm').length && $('#addTable').length) {
|
||||||
|
|
||||||
|
// ✅ DEFAULT VIEW → SHOW FORM
|
||||||
|
$('#addForm').show();
|
||||||
|
$('#addTable').hide();
|
||||||
|
|
||||||
|
|
||||||
|
// 🔥 BUTTON TOGGLE
|
||||||
|
$('#addButton').click(function () {
|
||||||
|
$('#addForm').show();
|
||||||
|
$('#addTable').hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#displayButton').click(function () {
|
||||||
|
$('#addForm').hide();
|
||||||
|
$('#addTable').show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
// STATE → DISTRICT
|
// STATE → DISTRICT
|
||||||
|
// ===============================
|
||||||
|
if ($('#state_Id').length) {
|
||||||
|
|
||||||
$('#state_Id').change(function () {
|
$('#state_Id').change(function () {
|
||||||
|
|
||||||
var stateId = $(this).val();
|
var stateId = $(this).val();
|
||||||
@@ -23,25 +50,24 @@ $(document).ready(function () {
|
|||||||
districtDropdown.append('<option value="" disabled selected>Select District</option>');
|
districtDropdown.append('<option value="" disabled selected>Select District</option>');
|
||||||
|
|
||||||
data.forEach(function (district) {
|
data.forEach(function (district) {
|
||||||
|
|
||||||
districtDropdown.append(
|
districtDropdown.append(
|
||||||
'<option value="' + district.id + '">' + district.name + '</option>'
|
'<option value="' + district.id + '">' + district.name + '</option>'
|
||||||
);
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
districtDropdown.prop('disabled', false);
|
districtDropdown.prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
// DISTRICT → BLOCK
|
// DISTRICT → BLOCK
|
||||||
|
// ===============================
|
||||||
|
if ($('#district_Id').length) {
|
||||||
|
|
||||||
$('#district_Id').change(function () {
|
$('#district_Id').change(function () {
|
||||||
|
|
||||||
var districtId = $(this).val();
|
var districtId = $(this).val();
|
||||||
@@ -60,25 +86,24 @@ $(document).ready(function () {
|
|||||||
blockDropdown.append('<option value="" disabled selected>Select Block</option>');
|
blockDropdown.append('<option value="" disabled selected>Select Block</option>');
|
||||||
|
|
||||||
data.forEach(function (block) {
|
data.forEach(function (block) {
|
||||||
|
|
||||||
blockDropdown.append(
|
blockDropdown.append(
|
||||||
'<option value="' + block.id + '">' + block.name + '</option>'
|
'<option value="' + block.id + '">' + block.name + '</option>'
|
||||||
);
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
blockDropdown.prop('disabled', false);
|
blockDropdown.prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
// VILLAGE NAME VALIDATION
|
// VILLAGE NAME VALIDATION
|
||||||
|
// ===============================
|
||||||
|
if ($('#Village_Name').length) {
|
||||||
|
|
||||||
$('#Village_Name').on('input', function () {
|
$('#Village_Name').on('input', function () {
|
||||||
|
|
||||||
var villageName = $(this).val();
|
var villageName = $(this).val();
|
||||||
@@ -96,13 +121,16 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
$('#villageMessage').text('');
|
$('#villageMessage').text('');
|
||||||
$('#submitVillage').prop('disabled', false);
|
$('#submitVillage').prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
// CHECK DUPLICATE VILLAGE
|
// CHECK DUPLICATE VILLAGE
|
||||||
|
// ===============================
|
||||||
|
if ($('#Village_Name').length && $('#block_Id').length) {
|
||||||
|
|
||||||
$('#Village_Name, #block_Id').on('change keyup', function () {
|
$('#Village_Name, #block_Id').on('change keyup', function () {
|
||||||
|
|
||||||
var blockId = $('#block_Id').val();
|
var blockId = $('#block_Id').val();
|
||||||
@@ -111,7 +139,6 @@ $(document).ready(function () {
|
|||||||
if (blockId && villageName) {
|
if (blockId && villageName) {
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
||||||
url: '/check_village',
|
url: '/check_village',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
|
|
||||||
@@ -137,9 +164,7 @@ $(document).ready(function () {
|
|||||||
.css('color', 'green');
|
.css('color', 'green');
|
||||||
|
|
||||||
$('#submitVillage').prop('disabled', false);
|
$('#submitVillage').prop('disabled', false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
error: function () {
|
error: function () {
|
||||||
@@ -149,50 +174,77 @@ $(document).ready(function () {
|
|||||||
.css('color', 'red');
|
.css('color', 'red');
|
||||||
|
|
||||||
$('#submitVillage').prop('disabled', true);
|
$('#submitVillage').prop('disabled', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
// ===============================
|
||||||
|
// ADD VILLAGE (SAFE SCOPE FIX)
|
||||||
|
// ===============================
|
||||||
|
if ($('#villageForm').length) {
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// ADD VILLAGE
|
|
||||||
$('#villageForm').submit(function (event) {
|
$('#villageForm').submit(function (event) {
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
||||||
url: '/add_village',
|
url: '/add_village',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
data: $(this).serialize(),
|
data: $(this).serialize(),
|
||||||
|
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
|
|
||||||
if (response.status === 'success') {
|
if (response && response.status === 'success') {
|
||||||
|
|
||||||
alert('Village added successfully!');
|
alert(response.message || 'Village added successfully!');
|
||||||
|
|
||||||
|
// ✅ clear form
|
||||||
|
$('#villageForm')[0].reset();
|
||||||
|
|
||||||
|
// ✅ switch to table
|
||||||
|
$('#addForm').hide();
|
||||||
|
$('#addTable').show();
|
||||||
|
|
||||||
|
// optional refresh
|
||||||
location.reload();
|
location.reload();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
alert(response.message || 'Error adding village. Please try again.');
|
||||||
alert('Error adding village. Please try again.');
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
error: function () {
|
error: function () {
|
||||||
|
|
||||||
alert('An error occurred. Please try again.');
|
alert('An error occurred. Please try again.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ===============================
|
||||||
|
// DELETE FUNCTION (SAFE)
|
||||||
|
// ===============================
|
||||||
|
function deleteVillage(villageId, element) {
|
||||||
|
if (!confirm("Are you sure you want to delete this village?")) return;
|
||||||
|
|
||||||
|
$.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();
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
alert("Error deleting village. Please try again.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -22,10 +22,14 @@
|
|||||||
<div class="row1">
|
<div class="row1">
|
||||||
<div>
|
<div>
|
||||||
<label for="subcontractor">Subcontractor Name:</label>
|
<label for="subcontractor">Subcontractor Name:</label>
|
||||||
|
<!-- Text input for user-friendly autocomplete -->
|
||||||
<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"/>
|
|
||||||
|
<!-- Hidden input for backend; must match model's Contractor_ID -->
|
||||||
|
<input type="hidden" id="subcontractor_id" name="Contractor_ID"/>
|
||||||
|
|
||||||
<div id="subcontractor_list" class="autocomplete-items"></div>
|
<div id="subcontractor_list" class="autocomplete-items"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label for="PMC_No">PMC No:</label><br>
|
<label for="PMC_No">PMC No:</label><br>
|
||||||
@@ -37,19 +41,19 @@
|
|||||||
</select><br><br>
|
</select><br><br>
|
||||||
|
|
||||||
<label for="invoice_No">Invoice No:</label><br>
|
<label for="invoice_No">Invoice No:</label><br>
|
||||||
<input type="text" id="invoice_No" name="invoice_No" required><br><br>
|
<input type="text" id="invoice_No" name="Invoice_No" required><br><br>
|
||||||
|
|
||||||
<label for="basic_amount">Basic Amount:</label><br>
|
<label for="basic_amount">Basic Amount:</label><br>
|
||||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required><br><br>
|
<input type="number" step="0.01" id="basic_amount" name="Basic_Amount" placeholder="₹ - 00.00" required><br><br>
|
||||||
|
|
||||||
<label for="final_amount">Final Amount:</label><br>
|
<label for="final_amount">Final Amount:</label><br>
|
||||||
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required><br><br>
|
<input type="number" step="0.01" id="final_amount" name="Final_Amount" placeholder="₹ - 00.00" required><br><br>
|
||||||
|
|
||||||
<label for="total_amount">Total Amount:</label><br>
|
<label for="total_amount">Total Amount:</label><br>
|
||||||
<input type="number" step="0.01" id="total_amount" name="total_amount" placeholder="₹ - 00.00" required><br><br>
|
<input type="number" step="0.01" id="total_amount" name="Total_Amount" placeholder="₹ - 00.00" required><br><br>
|
||||||
|
|
||||||
<label for="utr">UTR:</label><br>
|
<label for="utr">UTR:</label><br>
|
||||||
<input type="text" id="utr" name="utr" required><br><br>
|
<input type="text" id="utr" name="UTR" required><br><br>
|
||||||
|
|
||||||
<button type="submit">Submit GST Release</button>
|
<button type="submit">Submit GST Release</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -68,10 +72,11 @@
|
|||||||
{% 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>
|
||||||
@@ -90,24 +95,22 @@
|
|||||||
<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="/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?')">
|
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"
|
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
|
||||||
class="icon">
|
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -118,46 +121,61 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Handle subcontractor autocomplete
|
|
||||||
document.getElementById("subcontractor").addEventListener("input", function () {
|
const subcontractorInput = document.getElementById("subcontractor");
|
||||||
|
const subcontractorIdInput = document.getElementById("subcontractor_id");
|
||||||
|
const subcontractorList = document.getElementById("subcontractor_list");
|
||||||
|
const pmcDropdown = document.getElementById("PMC_No");
|
||||||
|
const form = document.querySelector('form');
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Subcontractor autocomplete
|
||||||
|
// --------------------------
|
||||||
|
subcontractorInput.addEventListener("input", function () {
|
||||||
const query = this.value;
|
const query = this.value;
|
||||||
const list = document.getElementById("subcontractor_list");
|
|
||||||
|
|
||||||
if (query.length < 2) {
|
if (query.length < 2) {
|
||||||
list.innerHTML = '';
|
subcontractorList.innerHTML = '';
|
||||||
|
subcontractorIdInput.value = ''; // reset hidden id
|
||||||
|
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>'; // reset PMC dropdown
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
|
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
list.innerHTML = '';
|
subcontractorList.innerHTML = '';
|
||||||
data.results.forEach(item => {
|
data.results.forEach(item => {
|
||||||
const div = document.createElement("div");
|
const div = document.createElement("div");
|
||||||
div.setAttribute("data-id", item.id);
|
div.setAttribute("data-id", item.id);
|
||||||
div.textContent = item.name;
|
div.textContent = item.name;
|
||||||
list.appendChild(div);
|
subcontractorList.appendChild(div);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle subcontractor selection
|
// --------------------------
|
||||||
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
|
// Subcontractor selection
|
||||||
|
// --------------------------
|
||||||
|
subcontractorList.addEventListener("click", function (e) {
|
||||||
const selectedId = e.target.getAttribute("data-id");
|
const selectedId = e.target.getAttribute("data-id");
|
||||||
const selectedName = e.target.textContent;
|
const selectedName = e.target.textContent;
|
||||||
|
|
||||||
if (selectedId) {
|
if (selectedId) {
|
||||||
document.getElementById("subcontractor_id").value = selectedId;
|
// Set hidden field for backend
|
||||||
document.getElementById("subcontractor").value = selectedName;
|
subcontractorIdInput.value = selectedId;
|
||||||
document.getElementById("subcontractor_list").innerHTML = "";
|
|
||||||
|
|
||||||
// Update PMC dropdown for selected subcontractor
|
// Set text input to selected name
|
||||||
|
subcontractorInput.value = selectedName;
|
||||||
|
|
||||||
|
// Clear the autocomplete list
|
||||||
|
subcontractorList.innerHTML = "";
|
||||||
|
|
||||||
|
// Fetch and populate PMC dropdown
|
||||||
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
|
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const pmcDropdown = document.getElementById("PMC_No");
|
|
||||||
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>';
|
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>';
|
||||||
|
|
||||||
data.pmc_nos.forEach(pmc => {
|
data.pmc_nos.forEach(pmc => {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.value = pmc;
|
option.value = pmc;
|
||||||
@@ -167,6 +185,22 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --------------------------
|
||||||
|
// Form submit validation
|
||||||
|
// --------------------------
|
||||||
|
form.addEventListener('submit', function(e) {
|
||||||
|
if (!subcontractorIdInput.value) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert("Please select a subcontractor from the list.");
|
||||||
|
subcontractorInput.focus();
|
||||||
|
} else if (!pmcDropdown.value) {
|
||||||
|
e.preventDefault();
|
||||||
|
alert("Please select a PMC No.");
|
||||||
|
pmcDropdown.focus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Manage Hold Types</title>
|
<title>Manage Hold Types</title>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
@@ -7,14 +8,15 @@
|
|||||||
<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/search_on_table.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="button-container">
|
<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">
|
<div id="addForm">
|
||||||
<h2>Add Hold Types</h2>
|
<h2>Add Hold Types</h2>
|
||||||
<form id="holdTypeForm" method="POST" action="{{ url_for('hold_types.add_hold_type') }}">
|
<form id="holdTypeForm" method="POST" action="{{ url_for('hold_types.add_hold_type') }}">
|
||||||
<label>Enter Hold Amount Type:</label>
|
<label>Enter Hold Amount Type:</label>
|
||||||
@@ -22,9 +24,9 @@
|
|||||||
<span id="holdTypeMessage"></span>
|
<span id="holdTypeMessage"></span>
|
||||||
<button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button>
|
<button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="addTable" style="display: none;">
|
<div id="addTable" style="display: none;">
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<h2>Hold Type List</h2>
|
<h2>Hold Type List</h2>
|
||||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||||
@@ -46,14 +48,26 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ htd['hold_type_id'] }}</td>
|
<td>{{ htd['hold_type_id'] }}</td>
|
||||||
<td>{{ htd['hold_type'] }}</td>
|
<td>{{ htd['hold_type'] }}</td>
|
||||||
<td><a href="{{ url_for('hold_types.edit_hold_type', id=htd['hold_type_id']) }}">Edit</a></td>
|
<td style="text-align:center;">
|
||||||
<td><button class="delete-button" data-id="{{ htd['hold_type_id'] }}">Delete</button></td>
|
<a href="{{ url_for('hold_types.edit_hold_type', id=htd['hold_type_id']) }}">
|
||||||
|
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||||
|
class="icon">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td style="text-align:center;">
|
||||||
|
<a href="{{ url_for('hold_types.delete_hold_type', id=htd['hold_type_id']) }}"
|
||||||
|
onclick="return confirm('Are you sure you want to delete this hold type?');">
|
||||||
|
|
||||||
|
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
|
||||||
|
class="icon">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<a href="/">Back to Dashboard</a>
|
<a href="/">Back to Dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,48 +1,67 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %} {% block content %}
|
||||||
{% block content %}
|
|
||||||
<head xmlns="http://www.w3.org/1999/html">
|
<head xmlns="http://www.w3.org/1999/html">
|
||||||
<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>Add Invoice</title>
|
<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/invoice.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{% if success == 'true' %}
|
{% 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!
|
✅ Invoice added successfully!
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
<button
|
||||||
</div>
|
type="button"
|
||||||
{% endif %}
|
class="btn-close"
|
||||||
|
data-bs-dismiss="alert"
|
||||||
|
aria-label="Close"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Flash Messages -->
|
||||||
<!-- Flash Messages -->
|
{% with messages = get_flashed_messages(with_categories=true) %} {% if
|
||||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
messages %}
|
||||||
{% if messages %}
|
|
||||||
<div class="flash-messages">
|
<div class="flash-messages">
|
||||||
{% for category, message in messages %}
|
{% for category, message in messages %}
|
||||||
<div class="alert {{ category }}">{{ message }}</div>
|
<div class="alert {{ category }}">{{ message }}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %} {% endwith %}
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
<div class="button-container">
|
<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">
|
||||||
<h2>Add Invoice</h2>
|
<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 class="row1">
|
||||||
<div>
|
<div>
|
||||||
<label for="subcontractor">Subcontractor Name:</label>
|
<label for="subcontractor">Subcontractor Name:</label>
|
||||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
|
<input
|
||||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
|
type="text"
|
||||||
|
id="subcontractor"
|
||||||
|
name="subcontractor"
|
||||||
|
required
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<input type="hidden" id="subcontractor_id" name="subcontractor_id" />
|
||||||
<div id="subcontractor_list"></div>
|
<div id="subcontractor_list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,13 +72,15 @@
|
|||||||
<select id="village" name="village" required>
|
<select id="village" name="village" required>
|
||||||
<option value="">-- Select Village --</option>
|
<option value="">-- Select Village --</option>
|
||||||
{% for village in villages %}
|
{% for village in villages %}
|
||||||
<option value="{{ village.Village_Name }}">{{ village.Village_Name }}</option>
|
<option value="{{ village.Village_Name }}">
|
||||||
|
{{ village.Village_Name }}
|
||||||
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="pmc_no">PMC No:</label>
|
<label for="pmc_no">PMC No:</label>
|
||||||
<input type="text" id="pmc_no" name="pmc_no" required/>
|
<input type="text" id="pmc_no" name="pmc_no" required />
|
||||||
<div id="pmc_no_list" class="autocomplete-list"></div>
|
<div id="pmc_no_list" class="autocomplete-list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -67,81 +88,187 @@
|
|||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="work_type">Work Type:</label>
|
<label for="work_type">Work Type:</label>
|
||||||
<input type="text" id="work_type" name="work_type" required/>
|
<input type="text" id="work_type" name="work_type" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="invoice_details">Invoice Details:</label>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="invoice_no">Invoice No:</label>
|
<label for="invoice_no">Invoice No:</label>
|
||||||
<input type="text" id="invoice_no" name="invoice_no" required/>
|
<input type="text" id="invoice_no" name="invoice_no" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="invoice_date">Invoice Date:</label>
|
<label for="invoice_date">Invoice Date:</label>
|
||||||
<input type="date" id="invoice_date" name="invoice_date" required/>
|
<input type="date" id="invoice_date" name="invoice_date" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row3">
|
<div class="row3">
|
||||||
<div>
|
<div>
|
||||||
<label for="basic_amount">Basic Amount:</label>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<label for="debit_amount">Debit Amount:</label>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<label for="after_debit_amount">After Debit Amount:</label>
|
<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>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row3">
|
<div class="row3">
|
||||||
<div class="percentage-field">
|
<div class="percentage-field">
|
||||||
<label for="gst_percentage">GST %:</label>
|
<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>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<label for="amount">Amount:</label>
|
<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>
|
||||||
<div class="percentage-field">
|
<div class="percentage-field">
|
||||||
<label for="tds_percentage">TDS %:</label>
|
<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>
|
<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>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row3">
|
<div class="row3">
|
||||||
<div class="percentage-field">
|
<div class="percentage-field">
|
||||||
<label for="sd_percentage">SD %:</label>
|
<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>
|
<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>
|
||||||
<div class="percentage-field">
|
<div class="percentage-field">
|
||||||
<label for="commission_percentage">On Commission %:</label>
|
<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>
|
<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>
|
||||||
<div class="percentage-field">
|
<div class="percentage-field">
|
||||||
<label for="hydro_percentage">Hydro Testing %:</label>
|
<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>
|
<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>
|
||||||
</div>
|
|
||||||
<div class="hold-row">
|
<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>
|
</div>
|
||||||
|
|
||||||
<!-- Dynamically added hold amount fields -->
|
<!-- Dynamically added hold amount fields -->
|
||||||
@@ -150,23 +277,42 @@
|
|||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
<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>
|
||||||
<div>
|
<div>
|
||||||
<label for="final_amount">Final Amount:</label>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="button">Submit</button>
|
<button type="submit" class="button">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="addTable" style="display: none;">
|
<div id="addTable" style="display: none">
|
||||||
<!-- Invoice Table Section -->
|
<!-- Invoice Table Section -->
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<h2>Invoice List</h2>
|
<h2>Invoice List</h2>
|
||||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
<input
|
||||||
|
type="text"
|
||||||
|
id="searchBar"
|
||||||
|
placeholder="Searching..."
|
||||||
|
onkeyup="searchTable()"
|
||||||
|
/>
|
||||||
{% if invoices %}
|
{% if invoices %}
|
||||||
<table class="invoice-table">
|
<table class="invoice-table">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -218,14 +364,27 @@
|
|||||||
<td>{{ invoice.Final_Amount }}</td>
|
<td>{{ invoice.Final_Amount }}</td>
|
||||||
<td>
|
<td>
|
||||||
<!-- Edit -->
|
<!-- Edit -->
|
||||||
<a href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}">
|
<a
|
||||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
|
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>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<!-- Delete -->
|
<a
|
||||||
<a href="{{ url_for('invoice.delete_invoice_route', invoice_id=invoice.Invoice_Id) }}" onclick="return confirm('Are you sure?')">
|
href="javascript:void(0);"
|
||||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
|
onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||||
|
alt="Delete"
|
||||||
|
class="icon"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -235,29 +394,31 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<p>No invoices found.</p>
|
<p>No invoices found.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
// Get all the input fields
|
// Get all the input fields
|
||||||
const basicAmount = document.getElementById('basic_amount');
|
const basicAmount = document.getElementById("basic_amount");
|
||||||
const debitAmount = document.getElementById('debit_amount');
|
const debitAmount = document.getElementById("debit_amount");
|
||||||
const afterDebitAmount = document.getElementById('after_debit_amount');
|
const afterDebitAmount = document.getElementById("after_debit_amount");
|
||||||
const amount = document.getElementById('amount');
|
const amount = document.getElementById("amount");
|
||||||
|
|
||||||
// Percentage fields
|
// Percentage fields
|
||||||
const gstPercentage = document.getElementById('gst_percentage');
|
const gstPercentage = document.getElementById("gst_percentage");
|
||||||
const gstAmount = document.getElementById('gst_amount');
|
const gstAmount = document.getElementById("gst_amount");
|
||||||
const tdsPercentage = document.getElementById('tds_percentage');
|
const tdsPercentage = document.getElementById("tds_percentage");
|
||||||
const tdsAmount = document.getElementById('tds_amount');
|
const tdsAmount = document.getElementById("tds_amount");
|
||||||
const sdPercentage = document.getElementById('sd_percentage');
|
const sdPercentage = document.getElementById("sd_percentage");
|
||||||
const sdAmountInput = document.getElementById('sd_amount');
|
const sdAmountInput = document.getElementById("sd_amount");
|
||||||
const commissionPercentage = document.getElementById('commission_percentage');
|
const commissionPercentage = document.getElementById(
|
||||||
const onCommission = document.getElementById('on_commission');
|
"commission_percentage",
|
||||||
const hydroPercentage = document.getElementById('hydro_percentage');
|
);
|
||||||
const hydroTesting = document.getElementById('hydro_testing');
|
const onCommission = document.getElementById("on_commission");
|
||||||
const gstSdAmount = document.getElementById('gst_sd_amount');
|
const hydroPercentage = document.getElementById("hydro_percentage");
|
||||||
const finalAmount = document.getElementById('final_amount');
|
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
|
// Calculate after debit amount when basic or debit amount changes
|
||||||
function calculateAfterDebitAmount() {
|
function calculateAfterDebitAmount() {
|
||||||
@@ -333,7 +494,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Get hold amounts
|
// Get hold amounts
|
||||||
let totalHold = 0;
|
let totalHold = 0;
|
||||||
document.querySelectorAll('input[name="hold_amount[]"]').forEach(input => {
|
document
|
||||||
|
.querySelectorAll('input[name="hold_amount[]"]')
|
||||||
|
.forEach((input) => {
|
||||||
totalHold += parseFloat(input.value) || 0;
|
totalHold += parseFloat(input.value) || 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -343,28 +506,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add event listeners
|
// Add event listeners
|
||||||
basicAmount.addEventListener('input', calculateAfterDebitAmount);
|
basicAmount.addEventListener("input", calculateAfterDebitAmount);
|
||||||
debitAmount.addEventListener('input', calculateAfterDebitAmount);
|
debitAmount.addEventListener("input", calculateAfterDebitAmount);
|
||||||
|
|
||||||
// Percentage fields
|
// Percentage fields
|
||||||
gstPercentage.addEventListener('input', calculateGST);
|
gstPercentage.addEventListener("input", calculateGST);
|
||||||
tdsPercentage.addEventListener('input', calculateOtherDeductions);
|
tdsPercentage.addEventListener("input", calculateOtherDeductions);
|
||||||
sdPercentage.addEventListener('input', calculateOtherDeductions);
|
sdPercentage.addEventListener("input", calculateOtherDeductions);
|
||||||
commissionPercentage.addEventListener('input', calculateOtherDeductions);
|
commissionPercentage.addEventListener(
|
||||||
hydroPercentage.addEventListener('input', calculateOtherDeductions);
|
"input",
|
||||||
|
calculateOtherDeductions,
|
||||||
|
);
|
||||||
|
hydroPercentage.addEventListener("input", calculateOtherDeductions);
|
||||||
|
|
||||||
// Listen for changes in hold amounts
|
// Listen for changes in hold amounts
|
||||||
document.addEventListener('holdAmountChanged', calculateFinalAmount);
|
document.addEventListener("holdAmountChanged", calculateFinalAmount);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Optional JS for auto-hiding flash
|
// Optional JS for auto-hiding flash
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.querySelectorAll('.alert').forEach(el => el.style.display = 'none');
|
document
|
||||||
}, 5000);
|
.querySelectorAll(".alert")
|
||||||
</script>
|
.forEach((el) => (el.style.display = "none"));
|
||||||
|
}, 5000);
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% block content %}
|
{% 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">
|
||||||
@@ -8,22 +9,23 @@
|
|||||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="button-container">
|
<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;">
|
||||||
<h2>Add Payment</h2>
|
<h2>Add Payment</h2>
|
||||||
|
|
||||||
<form action="/add_payment" method="POST" onsubmit="showSuccessAlert(event)">
|
<form action="/add_payment" method="POST" onsubmit="showSuccessAlert(event)">
|
||||||
<div class="row1">
|
<div class="row1">
|
||||||
<div>
|
<div>
|
||||||
<label for="subcontractor">Subcontractor Name:</label>
|
<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"/>
|
<input type="hidden" id="subcontractor_id" name="subcontractor_id" />
|
||||||
<div id="subcontractor_list" class="autocomplete-items"></div>
|
<div id="subcontractor_list" class="autocomplete-items"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,19 +36,22 @@
|
|||||||
</select><br><br>
|
</select><br><br>
|
||||||
|
|
||||||
<label for="invoice_No">Invoice No:</label><br>
|
<label for="invoice_No">Invoice No:</label><br>
|
||||||
<input type="number" step="0.01" id="invoice_No" name="invoice_No" ><br><br>
|
<input type="number" step="0.01" id="invoice_No" name="invoice_No"><br><br>
|
||||||
|
|
||||||
<label for="Payment_Amount">Amount:</label><br>
|
<label for="Payment_Amount">Amount:</label><br>
|
||||||
<input type="number" step="0.01" id="Payment_Amount" name="Payment_Amount" required oninput="calculateTDSAndTotal()"><br><br>
|
<input type="number" step="0.01" id="Payment_Amount" name="Payment_Amount" required
|
||||||
|
oninput="calculateTDSAndTotal()"><br><br>
|
||||||
|
|
||||||
<label for="TDS_Percentage">TDS Percentage (%):</label><br>
|
<label for="TDS_Percentage">TDS Percentage (%):</label><br>
|
||||||
<input type="number" step="0.01" id="TDS_Percentage" name="TDS_Percentage" oninput="calculateTDSAndTotal()"><br><br>
|
<input type="number" step="0.01" id="TDS_Percentage" name="TDS_Percentage"
|
||||||
|
oninput="calculateTDSAndTotal()"><br><br>
|
||||||
|
|
||||||
<label for="TDS_Payment_Amount">TDS Amount:</label><br>
|
<label for="TDS_Payment_Amount">TDS Amount:</label><br>
|
||||||
<input type="number" step="0.01" id="TDS_Payment_Amount" name="TDS_Payment_Amount" required readonly><br><br>
|
<input type="number" step="0.01" id="TDS_Payment_Amount" name="TDS_Payment_Amount" required
|
||||||
|
readonly><br><br>
|
||||||
|
|
||||||
<label for="total_amount">Total Amount:</label><br>
|
<label for="total_amount">Total Amount:</label><br>
|
||||||
<input type="number" step="0.01" id="total_amount" name="total_amount" required readonly><br><br>
|
<input type="number" step="0.01" id="total_amount" name="total_amount" required readonly><br><br>
|
||||||
|
|
||||||
|
|
||||||
<label for="utr">UTR:</label><br>
|
<label for="utr">UTR:</label><br>
|
||||||
@@ -54,13 +59,13 @@
|
|||||||
|
|
||||||
<button type="submit">Submit Payment</button>
|
<button type="submit">Submit Payment</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="successPopup" class="success-popup">
|
<div id="successPopup" class="success-popup">
|
||||||
<i>✔</i> Payment added successfully!
|
<i>✔</i> Payment added successfully!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="addTable" style="display: none;">
|
<div id="addTable" style="display: none;">
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<h2>Payment History</h2>
|
<h2>Payment History</h2>
|
||||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||||
@@ -89,8 +94,17 @@
|
|||||||
<td>{{ payment[4] }}</td>
|
<td>{{ payment[4] }}</td>
|
||||||
<td>{{ payment[5] }}</td>
|
<td>{{ payment[5] }}</td>
|
||||||
<td>{{ payment[6] }}</td>
|
<td>{{ payment[6] }}</td>
|
||||||
<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><a href="/edit_payment/{{ payment[0] }}"><img
|
||||||
<td><a href="/delete_payment/{{ 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>
|
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||||
|
class="icon"></a></td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
<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>
|
||||||
<!-- <tr>
|
<!-- <tr>
|
||||||
<td>{{ payment['Payment_Id'] }}</td>
|
<td>{{ payment['Payment_Id'] }}</td>
|
||||||
@@ -106,10 +120,10 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.getElementById("subcontractor").addEventListener("input", function () {
|
document.getElementById("subcontractor").addEventListener("input", function () {
|
||||||
const query = this.value;
|
const query = this.value;
|
||||||
const list = document.getElementById("subcontractor_list");
|
const list = document.getElementById("subcontractor_list");
|
||||||
|
|
||||||
@@ -129,9 +143,9 @@ document.getElementById("subcontractor").addEventListener("input", function () {
|
|||||||
list.appendChild(div);
|
list.appendChild(div);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
|
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
|
||||||
const selectedId = e.target.getAttribute("data-id");
|
const selectedId = e.target.getAttribute("data-id");
|
||||||
const selectedName = e.target.textContent;
|
const selectedName = e.target.textContent;
|
||||||
|
|
||||||
@@ -171,11 +185,11 @@ document.getElementById("subcontractor_list").addEventListener("click", function
|
|||||||
alert("Failed to fetch PMC numbers.");
|
alert("Failed to fetch PMC numbers.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function calculateTDSAndTotal() {
|
function calculateTDSAndTotal() {
|
||||||
const amount = parseFloat(document.getElementById("Payment_Amount").value) || 0;
|
const amount = parseFloat(document.getElementById("Payment_Amount").value) || 0;
|
||||||
const tdsPercent = parseFloat(document.getElementById("TDS_Percentage").value) || 0;
|
const tdsPercent = parseFloat(document.getElementById("TDS_Percentage").value) || 0;
|
||||||
|
|
||||||
@@ -184,10 +198,10 @@ function calculateTDSAndTotal() {
|
|||||||
|
|
||||||
document.getElementById("TDS_Payment_Amount").value = tdsAmount;
|
document.getElementById("TDS_Payment_Amount").value = tdsAmount;
|
||||||
document.getElementById("total_amount").value = totalAmount;
|
document.getElementById("total_amount").value = totalAmount;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script src="{{ url_for('static', filename='js/showSuccessAlert.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/showSuccessAlert.js') }}"></script>
|
||||||
</body>
|
</body>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %} {% block content %}
|
||||||
{% 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 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/village.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<!-- Button Container to Center Buttons -->
|
||||||
<!-- Button Container to Center Buttons -->
|
<div class="button-container">
|
||||||
<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>
|
||||||
@@ -40,19 +42,30 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="Village_Name">Village Name:</label>
|
<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>
|
<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 type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
<input
|
||||||
|
type="text"
|
||||||
|
id="searchBar"
|
||||||
|
placeholder="Searching..."
|
||||||
|
onkeyup="searchTable()"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="sortableTable" border="1">
|
<table id="sortableTable" border="1">
|
||||||
@@ -63,12 +76,15 @@
|
|||||||
<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></th>
|
</span>
|
||||||
<th class="sortable-header">Block Name
|
</th>
|
||||||
|
<th class="sortable-header">
|
||||||
|
Block 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></th>
|
</span>
|
||||||
|
</th>
|
||||||
<th>Update</th>
|
<th>Update</th>
|
||||||
<th>Delete</th>
|
<th>Delete</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -78,22 +94,36 @@
|
|||||||
<td>{{ village[1] }}</td>
|
<td>{{ village[1] }}</td>
|
||||||
<td>{{ village[2] }}</td>
|
<td>{{ village[2] }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('village.edit_village', village_id=village[0]) }}">
|
<a
|
||||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
href="{{ url_for('village.edit_village', village_id=village[0]) }}"
|
||||||
class="icon">
|
>
|
||||||
|
<img
|
||||||
|
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
|
||||||
|
alt="Edit"
|
||||||
|
class="icon"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url_for('village.delete_village', village_id=village[0]) }}"
|
<a href="javascript:void(0);"
|
||||||
onclick="return confirm('Are you sure you want to delete this village?');">
|
onclick="deleteVillage({{ village[0] }}, this)">
|
||||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
|
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||||
class="icon">
|
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 %}
|
||||||
|
|||||||
@@ -9,37 +9,37 @@
|
|||||||
<body>
|
<body>
|
||||||
<h2>Edit GST Release</h2>
|
<h2>Edit GST Release</h2>
|
||||||
|
|
||||||
<form action="/edit_gst_release/{{ gst_release_data[0] }}" method="POST">
|
<form action="/edit_gst_release/{{ gst_release_data.gst_release_id }}" method="POST">
|
||||||
<!-- <label for="invoice_id">Invoice Id:</label><br>-->
|
|
||||||
<!-- <input type="number" id="invoice_id" name="invoice_id" value="{{ gst_release_data[0] }}" required><br><br>-->
|
|
||||||
|
|
||||||
|
<!-- PMC Number -->
|
||||||
<label for="PMC_No">PMC No :</label><br>
|
<label for="PMC_No">PMC No :</label><br>
|
||||||
<input type="number" id="PMC_No" name="PMC_No" value="{{ gst_release_data[1] }}" required><br><br>
|
<input type="text" id="PMC_No" name="PMC_No" value="{{ gst_release_data.pmc_no }}" required><br><br>
|
||||||
|
|
||||||
<label for="invoice_No">Invoice No:</label><br>
|
<!-- Invoice Number -->
|
||||||
<input type="number" step="0.01" id="invoice_No" name="invoice_No" value="{{ gst_release_data[2] }}"
|
<label for="invoice_no">Invoice No:</label><br>
|
||||||
required><br><br>
|
<input type="text" id="invoice_no" name="invoice_no" value="{{ gst_release_data.invoice_no }}" required><br><br>
|
||||||
|
|
||||||
|
<!-- Basic Amount -->
|
||||||
|
<label for="Basic_Amount">Basic Amount:</label><br>
|
||||||
|
<input type="number" step="0.01" id="Basic_Amount" name="Basic_Amount" value="{{ gst_release_data.basic_amount }}" required><br><br>
|
||||||
|
|
||||||
<label for="basic_amount">Basic Amount:</label><br>
|
<!-- Final Amount -->
|
||||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ gst_release_data[3] }}"
|
<label for="Final_Amount">Final Amount:</label><br>
|
||||||
required><br><br>
|
<input type="number" step="0.01" id="Final_Amount" name="Final_Amount" value="{{ gst_release_data.final_amount }}" required><br><br>
|
||||||
|
|
||||||
<label for="final_amount">Final Amount:</label><br>
|
<!-- Total Amount -->
|
||||||
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ gst_release_data[4] }}"
|
<label for="Total_Amount">Total Amount:</label><br>
|
||||||
required><br><br>
|
<input type="number" step="0.01" id="Total_Amount" name="Total_Amount" value="{{ gst_release_data.total_amount }}" required><br><br>
|
||||||
|
|
||||||
<label for="total_amount">Total Amount:</label><br>
|
<!-- UTR -->
|
||||||
<input type="number" step="0.01" id="total_amount" name="total_amount" value="{{ gst_release_data[5] }}"
|
<label for="UTR">UTR:</label><br>
|
||||||
required><br><br>
|
<input type="text" id="UTR" name="UTR" value="{{ gst_release_data.utr }}" readonly required><br><br>
|
||||||
|
|
||||||
<label for="utr">UTR:</label><br>
|
<!-- Hidden Contractor ID -->
|
||||||
<input type="text" id="utr" name="utr" value="{{ gst_release_data[6] }}"
|
<input type="hidden" id="Contractor_ID" name="Contractor_ID" value="{{ gst_release_data.contractor_id }}">
|
||||||
required readonly><br><br>
|
|
||||||
|
|
||||||
<button type="submit">Update GST Release</button>
|
<button type="submit">Update GST Release</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Edit Hold Type</title>
|
<title>Edit Hold Type</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') }}">
|
||||||
@@ -10,10 +10,10 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<h2>Edit Hold Type</h2>
|
<h2>Edit Hold Type</h2>
|
||||||
<form id="updateHoldTypeForm">
|
<form id="updateHoldTypeForm" method="POST">
|
||||||
<input type="hidden" id="hold_type_id" value="{{ hold_type[0] }}">
|
<input type="hidden" id="hold_type_id" value="{{ hold_type.hold_type_id }}">
|
||||||
<label for="edit_hold_type">Hold Type:</label>
|
<label for="edit_hold_type">Hold Type:</label>
|
||||||
<input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type[1] }}" required>
|
<input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type.hold_type }}" required>
|
||||||
<button type="submit">Update</button>
|
<button type="submit">Update</button>
|
||||||
<a href="{{ url_for('hold_types.add_hold_type') }}"></a>
|
<a href="{{ url_for('hold_types.add_hold_type') }}"></a>
|
||||||
</form>
|
</form>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
formData.append('hold_type', newHoldType);
|
formData.append('hold_type', newHoldType);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/update_hold_type/' + holdTypeId,
|
url: '/edit_hold_type/' + holdTypeId,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: formData,
|
data: formData,
|
||||||
processData: false,
|
processData: false,
|
||||||
@@ -55,8 +55,3 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,18 @@
|
|||||||
{% block content %}
|
{% 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>Edit Invoice</title>
|
<title>Edit 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') }}">
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style1.css') }}">
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style1.css') }}">
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="editForm">
|
<div id="editForm">
|
||||||
<h2>Edit Invoice</h2>
|
<h2>Edit Invoice</h2>
|
||||||
|
|
||||||
<!-- Success Alert Box -->
|
<!-- Success Alert Box -->
|
||||||
@@ -20,7 +21,8 @@
|
|||||||
Invoice successfully updated!
|
Invoice successfully updated!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}" method="POST">
|
<form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
|
||||||
|
method="POST">
|
||||||
|
|
||||||
<!-- Subcontractor Field -->
|
<!-- Subcontractor Field -->
|
||||||
<div class="row1">
|
<div class="row1">
|
||||||
@@ -28,7 +30,8 @@
|
|||||||
<label for="subcontractor">Subcontractor Name:</label>
|
<label for="subcontractor">Subcontractor Name:</label>
|
||||||
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor"
|
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor"
|
||||||
value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required>
|
value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required>
|
||||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id" value="{{ invoice.Subcontractor_Id }}">
|
<input type="hidden" id="subcontractor_id" name="subcontractor_id"
|
||||||
|
value="{{ invoice.Subcontractor_Id }}">
|
||||||
<datalist id="subcontractor_list"></datalist>
|
<datalist id="subcontractor_list"></datalist>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,12 +40,12 @@
|
|||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="village">Village Name:</label>
|
<label for="village">Village Name:</label>
|
||||||
<input type="text" id="village" name="village" value="{{ invoice.Village_Name }}" required/>
|
<input type="text" id="village" name="village" value="{{ invoice.Village_Name }}" required />
|
||||||
<datalist id="village_list"></datalist>
|
<datalist id="village_list"></datalist>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="pmc_no">PMC No:</label>
|
<label for="pmc_no">PMC No:</label>
|
||||||
<input type="text" id="pmc_no" name="pmc_no" value="{{ invoice.PMC_No }}" required/>
|
<input type="text" id="pmc_no" name="pmc_no" value="{{ invoice.PMC_No }}" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -50,11 +53,12 @@
|
|||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="work_type">Work Type:</label>
|
<label for="work_type">Work Type:</label>
|
||||||
<input type="text" id="work_type" name="work_type" value="{{ invoice.Work_Type }}" required/>
|
<input type="text" id="work_type" name="work_type" value="{{ invoice.Work_Type }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="invoice_details">Invoice Details:</label>
|
<label for="invoice_details">Invoice Details:</label>
|
||||||
<textarea id="invoice_details" name="invoice_details" required>{{ invoice.Invoice_Details }}</textarea>
|
<textarea id="invoice_details" name="invoice_details"
|
||||||
|
required>{{ invoice.Invoice_Details }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -62,11 +66,12 @@
|
|||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="invoice_no">Invoice No:</label>
|
<label for="invoice_no">Invoice No:</label>
|
||||||
<input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.Invoice_No }}" required/>
|
<input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.invoice_no }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="invoice_date">Invoice Date:</label>
|
<label for="invoice_date">Invoice Date:</label>
|
||||||
<input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}" required/>
|
<input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}"
|
||||||
|
required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -74,15 +79,18 @@
|
|||||||
<div class="row3">
|
<div class="row3">
|
||||||
<div>
|
<div>
|
||||||
<label for="basic_amount">Basic Amount:</label>
|
<label for="basic_amount">Basic Amount:</label>
|
||||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ invoice.Basic_Amount }}" required/>
|
<input type="number" step="0.01" id="basic_amount" name="basic_amount"
|
||||||
|
value="{{ invoice.Basic_Amount }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="debit_amount">Debit Amount:</label>
|
<label for="debit_amount">Debit Amount:</label>
|
||||||
<input type="number" step="0.01" id="debit_amount" name="debit_amount" value="{{ invoice.Debit_Amount }}" required/>
|
<input type="number" step="0.01" id="debit_amount" name="debit_amount"
|
||||||
|
value="{{ invoice.Debit_Amount }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="after_debit_amount">After Debit Amount:</label>
|
<label for="after_debit_amount">After Debit Amount:</label>
|
||||||
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" value="{{ invoice.After_Debit_Amount }}" required/>
|
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount"
|
||||||
|
value="{{ invoice.After_Debit_Amount }}" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -90,15 +98,17 @@
|
|||||||
<div class="row3">
|
<div class="row3">
|
||||||
<div>
|
<div>
|
||||||
<label for="amount">Amount:</label>
|
<label for="amount">Amount:</label>
|
||||||
<input type="number" step="0.01" id="amount" name="amount" value="{{ invoice.Amount }}" required/>
|
<input type="number" step="0.01" id="amount" name="amount" value="{{ invoice.Amount }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="gst_amount">GST Amount:</label>
|
<label for="gst_amount">GST Amount:</label>
|
||||||
<input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}" required/>
|
<input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}"
|
||||||
|
required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="tds_amount">TDS Amount:</label>
|
<label for="tds_amount">TDS Amount:</label>
|
||||||
<input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}" required/>
|
<input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}"
|
||||||
|
required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -106,34 +116,39 @@
|
|||||||
<div class="row3">
|
<div class="row3">
|
||||||
<div>
|
<div>
|
||||||
<label for="sd_amount">SD Amount:</label>
|
<label for="sd_amount">SD Amount:</label>
|
||||||
<input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}" required/>
|
<input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}"
|
||||||
|
required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="on_commission">On Commission:</label>
|
<label for="on_commission">On Commission:</label>
|
||||||
<input type="number" step="0.01" id="on_commission" name="on_commission" value="{{ invoice.On_Commission }}" required/>
|
<input type="number" step="0.01" id="on_commission" name="on_commission"
|
||||||
|
value="{{ invoice.On_Commission }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="hydro_testing">Hydro Testing:</label>
|
<label for="hydro_testing">Hydro Testing:</label>
|
||||||
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" value="{{ invoice.Hydro_Testing }}" required/>
|
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing"
|
||||||
|
value="{{ invoice.Hydro_Testing }}" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hold Amount Section -->
|
<!-- Hold Amount Section -->
|
||||||
<div id="hold_amount_container">
|
<div id="hold_amount_container">
|
||||||
{% set seen_types = [] %}
|
{% set seen_types = [] %}
|
||||||
{% for hold in invoice.hold_amounts %}
|
{% for hold in invoice.hold_amounts %}
|
||||||
{% if hold.hold_type not in seen_types %}
|
{% if hold.hold_type not in seen_types %}
|
||||||
{% set _ = seen_types.append(hold.hold_type) %}
|
{% set _ = seen_types.append(hold.hold_type) %}
|
||||||
<div class="hold-amount-row">
|
<div class="hold-amount-row">
|
||||||
<label for="hold_type_{{ loop.index }}">Hold Type:</label>
|
<label for="hold_type_{{ loop.index }}">Hold Type:</label>
|
||||||
<input type="text" id="hold_type_{{ loop.index }}" name="hold_type[]" value="{{ hold.hold_type }}" required/>
|
<input type="text" id="hold_type_{{ loop.index }}" name="hold_type[]" value="{{ hold.hold_type }}"
|
||||||
|
required />
|
||||||
<label for="hold_amount_{{ loop.index }}">Hold Amount:</label>
|
<label for="hold_amount_{{ loop.index }}">Hold Amount:</label>
|
||||||
<input type="number" step="0.01" id="hold_amount_{{ loop.index }}" name="hold_amount[]" value="{{ hold.hold_amount }}" required/>
|
<input type="number" step="0.01" id="hold_amount_{{ loop.index }}" name="hold_amount[]"
|
||||||
|
value="{{ hold.hold_amount }}" required />
|
||||||
<button type="button" class="remove-hold-amount">Remove</button>
|
<button type="button" class="remove-hold-amount">Remove</button>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="hold-row">
|
<div class="hold-row">
|
||||||
@@ -144,24 +159,26 @@
|
|||||||
<div class="row2">
|
<div class="row2">
|
||||||
<div>
|
<div>
|
||||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
<label for="gst_sd_amount">GST SD Amount:</label>
|
||||||
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" value="{{ invoice.GST_SD_Amount }}" required/>
|
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount"
|
||||||
|
value="{{ invoice.GST_SD_Amount }}" required />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="final_amount">Final Amount:</label>
|
<label for="final_amount">Final Amount:</label>
|
||||||
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ invoice.Final_Amount }}" required/>
|
<input type="number" step="0.01" id="final_amount" name="final_amount"
|
||||||
|
value="{{ invoice.Final_Amount }}" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<button type="submit" class="button">Update</button>
|
<button type="submit" class="button">Update</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- JS for dynamic hold amount rows -->
|
<!-- JS for dynamic hold amount rows -->
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function () {
|
||||||
// Add new hold amount row
|
// Add new hold amount row
|
||||||
$("#add_hold_amount").click(function() {
|
$("#add_hold_amount").click(function () {
|
||||||
const index = $("#hold_amount_container .hold-amount-row").length;
|
const index = $("#hold_amount_container .hold-amount-row").length;
|
||||||
const newRow = `
|
const newRow = `
|
||||||
<div class="hold-amount-row">
|
<div class="hold-amount-row">
|
||||||
@@ -176,32 +193,34 @@ $(document).ready(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Remove hold amount row
|
// Remove hold amount row
|
||||||
$(document).on("click", ".remove-hold-amount", function() {
|
$(document).on("click", ".remove-hold-amount", function () {
|
||||||
$(this).closest(".hold-amount-row").remove();
|
$(this).closest(".hold-amount-row").remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Submit form via AJAX
|
// Submit form via AJAX
|
||||||
$("#invoiceForm").submit(function(e) {
|
$("#invoiceForm").submit(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: $(this).attr("action"),
|
url: $(this).attr("action"),
|
||||||
data: $(this).serialize(),
|
data: $(this).serialize(),
|
||||||
success: function(response) {
|
dataType: 'json', // ensure JSON is returned
|
||||||
if(response.status === "success") {
|
success: function (response) {
|
||||||
$("#invoiceSuccessAlert").fadeIn().delay(3000).fadeOut();
|
if (response.status === "success") {
|
||||||
alert("Invoice updated successfully!"); // <-- Popup alert
|
alert("Invoice updated successfully!"); // <-- Popup alert
|
||||||
}
|
|
||||||
|
|
||||||
|
// ✅ Redirect to Add Invoice page (table part visible)
|
||||||
|
window.location.href = "{{ url_for('invoice.add_invoice') }}#addTable";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: function(xhr) {
|
error: function (xhr) {
|
||||||
alert("Error: " + xhr.responseJSON.message);
|
alert("Error: " + xhr.responseJSON?.message || "Something went wrong!");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -28,25 +28,17 @@
|
|||||||
|
|
||||||
<button type="submit">Update Village</button>
|
<button type="submit">Update Village</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<!-- Flash Messages (hidden, used for JS popup) -->
|
||||||
|
<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 id="flash-message" data-category="{{ category }}" style="display:none;">{{ message }}</div>
|
<div class="flash-message" data-category="{{ category }}">{{ 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 %}
|
||||||
|
|||||||
Reference in New Issue
Block a user