Compare commits
25 Commits
f184d6cecc
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 1cf0093029 | |||
| 73cd97f3c8 | |||
| 0b72adef7d | |||
| 225475e843 | |||
|
|
d84ba520cf | ||
| 0aeaf775dd | |||
| 88e8771b51 | |||
| 6c74b5d3bf | |||
| 47ba78d72c | |||
| 1946a98d59 | |||
| 8f35e08429 | |||
| 82bedc3117 | |||
| cb68e454bc | |||
|
|
91b078a0c3 | ||
|
|
eb46929893 | ||
| 675301df7f | |||
|
|
14e799a1d4 | ||
| 8ab1b69033 | |||
| dbeec9962d | |||
| 8750f268db | |||
|
|
b78526ad9f | ||
| 7146391c18 | |||
| 94b5563d15 | |||
| 937018dc16 | |||
| eda238c235 |
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.
@@ -6,7 +6,6 @@ from model.Log import LogHelper
|
||||
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
|
||||
|
||||
@auth_bp.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@ from model.Block import Block
|
||||
from model.Utilities import HtmlHelper
|
||||
|
||||
block_bp = Blueprint('block', __name__)
|
||||
|
||||
block = Block()
|
||||
# --- Add Block page -------
|
||||
@block_bp.route('/add_block', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_block():
|
||||
block = Block()
|
||||
# block = Block()
|
||||
|
||||
if request.method == 'POST':
|
||||
block.AddBlock(request)
|
||||
@@ -62,7 +62,7 @@ def get_districts(state_id):
|
||||
@login_required
|
||||
def check_block():
|
||||
|
||||
block = Block()
|
||||
# block = Block()
|
||||
return block.CheckBlock(request)
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ def check_block():
|
||||
@login_required
|
||||
def edit_block(block_id):
|
||||
|
||||
block = Block()
|
||||
|
||||
|
||||
# block = Block()
|
||||
if request.method == 'POST':
|
||||
block.EditBlock(request, block_id)
|
||||
block.resultMessage
|
||||
@@ -90,7 +90,10 @@ def edit_block(block_id):
|
||||
for rs in cursor.stored_results():
|
||||
states = rs.fetchall()
|
||||
|
||||
cursor.callproc("GetAllDistrictsData")
|
||||
# cursor.callproc("GetAllDistrictsData")
|
||||
# for rs in cursor.stored_results():
|
||||
# districts = rs.fetchall()
|
||||
cursor.callproc("GetAllDistricts")
|
||||
for rs in cursor.stored_results():
|
||||
districts = rs.fetchall()
|
||||
|
||||
@@ -111,7 +114,7 @@ def edit_block(block_id):
|
||||
@login_required
|
||||
def delete_block(block_id):
|
||||
|
||||
block = Block()
|
||||
# block = Block()
|
||||
block.DeleteBlock(request, block_id)
|
||||
|
||||
return redirect(url_for('block.add_block'))
|
||||
@@ -5,12 +5,13 @@ from model.District import District
|
||||
from model.State import State
|
||||
|
||||
district_bp = Blueprint('district', __name__)
|
||||
district = District()
|
||||
|
||||
# ------- District page --------
|
||||
@district_bp.route('/add_district', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_district():
|
||||
district = District()
|
||||
# district = District()
|
||||
|
||||
if request.method == 'POST':
|
||||
district.AddDistrict(request=request)
|
||||
@@ -32,7 +33,7 @@ def add_district():
|
||||
@login_required
|
||||
def check_district():
|
||||
|
||||
district = District()
|
||||
# district = District()
|
||||
|
||||
return district.CheckDistrict(request=request)
|
||||
|
||||
@@ -41,7 +42,7 @@ def check_district():
|
||||
@login_required
|
||||
def delete_district(district_id):
|
||||
|
||||
district = District()
|
||||
# district = District()
|
||||
|
||||
district.DeleteDistrict(request=request, district_id=district_id)
|
||||
|
||||
@@ -56,7 +57,7 @@ def delete_district(district_id):
|
||||
@login_required
|
||||
def edit_district(district_id):
|
||||
|
||||
district = District()
|
||||
# district = District()
|
||||
state = State()
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
@@ -59,21 +59,21 @@ def show_table(filename):
|
||||
try:
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
cursor.callproc('GetStateByName', [file_info['State']])
|
||||
cursor.callproc('CheckStateExists', [file_info['State']])
|
||||
for result in cursor.stored_results():
|
||||
state_data = result.fetchone()
|
||||
if not state_data:
|
||||
errors.append(f"State '{file_info['State']}' is not valid. Please add it.")
|
||||
|
||||
if state_data:
|
||||
cursor.callproc('GetDistrictByNameAndStates', [file_info['District'], state_data['State_ID']])
|
||||
cursor.callproc('GetDistrictByNameAndState', [file_info['District'], state_data['State_Id']]) # Change GetDistrictByNameAndStates to GetDistrictByNameAndState
|
||||
for result in cursor.stored_results():
|
||||
district_data = result.fetchone()
|
||||
if not district_data:
|
||||
errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.")
|
||||
|
||||
if district_data:
|
||||
cursor.callproc('GetBlockByNameAndDistricts', [file_info['Block'], district_data['District_ID']])
|
||||
cursor.callproc('GetBlockByNameAndDistrict', [file_info['Block'], district_data['District_id']]) #Change District_ID to District_id and GetBlockByNameAndDistricts to GetBlockByNameAndDistrict
|
||||
for result in cursor.stored_results():
|
||||
block_data = result.fetchone()
|
||||
if not block_data:
|
||||
@@ -84,7 +84,9 @@ def show_table(filename):
|
||||
subcontractor_data = result.fetchone()
|
||||
|
||||
if not subcontractor_data:
|
||||
cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
|
||||
# cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
|
||||
# connection.commit()
|
||||
cursor.callproc('SaveContractor', [file_info.get('Subcontractor'),None,None,None,None,None,None,None,None])
|
||||
connection.commit()
|
||||
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
|
||||
for result in cursor.stored_results():
|
||||
@@ -229,7 +231,7 @@ def save_data():
|
||||
else:
|
||||
work_type = " ".join(words[:work_pos + 1])
|
||||
if Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower():
|
||||
print("village_name ::", village_name, "|| work_type ::", work_type)
|
||||
# print("village_name ::", village_name, "|| work_type ::", work_type)
|
||||
if block_id and village_name:
|
||||
village_id = None
|
||||
cursor.callproc("GetVillageId", (block_id, village_name))
|
||||
@@ -242,11 +244,11 @@ def save_data():
|
||||
for result in cursor.stored_results():
|
||||
result = result.fetchone()
|
||||
village_id = result[0] if result else None
|
||||
print("village_id :", village_id)
|
||||
print("block_id :", block_id)
|
||||
print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
|
||||
Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
|
||||
SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount)
|
||||
# print("village_id :", village_id)
|
||||
# print("block_id :", block_id)
|
||||
# print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
|
||||
# Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
|
||||
# SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount)
|
||||
|
||||
args = (
|
||||
PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
|
||||
@@ -255,22 +257,39 @@ def save_data():
|
||||
subcontractor_id, 0
|
||||
)
|
||||
|
||||
print("All invoice Details ",args)
|
||||
# print("All invoice Details ",args)
|
||||
# add subcontarctor id in invoice table
|
||||
results = cursor.callproc('SaveInvoice', args)
|
||||
invoice_id = results[-1]
|
||||
print("invoice id from the excel ", invoice_id)
|
||||
print("**************************************************************")
|
||||
print(invoice_id)
|
||||
print("**************************************************************")
|
||||
cursor.callproc(
|
||||
"SavePayment",
|
||||
(
|
||||
PMC_No,
|
||||
Invoice_No, # required
|
||||
Payment_Amount,
|
||||
TDS_Payment_Amount,
|
||||
Total_Amount,
|
||||
UTR,
|
||||
invoice_id # last
|
||||
)
|
||||
)
|
||||
|
||||
# print("invoice id from the excel ", invoice_id)
|
||||
if isinstance(hold_columns, str):
|
||||
hold_columns = ast.literal_eval(hold_columns)
|
||||
if isinstance(hold_columns, list) and all(isinstance(hold, dict) for hold in hold_columns):
|
||||
for hold in hold_columns:
|
||||
print(f"Processing hold: {hold}")
|
||||
# print(f"Processing hold: {hold}")
|
||||
hold_column_name = hold.get('column_name') # Get column name
|
||||
hold_type_id = hold.get('hold_type_id') # Get hold_type_id
|
||||
if hold_column_name:
|
||||
hold_amount = entry.get(
|
||||
hold_column_name) # Get the value for that specific hold column
|
||||
if hold_amount is not None:
|
||||
print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}")
|
||||
# print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}")
|
||||
hold_join_data = {
|
||||
"Contractor_Id": subcontractor_id,
|
||||
"Invoice_Id": invoice_id,
|
||||
@@ -289,8 +308,8 @@ def save_data():
|
||||
print("Hold columns data is not a valid list of dictionaries.")
|
||||
#---------------------------------------------Credit Note---------------------------------------------------------------------------
|
||||
elif any(keyword in Invoice_Details.lower() for keyword in ['credit note','logging report']):
|
||||
print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount,
|
||||
After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No)
|
||||
# print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount,
|
||||
# After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No)
|
||||
cursor.callproc(
|
||||
'AddCreditNoteFromExcel',
|
||||
[
|
||||
@@ -315,52 +334,108 @@ def save_data():
|
||||
]
|
||||
# Step 3: Matching condition
|
||||
if any(kw in normalized_details for kw in keywords):
|
||||
print("✅ Match found. Inserting hold release for:", Invoice_Details)
|
||||
# print("✅ Match found. Inserting hold release for:", Invoice_Details)
|
||||
cursor.callproc(
|
||||
'AddHoldReleaseFromExcel',
|
||||
[PMC_No, Invoice_No, Invoice_Details, Basic_Amount, Final_Amount, UTR, subcontractor_id]
|
||||
)
|
||||
connection.commit()
|
||||
print("✅ Hold release inserted for:", PMC_No, Invoice_Details)
|
||||
# print("✅ Hold release inserted for:", PMC_No, Invoice_Details)
|
||||
#------------------------------------------------------------------------------------------------------------------
|
||||
elif Invoice_Details and any(
|
||||
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']):
|
||||
print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
|
||||
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'gst release note']):
|
||||
# print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
|
||||
cursor.callproc(
|
||||
'AddGSTReleaseFromExcel',
|
||||
[PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id]
|
||||
)
|
||||
|
||||
if PMC_No and Total_Amount and UTR:
|
||||
print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )
|
||||
cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR ))
|
||||
if not village_id:
|
||||
village_id = None
|
||||
cursor.callproc('InsertOrUpdateInPayment', (
|
||||
PMC_No,
|
||||
village_id,
|
||||
work_type,
|
||||
Invoice_Details,
|
||||
Invoice_Date,
|
||||
Invoice_No,
|
||||
Basic_Amount,
|
||||
Debit_Amount,
|
||||
After_Debit_Amount,
|
||||
Amount,
|
||||
GST_Amount,
|
||||
TDS_Amount,
|
||||
SD_Amount,
|
||||
On_Commission,
|
||||
Hydro_Testing,
|
||||
0,
|
||||
GST_SD_Amount,
|
||||
Final_Amount,
|
||||
Payment_Amount,
|
||||
TDS_Payment_Amount,
|
||||
Total_Amount,
|
||||
UTR,
|
||||
subcontractor_id
|
||||
))
|
||||
# --------------------------------------
|
||||
# If no village/work detected, only PMC/Payment
|
||||
if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()):
|
||||
# if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower() and 'gst' in Invoice_Details.lower() and 'gst release note' in Invoice_Details.lower() and 'release' in Invoice_Details.lower()):
|
||||
|
||||
# ---------- Only PMC / Payment rows ----------
|
||||
if PMC_No and not Invoice_No and UTR :
|
||||
# print("No village/work, using PMC only :", PMC_No)
|
||||
|
||||
# check invoice exists
|
||||
# cursor.execute(
|
||||
# "SELECT invoice_id FROM invoice WHERE PMC_No=%s ORDER BY invoice_id DESC LIMIT 1",
|
||||
# (PMC_No,)
|
||||
# )
|
||||
# row = cursor.fetchone()
|
||||
# invoice_id = row[0] if row else None
|
||||
|
||||
# # insert invoice if not exists
|
||||
|
||||
# if not invoice_id:
|
||||
print(" extra payment :", PMC_No,Total_Amount,UTR, subcontractor_id)
|
||||
|
||||
# cursor.execute(
|
||||
# """
|
||||
# INSERT INTO invoice (PMC_No,Contractor_Id) VALUES (%s, %s);
|
||||
# """,
|
||||
# (PMC_No, subcontractor_id)
|
||||
# )
|
||||
# connection.commit()
|
||||
|
||||
# cursor.execute(
|
||||
# "SELECT invoice_id FROM invoice WHERE PMC_No=%s AND Contractor_Id =%s ORDER BY invoice_id DESC LIMIT 1",
|
||||
# (PMC_No, subcontractor_id)
|
||||
# )
|
||||
# row = cursor.fetchone()
|
||||
cursor.callproc("insertExtrapaymet",(PMC_No, subcontractor_id))
|
||||
for result in cursor.stored_results():
|
||||
row = result.fetchone()
|
||||
invoice_id = row[0] if row else None
|
||||
# insert payment
|
||||
cursor.callproc(
|
||||
"SavePayment",
|
||||
(
|
||||
PMC_No,
|
||||
Invoice_No, # required
|
||||
Payment_Amount,
|
||||
TDS_Payment_Amount,
|
||||
Total_Amount,
|
||||
UTR,
|
||||
invoice_id
|
||||
)
|
||||
)
|
||||
|
||||
# if PMC_No and Total_Amount and UTR:
|
||||
# print("Payment :", PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )
|
||||
|
||||
# Add inoice id in payment table
|
||||
# cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR, invoice_id))
|
||||
|
||||
# if not village_id:
|
||||
# village_id = None
|
||||
# cursor.callproc('InsertOrUpdateInPayment', (
|
||||
# PMC_No,
|
||||
# village_id,
|
||||
# work_type,
|
||||
# Invoice_Details,
|
||||
# Invoice_Date,
|
||||
# Invoice_No,
|
||||
# Basic_Amount,
|
||||
# Debit_Amount,
|
||||
# After_Debit_Amount,
|
||||
# Amount,
|
||||
# GST_Amount,
|
||||
# TDS_Amount,
|
||||
# SD_Amount,
|
||||
# On_Commission,
|
||||
# Hydro_Testing,
|
||||
# 0,
|
||||
# GST_SD_Amount,
|
||||
# Final_Amount,
|
||||
# Payment_Amount,
|
||||
# TDS_Payment_Amount,
|
||||
# Total_Amount,
|
||||
# UTR,f
|
||||
# subcontractor_id
|
||||
# ))
|
||||
connection.commit()
|
||||
return jsonify({"success": "Data saved successfully!"}), 200
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for
|
||||
# routes/gst_release_routes.py
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required
|
||||
from model.gst_release import GSTRelease
|
||||
from model.Log import LogHelper
|
||||
from flask import flash, current_app
|
||||
|
||||
gst_release_bp = Blueprint('gst_release_bp', __name__)
|
||||
gst_service = GSTRelease()
|
||||
@@ -13,7 +13,7 @@ gst_service = GSTRelease()
|
||||
def add_gst_release():
|
||||
if request.method == 'POST':
|
||||
gst_service.AddGSTRelease(request)
|
||||
LogHelper.log_action("Add GST Release", f"User added GST release")
|
||||
LogHelper.log_action("Add GST Release", "User added GST release")
|
||||
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
|
||||
return redirect(url_for('gst_release_bp.add_gst_release'))
|
||||
|
||||
@@ -30,7 +30,7 @@ def edit_gst_release(gst_release_id):
|
||||
|
||||
if request.method == 'POST':
|
||||
gst_service.EditGSTRelease(request, gst_release_id)
|
||||
LogHelper.log_action("Edit GST Release", f"User edited GST release")
|
||||
LogHelper.log_action("Edit GST Release", "User edited GST release")
|
||||
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
|
||||
return redirect(url_for('gst_release_bp.add_gst_release'))
|
||||
|
||||
@@ -40,7 +40,7 @@ def edit_gst_release(gst_release_id):
|
||||
@gst_release_bp.route('/delete_gst_release/<int:gst_release_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_gst_release(gst_release_id):
|
||||
gst_service.DeleteGSTRelease(gst_release_id) # remove request
|
||||
LogHelper.log_action("Delete GST Release", f"User deleted GST release")
|
||||
gst_service.DeleteGSTRelease(gst_release_id)
|
||||
LogHelper.log_action("Delete GST Release", "User deleted GST release")
|
||||
flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
|
||||
return redirect(url_for('gst_release_bp.add_gst_release'))
|
||||
@@ -5,32 +5,32 @@ from model.GST import GST
|
||||
|
||||
hold_bp = Blueprint("hold_types", __name__)
|
||||
|
||||
|
||||
hold = HoldTypes()
|
||||
# ---------------- ADD HOLD TYPE ----------------
|
||||
@hold_bp.route('/add_hold_type', methods=['GET','POST'])
|
||||
@login_required
|
||||
def add_hold_type():
|
||||
|
||||
hold = HoldTypes()
|
||||
# hold = HoldTypes()
|
||||
|
||||
if request.method == 'POST':
|
||||
hold.AddHoldType(request) # ✅
|
||||
return hold.resultMessage
|
||||
hold.AddHoldType(request)
|
||||
# ✅ 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(
|
||||
"add_hold_type.html",
|
||||
Hold_Types_data=hold_types
|
||||
)
|
||||
|
||||
|
||||
# ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ----------------
|
||||
@hold_bp.route('/check_hold_type', methods=['POST'])
|
||||
@login_required
|
||||
def check_hold_type():
|
||||
|
||||
hold = HoldTypes()
|
||||
# hold = HoldTypes()
|
||||
return hold.CheckHoldType(request) # if exists
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ def check_hold_type():
|
||||
@login_required
|
||||
def edit_hold_type(id):
|
||||
|
||||
hold = HoldTypes()
|
||||
# hold = HoldTypes()
|
||||
|
||||
if request.method == 'POST':
|
||||
hold.EditHoldType(request, id) # ✅
|
||||
@@ -58,7 +58,7 @@ def edit_hold_type(id):
|
||||
@login_required
|
||||
def delete_hold_type(id):
|
||||
|
||||
hold = HoldTypes()
|
||||
# hold = HoldTypes()
|
||||
hold.DeleteHoldType(request, id) # ✅
|
||||
|
||||
return redirect(url_for("hold_types.add_hold_type"))
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
# controllers/invoice_controller.py
|
||||
|
||||
from flask import Blueprint, request, jsonify, render_template
|
||||
@@ -40,7 +37,11 @@ def add_invoice():
|
||||
|
||||
village_id = village_result['Village_Id']
|
||||
invoice_id = insert_invoice(data, village_id)
|
||||
assign_subcontractor(data, village_id)
|
||||
# assign_subcontractor(data, village_id)
|
||||
print("********************************************************************")
|
||||
print("Manully added invoice id :",invoice_id)
|
||||
print("********************************************************************")
|
||||
|
||||
insert_hold_types(data, invoice_id)
|
||||
|
||||
log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'")
|
||||
@@ -83,7 +84,7 @@ def edit_invoice(invoice_id):
|
||||
if request.method == 'POST':
|
||||
data = request.form
|
||||
update_invoice(data, invoice_id)
|
||||
update_inpayment(data)
|
||||
# update_inpayment(data)
|
||||
log_action("Edit invoice", f"edited invoice '{invoice_id}'")
|
||||
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ def activity_log():
|
||||
end_date,
|
||||
user_name
|
||||
)
|
||||
|
||||
return render_template(
|
||||
"activity_log.html",
|
||||
logs=filtered_logs,
|
||||
|
||||
@@ -28,8 +28,8 @@ def add_payment():
|
||||
utr = request.form['utr']
|
||||
|
||||
LogHelper.log_action("Add Payment", f"User {current_user.id} Add Payment '{pmc_no}'")
|
||||
Paymentmodel.insert_payment(pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
|
||||
Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
|
||||
Paymentmodel.insert_payment(subcontractor_id,pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
|
||||
# Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
|
||||
|
||||
return redirect(url_for('payment_bp.add_payment'))
|
||||
|
||||
@@ -72,26 +72,24 @@ def edit_payment(payment_id):
|
||||
Paymentmodel.call_update_payment_proc(payment_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
|
||||
|
||||
# Update inpayment
|
||||
connection = Paymentmodel.get_connection()
|
||||
cursor = connection.cursor()
|
||||
cursor.callproc(
|
||||
'UpdateInpaymentByPMCInvoiceUTR',
|
||||
[amount, tds_amount, total_amount, pmc_no, invoice_no, utr]
|
||||
)
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
connection.close()
|
||||
# connection = Paymentmodel.get_connection()
|
||||
# cursor = connection.cursor()
|
||||
# cursor.callproc('UpdateInpaymentByPMCInvoiceUTR',[amount, tds_amount, total_amount, pmc_no, invoice_no, utr])
|
||||
|
||||
# connection.commit()
|
||||
# cursor.close()
|
||||
# connection.close()
|
||||
|
||||
return redirect(url_for('payment_bp.add_payment'))
|
||||
|
||||
return render_template('edit_payment.html', payment_data=payment_data)
|
||||
|
||||
|
||||
# ------------------- Delete Payment -------------------
|
||||
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['POST'])
|
||||
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET'])
|
||||
@login_required
|
||||
def delete_payment(payment_id):
|
||||
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
|
||||
|
||||
if not success:
|
||||
flash("Payment not found or failed to delete", "error")
|
||||
else:
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
from flask import Blueprint, render_template, send_from_directory
|
||||
from flask_login import login_required
|
||||
# from flask import Blueprint, render_template, send_from_directory
|
||||
# from flask_login import login_required
|
||||
# from model.PmcReport import PmcReport
|
||||
|
||||
from model.PmcReport import PmcReport
|
||||
# pmc_report_bp = Blueprint("pmc_report", __name__)
|
||||
|
||||
pmc_report_bp = Blueprint("pmc_report", __name__)
|
||||
# # ---------------- Contractor Report by pmc no ----------------
|
||||
# @pmc_report_bp.route("/pmc_report/<pmc_no>")
|
||||
# @login_required
|
||||
# def pmc_report(pmc_no):
|
||||
# data = PmcReport.get_pmc_report(pmc_no)
|
||||
# if not data:
|
||||
# return "No PMC found with this number", 404
|
||||
|
||||
# ---------------- Contractor Report by pmc no ----------------
|
||||
@pmc_report_bp.route("/pmc_report/<pmc_no>")
|
||||
@login_required
|
||||
def pmc_report(pmc_no):
|
||||
data = PmcReport.get_pmc_report(pmc_no)
|
||||
if not data:
|
||||
return "No PMC found with this number", 404
|
||||
# return render_template(
|
||||
# "pmc_report.html",
|
||||
# info=data["info"],
|
||||
# invoices=data["invoices"],
|
||||
# hold_types=data["hold_types"],
|
||||
# gst_rel=data["gst_rel"],
|
||||
# payments=data["payments"],
|
||||
# credit_note=data["credit_note"],
|
||||
# hold_release=data["hold_release"],
|
||||
# total=data["total"]
|
||||
# )
|
||||
|
||||
return render_template(
|
||||
"pmc_report.html",
|
||||
info=data["info"],
|
||||
invoices=data["invoices"],
|
||||
hold_types=data["hold_types"],
|
||||
gst_rel=data["gst_rel"],
|
||||
payments=data["payments"],
|
||||
credit_note=data["credit_note"],
|
||||
hold_release=data["hold_release"],
|
||||
total=data["total"]
|
||||
)
|
||||
# # ---------------- Contractor Download Report by pmc no ----------------
|
||||
# @pmc_report_bp.route("/download_pmc_report/<pmc_no>")
|
||||
# @login_required
|
||||
# def download_pmc_report(pmc_no):
|
||||
|
||||
# ---------------- Contractor Download Report by pmc no ----------------
|
||||
@pmc_report_bp.route("/download_pmc_report/<pmc_no>")
|
||||
@login_required
|
||||
def download_pmc_report(pmc_no):
|
||||
# result = PmcReport.download_pmc_report(pmc_no)
|
||||
|
||||
result = PmcReport.download_pmc_report(pmc_no)
|
||||
# if not result:
|
||||
# return "No contractor found for this PMC No", 404
|
||||
|
||||
if not result:
|
||||
return "No contractor found for this PMC No", 404
|
||||
# output_folder, file_name = result
|
||||
|
||||
output_folder, file_name = result
|
||||
# return send_from_directory(output_folder, file_name, as_attachment=True)
|
||||
|
||||
return send_from_directory(output_folder, file_name, as_attachment=True)
|
||||
@@ -1,13 +1,10 @@
|
||||
from flask import Blueprint, render_template, request, jsonify
|
||||
from flask import Blueprint, render_template, request, jsonify, send_file
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
from services.ReportService import ReportService
|
||||
from model.Report import ReportHelper
|
||||
from model.Log import LogHelper
|
||||
|
||||
|
||||
report_bp = Blueprint("report", __name__)
|
||||
|
||||
|
||||
# ---------------- Report Page ----------------
|
||||
@report_bp.route("/report")
|
||||
@login_required
|
||||
@@ -20,28 +17,45 @@ def report_page():
|
||||
@login_required
|
||||
def search_contractor():
|
||||
|
||||
subcontractor_name = request.form.get("subcontractor_name")
|
||||
|
||||
LogHelper.log_action(
|
||||
"Search Contractor",
|
||||
f"User {current_user.id} searched contractor '{subcontractor_name}'"
|
||||
)
|
||||
|
||||
data = ReportHelper.search_contractor(request)
|
||||
|
||||
return jsonify(data)
|
||||
# Pagination (basic)
|
||||
page = int(request.form.get("page", 1))
|
||||
per_page = 20
|
||||
|
||||
start = (page - 1) * per_page
|
||||
end = start + per_page
|
||||
|
||||
paginated_data = data[start:end]
|
||||
|
||||
return jsonify({
|
||||
"data": paginated_data,
|
||||
"total": len(data)
|
||||
})
|
||||
|
||||
# ---------------- Contractor Report by contractor id ----------------
|
||||
@report_bp.route('/contractor_report/<int:contractor_id>')
|
||||
@login_required
|
||||
def contractor_report(contractor_id):
|
||||
|
||||
data = ReportHelper.get_contractor_report(contractor_id)
|
||||
service = ReportService(contractor_id=contractor_id).load_data()
|
||||
|
||||
return render_template(
|
||||
'subcontractor_report.html',
|
||||
contractor_id=contractor_id,
|
||||
**data
|
||||
**service.get_web_data()
|
||||
)
|
||||
|
||||
# ---------------- Contractor Report by pmc no ----------------
|
||||
@report_bp.route("/pmc_report/<pmc_no>")
|
||||
@login_required
|
||||
def pmc_report(pmc_no):
|
||||
|
||||
service = ReportService(pmc_no=pmc_no).load_data()
|
||||
|
||||
return render_template(
|
||||
"pmc_report.html",
|
||||
**service.get_web_data()
|
||||
)
|
||||
|
||||
# ---------------- Contractor Download Report by contractor id ----------------
|
||||
@@ -49,5 +63,24 @@ def contractor_report(contractor_id):
|
||||
@login_required
|
||||
def download_report(contractor_id):
|
||||
|
||||
return ReportHelper().download_report(contractor_id=contractor_id)
|
||||
|
||||
service = ReportService(contractor_id=contractor_id).load_data()
|
||||
|
||||
file, error = service.download_excel()
|
||||
|
||||
if error:
|
||||
return error, 404
|
||||
|
||||
return send_file(file, as_attachment=True)
|
||||
|
||||
# ---------------- Contractor Download Report by pmc no ----------------
|
||||
@report_bp.route("/download_pmc_report/<pmc_no>")
|
||||
@login_required
|
||||
def download_pmc_report(pmc_no):
|
||||
|
||||
service = ReportService(pmc_no=pmc_no).load_data()
|
||||
|
||||
file, error = service.download_excel()
|
||||
if error:
|
||||
return error, 404
|
||||
|
||||
return send_file(file, as_attachment=True)
|
||||
@@ -3,13 +3,13 @@ from flask_login import login_required
|
||||
from model.State import State
|
||||
|
||||
state_bp = Blueprint('state', __name__)
|
||||
|
||||
state = State()
|
||||
# ----- State page ------
|
||||
@state_bp.route('/add_state', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_state():
|
||||
|
||||
state = State()
|
||||
# state = State()
|
||||
|
||||
if request.method == 'POST':
|
||||
state.AddState(request=request)
|
||||
@@ -24,7 +24,7 @@ def add_state():
|
||||
@login_required
|
||||
def check_state():
|
||||
|
||||
state = State()
|
||||
# state = State()
|
||||
|
||||
return state.CheckState(request=request)
|
||||
|
||||
@@ -33,7 +33,7 @@ def check_state():
|
||||
@login_required
|
||||
def deleteState(id):
|
||||
|
||||
state = State()
|
||||
# state = State()
|
||||
|
||||
state.DeleteState(request=request, id=id)
|
||||
|
||||
@@ -47,7 +47,7 @@ def deleteState(id):
|
||||
@login_required
|
||||
def editState(id):
|
||||
|
||||
state = State()
|
||||
# state = State()
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ from model.State import State
|
||||
|
||||
# Create Blueprint
|
||||
village_bp = Blueprint('village', __name__)
|
||||
|
||||
village = Village()
|
||||
|
||||
# ------------------------- Add Village -------------------------
|
||||
@village_bp.route('/add_village', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_village():
|
||||
|
||||
village = Village()
|
||||
# village = Village()
|
||||
|
||||
if request.method == 'POST':
|
||||
village.AddVillage(request=request)
|
||||
@@ -79,28 +79,40 @@ def get_blocks(district_id):
|
||||
@village_bp.route('/check_village', methods=['POST'])
|
||||
@login_required
|
||||
def check_village():
|
||||
village = Village()
|
||||
# village = Village()
|
||||
return village.CheckVillage(request=request)
|
||||
|
||||
|
||||
# ------------------------- Delete Village -------------------------
|
||||
@village_bp.route('/delete_village/<int:village_id>')
|
||||
@login_required
|
||||
def delete_village(village_id):
|
||||
|
||||
village = Village()
|
||||
# village = Village()
|
||||
village.DeleteVillage(request=request, village_id=village_id)
|
||||
|
||||
flash(village.resultMessage, "success" if village.isSuccess else "error")
|
||||
return redirect(url_for('village.add_village'))
|
||||
# ✅ Convert resultMessage to string if it's a Response or tuple
|
||||
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 -------------------------
|
||||
@village_bp.route('/edit_village/<int:village_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_village(village_id):
|
||||
|
||||
village = Village()
|
||||
# village = Village()
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
|
||||
4
main.py
4
main.py
@@ -16,7 +16,7 @@ from controllers.payment_controller import payment_bp
|
||||
from controllers.gst_release_controller import gst_release_bp
|
||||
from controllers.excel_upload_controller import excel_bp
|
||||
from controllers.report_controller import report_bp
|
||||
from controllers.pmc_report_controller import pmc_report_bp
|
||||
# from controllers.pmc_report_controller import pmc_report_bp
|
||||
|
||||
from controllers.hold_types_controller import hold_bp
|
||||
from dotenv import load_dotenv
|
||||
@@ -57,7 +57,7 @@ app.register_blueprint(payment_bp)
|
||||
app.register_blueprint(gst_release_bp)
|
||||
app.register_blueprint(excel_bp)
|
||||
app.register_blueprint(report_bp)
|
||||
app.register_blueprint(pmc_report_bp)
|
||||
# app.register_blueprint(pmc_report_bp)
|
||||
app.register_blueprint(hold_bp)
|
||||
|
||||
# ---------------- Run App ----------------
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
|
||||
|
||||
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
|
||||
from model.Log import LogData, LogHelper
|
||||
|
||||
import os
|
||||
import config
|
||||
import re
|
||||
|
||||
import mysql.connector
|
||||
from mysql.connector import Error
|
||||
|
||||
from model.ItemCRUD import ItemCRUD, itemCRUDMapping
|
||||
from model.ItemCRUD import ItemCRUD
|
||||
|
||||
|
||||
class Block:
|
||||
@@ -22,9 +12,7 @@ class Block:
|
||||
self.isSuccess = False
|
||||
self.resultMessage = ""
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Add Block
|
||||
# ----------------------------------------------------------
|
||||
def AddBlock(self, request):
|
||||
|
||||
block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
@@ -37,17 +25,7 @@ class Block:
|
||||
self.resultMessage = block.resultMessage
|
||||
return
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Get All Blocks
|
||||
# ----------------------------------------------------------
|
||||
# def GetAllBlocks(self):
|
||||
|
||||
# block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
# blocksdata = block.GetAllData(request=request, storedproc="GetAllBlock")
|
||||
# self.isSuccess = block.isSuccess
|
||||
# self.resultMessage = block.resultMessage
|
||||
# return blocksdata
|
||||
|
||||
# Get All Blocks
|
||||
def GetAllBlocks(self, request):
|
||||
|
||||
block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
@@ -57,18 +35,8 @@ class Block:
|
||||
self.resultMessage = block.resultMessage
|
||||
return blocksdata
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# Check Block Exists
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# def CheckBlock(self, request):
|
||||
# block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
# block_name = request.json.get('block_Name', '').strip()
|
||||
# district_id = request.json.get('district_Id')
|
||||
# result = block.CheckItem(request=request, parentid=district_id, childname=block_name, storedprocfetch="GetBlockByNameAndDistrict")
|
||||
# self.isSuccess = block.isSuccess
|
||||
# self.resultMessage = block.resultMessage
|
||||
# return result
|
||||
def CheckBlock(self, request):
|
||||
block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
data = request.get_json(silent=True) or request.form
|
||||
@@ -85,24 +53,7 @@ class Block:
|
||||
self.resultMessage = block.resultMessage
|
||||
return result
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Get Block By ID
|
||||
# ----------------------------------------------------------
|
||||
# def GetBlockByID(self, id):
|
||||
|
||||
# block = ItemCRUD(itemType=ItemCRUDType.Village)
|
||||
# blockdata = block.GetAllData(id=id,storedproc="GetBlockDataByID")
|
||||
# self.isSuccess = block.isSuccess
|
||||
# self.resultMessage = block.resultMessage
|
||||
# print("akash"+blockdata)
|
||||
# return blockdata
|
||||
|
||||
# def GetBlockByID(self,request,id):
|
||||
# block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
# blockdata = block.GetDataByID(request=request,id=id,storedproc="GetBlockDataByID")
|
||||
# self.isSuccess = block.isSuccess
|
||||
# self.resultMessage = block.resultMessage
|
||||
# return blockdata
|
||||
def GetBlockByID(self, id):
|
||||
|
||||
block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
@@ -116,20 +67,8 @@ class Block:
|
||||
self.resultMessage = block.resultMessage
|
||||
|
||||
return blockdata
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# Update Block
|
||||
# ----------------------------------------------------------
|
||||
# def EditBlock(self, request, block_id):
|
||||
|
||||
# block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
|
||||
# district_id = request.form.get('district_Id')
|
||||
# block_name = request.form.get('block_Name', '').strip()
|
||||
|
||||
# block.EditItem(request=request, childid=block_id, parentid=district_id, childname=block_name, storedprocadd="UpdateBlockById" )
|
||||
# self.isSuccess = block.isSuccess
|
||||
# self.resultMessage = block.resultMessage
|
||||
# return
|
||||
def EditBlock(self, request, block_id):
|
||||
|
||||
block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
@@ -149,9 +88,8 @@ class Block:
|
||||
self.resultMessage = block.resultMessage
|
||||
return
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Delete Block
|
||||
# ---------------------------------------------------------
|
||||
|
||||
# Delete Block
|
||||
def DeleteBlock(self,request, id):
|
||||
block = ItemCRUD(itemType=ItemCRUDType.Block)
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
|
||||
|
||||
|
||||
from mysql.connector import Error
|
||||
import config
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ContractorInfo:
|
||||
def __init__(self, contractor_id):
|
||||
|
||||
@@ -27,13 +27,27 @@ class FolderAndFile:
|
||||
os.makedirs(folder, exist_ok=True)
|
||||
return folder
|
||||
|
||||
# -----------------------------
|
||||
# FILE PATH METHODS
|
||||
# -----------------------------
|
||||
@staticmethod
|
||||
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
|
||||
def get_download_path(filename):
|
||||
return os.path.join(FolderAndFile.get_download_folder(), filename)
|
||||
|
||||
|
||||
# FILE PATH METHODS - upload file
|
||||
@staticmethod
|
||||
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)
|
||||
@@ -3,7 +3,6 @@ from model.ItemCRUD import ItemCRUD
|
||||
from model.Utilities import ItemCRUDType
|
||||
|
||||
class HoldTypes:
|
||||
"""CRUD operations for Hold Types using ItemCRUD"""
|
||||
|
||||
def __init__(self):
|
||||
self.isSuccess = False
|
||||
@@ -33,7 +32,7 @@ class HoldTypes:
|
||||
self.isSuccess = hold.isSuccess
|
||||
self.resultMessage = hold.resultMessage
|
||||
|
||||
# ✅ Convert tuple → dictionary
|
||||
# Convert tuple → dictionary
|
||||
data = []
|
||||
for row in rows:
|
||||
data.append({
|
||||
@@ -51,7 +50,7 @@ class HoldTypes:
|
||||
self.isSuccess = hold.isSuccess
|
||||
self.resultMessage = hold.resultMessage
|
||||
|
||||
# ✅ Convert tuple → dictionary
|
||||
# Convert tuple → dictionary
|
||||
if row:
|
||||
return {
|
||||
"hold_type_id": row[0],
|
||||
|
||||
100
model/Invoice.py
100
model/Invoice.py
@@ -66,27 +66,27 @@ def get_all_villages():
|
||||
return fetch_all(cursor)
|
||||
return execute_db_operation(operation)
|
||||
|
||||
|
||||
|
||||
# ------------------- Invoice Functions -------------------
|
||||
def insert_invoice(data, village_id):
|
||||
def operation(cursor):
|
||||
# Insert invoice
|
||||
cursor.callproc('InsertInvoice', [
|
||||
data.get('pmc_no'),
|
||||
village_id,
|
||||
data.get('work_type'),
|
||||
data.get('invoice_details'),
|
||||
data.get('invoice_date'),
|
||||
data.get('invoice_no'),
|
||||
*get_numeric_values(data)
|
||||
])
|
||||
invoice_row = fetch_one(cursor)
|
||||
if not invoice_row:
|
||||
raise Exception("Invoice ID not returned")
|
||||
invoice_id = invoice_row.get('invoice_id')
|
||||
# cursor.callproc('InsertInvoice', [
|
||||
# data.get('pmc_no'),
|
||||
# village_id,
|
||||
# data.get('work_type'),
|
||||
# data.get('invoice_details'),
|
||||
# data.get('invoice_date'),
|
||||
# data.get('invoice_no'),
|
||||
# *get_numeric_values(data),
|
||||
# data.get('subcontractor_id')
|
||||
|
||||
# Insert inpayment
|
||||
cursor.callproc('InsertInpayment', [
|
||||
# ])
|
||||
# invoice_row = fetch_one(cursor)
|
||||
# if not invoice_row:
|
||||
# raise Exception("Invoice ID not returned")
|
||||
# invoice_id = invoice_row.get('invoice_id')
|
||||
cursor.callproc('SaveInvoice', [
|
||||
data.get('pmc_no'),
|
||||
village_id,
|
||||
data.get('work_type'),
|
||||
@@ -94,9 +94,27 @@ def insert_invoice(data, village_id):
|
||||
data.get('invoice_date'),
|
||||
data.get('invoice_no'),
|
||||
*get_numeric_values(data),
|
||||
data.get('subcontractor_id')
|
||||
data.get('subcontractor_id'),
|
||||
0
|
||||
])
|
||||
clear_results(cursor)
|
||||
invoice_id = None
|
||||
for result in cursor.stored_results():
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
invoice_id = row['invoice_id']
|
||||
|
||||
# # Insert inpayment
|
||||
# cursor.callproc('InsertInpayment', [
|
||||
# data.get('pmc_no'),
|
||||
# village_id,
|
||||
# data.get('work_type'),
|
||||
# data.get('invoice_details'),
|
||||
# data.get('invoice_date'),
|
||||
# data.get('invoice_no'),
|
||||
# *get_numeric_values(data),
|
||||
# data.get('subcontractor_id')
|
||||
# ])
|
||||
# clear_results(cursor)
|
||||
return invoice_id
|
||||
|
||||
return execute_db_operation(operation)
|
||||
@@ -141,18 +159,18 @@ def update_invoice(data, invoice_id):
|
||||
clear_results(cursor)
|
||||
execute_db_operation(operation)
|
||||
|
||||
def update_inpayment(data):
|
||||
def operation(cursor):
|
||||
cursor.callproc('UpdateInpayment', [
|
||||
data.get('work_type'),
|
||||
data.get('invoice_details'),
|
||||
data.get('invoice_date'),
|
||||
*get_numeric_values(data),
|
||||
data.get('pmc_no'),
|
||||
data.get('invoice_no')
|
||||
])
|
||||
clear_results(cursor)
|
||||
execute_db_operation(operation)
|
||||
# def update_inpayment(data):
|
||||
# def operation(cursor):
|
||||
# cursor.callproc('UpdateInpayment', [
|
||||
# data.get('work_type'),
|
||||
# data.get('invoice_details'),
|
||||
# data.get('invoice_date'),
|
||||
# *get_numeric_values(data),
|
||||
# data.get('pmc_no'),
|
||||
# data.get('invoice_no')
|
||||
# ])
|
||||
# clear_results(cursor)
|
||||
# execute_db_operation(operation)
|
||||
|
||||
def delete_invoice_data(invoice_id, user_id):
|
||||
def operation(cursor):
|
||||
@@ -173,22 +191,22 @@ def delete_invoice_data(invoice_id, user_id):
|
||||
clear_results(cursor)
|
||||
|
||||
# Delete inpayment
|
||||
cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
|
||||
clear_results(cursor)
|
||||
# cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
|
||||
# clear_results(cursor)
|
||||
|
||||
execute_db_operation(operation)
|
||||
|
||||
|
||||
# ------------------- Subcontractor Functions -------------------
|
||||
def assign_subcontractor(data, village_id):
|
||||
def operation(cursor):
|
||||
cursor.callproc('AssignSubcontractor', [
|
||||
data.get('pmc_no'),
|
||||
data.get('subcontractor_id'),
|
||||
village_id
|
||||
])
|
||||
clear_results(cursor)
|
||||
execute_db_operation(operation)
|
||||
# def assign_subcontractor(data, village_id):
|
||||
# def operation(cursor):
|
||||
# cursor.callproc('AssignSubcontractor', [
|
||||
# data.get('pmc_no'),
|
||||
# data.get('subcontractor_id'),
|
||||
# village_id
|
||||
# ])
|
||||
# clear_results(cursor)
|
||||
# execute_db_operation(operation)
|
||||
|
||||
|
||||
# ------------------- Hold Types Functions -------------------
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
from flask_login import current_user
|
||||
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
|
||||
from model.Log import LogHelper
|
||||
@@ -9,7 +6,6 @@ import config
|
||||
import re
|
||||
import mysql.connector
|
||||
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Mapping Class
|
||||
# ----------------------------------------------------------
|
||||
@@ -26,10 +22,11 @@ class itemCRUDMapping:
|
||||
self.name = "Hold Type"
|
||||
elif itemType is ItemCRUDType.Subcontractor:
|
||||
self.name = "Subcontractor"
|
||||
elif itemType.name == "GSTRelease":
|
||||
self.name = "GSTRelease"
|
||||
else:
|
||||
self.name = "Item"
|
||||
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# Generic CRUD Class
|
||||
# ----------------------------------------------------------
|
||||
@@ -38,7 +35,6 @@ class ItemCRUD:
|
||||
def __init__(self, itemType):
|
||||
self.isSuccess = False
|
||||
self.resultMessage = ""
|
||||
self.response = {} # ✅ ADDED
|
||||
self.itemCRUDType = itemType
|
||||
self.itemCRUDMapping = itemCRUDMapping(itemType)
|
||||
|
||||
@@ -60,14 +56,16 @@ class ItemCRUD:
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.response = ResponseHandler.delete_success(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.delete_success(self.itemCRUDMapping.name), 200
|
||||
)
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error deleting {self.itemCRUDMapping.name}: {e}")
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.delete_failure(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.delete_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
@@ -81,8 +79,9 @@ class ItemCRUD:
|
||||
connection = config.get_db_connection()
|
||||
if not connection:
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.add_failure(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.db_connection_failure(), 500
|
||||
)
|
||||
return
|
||||
|
||||
cursor = connection.cursor()
|
||||
@@ -93,18 +92,57 @@ class ItemCRUD:
|
||||
)
|
||||
|
||||
try:
|
||||
# SUBCONTRACTOR
|
||||
if data:
|
||||
cursor.callproc(storedprocfetch, (data['Contractor_Name'],))
|
||||
# ======================================================
|
||||
# GSTRelease MULTI-FIELD
|
||||
# ======================================================
|
||||
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:
|
||||
|
||||
cursor.callproc(storedprocfetch, (data['Contractor_Name'],))
|
||||
existing_item = None
|
||||
for rs in cursor.stored_results():
|
||||
existing_item = rs.fetchone()
|
||||
|
||||
if existing_item:
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.already_exists(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
|
||||
)
|
||||
return
|
||||
|
||||
cursor.callproc(storedprocadd, (
|
||||
@@ -118,19 +156,22 @@ class ItemCRUD:
|
||||
data['GST_No'],
|
||||
data['Contractor_password']
|
||||
))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.response = ResponseHandler.add_success(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
# NORMAL
|
||||
if not re.match(RegEx.patternAlphabetOnly, childname):
|
||||
# ======================================================
|
||||
# NORMAL SINGLE-FIELD (Village / Block / State)
|
||||
# ======================================================
|
||||
if not re.match(RegEx.allPattern, childname):
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.invalid_name(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
|
||||
)
|
||||
return
|
||||
|
||||
if parentid is None:
|
||||
@@ -144,8 +185,9 @@ class ItemCRUD:
|
||||
|
||||
if existing_item:
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.already_exists(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
|
||||
)
|
||||
return
|
||||
|
||||
if parentid is None:
|
||||
@@ -154,16 +196,17 @@ class ItemCRUD:
|
||||
cursor.callproc(storedprocadd, (childname, parentid))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.response = ResponseHandler.add_success(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
|
||||
)
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Database Error: {e}")
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.add_failure(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.add_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
@@ -183,7 +226,33 @@ class ItemCRUD:
|
||||
)
|
||||
|
||||
try:
|
||||
if data:
|
||||
# ======================================================
|
||||
# GSTRelease MULTI-FIELD
|
||||
# ======================================================
|
||||
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, (
|
||||
childid,
|
||||
data['Contractor_Name'],
|
||||
@@ -196,18 +265,19 @@ class ItemCRUD:
|
||||
data['GST_No'],
|
||||
data['Contractor_password']
|
||||
))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.response = ResponseHandler.update_success(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.update_success(self.itemCRUDMapping.name), 200
|
||||
)
|
||||
return
|
||||
|
||||
if not re.match(RegEx.patternAlphabetOnly, childname):
|
||||
# ======================================================
|
||||
# NORMAL SINGLE-FIELD
|
||||
# ======================================================
|
||||
if not re.match(RegEx.allPattern, childname):
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.update_failure(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
|
||||
return
|
||||
|
||||
if parentid is None:
|
||||
@@ -216,16 +286,15 @@ class ItemCRUD:
|
||||
cursor.callproc(storedprocupdate, (childid, parentid, childname))
|
||||
|
||||
connection.commit()
|
||||
|
||||
self.isSuccess = True
|
||||
self.response = ResponseHandler.update_success(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message']
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error updating {self.itemCRUDMapping.name}: {e}")
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.update_failure(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.update_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
@@ -238,27 +307,22 @@ class ItemCRUD:
|
||||
|
||||
data = []
|
||||
connection = config.get_db_connection()
|
||||
|
||||
if not connection:
|
||||
return []
|
||||
|
||||
cursor = connection.cursor()
|
||||
|
||||
try:
|
||||
cursor.callproc(storedproc)
|
||||
|
||||
for result in cursor.stored_results():
|
||||
data = result.fetchall()
|
||||
|
||||
self.isSuccess = True
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
|
||||
self.isSuccess = False
|
||||
self.response = ResponseHandler.fetch_failure(self.itemCRUDMapping.name)
|
||||
self.resultMessage = self.response["message"]
|
||||
self.resultMessage = HtmlHelper.json_response(
|
||||
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
return []
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
@@ -276,13 +340,10 @@ class ItemCRUD:
|
||||
|
||||
try:
|
||||
cursor.callproc(storedproc, (id,))
|
||||
|
||||
for rs in cursor.stored_results():
|
||||
data = rs.fetchone()
|
||||
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
@@ -290,7 +351,7 @@ class ItemCRUD:
|
||||
return data
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# CHECK ITEM (KEEP AS IS - API USE)
|
||||
# CHECK ITEM
|
||||
# ----------------------------------------------------------
|
||||
def CheckItem(self, request, parentid, childname, storedprocfetch):
|
||||
|
||||
@@ -302,7 +363,7 @@ class ItemCRUD:
|
||||
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(
|
||||
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
|
||||
)
|
||||
@@ -331,7 +392,6 @@ class ItemCRUD:
|
||||
return HtmlHelper.json_response(
|
||||
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
|
||||
)
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
119
model/Log.py
119
model/Log.py
@@ -1,29 +1,40 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
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:
|
||||
@staticmethod
|
||||
def log_action(action, details=""):
|
||||
"""Add a log entry."""
|
||||
log_data = LogData()
|
||||
log_data.add_log(action, details)
|
||||
|
||||
"""Log user actions with timestamp, user, action, and details."""
|
||||
logData = LogData()
|
||||
logData.WriteLog(action, details="")
|
||||
|
||||
class LogData:
|
||||
filepath = ""
|
||||
timestamp = None
|
||||
|
||||
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.user = getattr(current_user, "cn", None) \
|
||||
or getattr(current_user, "username", None) \
|
||||
or getattr(current_user, "sAMAccountName", "Unknown")
|
||||
self.user = LogData.get_current_user()
|
||||
|
||||
|
||||
def add_log(self, action, details=""):
|
||||
"""Create/Add a log entry."""
|
||||
@staticmethod
|
||||
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:
|
||||
f.write(
|
||||
f"Timestamp: {self.timestamp} | "
|
||||
@@ -32,73 +43,41 @@ class LogData:
|
||||
f"Details: {details}\n"
|
||||
)
|
||||
|
||||
def get_all_logs(self):
|
||||
"""Read all logs."""
|
||||
def GetActivitiesLog(self):
|
||||
logs = []
|
||||
|
||||
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:
|
||||
parts = line.strip().split(" | ")
|
||||
if len(parts) == 4:
|
||||
logs.append({
|
||||
"timestamp": parts[0].split(":", 1)[1].strip(),
|
||||
"user": parts[1].split(":", 1)[1].strip(),
|
||||
"action": parts[2].split(":", 1)[1].strip(),
|
||||
"details": parts[3].split(":", 1)[1].strip()
|
||||
"timestamp": parts[0].replace("Timestamp:", "").strip(),
|
||||
"user": parts[1].replace("User:", "").strip(),
|
||||
"action": parts[2].replace("Action:", "").strip(),
|
||||
"details": parts[3].replace("Details:", "").strip()
|
||||
})
|
||||
return logs
|
||||
|
||||
def get_filtered_logs(self, start_date=None, end_date=None, user_name=None):
|
||||
"""Filter logs by date and/or user."""
|
||||
logs = self.get_all_logs()
|
||||
def GetFilteredActivitiesLog(self, startDate, endDate, userName):
|
||||
filtered_logs = self.GetActivitiesLog()
|
||||
|
||||
# Filter by date
|
||||
if start_date or end_date:
|
||||
start_dt = datetime.strptime(start_date, "%Y-%m-%d") if start_date else datetime.min
|
||||
end_dt = datetime.strptime(end_date, "%Y-%m-%d") if end_date else datetime.max
|
||||
logs = [
|
||||
log for log in logs
|
||||
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
|
||||
]
|
||||
# Date filter
|
||||
if startDate or endDate:
|
||||
try:
|
||||
start_dt = datetime.strptime(startDate, "%Y-%m-%d") if startDate else datetime.min
|
||||
end_dt = datetime.strptime(endDate, "%Y-%m-%d") if endDate else datetime.max
|
||||
|
||||
# Filter by username
|
||||
if user_name:
|
||||
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"
|
||||
)
|
||||
filtered_logs = [
|
||||
log for log in filtered_logs
|
||||
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
|
||||
]
|
||||
|
||||
except Exception as e:
|
||||
print("Date filter error:", e)
|
||||
|
||||
# Username filter
|
||||
if userName:
|
||||
filtered_logs = [log for log in filtered_logs if userName.lower() in log["user"].lower()]
|
||||
|
||||
return filtered_logs
|
||||
@@ -1,456 +1,137 @@
|
||||
import openpyxl
|
||||
from openpyxl.styles import Font, PatternFill
|
||||
import config
|
||||
from flask_login import current_user
|
||||
from model.Log import LogHelper
|
||||
|
||||
from model.Report import ReportHelper
|
||||
from services.Generalservice import GeneralUse
|
||||
from model.FolderAndFile import FolderAndFile
|
||||
from model.Report import ReportHelper
|
||||
|
||||
class PmcReport:
|
||||
data=[]
|
||||
|
||||
@staticmethod
|
||||
def get_pmc_report(pmc_no):
|
||||
# @staticmethod
|
||||
# def get_pmc_report(pmc_no):
|
||||
|
||||
connection = config.get_db_connection()
|
||||
cursor = connection.cursor(dictionary=True, buffered=True)
|
||||
# connection = config.get_db_connection()
|
||||
# cursor = connection.cursor(dictionary=True, buffered=True)
|
||||
|
||||
try:
|
||||
# try:
|
||||
# pmc_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
|
||||
# cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"]))
|
||||
# hold_types = next(cursor.stored_results()).fetchall()
|
||||
|
||||
# cursor.callproc("GetContractorInfoByPmcNo", (pmc_no,))
|
||||
# pmc_info = next(cursor.stored_results()).fetchone()
|
||||
pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
|
||||
# # Extract hold_type_ids
|
||||
# hold_type_ids = [ht['hold_type_id'] for ht in hold_types]
|
||||
|
||||
if not pmc_info:
|
||||
return None
|
||||
# invoices = []
|
||||
# hold_type_ids_str = ",".join(map(str, hold_type_ids))
|
||||
# cursor.callproc('GetInvoices_WithHold',[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str])
|
||||
# for result in cursor.stored_results():
|
||||
# invoices = result.fetchall()
|
||||
|
||||
cursor.callproc("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"]))
|
||||
hold_types = next(cursor.stored_results()).fetchall()
|
||||
|
||||
# Extract hold_type_ids
|
||||
hold_type_ids = [ht['hold_type_id'] for ht in hold_types]
|
||||
|
||||
invoices = []
|
||||
hold_amount_total = 0
|
||||
if hold_type_ids:
|
||||
hold_type_ids_str = ",".join(map(str, hold_type_ids))
|
||||
cursor.callproc(
|
||||
'GetInvoices_WithHold',
|
||||
[pmc_no, pmc_info["Contractor_Id"], hold_type_ids_str]
|
||||
)
|
||||
else:
|
||||
cursor.callproc(
|
||||
'GetInvoices_NoHold',
|
||||
[pmc_no, pmc_info["Contractor_Id"]]
|
||||
)
|
||||
for result in cursor.stored_results():
|
||||
invoices = result.fetchall()
|
||||
|
||||
if hold_type_ids:
|
||||
hold_amount_total = sum(row.get('hold_amount', 0) or 0 for row in invoices)
|
||||
|
||||
total_invo_final = sum(row.get('Final_Amount', 0) or 0 for row in invoices)
|
||||
|
||||
|
||||
# GST RELEASE
|
||||
# cursor.callproc('GetGSTReleaseByPMC', [pmc_no])
|
||||
# gst_rel = []
|
||||
# for result in cursor.stored_results():
|
||||
# gst_rel = result.fetchall()
|
||||
# gst_rel = GeneralUse.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
|
||||
|
||||
# hold_release = GeneralUse.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
|
||||
|
||||
gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
|
||||
# credit_note = GeneralUse.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
|
||||
|
||||
total_gst_basic = sum(row.get('basic_amount', 0) or 0 for row in gst_rel)
|
||||
total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel)
|
||||
# payments = GeneralUse.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
|
||||
|
||||
# totals = {
|
||||
# "sum_invo_basic_amt": sum(row.get('Basic_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_debit_amt": sum(row.get('Debit_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_after_debit_amt": sum(row.get('After_Debit_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_amt": sum(row.get('Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_gst_amt": sum(row.get('GST_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_tds_amt": sum(row.get('TDS_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_ds_amt": sum(row.get('SD_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_on_commission": sum(row.get('On_Commission', 0) or 0 for row in invoices),
|
||||
# "sum_invo_hydro_test": sum(row.get('Hydro_Testing', 0) or 0 for row in invoices),
|
||||
# "sum_invo_gst_sd_amt": sum(row.get('GST_SD_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_final_amt": sum(row.get('Final_Amount', 0) or 0 for row in invoices),
|
||||
# "sum_invo_hold_amt": sum(row.get('hold_amount', 0) or 0 for row in invoices),
|
||||
# "sum_gst_basic_amt": sum(row.get('basic_amount', 0) or 0 for row in gst_rel),
|
||||
# "sum_gst_final_amt": sum(row.get('final_amount', 0) or 0 for row in gst_rel),
|
||||
# "sum_pay_payment_amt": sum(row.get('Payment_Amount', 0) or 0 for row in payments),
|
||||
# "sum_pay_tds_payment_amt": sum(row.get('TDS_Payment_Amount', 0) or 0 for row in payments),
|
||||
# "sum_pay_total_amt": sum(row.get('Total_amount', 0) or 0 for row in payments)
|
||||
# }
|
||||
|
||||
# ---------------- HOLD RELEASE ----------------
|
||||
# cursor.callproc('GetHoldReleaseByPMC', [pmc_no])
|
||||
# hold_release = []
|
||||
# for result in cursor.stored_results():
|
||||
# hold_release = result.fetchall()
|
||||
# return {
|
||||
# "info": pmc_info,
|
||||
# "invoices": invoices,
|
||||
# "hold_types": hold_types,
|
||||
# "gst_rel": gst_rel,
|
||||
# "payments": payments,
|
||||
# "credit_note": credit_note,
|
||||
# "hold_release": hold_release,
|
||||
# "total": totals
|
||||
# }
|
||||
|
||||
hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
|
||||
# finally:
|
||||
# cursor.close()
|
||||
# connection.close()
|
||||
|
||||
# ---------------- CREDIT NOTE ----------------
|
||||
# cursor.callproc('GetCreditNoteByPMC', [pmc_no])
|
||||
# credit_note = []
|
||||
# for result in cursor.stored_results():
|
||||
# credit_note = result.fetchall()
|
||||
|
||||
credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
|
||||
|
||||
payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
|
||||
|
||||
|
||||
# ---------------- PAYMENTS ----------------
|
||||
# cursor.callproc('GetPaymentsByPMC', [pmc_no])
|
||||
# payments = []
|
||||
# for result in cursor.stored_results():
|
||||
# payments = result.fetchall()
|
||||
|
||||
|
||||
|
||||
total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments)
|
||||
total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments)
|
||||
|
||||
totals = {
|
||||
"sum_invo_basic_amt": sum(row.get('Basic_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_debit_amt": sum(row.get('Debit_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_after_debit_amt": sum(row.get('After_Debit_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_amt": sum(row.get('Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_gst_amt": sum(row.get('GST_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_tds_amt": sum(row.get('TDS_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_ds_amt": sum(row.get('SD_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_on_commission": sum(row.get('On_Commission', 0) or 0 for row in invoices),
|
||||
"sum_invo_hydro_test": sum(row.get('Hydro_Testing', 0) or 0 for row in invoices),
|
||||
"sum_invo_gst_sd_amt": sum(row.get('GST_SD_Amount', 0) or 0 for row in invoices),
|
||||
"sum_invo_final_amt": total_invo_final,
|
||||
"sum_invo_hold_amt": hold_amount_total,
|
||||
"sum_gst_basic_amt": total_gst_basic,
|
||||
"sum_gst_final_amt": total_gst_final,
|
||||
"sum_pay_payment_amt": total_pay_amount,
|
||||
"sum_pay_tds_payment_amt": sum(row.get('TDS_Payment_Amount', 0) or 0 for row in payments),
|
||||
"sum_pay_total_amt": total_pay_total
|
||||
}
|
||||
|
||||
return {
|
||||
"info": pmc_info,
|
||||
"invoices": invoices,
|
||||
"hold_types": hold_types,
|
||||
"gst_rel": gst_rel,
|
||||
"payments": payments,
|
||||
"credit_note": credit_note,
|
||||
"hold_release": hold_release,
|
||||
"total": totals
|
||||
}
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def download_pmc_report(pmc_no):
|
||||
|
||||
connection = config.get_db_connection()
|
||||
if not connection:
|
||||
return None
|
||||
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
# filename
|
||||
filename = f"PMC_Report_{pmc_no}.xlsx"
|
||||
|
||||
output_folder = FolderAndFile.get_download_folder()
|
||||
output_file = FolderAndFile.get_download_path(filename)
|
||||
|
||||
# ================= DATA FETCH =================
|
||||
|
||||
contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no], "one")
|
||||
|
||||
if not contractor_info:
|
||||
return None
|
||||
|
||||
hold_types = ReportHelper.execute_sp(cursor, 'GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
|
||||
|
||||
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
|
||||
|
||||
invoices = ReportHelper.execute_sp(cursor, 'GetInvoicesAndGstReleaseByPmcNo', [pmc_no])
|
||||
|
||||
credit_notes = ReportHelper.execute_sp(cursor, 'GetCreditNoteByContractor', [contractor_info["Contractor_Id"]])
|
||||
|
||||
hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
|
||||
|
||||
all_payments = ReportHelper.execute_sp(cursor, 'GetAllPaymentsByPMC', [pmc_no])
|
||||
|
||||
gst_releases = ReportHelper.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no])
|
||||
|
||||
# ================= DATA MAPPING =================
|
||||
|
||||
hold_data = {}
|
||||
for h in hold_amounts:
|
||||
hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
|
||||
|
||||
payments_map = {}
|
||||
for pay in all_payments:
|
||||
if pay['invoice_no']:
|
||||
payments_map.setdefault(pay['invoice_no'], []).append(pay)
|
||||
|
||||
# ================= LOG =================
|
||||
LogHelper.log_action(
|
||||
"Download PMC Report",
|
||||
f"User {current_user.id} Download PMC Report '{pmc_no}'"
|
||||
)
|
||||
|
||||
# ================= EXCEL =================
|
||||
workbook = openpyxl.Workbook()
|
||||
sheet = workbook.active
|
||||
sheet.title = "PMC Report"
|
||||
|
||||
# HEADER INFO
|
||||
sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."])
|
||||
sheet.append(["Contractor Name", contractor_info["Contractor_Name"]])
|
||||
sheet.append(["State", contractor_info["State_Name"]])
|
||||
sheet.append(["District", contractor_info["District_Name"]])
|
||||
sheet.append(["Block", contractor_info["Block_Name"]])
|
||||
sheet.append([])
|
||||
|
||||
base_headers = [
|
||||
"PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No",
|
||||
"Basic Amount","Debit","After Debit Amount","GST","Amount","TDS",
|
||||
"SD","On Commission","Hydro Testing","GST SD Amount"
|
||||
]
|
||||
|
||||
hold_headers = [ht['hold_type'] for ht in hold_types]
|
||||
|
||||
payment_headers = [
|
||||
"Final Amount","Payment Amount","TDS Payment","Total Paid","UTR"
|
||||
]
|
||||
|
||||
headers = base_headers + hold_headers + payment_headers
|
||||
sheet.append(headers)
|
||||
|
||||
# STYLE
|
||||
for cell in sheet[sheet.max_row]:
|
||||
cell.font = Font(bold=True)
|
||||
|
||||
# DATA
|
||||
seen_invoices = set()
|
||||
|
||||
for inv in invoices:
|
||||
|
||||
invoice_no = inv["Invoice_No"]
|
||||
payments = payments_map.get(invoice_no, [])
|
||||
|
||||
if invoice_no in seen_invoices:
|
||||
continue
|
||||
|
||||
seen_invoices.add(invoice_no)
|
||||
|
||||
first_payment = payments[0] if payments else None
|
||||
|
||||
row = [
|
||||
pmc_no,
|
||||
inv["Village_Name"],
|
||||
inv["Work_Type"],
|
||||
inv["Invoice_Details"],
|
||||
inv["Invoice_Date"],
|
||||
invoice_no,
|
||||
inv["Basic_Amount"],
|
||||
inv["Debit_Amount"],
|
||||
inv["After_Debit_Amount"],
|
||||
inv["GST_Amount"],
|
||||
inv["Amount"],
|
||||
inv["TDS_Amount"],
|
||||
inv["SD_Amount"],
|
||||
inv["On_Commission"],
|
||||
inv["Hydro_Testing"],
|
||||
inv["GST_SD_Amount"]
|
||||
]
|
||||
|
||||
# HOLD DATA
|
||||
invoice_holds = hold_data.get(inv["Invoice_Id"], {})
|
||||
for ht_id in hold_type_map.keys():
|
||||
row.append(invoice_holds.get(ht_id, ""))
|
||||
|
||||
# PAYMENT DATA
|
||||
row += [
|
||||
inv["Final_Amount"],
|
||||
first_payment["Payment_Amount"] if first_payment else "",
|
||||
first_payment["TDS_Payment_Amount"] if first_payment else "",
|
||||
first_payment["Total_amount"] if first_payment else "",
|
||||
first_payment["UTR"] if first_payment else ""
|
||||
]
|
||||
|
||||
sheet.append(row)
|
||||
|
||||
# AUTO WIDTH
|
||||
for col in sheet.columns:
|
||||
max_len = max((len(str(cell.value)) for cell in col if cell.value), default=0)
|
||||
sheet.column_dimensions[col[0].column_letter].width = max_len + 2
|
||||
|
||||
# SAVE
|
||||
workbook.save(output_file)
|
||||
workbook.close()
|
||||
|
||||
return output_folder, filename
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error generating PMC report: {e}")
|
||||
return None
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
# @staticmethod
|
||||
# def download_pmc_report(pmc_no):
|
||||
|
||||
# connection = config.get_db_connection()
|
||||
# if not connection:
|
||||
# return None
|
||||
|
||||
# cursor = connection.cursor(dictionary=True)
|
||||
|
||||
# # output_folder = "static/download"
|
||||
# # output_file = os.path.join(output_folder, f"PMC_Report_{pmc_no}.xlsx")
|
||||
# output_folder = FolderAndFile.get_download_folder
|
||||
# filename = f"PMC_Report_{pmc_no}.xlsx"
|
||||
# output_file = FolderAndFile.get_download_path(filename)
|
||||
|
||||
# try:
|
||||
# filename = f"PMC_Report_{pmc_no}.xlsx"
|
||||
|
||||
# cursor.callproc('GetContractorDetailsByPMC', [pmc_no])
|
||||
# contractor_info = next(cursor.stored_results()).fetchone()
|
||||
# output_folder = FolderAndFile.get_download_folder()
|
||||
# output_file = FolderAndFile.get_download_path(filename)
|
||||
|
||||
# contractor_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no])
|
||||
|
||||
# contractor_info = contractor_info[0] if contractor_info else None
|
||||
# print("contractor_info:::",contractor_info)
|
||||
|
||||
# if not contractor_info:
|
||||
# return None
|
||||
|
||||
# cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]])
|
||||
# hold_types = next(cursor.stored_results()).fetchall()
|
||||
# hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor',[contractor_info["Contractor_Id"]])
|
||||
|
||||
# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
|
||||
|
||||
# cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no])
|
||||
# invoices = next(cursor.stored_results()).fetchall()
|
||||
|
||||
# cursor.callproc('GetCreditNoteByContractor',[contractor_info["Contractor_Id"]])
|
||||
|
||||
# credit_notes = []
|
||||
# for result in cursor.stored_results():
|
||||
# credit_notes = result.fetchall()
|
||||
# invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None,pmc_no])
|
||||
|
||||
# credit_notes = GeneralUse.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no])
|
||||
# credit_note_map = {}
|
||||
# for cn in credit_notes:
|
||||
# key = (cn["PMC_No"], cn["Invoice_No"])
|
||||
|
||||
# key = (str(cn['PMC_No']).strip())
|
||||
# credit_note_map.setdefault(key, []).append(cn)
|
||||
|
||||
# cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
|
||||
# hold_amounts = next(cursor.stored_results()).fetchall()
|
||||
# hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
|
||||
|
||||
# gst_releases = GeneralUse.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no])
|
||||
# gst_release_map = {}
|
||||
# for gr in gst_releases:
|
||||
# key = (str(gr['PMC_No']).strip())
|
||||
# gst_release_map.setdefault(key, []).append(gr)
|
||||
|
||||
# # ================= DATA MAPPING =================
|
||||
# hold_data = {}
|
||||
# for h in hold_amounts:
|
||||
# hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
|
||||
|
||||
# cursor.callproc('GetAllPaymentsByPMC', [pmc_no])
|
||||
# all_payments = next(cursor.stored_results()).fetchall()
|
||||
|
||||
# payments_map = {}
|
||||
# extra_payments = []
|
||||
|
||||
# for pay in all_payments:
|
||||
# if pay['invoice_no']:
|
||||
# payments_map.setdefault(pay['invoice_no'], []).append(pay)
|
||||
# else:
|
||||
# extra_payments.append(pay)
|
||||
|
||||
# # ---------------- GST RELEASE DETAILS ----------------
|
||||
# cursor.callproc('GetGSTReleaseDetailsByPMC', [pmc_no])
|
||||
|
||||
# gst_releases = []
|
||||
# for result in cursor.stored_results():
|
||||
# gst_releases = result.fetchall()
|
||||
|
||||
# gst_release_map = {}
|
||||
|
||||
# for gr in gst_releases:
|
||||
|
||||
# invoice_nos = []
|
||||
|
||||
# if gr['Invoice_No']:
|
||||
|
||||
# cleaned = gr['Invoice_No'].replace(' ', '')
|
||||
|
||||
# if '&' in cleaned:
|
||||
# invoice_nos = cleaned.split('&')
|
||||
|
||||
# elif ',' in cleaned:
|
||||
# invoice_nos = cleaned.split(',')
|
||||
|
||||
# else:
|
||||
# invoice_nos = [cleaned]
|
||||
|
||||
# for inv_no in invoice_nos:
|
||||
# gst_release_map.setdefault(inv_no, []).append(gr)
|
||||
|
||||
# LogHelper.log_action(
|
||||
# "Download PMC Report",
|
||||
# f"User {current_user.id} Download PMC Report '{pmc_no}'"
|
||||
# )
|
||||
|
||||
# workbook = openpyxl.Workbook()
|
||||
# sheet = workbook.active
|
||||
# sheet.title = "PMC Report"
|
||||
|
||||
# sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."])
|
||||
# sheet.append(["Contractor Name", contractor_info["Contractor_Name"], "", "GST No", contractor_info["GST_No"], "", "GST Type", contractor_info["GST_Registration_Type"]])
|
||||
# sheet.append(["State", contractor_info["State_Name"], "", "PAN No", contractor_info["PAN_No"], "", "Address", contractor_info["Address"]])
|
||||
# sheet.append(["District", contractor_info["District_Name"], "", "Mobile No", contractor_info["Mobile_No"]])
|
||||
# sheet.append(["Block", contractor_info["Block_Name"], "", "Email", contractor_info["Email"]])
|
||||
# sheet.append([])
|
||||
|
||||
# base_headers = [
|
||||
# "PMC No","Village","Work Type","Invoice Details","Invoice Date","Invoice No",
|
||||
# "Basic Amount","Debit","After Debit Amount","GST (18%)","Amount","TDS (1%)",
|
||||
# "SD (5%)","On Commission","Hydro Testing","GST SD Amount"
|
||||
# ]
|
||||
|
||||
# hold_headers = [ht['hold_type'] for ht in hold_types]
|
||||
|
||||
# payment_headers = [
|
||||
# "Final Amount","Payment Amount","TDS Payment","Total Paid","UTR"
|
||||
# ]
|
||||
|
||||
# sheet.append(base_headers + hold_headers + payment_headers)
|
||||
|
||||
# header_fill = PatternFill(start_color="ADD8E6",end_color="ADD8E6",fill_type="solid")
|
||||
# header_font = Font(bold=True)
|
||||
|
||||
# for cell in sheet[sheet.max_row]:
|
||||
# cell.font = header_font
|
||||
# cell.fill = header_fill
|
||||
|
||||
# seen_invoices = set()
|
||||
# processed_payments = set()
|
||||
|
||||
# for inv in invoices:
|
||||
|
||||
# invoice_no = inv["Invoice_No"]
|
||||
# payments = payments_map.get(invoice_no, [])
|
||||
|
||||
# if invoice_no not in seen_invoices:
|
||||
|
||||
# seen_invoices.add(invoice_no)
|
||||
# first_payment = payments[0] if payments else None
|
||||
|
||||
# row = [
|
||||
# pmc_no, inv["Village_Name"], inv["Work_Type"],
|
||||
# inv["Invoice_Details"], inv["Invoice_Date"], invoice_no,
|
||||
# inv["Basic_Amount"], inv["Debit_Amount"],
|
||||
# inv["After_Debit_Amount"], inv["GST_Amount"],
|
||||
# inv["Amount"], inv["TDS_Amount"], inv["SD_Amount"],
|
||||
# inv["On_Commission"], inv["Hydro_Testing"], inv["GST_SD_Amount"]
|
||||
# ]
|
||||
|
||||
# invoice_holds = hold_data.get(inv["Invoice_Id"], {})
|
||||
|
||||
# for ht_id in hold_type_map.keys():
|
||||
# row.append(invoice_holds.get(ht_id, ""))
|
||||
|
||||
# row += [
|
||||
# inv["Final_Amount"],
|
||||
# first_payment["Payment_Amount"] if first_payment else "",
|
||||
# first_payment["TDS_Payment_Amount"] if first_payment else "",
|
||||
# first_payment["Total_amount"] if first_payment else "",
|
||||
# first_payment["UTR"] if first_payment else ""
|
||||
# ]
|
||||
|
||||
# sheet.append(row)
|
||||
|
||||
# workbook.save(output_file)
|
||||
# workbook.close()
|
||||
# # ================= LOG =================
|
||||
# LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'")
|
||||
|
||||
# ReportHelper.generate_excel(
|
||||
# 0, contractor_info, invoices, hold_types, hold_data,
|
||||
# credit_note_map,gst_release_map, output_file)
|
||||
|
||||
# return output_folder, filename
|
||||
|
||||
# finally:
|
||||
|
||||
# cursor.close()
|
||||
# connection.close()
|
||||
# connection.close()
|
||||
|
||||
|
||||
335
model/Report.py
335
model/Report.py
@@ -2,9 +2,10 @@ import config
|
||||
from datetime import datetime
|
||||
from flask import send_file
|
||||
import openpyxl
|
||||
from openpyxl.styles import Font
|
||||
from openpyxl.styles import Font, PatternFill
|
||||
|
||||
from model.FolderAndFile import FolderAndFile
|
||||
from services.Generalservice import GeneralUse
|
||||
|
||||
class ReportHelper:
|
||||
isSuccess = False
|
||||
@@ -16,30 +17,6 @@ class ReportHelper:
|
||||
self.resultMessage = ""
|
||||
self.data = []
|
||||
|
||||
@staticmethod
|
||||
def execute_sp(cursor, proc_name, params=[], fetch_one=False):
|
||||
cursor.callproc(proc_name, params)
|
||||
return (
|
||||
ReportHelper.fetch_one_result(cursor)
|
||||
if fetch_one else
|
||||
ReportHelper.fetch_all_results(cursor)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def fetch_all_results(cursor):
|
||||
data = []
|
||||
for result in cursor.stored_results():
|
||||
data = result.fetchall()
|
||||
return data
|
||||
|
||||
|
||||
@staticmethod
|
||||
def fetch_one_result(cursor):
|
||||
data = None
|
||||
for result in cursor.stored_results():
|
||||
data = result.fetchone()
|
||||
return data
|
||||
|
||||
|
||||
@staticmethod
|
||||
def search_contractor(request):
|
||||
@@ -59,10 +36,7 @@ class ReportHelper:
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
try:
|
||||
data = ReportHelper.execute_sp(
|
||||
cursor,
|
||||
"search_contractor_info",
|
||||
[
|
||||
data = GeneralUse.execute_sp(cursor,"search_contractor_info",[
|
||||
subcontractor_name or None,
|
||||
pmc_no or None,
|
||||
state or None,
|
||||
@@ -71,8 +45,7 @@ class ReportHelper:
|
||||
village or None,
|
||||
year_from or None,
|
||||
year_to or None
|
||||
]
|
||||
)
|
||||
])
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in search_contractor: {e}")
|
||||
@@ -84,192 +57,156 @@ class ReportHelper:
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_contractor_report(contractor_id):
|
||||
connection = config.get_db_connection()
|
||||
cursor = connection.cursor(dictionary=True, buffered=True)
|
||||
|
||||
try:
|
||||
# Contractor Info (only one fetch)
|
||||
contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
|
||||
# Hold Types
|
||||
hold_types = ReportHelper.execute_sp(cursor, 'GetContractorHoldTypes', [contractor_id])
|
||||
# Invoices
|
||||
invoices = ReportHelper.execute_sp(cursor, 'GetContractorInvoices', [contractor_id])
|
||||
# GST Release
|
||||
gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTRelease', [contractor_id])
|
||||
# Hold Release
|
||||
hold_release = ReportHelper.execute_sp(cursor, 'GetHoldRelease', [contractor_id])
|
||||
# Credit Note
|
||||
credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNote', [contractor_id])
|
||||
# Payments
|
||||
payments = ReportHelper.execute_sp(cursor, 'GetPayments', [contractor_id])
|
||||
|
||||
# Totals
|
||||
total = {
|
||||
"sum_invo_basic_amt": float(sum(row['Basic_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_debit_amt": float(sum(row['Debit_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_after_debit_amt": float(sum(row['After_Debit_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_amt": float(sum(row['Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_gst_amt": float(sum(row['GST_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_tds_amt": float(sum(row['TDS_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_ds_amt": float(sum(row['SD_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_on_commission": float(sum(row['On_Commission'] or 0 for row in invoices)),
|
||||
"sum_invo_hydro_test": float(sum(row['Hydro_Testing'] or 0 for row in invoices)),
|
||||
"sum_invo_gst_sd_amt": float(sum(row['GST_SD_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_final_amt": float(sum(row['Final_Amount'] or 0 for row in invoices)),
|
||||
"sum_invo_hold_amt": float(sum(row['hold_amount'] or 0 for row in invoices)),
|
||||
|
||||
"sum_gst_basic_amt": float(sum(row['basic_amount'] or 0 for row in gst_rel)),
|
||||
"sum_gst_final_amt": float(sum(row['final_amount'] or 0 for row in gst_rel)),
|
||||
|
||||
"sum_pay_payment_amt": float(sum(row['Payment_Amount'] or 0 for row in payments)),
|
||||
"sum_pay_tds_payment_amt": float(sum(row['TDS_Payment_Amount'] or 0 for row in payments)),
|
||||
"sum_pay_total_amt": float(sum(row['Total_amount'] or 0 for row in payments))
|
||||
}
|
||||
|
||||
current_date = datetime.now().strftime('%Y-%m-%d')
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
return {
|
||||
"contInfo": contInfo,
|
||||
"invoices": invoices,
|
||||
"hold_types": hold_types,
|
||||
"gst_rel": gst_rel,
|
||||
"payments": payments,
|
||||
"credit_note": credit_note,
|
||||
"hold_release": hold_release,
|
||||
"total": total,
|
||||
"current_date": current_date
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def download_report(contractor_id):
|
||||
try:
|
||||
connection = config.get_db_connection()
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
def get_contractor_info(contractor_id):
|
||||
from model.ContractorInfo import ContractorInfo
|
||||
contractor = ContractorInfo(contractor_id)
|
||||
return contractor.contInfo if contractor.contInfo else None
|
||||
|
||||
# -------- Contractor Info --------
|
||||
contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
|
||||
|
||||
if not contInfo:
|
||||
return "No contractor found", 404
|
||||
# call this method for excel formate written
|
||||
@staticmethod
|
||||
def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data,
|
||||
credit_note_map, gst_release_map, output_file):
|
||||
|
||||
workbook = openpyxl.Workbook()
|
||||
sheet = workbook.active
|
||||
sheet.title = "Contractor Report"
|
||||
|
||||
# -------- Invoice Data --------
|
||||
cursor.callproc('FetchInvoicesByContractor', [contractor_id])
|
||||
# Contractor Info
|
||||
for field, value in contInfo.items():
|
||||
sheet.append([field.replace("_", " "), value])
|
||||
sheet.append([])
|
||||
|
||||
invoices = []
|
||||
for result in cursor.stored_results():
|
||||
invoices.extend(result.fetchall())
|
||||
# Headers
|
||||
base_headers = ["PMC No", "Village", "Work Type", "Invoice Details", "Invoice Date", "Invoice No",
|
||||
"Basic Amount", "Debit", "After Debit Amount", "GST (18%)", "Amount", "TDS (1%)",
|
||||
"SD (5%)", "On Commission", "Hydro Testing", "GST SD Amount"]
|
||||
|
||||
if not invoices:
|
||||
return "No invoice data found"
|
||||
hold_headers = [ht['hold_type'] for ht in hold_types]
|
||||
|
||||
# -------- Create Workbook --------
|
||||
workbook = openpyxl.Workbook()
|
||||
sheet = workbook.active
|
||||
sheet.title = "Contractor Report"
|
||||
payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"]
|
||||
|
||||
# ================= CONTRACTOR DETAILS =================
|
||||
sheet.append(["SUB CONTRACTOR DETAILS"])
|
||||
sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
|
||||
sheet.append([])
|
||||
all_headers = base_headers + hold_headers + payment_headers
|
||||
sheet.append(all_headers)
|
||||
|
||||
sheet.append(["Name", contInfo.get("Contractor_Name") or ""])
|
||||
sheet.append(["Mobile No", contInfo.get("Mobile_No") or ""])
|
||||
sheet.append(["Email", contInfo.get("Email") or ""])
|
||||
sheet.append(["Village", contInfo.get("Village_Name") or ""])
|
||||
sheet.append(["Block", contInfo.get("Block_Name") or ""])
|
||||
sheet.append(["District", contInfo.get("District_Name") or ""])
|
||||
sheet.append(["State", contInfo.get("State_Name") or ""])
|
||||
sheet.append(["Address", contInfo.get("Address") or ""])
|
||||
sheet.append(["GST No", contInfo.get("GST_No") or ""])
|
||||
sheet.append(["PAN No", contInfo.get("PAN_No") or ""])
|
||||
sheet.append([])
|
||||
sheet.append([])
|
||||
for cell in sheet[sheet.max_row]:
|
||||
cell.font = Font(bold=True)
|
||||
cell.fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid")
|
||||
|
||||
# ================= TABLE HEADERS =================
|
||||
headers = [
|
||||
"PMC No", "Village", "Invoice No", "Invoice Date", "Work Type","Invoice_Details",
|
||||
"Basic Amount", "Debit Amount", "After Debit Amount",
|
||||
"Amount", "GST Amount", "TDS Amount", "SD Amount",
|
||||
"On Commission", "Hydro Testing", "Hold Amount",
|
||||
"GST SD Amount", "Final Amount",
|
||||
"Payment Amount", "TDS Payment",
|
||||
"Total Amount", "UTR"
|
||||
processed_gst_releases = set()
|
||||
appended_credit_keys = set()
|
||||
previous_pmc_no = None
|
||||
|
||||
for inv in invoices:
|
||||
pmc_no = str(inv["PMC_No"]).strip()
|
||||
|
||||
invoice_no = (
|
||||
inv["invoice_no"].replace(" ", "") if inv["invoice_no"] else ""
|
||||
if inv["invoice_no"] not in (None, "", 0)
|
||||
else ""
|
||||
)
|
||||
key = (pmc_no)
|
||||
|
||||
# Yellow separator
|
||||
if previous_pmc_no and pmc_no != previous_pmc_no:
|
||||
sheet.append([""] * len(all_headers))
|
||||
yellow_fill = PatternFill(start_color="FFFF99", end_color="FFFF99", fill_type="solid")
|
||||
for cell in sheet[sheet.max_row]:
|
||||
cell.fill = yellow_fill
|
||||
|
||||
previous_pmc_no = pmc_no
|
||||
|
||||
# Invoice Row
|
||||
row = [
|
||||
pmc_no,
|
||||
inv.get("Village_Name", ""),
|
||||
inv.get("Work_Type", ""),
|
||||
inv.get("Invoice_Details", ""),
|
||||
inv.get("Invoice_Date", ""),
|
||||
# inv.get("invoice_no",""),
|
||||
invoice_no,
|
||||
inv.get("Basic_Amount", ""),
|
||||
inv.get("Debit_Amount", ""),
|
||||
inv.get("After_Debit_Amount", ""),
|
||||
inv.get("GST_Amount", ""),
|
||||
inv.get("Amount", ""),
|
||||
inv.get("TDS_Amount", ""),
|
||||
inv.get("SD_Amount", ""),
|
||||
inv.get("On_Commission", ""),
|
||||
inv.get("Hydro_Testing", ""),
|
||||
inv.get("GST_SD_Amount", "")
|
||||
]
|
||||
sheet.append(headers)
|
||||
for col in range(1, len(headers) + 1):
|
||||
sheet.cell(row=sheet.max_row, column=col).font = Font(bold=True)
|
||||
|
||||
# ================= DATA =================
|
||||
total_final = 0
|
||||
total_payment = 0
|
||||
total_amount = 0
|
||||
# Hold values
|
||||
invoice_holds = hold_data.get(inv["Invoice_Id"], {})
|
||||
for ht_id in [ht['hold_type_id'] for ht in hold_types]:
|
||||
row.append(invoice_holds.get(ht_id, ""))
|
||||
|
||||
for inv in invoices:
|
||||
row = [
|
||||
inv.get("PMC_No"),
|
||||
inv.get("Village_Name"),
|
||||
inv.get("invoice_no"),
|
||||
inv.get("Invoice_Date"),
|
||||
inv.get("Work_Type"),
|
||||
inv.get("Invoice_Details"),
|
||||
inv.get("Basic_Amount"),
|
||||
inv.get("Debit_Amount"),
|
||||
inv.get("After_Debit_Amount"),
|
||||
inv.get("Amount"),
|
||||
inv.get("GST_Amount"),
|
||||
inv.get("TDS_Amount"),
|
||||
inv.get("SD_Amount"),
|
||||
inv.get("On_Commission"),
|
||||
inv.get("Hydro_Testing"),
|
||||
inv.get("Hold_Amount"),
|
||||
inv.get("GST_SD_Amount"),
|
||||
inv.get("Final_Amount"),
|
||||
inv.get("Payment_Amount"),
|
||||
inv.get("TDS_Payment_Amount"),
|
||||
inv.get("Total_Amount"),
|
||||
inv.get("UTR")
|
||||
]
|
||||
# Payment values
|
||||
row += [
|
||||
inv.get("Final_Amount", ""),
|
||||
inv.get("Payment_Amount", ""),
|
||||
inv.get("TDS_Payment_Amount", ""),
|
||||
inv.get("Total_Amount", ""),
|
||||
inv.get("UTR", "")
|
||||
]
|
||||
|
||||
total_final += float(inv.get("Final_Amount") or 0)
|
||||
total_payment += float(inv.get("Payment_Amount") or 0)
|
||||
total_amount += float(inv.get("Total_Amount") or 0)
|
||||
sheet.append(row)
|
||||
|
||||
sheet.append(row)
|
||||
# GST Releases
|
||||
if key in gst_release_map and key not in processed_gst_releases:
|
||||
for gr in gst_release_map[key]:
|
||||
gst_row = [
|
||||
pmc_no, "", "", "GST Release Note", "", gr.get("Invoice_No", ""),
|
||||
gr.get("Basic_Amount", ""), "", "", "", "", "", "", "", "", ""
|
||||
]
|
||||
|
||||
# ================= TOTAL ROW =================
|
||||
sheet.append([])
|
||||
sheet.append([
|
||||
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
|
||||
"TOTAL",
|
||||
total_final,
|
||||
total_payment,
|
||||
"",
|
||||
total_amount,
|
||||
""
|
||||
])
|
||||
gst_row += [""] * len(hold_headers)
|
||||
|
||||
# ================= AUTO WIDTH =================
|
||||
for column in sheet.columns:
|
||||
max_length = 0
|
||||
column_letter = column[0].column_letter
|
||||
for cell in column:
|
||||
if cell.value:
|
||||
max_length = max(max_length, len(str(cell.value)))
|
||||
sheet.column_dimensions[column_letter].width = max_length + 2
|
||||
gst_row += [
|
||||
gr.get("Final_Amount", ""),
|
||||
"",
|
||||
"",
|
||||
gr.get("Total_Amount", ""),
|
||||
gr.get("UTR", "")
|
||||
]
|
||||
|
||||
sheet.append(gst_row)
|
||||
|
||||
processed_gst_releases.add(key)
|
||||
|
||||
# Credit Notes
|
||||
if key in credit_note_map and key not in appended_credit_keys:
|
||||
for cn in credit_note_map[key]:
|
||||
cn_row = [
|
||||
pmc_no, "", "", cn.get("Invoice_Details", "Credit Note"), "",
|
||||
cn.get("Invoice_No", ""),
|
||||
cn.get("Basic_Amount", ""),
|
||||
cn.get("Debit_Amount", ""),
|
||||
cn.get("After_Debit_Amount", ""),
|
||||
cn.get("GST_Amount", ""),
|
||||
cn.get("Amount", ""),
|
||||
"", "", "", "", ""
|
||||
]
|
||||
|
||||
cn_row += [""] * len(hold_headers)
|
||||
|
||||
cn_row += [
|
||||
cn.get("Final_Amount", ""),
|
||||
"",
|
||||
"",
|
||||
cn.get("Total_Amount", ""),
|
||||
cn.get("UTR", "")
|
||||
]
|
||||
|
||||
sheet.append(cn_row)
|
||||
|
||||
appended_credit_keys.add(key)
|
||||
|
||||
# SAVE ONCE AT END
|
||||
workbook.save(output_file)
|
||||
|
||||
# ================= SAVE FILE =================
|
||||
filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx"
|
||||
output_file = FolderAndFile.get_download_path(filename)
|
||||
workbook.save(output_file)
|
||||
|
||||
return send_file(output_file, as_attachment=True)
|
||||
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
@@ -1,7 +1,6 @@
|
||||
from model.Utilities import ItemCRUDType
|
||||
from model.ItemCRUD import ItemCRUD
|
||||
|
||||
|
||||
class Subcontractor:
|
||||
def __init__(self):
|
||||
self.isSuccess = False
|
||||
|
||||
@@ -8,10 +8,12 @@ class ItemCRUDType(Enum):
|
||||
State = 4
|
||||
HoldType = 5
|
||||
Subcontractor = 6
|
||||
|
||||
GSTRelease = 7
|
||||
Invoice = 8
|
||||
|
||||
class RegEx:
|
||||
patternAlphabetOnly = "^[A-Za-z ]+$"
|
||||
patternAlphabetOnly = r"^[A-Za-z ]+$"
|
||||
allPattern = r"^(?!\s*$).+"
|
||||
|
||||
|
||||
class ResponseHandler:
|
||||
|
||||
@@ -13,14 +13,14 @@ class Village:
|
||||
def __init__(self):
|
||||
self.isSuccess = False
|
||||
self.resultMessage = ""
|
||||
self.response = {} # ✅ ADDED
|
||||
self.response = {}
|
||||
self.village = ItemCRUD(itemType=ItemCRUDType.Village)
|
||||
|
||||
# 🔹 Helper: sync status
|
||||
def _set_status(self, village):
|
||||
self.isSuccess = village.isSuccess
|
||||
|
||||
# ✅ UPDATED (safe handling)
|
||||
# UPDATED (safe handling)
|
||||
if hasattr(village, "response"):
|
||||
self.response = village.response
|
||||
self.resultMessage = village.response.get("message", "")
|
||||
@@ -37,7 +37,7 @@ class Village:
|
||||
block_id, village_name = self._get_form_data(request)
|
||||
|
||||
if not village_name:
|
||||
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
|
||||
self.response = ResponseHandler.invalid_name("village")
|
||||
self.resultMessage = self.response["message"]
|
||||
self.isSuccess = False
|
||||
return
|
||||
@@ -75,7 +75,7 @@ class Village:
|
||||
block_id, village_name = self._get_form_data(request)
|
||||
|
||||
if not village_name:
|
||||
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
|
||||
self.response = ResponseHandler.invalid_name("village")
|
||||
self.resultMessage = self.response["message"]
|
||||
self.isSuccess = False
|
||||
return None
|
||||
@@ -113,7 +113,7 @@ class Village:
|
||||
block_id, village_name = self._get_form_data(request)
|
||||
|
||||
if not village_name:
|
||||
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
|
||||
self.response = ResponseHandler.invalid_name("village")
|
||||
self.resultMessage = self.response["message"]
|
||||
self.isSuccess = False
|
||||
return
|
||||
@@ -176,7 +176,7 @@ class Village:
|
||||
print(f"Error fetching blocks: {e}")
|
||||
self.isSuccess = False
|
||||
|
||||
# ✅ FIXED (removed jsonify response)
|
||||
# FIXED (removed jsonify response)
|
||||
self.response = ResponseHandler.fetch_failure("block")
|
||||
self.resultMessage = self.response["message"]
|
||||
|
||||
|
||||
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,120 +1,25 @@
|
||||
# from flask import request
|
||||
# from model.ItemCRUD import ItemCRUD
|
||||
# from model.Utilities import ItemCRUDType
|
||||
|
||||
# class GSTRelease:
|
||||
# """CRUD operations for GST Release using ItemCRUD"""
|
||||
|
||||
# def __init__(self):
|
||||
# self.isSuccess = False
|
||||
# self.resultMessage = ""
|
||||
|
||||
# # ------------------- Add GST Release -------------------
|
||||
# def AddGSTRelease(self, request):
|
||||
# pmc_no = request.form.get('PMC_No', '').strip()
|
||||
# invoice_no = request.form.get('invoice_No', '').strip()
|
||||
|
||||
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
# gst.AddItem(
|
||||
# request=request,
|
||||
# parentid=None,
|
||||
# childname=f"{pmc_no}-{invoice_no}",
|
||||
# storedprocfetch="CheckGSTReleaseExists",
|
||||
# storedprocadd="AddGSTReleaseFromExcel" # your stored procedure handles extra fields
|
||||
# )
|
||||
|
||||
# self.isSuccess = gst.isSuccess
|
||||
# self.resultMessage = str(gst.resultMessage)
|
||||
|
||||
# # ------------------- Get All GST Releases -------------------
|
||||
# def GetAllGSTReleases(self):
|
||||
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
# # Pass request=None for fetch
|
||||
# rows = gst.GetAllData(request=None, storedproc="GetAllGSTReleases")
|
||||
|
||||
# self.isSuccess = gst.isSuccess
|
||||
# self.resultMessage = str(gst.resultMessage)
|
||||
|
||||
# data = []
|
||||
# for row in rows:
|
||||
# data.append({
|
||||
# "gst_release_id": row[0],
|
||||
# "pmc_no": row[1],
|
||||
# "invoice_no": row[2],
|
||||
# "basic_amount": row[3],
|
||||
# "final_amount": row[4],
|
||||
# "total_amount": row[5],
|
||||
# "utr": row[6],
|
||||
# "contractor_id": row[7]
|
||||
# })
|
||||
# return data
|
||||
|
||||
# # ------------------- Get GST Release By ID -------------------
|
||||
# def GetGSTReleaseByID(self, gst_release_id):
|
||||
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
# row = gst.GetDataByID(gst_release_id, request=None, storedproc="GetGSTReleaseById")
|
||||
|
||||
# self.isSuccess = gst.isSuccess
|
||||
# self.resultMessage = str(gst.resultMessage)
|
||||
|
||||
# if row:
|
||||
# return {
|
||||
# "gst_release_id": row[0],
|
||||
# "pmc_no": row[1],
|
||||
# "invoice_no": row[2],
|
||||
# "basic_amount": row[3],
|
||||
# "final_amount": row[4],
|
||||
# "total_amount": row[5],
|
||||
# "utr": row[6],
|
||||
# "contractor_id": row[7]
|
||||
# }
|
||||
# return None
|
||||
|
||||
# # ------------------- Edit GST Release -------------------
|
||||
# def EditGSTRelease(self, request, gst_release_id):
|
||||
# pmc_no = request.form.get('PMC_No', '').strip()
|
||||
# invoice_no = request.form.get('invoice_No', '').strip()
|
||||
|
||||
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
# gst.EditItem(
|
||||
# request=request,
|
||||
# childid=gst_release_id,
|
||||
# parentid=None,
|
||||
# childname=f"{pmc_no}-{invoice_no}",
|
||||
# storedprocupdate="UpdateGSTRelease" # stored procedure handles extra fields
|
||||
# )
|
||||
|
||||
# self.isSuccess = gst.isSuccess
|
||||
# self.resultMessage = str(gst.resultMessage)
|
||||
|
||||
# # ------------------- Delete GST Release -------------------
|
||||
# def DeleteGSTRelease(self, gst_release_id):
|
||||
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
# gst.DeleteItem(
|
||||
# itemID=gst_release_id,
|
||||
# request=None,
|
||||
# storedprocDelete="DeleteGSTReleaseById"
|
||||
# )
|
||||
|
||||
# self.isSuccess = gst.isSuccess
|
||||
# self.resultMessage = str(gst.resultMessage)
|
||||
|
||||
# model/gst_release.py
|
||||
from flask import request, jsonify
|
||||
from model.ItemCRUD import ItemCRUD
|
||||
from model.Utilities import ItemCRUDType
|
||||
|
||||
|
||||
class GSTRelease:
|
||||
|
||||
def __init__(self):
|
||||
self.isSuccess = False
|
||||
self.resultMessage = ""
|
||||
|
||||
|
||||
# ------------------- Add GST Release -------------------
|
||||
def AddGSTRelease(self, request):
|
||||
try:
|
||||
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 = {
|
||||
"PMC_No": request.form.get("PMC_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)
|
||||
}
|
||||
|
||||
print("===== DEBUG: PARSED DATA =====")
|
||||
print(data)
|
||||
print("==============================")
|
||||
|
||||
# Add GST Release
|
||||
gst.AddItem(
|
||||
request=request,
|
||||
data=data,
|
||||
@@ -132,6 +42,8 @@ class GSTRelease:
|
||||
storedprocadd="AddGSTReleaseFromExcel"
|
||||
)
|
||||
|
||||
print(f"AddItem result: isSuccess={gst.isSuccess}, message={gst.resultMessage}")
|
||||
|
||||
self.isSuccess = gst.isSuccess
|
||||
self.resultMessage = str(gst.resultMessage)
|
||||
|
||||
@@ -142,20 +54,26 @@ class GSTRelease:
|
||||
|
||||
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
|
||||
|
||||
# ------------------- Edit GST Release -------------------
|
||||
def EditGSTRelease(self, request, gst_release_id):
|
||||
try:
|
||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
|
||||
# Map form inputs to stored procedure parameters
|
||||
data = {
|
||||
"PMC_No": request.form.get("PMC_No", "").strip(),
|
||||
"Invoice_No": request.form.get("Invoice_No", "").strip(),
|
||||
"Basic_Amount": float(request.form.get("Basic_Amount", 0) or 0),
|
||||
"Final_Amount": float(request.form.get("Final_Amount", 0) or 0),
|
||||
"Total_Amount": float(request.form.get("Total_Amount", 0) or 0),
|
||||
"UTR": request.form.get("UTR", "").strip()
|
||||
"p_pmc_no": request.form.get("PMC_No", "").strip(),
|
||||
"p_invoice_no": request.form.get("invoice_no", "").strip(),
|
||||
"p_basic_amount": float(request.form.get("Basic_Amount", 0) or 0),
|
||||
"p_final_amount": float(request.form.get("Final_Amount", 0) or 0),
|
||||
"p_total_amount": float(request.form.get("Total_Amount", 0) or 0),
|
||||
"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(
|
||||
request=request,
|
||||
childid=gst_release_id,
|
||||
@@ -171,8 +89,6 @@ class GSTRelease:
|
||||
self.isSuccess = False
|
||||
self.resultMessage = str(e)
|
||||
|
||||
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
|
||||
|
||||
# ------------------- Delete GST Release -------------------
|
||||
def DeleteGSTRelease(self, gst_release_id):
|
||||
try:
|
||||
@@ -198,7 +114,6 @@ class GSTRelease:
|
||||
def GetAllGSTReleases(self):
|
||||
try:
|
||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
|
||||
rows = gst.GetAllData(None, "GetAllGSTReleases")
|
||||
|
||||
data = []
|
||||
@@ -224,7 +139,6 @@ class GSTRelease:
|
||||
def GetGSTReleaseByID(self, gst_release_id):
|
||||
try:
|
||||
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
|
||||
|
||||
row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById")
|
||||
|
||||
if row:
|
||||
|
||||
@@ -2,7 +2,6 @@ import config
|
||||
import mysql.connector
|
||||
import config
|
||||
import mysql.connector
|
||||
from enum import Enum
|
||||
from model.Utilities import ItemCRUDType
|
||||
|
||||
class Paymentmodel:
|
||||
@@ -34,40 +33,44 @@ class Paymentmodel:
|
||||
return payments
|
||||
|
||||
@staticmethod
|
||||
def insert_payment(pmc_no, invoice_no, amount, tds_amount, total_amount, utr):
|
||||
def insert_payment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr):
|
||||
connection = Paymentmodel.get_connection()
|
||||
if not connection:
|
||||
return False
|
||||
try:
|
||||
cursor = connection.cursor()
|
||||
cursor.callproc('InsertPayments', [pmc_no, invoice_no, amount, tds_amount, total_amount, utr])
|
||||
connection.commit()
|
||||
return True
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error inserting payment: {e}")
|
||||
return False
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
@staticmethod
|
||||
def update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr):
|
||||
connection = Paymentmodel.get_connection()
|
||||
if not connection:
|
||||
return False
|
||||
cursor = None
|
||||
try:
|
||||
cursor = connection.cursor()
|
||||
cursor.callproc('UpdateInpaymentRecord', [
|
||||
subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr
|
||||
])
|
||||
|
||||
cursor.callproc('GetInvoiceId', [subcontractor_id, pmc_no, invoice_no])
|
||||
|
||||
invoice_id = None
|
||||
for result in cursor.stored_results():
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
invoice_id = row[0]
|
||||
|
||||
if not invoice_id:
|
||||
return False
|
||||
|
||||
cursor.callproc(
|
||||
'InsertPayments',
|
||||
[pmc_no, invoice_no, amount, tds_amount, total_amount, utr, invoice_id]
|
||||
)
|
||||
|
||||
connection.commit()
|
||||
return True
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error updating inpayment: {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if connection:
|
||||
connection.close()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def fetch_payment_by_id(payment_id):
|
||||
@@ -133,9 +136,7 @@ class Paymentmodel:
|
||||
# Delete payment
|
||||
cursor.callproc("DeletePayment", (payment_id,))
|
||||
connection.commit()
|
||||
# Reset inpayment fields
|
||||
cursor.callproc("ResetInpayment", [pmc_no, invoice_no])
|
||||
connection.commit()
|
||||
|
||||
return True, pmc_no, invoice_no
|
||||
except mysql.connector.Error as e:
|
||||
print(f"Error deleting payment: {e}")
|
||||
|
||||
30
services/Generalservice.py
Normal file
30
services/Generalservice.py
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
|
||||
class GeneralUse:
|
||||
data=[]
|
||||
|
||||
@staticmethod
|
||||
def execute_sp(cursor, proc_name, params=[], fetch_one=False):
|
||||
cursor.callproc(proc_name, params)
|
||||
return (
|
||||
GeneralUse.fetch_one_result(cursor)
|
||||
if fetch_one else
|
||||
GeneralUse.fetch_all_results(cursor)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def fetch_all_results(cursor):
|
||||
data = []
|
||||
for result in cursor.stored_results():
|
||||
data = result.fetchall()
|
||||
return data
|
||||
|
||||
|
||||
@staticmethod
|
||||
def fetch_one_result(cursor):
|
||||
data = None
|
||||
for result in cursor.stored_results():
|
||||
data = result.fetchone()
|
||||
return data
|
||||
|
||||
177
services/ReportService.py
Normal file
177
services/ReportService.py
Normal file
@@ -0,0 +1,177 @@
|
||||
import config
|
||||
|
||||
from model.FolderAndFile import FolderAndFile
|
||||
from services.Generalservice import GeneralUse
|
||||
from model.Report import ReportHelper
|
||||
|
||||
from decimal import Decimal
|
||||
def safe_decimal(value):
|
||||
if value is None:
|
||||
return Decimal(0)
|
||||
return Decimal(value)
|
||||
|
||||
|
||||
class ReportService:
|
||||
|
||||
|
||||
def __init__(self, contractor_id=None, pmc_no=None):
|
||||
self.contractor_id = contractor_id
|
||||
self.pmc_no = pmc_no
|
||||
|
||||
self.contInfo = None
|
||||
self.hold_types = []
|
||||
self.invoices = []
|
||||
|
||||
self.hold_amounts = []
|
||||
self.hold_data = {}
|
||||
|
||||
self.credit_note_raw = []
|
||||
self.credit_note_map = {}
|
||||
|
||||
self.gst_release_raw = []
|
||||
self.gst_release_map = {}
|
||||
|
||||
self.output_file = None
|
||||
|
||||
# ---------------- LOAD DATA ----------------
|
||||
def load_data(self):
|
||||
connection = config.get_db_connection()
|
||||
cursor = connection.cursor(dictionary=True, buffered=True)
|
||||
|
||||
try:
|
||||
# ---------- CONTRACTOR ----------
|
||||
if self.contractor_id:
|
||||
self.contInfo = GeneralUse.execute_sp(cursor, 'GetContractorInfo', [self.contractor_id], True)
|
||||
self.hold_types = GeneralUse.execute_sp(cursor, 'HoldTypesByContractorId', [self.contractor_id])
|
||||
self.invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [self.contractor_id, None])
|
||||
|
||||
# ---------- PMC ----------
|
||||
elif self.pmc_no:
|
||||
self.contInfo = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [self.pmc_no], True)
|
||||
self.contractor_id = self.contInfo["Contractor_Id"]
|
||||
|
||||
self.hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor', [self.contractor_id])
|
||||
self.invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None, self.pmc_no])
|
||||
|
||||
# ---------- COMMON ----------
|
||||
self.hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [self.contractor_id])
|
||||
self.credit_note_raw = GeneralUse.execute_sp(cursor, 'GetCreditNotesByContractor', [self.contractor_id])
|
||||
self.gst_release_raw = GeneralUse.execute_sp(cursor, 'GetGSTRelease', [self.contractor_id])
|
||||
|
||||
|
||||
self.prepare_maps()
|
||||
self.total = self.calculate_totals()
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
return self
|
||||
|
||||
# ---------------- MAPS ----------------
|
||||
def prepare_maps(self):
|
||||
# HOLD MAP
|
||||
for h in self.hold_amounts:
|
||||
self.hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
|
||||
|
||||
# CREDIT MAP
|
||||
for cn in self.credit_note_raw:
|
||||
key = str(cn.get('PMC_No') or cn.get('pmc_no')).strip()
|
||||
self.credit_note_map.setdefault(key, []).append(cn)
|
||||
|
||||
# GST MAP (FIXED)
|
||||
for gr in self.gst_release_raw:
|
||||
pmc_value = gr.get('PMC_No') or gr.get('pmc_no') or gr.get('PMC_NO')
|
||||
|
||||
if not pmc_value:
|
||||
continue # skip if missing
|
||||
|
||||
key = str(pmc_value).strip()
|
||||
self.gst_release_map.setdefault(key, []).append(gr)
|
||||
|
||||
# ---------------- calculate total ----------------
|
||||
def calculate_totals(self):
|
||||
total = {
|
||||
"sum_invo_basic_amt": Decimal(0),
|
||||
"sum_invo_debit_amt": Decimal(0),
|
||||
"sum_invo_after_debit_amt": Decimal(0),
|
||||
"sum_invo_gst_amt": Decimal(0),
|
||||
"sum_invo_amt": Decimal(0),
|
||||
"sum_invo_tds_amt": Decimal(0),
|
||||
"sum_invo_ds_amt": Decimal(0),
|
||||
"sum_invo_on_commission": Decimal(0),
|
||||
"sum_invo_hydro_test": Decimal(0),
|
||||
"sum_invo_hold_amt": Decimal(0),
|
||||
"sum_invo_gst_sd_amt": Decimal(0),
|
||||
"sum_invo_final_amt": Decimal(0),
|
||||
|
||||
"sum_gst_basic_amt": Decimal(0),
|
||||
"sum_gst_final_amt": Decimal(0),
|
||||
|
||||
"sum_pay_payment_amt": Decimal(0),
|
||||
"sum_pay_tds_payment_amt": Decimal(0),
|
||||
"sum_pay_total_amt": Decimal(0)
|
||||
}
|
||||
|
||||
# ---------- INVOICE ----------
|
||||
for inv in self.invoices:
|
||||
total["sum_invo_basic_amt"] += safe_decimal(inv.get("Basic_Amount"))
|
||||
total["sum_invo_debit_amt"] += safe_decimal(inv.get("Debit_Amount"))
|
||||
total["sum_invo_after_debit_amt"] += safe_decimal(inv.get("After_Debit_Amount"))
|
||||
total["sum_invo_gst_amt"] += safe_decimal(inv.get("GST_Amount"))
|
||||
total["sum_invo_amt"] += safe_decimal(inv.get("Amount"))
|
||||
total["sum_invo_tds_amt"] += safe_decimal(inv.get("TDS_Amount"))
|
||||
total["sum_invo_ds_amt"] += safe_decimal(inv.get("SD_Amount"))
|
||||
total["sum_invo_on_commission"] += safe_decimal(inv.get("On_Commission"))
|
||||
total["sum_invo_hydro_test"] += safe_decimal(inv.get("Hydro_Testing"))
|
||||
total["sum_invo_gst_sd_amt"] += safe_decimal(inv.get("GST_SD_Amount"))
|
||||
total["sum_invo_final_amt"] += safe_decimal(inv.get("Final_Amount"))
|
||||
total["sum_invo_hold_amt"] += safe_decimal(inv.get("hold_amount"))
|
||||
|
||||
# ---------- GST ----------
|
||||
for gst in self.gst_release_raw:
|
||||
total["sum_gst_basic_amt"] += safe_decimal(gst.get("basic_amount"))
|
||||
total["sum_gst_final_amt"] += safe_decimal(gst.get("final_amount"))
|
||||
|
||||
# ---------- PAYMENTS ----------
|
||||
if hasattr(self, "payments"):
|
||||
for pay in self.payments:
|
||||
total["sum_pay_payment_amt"] += safe_decimal(pay.get("Payment_Amount"))
|
||||
total["sum_pay_tds_payment_amt"] += safe_decimal(pay.get("TDS_Payment_Amount"))
|
||||
total["sum_pay_total_amt"] += safe_decimal(pay.get("Total_amount"))
|
||||
|
||||
return total
|
||||
|
||||
|
||||
# ---------------- WEB DATA ----------------
|
||||
def get_web_data(self):
|
||||
return {
|
||||
"contInfo": self.contInfo,
|
||||
"invoices": self.invoices,
|
||||
"hold_types": self.hold_types,
|
||||
"credit_note": self.credit_note_raw,
|
||||
"gst_rel": self.gst_release_raw,
|
||||
"total": self.total
|
||||
}
|
||||
|
||||
# ---------------- DOWNLOAD ----------------
|
||||
def download_excel(self):
|
||||
|
||||
if not self.contInfo:
|
||||
return None, "No data found"
|
||||
|
||||
filename = f"Report_{self.contractor_id or self.pmc_no}.xlsx"
|
||||
self.output_file = FolderAndFile.get_download_path(filename=filename)
|
||||
|
||||
ReportHelper.generate_excel(
|
||||
self.contractor_id or 0,
|
||||
self.contInfo,
|
||||
self.invoices,
|
||||
self.hold_types,
|
||||
self.hold_data,
|
||||
self.credit_note_map,
|
||||
self.gst_release_map,
|
||||
self.output_file
|
||||
)
|
||||
|
||||
return self.output_file, None
|
||||
BIN
static/images/icons/male_profile.jpg
Normal file
BIN
static/images/icons/male_profile.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
@@ -3,7 +3,7 @@ $(document).ready(function () {
|
||||
let holdType = $(this).val().replace(/^\s+/, "");
|
||||
$(this).val(holdType);
|
||||
|
||||
let reg = /^[A-Za-z]/;
|
||||
let reg = /^.+$/; // all pattern allow
|
||||
|
||||
if (!reg.test(holdType)) {
|
||||
$("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red");
|
||||
|
||||
@@ -1,62 +1,271 @@
|
||||
// Subcontractor autocomplete functionality
|
||||
$(document).ready(function () {
|
||||
$("#subcontractor").keyup(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 () {
|
||||
let query = $(this).val();
|
||||
if (query !== "") {
|
||||
$.ajax({
|
||||
url: "/search_subcontractor",
|
||||
method: "POST",
|
||||
data: { query: query },
|
||||
success: function (data) {
|
||||
$("#subcontractor_list").fadeIn().html(data);
|
||||
}
|
||||
});
|
||||
$.ajax({
|
||||
url: "/search_subcontractor",
|
||||
method: "POST",
|
||||
data: { query: query },
|
||||
success: function (data) {
|
||||
$("#subcontractor_list").fadeIn().html(data);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$("#subcontractor_list").fadeOut();
|
||||
$("#subcontractor_list").fadeOut();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("click", "li", function () {
|
||||
$(document).on("click", "li", function () {
|
||||
$("#subcontractor").val($(this).text());
|
||||
$("#subcontractor_id").val($(this).attr("data-id"));
|
||||
$("#subcontractor_list").fadeOut();
|
||||
});
|
||||
});
|
||||
|
||||
// Success Alert: show alert and reload after 3 seconds
|
||||
function showSuccessAlert() {
|
||||
const alertBox = document.getElementById("invoiceSuccessAlert");
|
||||
alertBox.classList.add("show");
|
||||
setTimeout(() => {
|
||||
alertBox.classList.remove("show");
|
||||
// Reload page or redirect after alert hides
|
||||
window.location.href = '/add_invoice';
|
||||
}, 3000);
|
||||
// Focus
|
||||
if (document.getElementById('subcontractor')) {
|
||||
document.getElementById('subcontractor').focus();
|
||||
}
|
||||
|
||||
// Submit form via AJAX
|
||||
$("#invoiceForm").on("submit", function (e) {
|
||||
e.preventDefault();
|
||||
let formData = $(this).serialize();
|
||||
$.ajax({
|
||||
url: '/add_invoice',
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
success: function (response) {
|
||||
if(response.status === "success") {
|
||||
showSuccessAlert();
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
alert("Submission failed: " + error);
|
||||
}
|
||||
});
|
||||
});
|
||||
// ===============================
|
||||
// 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) {
|
||||
let msg = xhr.responseJSON?.message || "Submission failed. Please try again.";
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// UPDATE INVOICE
|
||||
// ===============================
|
||||
function updateInvoice(invoiceId, formElement) {
|
||||
const formData = $(formElement).serialize();
|
||||
|
||||
window.onload = function () {
|
||||
document.getElementById('subcontractor').focus();
|
||||
};
|
||||
$.ajax({
|
||||
url: '/update_invoice/' + invoiceId,
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if(response.status === "success") {
|
||||
alert(response.message || "Invoice updated successfully!");
|
||||
|
||||
// Redirect to Add Invoice page's table part
|
||||
window.location.href = "/add_invoice#addTable";
|
||||
} else {
|
||||
alert(response.message || "Update failed. Please try again.");
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
let msg = xhr.responseJSON?.message || "Error updating invoice.";
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
window.updateInvoice = updateInvoice; // make globally accessible
|
||||
|
||||
// ===============================
|
||||
// DELETE INVOICE
|
||||
// ===============================
|
||||
function deleteInvoice(invoiceId, element) {
|
||||
if (!confirm("Are you sure you want to delete this invoice?")) return;
|
||||
|
||||
$.ajax({
|
||||
url: '/delete_invoice/' + invoiceId,
|
||||
method: 'GET',
|
||||
dataType: 'json',
|
||||
success: function (response) {
|
||||
if (response.status === "success") {
|
||||
alert(response.message || "Invoice deleted successfully!");
|
||||
if (element) $(element).closest("tr").remove();
|
||||
} else {
|
||||
alert(response.message || "Error deleting invoice.");
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
let msg = xhr.responseJSON?.message || "Error deleting invoice. Please try again.";
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
window.deleteInvoice = deleteInvoice; // make globally accessible
|
||||
});
|
||||
@@ -1,43 +1,57 @@
|
||||
$(document).ready(function () {
|
||||
function fetchResults() {
|
||||
let formData = $('#search-form').serialize();
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/search_contractor',
|
||||
data: formData,
|
||||
success: function (data) {
|
||||
let tableBody = $('#result-table tbody');
|
||||
tableBody.empty();
|
||||
const form = document.getElementById("search-form");
|
||||
const tableBody = document.querySelector("#result-table tbody");
|
||||
|
||||
if (data.length === 0) {
|
||||
tableBody.append('<tr><td colspan="6">No data found</td></tr>');
|
||||
} else {
|
||||
data.forEach(function (row) {
|
||||
tableBody.append(`
|
||||
<tr>
|
||||
<td><a href="/contractor_report/${row.Contractor_Id}" target="_blank">${row.Contractor_Name}</a></td>
|
||||
<td><a href="/pmc_report/${row.PMC_No}" target="_blank">${row.PMC_No}</a></td>
|
||||
<td>${row.State_Name}</td>
|
||||
<td>${row.District_Name}</td>
|
||||
<td>${row.Block_Name}</td>
|
||||
<td>${row.Village_Name}</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
alert(xhr.responseJSON.error);
|
||||
}
|
||||
function fetchData(page = 1) {
|
||||
const formData = new FormData(form);
|
||||
formData.append("page", page);
|
||||
|
||||
fetch("/search_contractor", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
tableBody.innerHTML = "";
|
||||
|
||||
res.data.forEach(row => {
|
||||
|
||||
const tr = document.createElement("tr");
|
||||
|
||||
tr.innerHTML = `
|
||||
<td class="contractor-link" data-id="${row.Contractor_Id}">
|
||||
${row.Contractor_Name}
|
||||
</td>
|
||||
<td class="pmc-link" data-pmc="${row.PMC_No}">
|
||||
${row.PMC_No}
|
||||
</td>
|
||||
<td>${row.State_Name}</td>
|
||||
<td>${row.District_Name}</td>
|
||||
<td>${row.Block_Name}</td>
|
||||
<td>${row.Village_Name}</td>
|
||||
`;
|
||||
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Auto search
|
||||
form.addEventListener("input", () => fetchData());
|
||||
|
||||
// Click Contractor
|
||||
document.addEventListener("click", function (e) {
|
||||
if (e.target.classList.contains("contractor-link")) {
|
||||
const id = e.target.dataset.id;
|
||||
window.location.href = `/contractor_report/${id}`;
|
||||
}
|
||||
|
||||
$('#search-form input').on('keyup change', function () {
|
||||
fetchResults();
|
||||
});
|
||||
if (e.target.classList.contains("pmc-link")) {
|
||||
const pmc = e.target.dataset.pmc;
|
||||
window.location.href = `/pmc_report/${pmc}`;
|
||||
}
|
||||
});
|
||||
|
||||
window.onload = function () {
|
||||
document.getElementById('subcontractor_name').focus();
|
||||
};
|
||||
fetchData();
|
||||
});
|
||||
@@ -1,26 +1,23 @@
|
||||
|
||||
// Search on table using search inpute options
|
||||
function searchTable() {
|
||||
let input = document.getElementById("searchBar").value.toLowerCase();
|
||||
let rows = document.querySelectorAll("table tbody tr");
|
||||
let tables = document.querySelectorAll("table");
|
||||
|
||||
rows.forEach(row => {
|
||||
let blockName = row.cells[1].textContent.toLowerCase();
|
||||
let districtName = row.cells[2].textContent.toLowerCase();
|
||||
let villageName = row.cells[3].textContent.toLowerCase();
|
||||
tables.forEach(table => {
|
||||
let rows = table.querySelectorAll("tr");
|
||||
|
||||
if (blockName.includes(input) || districtName.includes(input)|| villageName.includes(input)) {
|
||||
row.style.display = "";
|
||||
} else {
|
||||
row.style.display = "none";
|
||||
}
|
||||
rows.forEach((row, index) => {
|
||||
if (index === 0) return; // header skip
|
||||
|
||||
let text = row.textContent.toLowerCase();
|
||||
|
||||
row.style.display = text.includes(input) ? "" : "none";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Common Sorting Script for Tables
|
||||
function sortTable(n, dir) {
|
||||
var table, rows, switching, i, x, y, shouldSwitch;
|
||||
@@ -57,14 +54,14 @@ function sortTable(n, dir) {
|
||||
}
|
||||
|
||||
// Attach sorting functionality to all sortable tables
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Find all elements with the class "sortable-header"
|
||||
var sortableHeaders = document.querySelectorAll(".sortable-header");
|
||||
|
||||
sortableHeaders.forEach(function(header) {
|
||||
sortableHeaders.forEach(function (header) {
|
||||
// Attach click event for ascending sort
|
||||
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);
|
||||
sortTable(columnIndex, "asc");
|
||||
});
|
||||
@@ -72,7 +69,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
|
||||
// Attach click event for descending sort
|
||||
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);
|
||||
sortTable(columnIndex, "desc");
|
||||
});
|
||||
@@ -105,4 +102,31 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
displayButton.classList.add("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,264 +1,250 @@
|
||||
|
||||
|
||||
window.onload = function () {
|
||||
document.getElementById('Village_Name').focus();
|
||||
if (document.getElementById('Village_Name')) {
|
||||
document.getElementById('Village_Name').focus();
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// 🔥 RESTORE VIEW MODE AFTER RELOAD
|
||||
var viewMode = localStorage.getItem("viewMode");
|
||||
// ✅ RUN ONLY IF THIS PAGE HAS FORM/TABLE
|
||||
if ($('#addForm').length && $('#addTable').length) {
|
||||
|
||||
if (viewMode === "table") {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
} else {
|
||||
// ✅ DEFAULT VIEW → SHOW FORM
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
|
||||
|
||||
// 🔥 BUTTON TOGGLE
|
||||
$('#addButton').click(function () {
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
});
|
||||
|
||||
$('#displayButton').click(function () {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 🔥 BUTTON TOGGLE LOGIC
|
||||
|
||||
$('#addButton').click(function () {
|
||||
$('#addForm').show();
|
||||
$('#addTable').hide();
|
||||
|
||||
localStorage.setItem("viewMode", "form");
|
||||
});
|
||||
|
||||
$('#displayButton').click(function () {
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
|
||||
localStorage.setItem("viewMode", "table");
|
||||
});
|
||||
|
||||
|
||||
// ===============================
|
||||
// STATE → DISTRICT
|
||||
$('#state_Id').change(function () {
|
||||
// ===============================
|
||||
if ($('#state_Id').length) {
|
||||
|
||||
var stateId = $(this).val();
|
||||
$('#state_Id').change(function () {
|
||||
|
||||
if (stateId) {
|
||||
var stateId = $(this).val();
|
||||
|
||||
$.ajax({
|
||||
url: '/get_districts/' + stateId,
|
||||
type: 'GET',
|
||||
if (stateId) {
|
||||
|
||||
success: function (data) {
|
||||
$.ajax({
|
||||
url: '/get_districts/' + stateId,
|
||||
type: 'GET',
|
||||
|
||||
var districtDropdown = $('#district_Id');
|
||||
success: function (data) {
|
||||
|
||||
districtDropdown.empty();
|
||||
districtDropdown.append('<option value="" disabled selected>Select District</option>');
|
||||
var districtDropdown = $('#district_Id');
|
||||
|
||||
data.forEach(function (district) {
|
||||
districtDropdown.empty();
|
||||
districtDropdown.append('<option value="" disabled selected>Select District</option>');
|
||||
|
||||
districtDropdown.append(
|
||||
'<option value="' + district.id + '">' + district.name + '</option>'
|
||||
);
|
||||
data.forEach(function (district) {
|
||||
districtDropdown.append(
|
||||
'<option value="' + district.id + '">' + district.name + '</option>'
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
districtDropdown.prop('disabled', false);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
districtDropdown.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// DISTRICT → BLOCK
|
||||
$('#district_Id').change(function () {
|
||||
// ===============================
|
||||
if ($('#district_Id').length) {
|
||||
|
||||
var districtId = $(this).val();
|
||||
$('#district_Id').change(function () {
|
||||
|
||||
if (districtId) {
|
||||
var districtId = $(this).val();
|
||||
|
||||
$.ajax({
|
||||
url: '/get_blocks/' + districtId,
|
||||
type: 'GET',
|
||||
if (districtId) {
|
||||
|
||||
success: function (data) {
|
||||
$.ajax({
|
||||
url: '/get_blocks/' + districtId,
|
||||
type: 'GET',
|
||||
|
||||
var blockDropdown = $('#block_Id');
|
||||
success: function (data) {
|
||||
|
||||
blockDropdown.empty();
|
||||
blockDropdown.append('<option value="" disabled selected>Select Block</option>');
|
||||
var blockDropdown = $('#block_Id');
|
||||
|
||||
data.forEach(function (block) {
|
||||
blockDropdown.empty();
|
||||
blockDropdown.append('<option value="" disabled selected>Select Block</option>');
|
||||
|
||||
blockDropdown.append(
|
||||
'<option value="' + block.id + '">' + block.name + '</option>'
|
||||
);
|
||||
data.forEach(function (block) {
|
||||
blockDropdown.append(
|
||||
'<option value="' + block.id + '">' + block.name + '</option>'
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
blockDropdown.prop('disabled', false);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
blockDropdown.prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// VILLAGE NAME VALIDATION
|
||||
$('#Village_Name').on('input', function () {
|
||||
// ===============================
|
||||
if ($('#Village_Name').length) {
|
||||
|
||||
var villageName = $(this).val();
|
||||
var validPattern = /^[A-Za-z ]*$/;
|
||||
$('#Village_Name').on('input', function () {
|
||||
|
||||
if (!validPattern.test(villageName)) {
|
||||
var villageName = $(this).val();
|
||||
var validPattern = /^[A-Za-z ]*$/;
|
||||
|
||||
$('#villageMessage')
|
||||
.text('Only letters and spaces are allowed!')
|
||||
.css('color', 'red');
|
||||
if (!validPattern.test(villageName)) {
|
||||
|
||||
$('#submitVillage').prop('disabled', true);
|
||||
$('#villageMessage')
|
||||
.text('Only letters and spaces are allowed!')
|
||||
.css('color', 'red');
|
||||
|
||||
} else {
|
||||
$('#submitVillage').prop('disabled', true);
|
||||
|
||||
$('#villageMessage').text('');
|
||||
$('#submitVillage').prop('disabled', false);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
$('#villageMessage').text('');
|
||||
$('#submitVillage').prop('disabled', false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// CHECK DUPLICATE VILLAGE
|
||||
$('#Village_Name, #block_Id').on('change keyup', function () {
|
||||
// ===============================
|
||||
if ($('#Village_Name').length && $('#block_Id').length) {
|
||||
|
||||
var blockId = $('#block_Id').val();
|
||||
var villageName = $('#Village_Name').val().trim();
|
||||
$('#Village_Name, #block_Id').on('change keyup', function () {
|
||||
|
||||
if (blockId && villageName) {
|
||||
var blockId = $('#block_Id').val();
|
||||
var villageName = $('#Village_Name').val().trim();
|
||||
|
||||
$.ajax({
|
||||
if (blockId && villageName) {
|
||||
|
||||
url: '/check_village',
|
||||
type: 'POST',
|
||||
$.ajax({
|
||||
url: '/check_village',
|
||||
type: 'POST',
|
||||
|
||||
data: {
|
||||
block_Id: blockId,
|
||||
Village_Name: villageName
|
||||
},
|
||||
data: {
|
||||
block_Id: blockId,
|
||||
Village_Name: villageName
|
||||
},
|
||||
|
||||
success: function (response) {
|
||||
success: function (response) {
|
||||
|
||||
if (response.status === 'exists') {
|
||||
if (response.status === 'exists') {
|
||||
|
||||
$('#villageMessage')
|
||||
.text(response.message)
|
||||
.css('color', 'red');
|
||||
|
||||
$('#submitVillage').prop('disabled', true);
|
||||
|
||||
} else {
|
||||
|
||||
$('#villageMessage')
|
||||
.text(response.message)
|
||||
.css('color', 'green');
|
||||
|
||||
$('#submitVillage').prop('disabled', false);
|
||||
}
|
||||
},
|
||||
|
||||
error: function () {
|
||||
|
||||
$('#villageMessage')
|
||||
.text(response.message)
|
||||
.text('Error checking village name')
|
||||
.css('color', 'red');
|
||||
|
||||
$('#submitVillage').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===============================
|
||||
// ADD VILLAGE (SAFE SCOPE FIX)
|
||||
// ===============================
|
||||
if ($('#villageForm').length) {
|
||||
|
||||
$('#villageForm').submit(function (event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
url: '/add_village',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
|
||||
success: function (response) {
|
||||
|
||||
if (response && response.status === 'success') {
|
||||
|
||||
alert(response.message || 'Village added successfully!');
|
||||
|
||||
// ✅ clear form
|
||||
$('#villageForm')[0].reset();
|
||||
|
||||
// ✅ switch to table
|
||||
$('#addForm').hide();
|
||||
$('#addTable').show();
|
||||
|
||||
// optional refresh
|
||||
location.reload();
|
||||
|
||||
} else {
|
||||
|
||||
$('#villageMessage')
|
||||
.text(response.message)
|
||||
.css('color', 'green');
|
||||
|
||||
$('#submitVillage').prop('disabled', false);
|
||||
|
||||
alert(response.message || 'Error adding village. Please try again.');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
error: function () {
|
||||
|
||||
$('#villageMessage')
|
||||
.text('Error checking village name')
|
||||
.css('color', 'red');
|
||||
|
||||
$('#submitVillage').prop('disabled', true);
|
||||
|
||||
alert('An error occurred. Please try again.');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
// ADD VILLAGE
|
||||
$('#villageForm').submit(function (event) {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
|
||||
url: '/add_village',
|
||||
type: 'POST',
|
||||
data: $(this).serialize(),
|
||||
|
||||
success: function (response) {
|
||||
|
||||
if (response.status === 'success') {
|
||||
|
||||
alert('Village added successfully!');
|
||||
location.reload();
|
||||
|
||||
} else {
|
||||
|
||||
alert(response.message || 'Error adding village. Please try again.');
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
error: function () {
|
||||
|
||||
alert('An error occurred. Please try again.');
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
// 🔥 DELETE FUNCTION (UPDATED)
|
||||
function deleteVillage(villageId) {
|
||||
|
||||
if (!confirm("Are you sure you want to delete this village?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ save that user is on table
|
||||
localStorage.setItem("viewMode", "table");
|
||||
// ===============================
|
||||
// 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',
|
||||
|
||||
success: function () {
|
||||
|
||||
setTimeout(function () {
|
||||
|
||||
alert("Village deleted successfully!");
|
||||
|
||||
// reload but stay on table
|
||||
location.reload();
|
||||
|
||||
}, 1000);
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
@@ -15,17 +15,21 @@
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="addForm" style="display: none;">
|
||||
<h2>Add GST Release</h2>
|
||||
<form action="/add_gst_release" method="POST" onsubmit="showSuccessAlert(event)">
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
|
||||
<div id="subcontractor_list" class="autocomplete-items"></div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<!-- Text input for user-friendly autocomplete -->
|
||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
|
||||
|
||||
<!-- 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>
|
||||
</div>
|
||||
|
||||
<label for="PMC_No">PMC No:</label><br>
|
||||
@@ -37,19 +41,19 @@
|
||||
</select><br><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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</form>
|
||||
@@ -68,96 +72,110 @@
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<!-- GST Release History Table -->
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>GST Release History</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
<input type="text" id="searchBar" placeholder="Search..." onkeyup="searchTable()">
|
||||
</div>
|
||||
<table id="sortableTable" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable-header">GST_Release_Id</th>
|
||||
<th class="sortable-header">PMC_No</th>
|
||||
<th>Invoice_No</th>
|
||||
<th>Basic_Amount</th>
|
||||
<th>Final_Amount</th>
|
||||
<th>Total_Amount</th>
|
||||
<th>UTR</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="sortable-header">GST_Release_Id</th>
|
||||
<th class="sortable-header">PMC_No</th>
|
||||
<th>Invoice_No</th>
|
||||
<th>Basic_Amount</th>
|
||||
<th>Final_Amount</th>
|
||||
<th>Total_Amount</th>
|
||||
<th>UTR</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for gst_rel in gst_releases %}
|
||||
<tr>
|
||||
<td>{{ gst_rel[0] }}</td>
|
||||
<td>{{ gst_rel[1] }}</td>
|
||||
<td>{{ gst_rel[2] }}</td>
|
||||
<td>{{ gst_rel[3] }}</td>
|
||||
<td>{{ gst_rel[4] }}</td>
|
||||
<td>{{ gst_rel[5] }}</td>
|
||||
<td>{{ gst_rel[6] }}</td>
|
||||
<td>
|
||||
<a href="/edit_gst_release/{{ gst_rel[0] }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||
class="icon">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/delete_gst_release/{{ gst_rel[0] }}"
|
||||
onclick="return confirm('Are you sure you want to delete this GST Release?')">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete"
|
||||
class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% for gst_rel in gst_releases %}
|
||||
<tr>
|
||||
<td>{{ gst_rel.gst_release_id }}</td>
|
||||
<td>{{ gst_rel.pmc_no }}</td>
|
||||
<td>{{ gst_rel.invoice_no }}</td>
|
||||
<td>{{ gst_rel.basic_amount }}</td>
|
||||
<td>{{ gst_rel.final_amount }}</td>
|
||||
<td>{{ gst_rel.total_amount }}</td>
|
||||
<td>{{ gst_rel.utr }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('gst_release_bp.edit_gst_release', gst_release_id=gst_rel.gst_release_id) }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('gst_release_bp.delete_gst_release', gst_release_id=gst_rel.gst_release_id) }}"
|
||||
onclick="return confirm('Are you sure you want to delete this GST Release?')">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
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 list = document.getElementById("subcontractor_list");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
list.innerHTML = '';
|
||||
subcontractorList.innerHTML = '';
|
||||
data.results.forEach(item => {
|
||||
const div = document.createElement("div");
|
||||
div.setAttribute("data-id", item.id);
|
||||
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 selectedName = e.target.textContent;
|
||||
|
||||
if (selectedId) {
|
||||
document.getElementById("subcontractor_id").value = selectedId;
|
||||
document.getElementById("subcontractor").value = selectedName;
|
||||
document.getElementById("subcontractor_list").innerHTML = "";
|
||||
// Set hidden field for backend
|
||||
subcontractorIdInput.value = selectedId;
|
||||
|
||||
// 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)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const pmcDropdown = document.getElementById("PMC_No");
|
||||
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>';
|
||||
|
||||
data.pmc_nos.forEach(pmc => {
|
||||
const option = document.createElement("option");
|
||||
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>
|
||||
|
||||
|
||||
@@ -1,59 +1,73 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<title>Manage Hold Types</title>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- <script src="{{ url_for('static', filename='js/hold_types.js') }}"></script> -->
|
||||
<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>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
|
||||
<div id="addForm">
|
||||
<h2>Add Hold Types</h2>
|
||||
<form id="holdTypeForm" method="POST" action="{{ url_for('hold_types.add_hold_type') }}">
|
||||
<label>Enter Hold Amount Type:</label>
|
||||
<input type="text" id="hold_type" name="hold_type" placeholder="Enter Type" required>
|
||||
<span id="holdTypeMessage"></span>
|
||||
<button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>Hold Type List</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
</div>
|
||||
<table id="sortableTable" border="1">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th class="sortable-header">
|
||||
Hold Type
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span>
|
||||
</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
{% for htd in Hold_Types_data %}
|
||||
<tr>
|
||||
<td>{{ htd['hold_type_id'] }}</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><button class="delete-button" data-id="{{ htd['hold_type_id'] }}">Delete</button></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<div id="addForm">
|
||||
<h2>Add Hold Types</h2>
|
||||
<form id="holdTypeForm" method="POST" action="{{ url_for('hold_types.add_hold_type') }}">
|
||||
<label>Enter Hold Amount Type:</label>
|
||||
<input type="text" id="hold_type" name="hold_type" placeholder="Enter Type" required>
|
||||
<span id="holdTypeMessage"></span>
|
||||
<button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<a href="/">Back to Dashboard</a>
|
||||
</div>
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>Hold Type List</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
</div>
|
||||
<table id="sortableTable" border="1">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th class="sortable-header">
|
||||
Hold Type
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span>
|
||||
</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
{% for htd in Hold_Types_data %}
|
||||
<tr>
|
||||
<td>{{ htd['hold_type_id'] }}</td>
|
||||
<td>{{ htd['hold_type'] }}</td>
|
||||
<td style="text-align:center;">
|
||||
<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>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<a href="/">Back to Dashboard</a>
|
||||
</div>
|
||||
</body>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,176 +1,322 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
<head xmlns="http://www.w3.org/1999/html">
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Add Invoice</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Add Invoice</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='css/invoice.css') }}"
|
||||
/>
|
||||
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% if success == 'true' %}
|
||||
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert">
|
||||
{% if success == 'true' %}
|
||||
<div
|
||||
class="alert alert-success alert-dismissible fade show mt-3"
|
||||
role="alert"
|
||||
>
|
||||
✅ Invoice added successfully!
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<!-- Flash Messages -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="flash-messages">
|
||||
{% for category, message in messages %}
|
||||
<div class="alert {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="alert"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="button-container">
|
||||
<!-- Flash Messages -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %} {% if
|
||||
messages %}
|
||||
<div class="flash-messages">
|
||||
{% for category, message in messages %}
|
||||
<div class="alert {{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %} {% endwith %}
|
||||
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</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>
|
||||
|
||||
<form id="invoiceForm" action="{{ url_for('invoice.add_invoice') }}" method="POST">
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
|
||||
<div id="subcontractor_list"></div>
|
||||
</div>
|
||||
<form
|
||||
id="invoiceForm"
|
||||
action="{{ url_for('invoice.add_invoice') }}"
|
||||
method="POST"
|
||||
>
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="subcontractor"
|
||||
name="subcontractor"
|
||||
required
|
||||
autocomplete="off"
|
||||
/>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id" />
|
||||
<div id="subcontractor_list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="village">Village Name:</label>
|
||||
<select id="village" name="village" required>
|
||||
<option value="">-- Select Village --</option>
|
||||
{% for village in villages %}
|
||||
<option value="{{ village.Village_Name }}">{{ village.Village_Name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pmc_no">PMC No:</label>
|
||||
<input type="text" id="pmc_no" name="pmc_no" required/>
|
||||
<div id="pmc_no_list" class="autocomplete-list"></div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="village">Village Name:</label>
|
||||
<select id="village" name="village" required>
|
||||
<option value="">-- Select Village --</option>
|
||||
{% for village in villages %}
|
||||
<option value="{{ village.Village_Name }}">
|
||||
{{ village.Village_Name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="work_type">Work Type:</label>
|
||||
<input type="text" id="work_type" name="work_type" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_details">Invoice Details:</label>
|
||||
<textarea id="invoice_details" name="invoice_details" required></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pmc_no">PMC No:</label>
|
||||
<input type="text" id="pmc_no" name="pmc_no" required />
|
||||
<div id="pmc_no_list" class="autocomplete-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="invoice_no">Invoice No:</label>
|
||||
<input type="text" id="invoice_no" name="invoice_no" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_date">Invoice Date:</label>
|
||||
<input type="date" id="invoice_date" name="invoice_date" required/>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="work_type">Work Type:</label>
|
||||
<input type="text" id="work_type" name="work_type" required />
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="basic_amount">Basic Amount:</label>
|
||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="debit_amount">Debit Amount:</label>
|
||||
<input type="number" step="0.01" id="debit_amount" name="debit_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="after_debit_amount">After Debit Amount:</label>
|
||||
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div class="percentage-field">
|
||||
<label for="gst_percentage">GST %:</label>
|
||||
<input type="number" step="0.01" id="gst_percentage" name="gst_percentage" placeholder="%"/>
|
||||
<label for="gst_amount">GST Amount:</label>
|
||||
<input type="number" step="0.01" id="gst_amount" name="gst_amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="amount">Amount:</label>
|
||||
<input type="number" step="0.01" id="amount" name="amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="tds_percentage">TDS %:</label>
|
||||
<input type="number" step="0.01" id="tds_percentage" name="tds_percentage" placeholder="%"/>
|
||||
<label for="tds_amount">TDS Amount:</label>
|
||||
<input type="number" step="0.01" id="tds_amount" name="tds_amount" placeholder="₹ - 00.00" readonly required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div class="percentage-field">
|
||||
<label for="sd_percentage">SD %:</label>
|
||||
<input type="number" step="0.01" id="sd_percentage" name="sd_percentage" placeholder="%"/>
|
||||
<label for="sd_amount">SD Amount:</label>
|
||||
<input type="number" step="0.01" id="sd_amount" name="sd_amount" placeholder="₹ - 00.00" readonly required>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="commission_percentage">On Commission %:</label>
|
||||
<input type="number" step="0.01" id="commission_percentage" name="commission_percentage" placeholder="%"/>
|
||||
<label for="on_commission">On Commission:</label>
|
||||
<input type="number" step="0.01" id="on_commission" name="on_commission" placeholder="₹ - 00.00" readonly required>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="hydro_percentage">Hydro Testing %:</label>
|
||||
<input type="number" step="0.01" id="hydro_percentage" name="hydro_percentage" placeholder="%"/>
|
||||
<label for="hydro_testing">Hydro Testing:</label>
|
||||
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" placeholder="₹ - 00.00" readonly required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hold-row">
|
||||
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button>
|
||||
<div>
|
||||
<label for="invoice_details">Invoice Details:</label>
|
||||
<textarea
|
||||
id="invoice_details"
|
||||
name="invoice_details"
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dynamically added hold amount fields -->
|
||||
<div id="hold_amount_container"></div>
|
||||
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
||||
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="final_amount">Final Amount:</label>
|
||||
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required/>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="invoice_no">Invoice No:</label>
|
||||
<input type="text" id="invoice_no" name="invoice_no" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_date">Invoice Date:</label>
|
||||
<input type="date" id="invoice_date" name="invoice_date" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button">Submit</button>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="basic_amount">Basic Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="basic_amount"
|
||||
name="basic_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="debit_amount">Debit Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="debit_amount"
|
||||
name="debit_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="after_debit_amount">After Debit Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="after_debit_amount"
|
||||
name="after_debit_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div class="percentage-field">
|
||||
<label for="gst_percentage">GST %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="gst_percentage"
|
||||
name="gst_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<label for="gst_amount">GST Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="gst_amount"
|
||||
name="gst_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="amount">Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="amount"
|
||||
name="amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="tds_percentage">TDS %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="tds_percentage"
|
||||
name="tds_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<label for="tds_amount">TDS Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="tds_amount"
|
||||
name="tds_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row3">
|
||||
<div class="percentage-field">
|
||||
<label for="sd_percentage">SD %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="sd_percentage"
|
||||
name="sd_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<label for="sd_amount">SD Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="sd_amount"
|
||||
name="sd_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="commission_percentage">On Commission %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="commission_percentage"
|
||||
name="commission_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<label for="on_commission">On Commission:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="on_commission"
|
||||
name="on_commission"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="percentage-field">
|
||||
<label for="hydro_percentage">Hydro Testing %:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="hydro_percentage"
|
||||
name="hydro_percentage"
|
||||
placeholder="%"
|
||||
/>
|
||||
<label for="hydro_testing">Hydro Testing:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="hydro_testing"
|
||||
name="hydro_testing"
|
||||
placeholder="₹ - 00.00"
|
||||
readonly
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hold-row">
|
||||
<button type="button" id="add_hold_amount" class="button">
|
||||
+ Add Hold Amount
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Dynamically added hold amount fields -->
|
||||
<div id="hold_amount_container"></div>
|
||||
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="gst_sd_amount"
|
||||
name="gst_sd_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="final_amount">Final Amount:</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
id="final_amount"
|
||||
name="final_amount"
|
||||
placeholder="₹ - 00.00"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none;">
|
||||
<div id="addTable" style="display: none">
|
||||
<!-- Invoice Table Section -->
|
||||
<div class="search-container">
|
||||
<h2>Invoice List</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
{% if invoices %}
|
||||
<table class="invoice-table">
|
||||
<h2>Invoice List</h2>
|
||||
<input
|
||||
type="text"
|
||||
id="searchBar"
|
||||
placeholder="Searching..."
|
||||
onkeyup="searchTable()"
|
||||
/>
|
||||
{% if invoices %}
|
||||
<table class="invoice-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<tr>
|
||||
<th>Invoice Id</th>
|
||||
<th>SubContractor Name</th>
|
||||
<th>PMC No</th>
|
||||
@@ -192,11 +338,11 @@
|
||||
<th>Final Amount</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for invoice in invoices %}
|
||||
<tr>
|
||||
{% for invoice in invoices %}
|
||||
<tr>
|
||||
<td>{{ invoice.Invoice_Id }}</td>
|
||||
<td>{{ invoice.Contractor_Name }}</td>
|
||||
<td>{{ invoice.PMC_No }}</td>
|
||||
@@ -217,62 +363,77 @@
|
||||
<td>{{ invoice.GST_SD_Amount }}</td>
|
||||
<td>{{ invoice.Final_Amount }}</td>
|
||||
<td>
|
||||
<!-- Edit -->
|
||||
<a href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
|
||||
</a>
|
||||
<!-- Edit -->
|
||||
<a
|
||||
href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
|
||||
>
|
||||
<img
|
||||
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
|
||||
alt="Edit"
|
||||
class="icon edit-btn"
|
||||
data-id="{{ invoice.Invoice_Id }}"
|
||||
/>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<!-- Delete -->
|
||||
<a href="{{ url_for('invoice.delete_invoice_route', invoice_id=invoice.Invoice_Id) }}" onclick="return confirm('Are you sure?')">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
|
||||
</a>
|
||||
<a
|
||||
href="javascript:void(0);"
|
||||
onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
|
||||
>
|
||||
<img
|
||||
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||
alt="Delete"
|
||||
class="icon"
|
||||
/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No invoices found.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</table>
|
||||
{% else %}
|
||||
<p>No invoices found.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Get all the input fields
|
||||
const basicAmount = document.getElementById('basic_amount');
|
||||
const debitAmount = document.getElementById('debit_amount');
|
||||
const afterDebitAmount = document.getElementById('after_debit_amount');
|
||||
const amount = document.getElementById('amount');
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Get all the input fields
|
||||
const basicAmount = document.getElementById("basic_amount");
|
||||
const debitAmount = document.getElementById("debit_amount");
|
||||
const afterDebitAmount = document.getElementById("after_debit_amount");
|
||||
const amount = document.getElementById("amount");
|
||||
|
||||
// Percentage fields
|
||||
const gstPercentage = document.getElementById('gst_percentage');
|
||||
const gstAmount = document.getElementById('gst_amount');
|
||||
const tdsPercentage = document.getElementById('tds_percentage');
|
||||
const tdsAmount = document.getElementById('tds_amount');
|
||||
const sdPercentage = document.getElementById('sd_percentage');
|
||||
const sdAmountInput = document.getElementById('sd_amount');
|
||||
const commissionPercentage = document.getElementById('commission_percentage');
|
||||
const onCommission = document.getElementById('on_commission');
|
||||
const hydroPercentage = document.getElementById('hydro_percentage');
|
||||
const hydroTesting = document.getElementById('hydro_testing');
|
||||
const gstSdAmount = document.getElementById('gst_sd_amount');
|
||||
const finalAmount = document.getElementById('final_amount');
|
||||
// Percentage fields
|
||||
const gstPercentage = document.getElementById("gst_percentage");
|
||||
const gstAmount = document.getElementById("gst_amount");
|
||||
const tdsPercentage = document.getElementById("tds_percentage");
|
||||
const tdsAmount = document.getElementById("tds_amount");
|
||||
const sdPercentage = document.getElementById("sd_percentage");
|
||||
const sdAmountInput = document.getElementById("sd_amount");
|
||||
const commissionPercentage = document.getElementById(
|
||||
"commission_percentage",
|
||||
);
|
||||
const onCommission = document.getElementById("on_commission");
|
||||
const hydroPercentage = document.getElementById("hydro_percentage");
|
||||
const hydroTesting = document.getElementById("hydro_testing");
|
||||
const gstSdAmount = document.getElementById("gst_sd_amount");
|
||||
const finalAmount = document.getElementById("final_amount");
|
||||
|
||||
// Calculate after debit amount when basic or debit amount changes
|
||||
function calculateAfterDebitAmount() {
|
||||
const basic = parseFloat(basicAmount.value) || 0;
|
||||
const debit = parseFloat(debitAmount.value) || 0;
|
||||
const afterDebit = basic - debit;
|
||||
afterDebitAmount.value = afterDebit.toFixed(2);
|
||||
calculateGST();
|
||||
}
|
||||
// Calculate after debit amount when basic or debit amount changes
|
||||
function calculateAfterDebitAmount() {
|
||||
const basic = parseFloat(basicAmount.value) || 0;
|
||||
const debit = parseFloat(debitAmount.value) || 0;
|
||||
const afterDebit = basic - debit;
|
||||
afterDebitAmount.value = afterDebit.toFixed(2);
|
||||
calculateGST();
|
||||
}
|
||||
|
||||
// Calculate GST and Amount
|
||||
function calculateGST() {
|
||||
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
|
||||
// Calculate GST and Amount
|
||||
function calculateGST() {
|
||||
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
|
||||
|
||||
if (gstPercentage.value) {
|
||||
if (gstPercentage.value) {
|
||||
const gstPerc = parseFloat(gstPercentage.value) || 0;
|
||||
const gstAmt = (baseAmount * gstPerc) / 100;
|
||||
gstAmount.value = gstAmt.toFixed(2);
|
||||
@@ -280,91 +441,96 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
// Calculate Amount (After Debit + GST)
|
||||
amount.value = (baseAmount + gstAmt).toFixed(2);
|
||||
} else {
|
||||
} else {
|
||||
amount.value = baseAmount.toFixed(2);
|
||||
}
|
||||
|
||||
calculateOtherDeductions();
|
||||
}
|
||||
|
||||
calculateOtherDeductions();
|
||||
}
|
||||
// Calculate other deductions (TDS, SD, Commission, Hydro)
|
||||
function calculateOtherDeductions() {
|
||||
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
|
||||
|
||||
// Calculate other deductions (TDS, SD, Commission, Hydro)
|
||||
function calculateOtherDeductions() {
|
||||
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
|
||||
|
||||
// Calculate TDS
|
||||
if (tdsPercentage.value) {
|
||||
// Calculate TDS
|
||||
if (tdsPercentage.value) {
|
||||
const tdsPerc = parseFloat(tdsPercentage.value) || 0;
|
||||
const tdsAmt = (baseAmount * tdsPerc) / 100;
|
||||
tdsAmount.value = tdsAmt.toFixed(2);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate SD
|
||||
if (sdPercentage.value) {
|
||||
// Calculate SD
|
||||
if (sdPercentage.value) {
|
||||
const sdPerc = parseFloat(sdPercentage.value) || 0;
|
||||
const sdAmt = (baseAmount * sdPerc) / 100;
|
||||
sdAmountInput.value = sdAmt.toFixed(2);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Commission
|
||||
if (commissionPercentage.value) {
|
||||
// Calculate Commission
|
||||
if (commissionPercentage.value) {
|
||||
const commPerc = parseFloat(commissionPercentage.value) || 0;
|
||||
const commAmt = (baseAmount * commPerc) / 100;
|
||||
onCommission.value = commAmt.toFixed(2);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Hydro Testing
|
||||
if (hydroPercentage.value) {
|
||||
// Calculate Hydro Testing
|
||||
if (hydroPercentage.value) {
|
||||
const hydroPerc = parseFloat(hydroPercentage.value) || 0;
|
||||
const hydroAmt = (baseAmount * hydroPerc) / 100;
|
||||
hydroTesting.value = hydroAmt.toFixed(2);
|
||||
}
|
||||
|
||||
calculateFinalAmount();
|
||||
}
|
||||
|
||||
calculateFinalAmount();
|
||||
}
|
||||
// Calculate final amount
|
||||
function calculateFinalAmount() {
|
||||
const amt = parseFloat(amount.value) || 0;
|
||||
const tds = parseFloat(tdsAmount.value) || 0;
|
||||
const sd = parseFloat(sdAmountInput.value) || 0;
|
||||
const commission = parseFloat(onCommission.value) || 0;
|
||||
const hydro = parseFloat(hydroTesting.value) || 0;
|
||||
const gstSd = parseFloat(gstSdAmount.value) || 0;
|
||||
|
||||
// Calculate final amount
|
||||
function calculateFinalAmount() {
|
||||
const amt = parseFloat(amount.value) || 0;
|
||||
const tds = parseFloat(tdsAmount.value) || 0;
|
||||
const sd = parseFloat(sdAmountInput.value) || 0;
|
||||
const commission = parseFloat(onCommission.value) || 0;
|
||||
const hydro = parseFloat(hydroTesting.value) || 0;
|
||||
const gstSd = parseFloat(gstSdAmount.value) || 0;
|
||||
// Get hold amounts
|
||||
let totalHold = 0;
|
||||
document
|
||||
.querySelectorAll('input[name="hold_amount[]"]')
|
||||
.forEach((input) => {
|
||||
totalHold += parseFloat(input.value) || 0;
|
||||
});
|
||||
|
||||
// Get hold amounts
|
||||
let totalHold = 0;
|
||||
document.querySelectorAll('input[name="hold_amount[]"]').forEach(input => {
|
||||
totalHold += parseFloat(input.value) || 0;
|
||||
});
|
||||
// Final Amount = Amount - TDS - SD - Commission - Hydro - GST SD - Hold Amounts
|
||||
const final = amt - tds - sd - commission - hydro - gstSd - totalHold;
|
||||
finalAmount.value = final.toFixed(2);
|
||||
}
|
||||
|
||||
// Final Amount = Amount - TDS - SD - Commission - Hydro - GST SD - Hold Amounts
|
||||
const final = amt - tds - sd - commission - hydro - gstSd - totalHold;
|
||||
finalAmount.value = final.toFixed(2);
|
||||
}
|
||||
// Add event listeners
|
||||
basicAmount.addEventListener("input", calculateAfterDebitAmount);
|
||||
debitAmount.addEventListener("input", calculateAfterDebitAmount);
|
||||
|
||||
// Add event listeners
|
||||
basicAmount.addEventListener('input', calculateAfterDebitAmount);
|
||||
debitAmount.addEventListener('input', calculateAfterDebitAmount);
|
||||
// Percentage fields
|
||||
gstPercentage.addEventListener("input", calculateGST);
|
||||
tdsPercentage.addEventListener("input", calculateOtherDeductions);
|
||||
sdPercentage.addEventListener("input", calculateOtherDeductions);
|
||||
commissionPercentage.addEventListener(
|
||||
"input",
|
||||
calculateOtherDeductions,
|
||||
);
|
||||
hydroPercentage.addEventListener("input", calculateOtherDeductions);
|
||||
|
||||
// Percentage fields
|
||||
gstPercentage.addEventListener('input', calculateGST);
|
||||
tdsPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
sdPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
commissionPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
hydroPercentage.addEventListener('input', calculateOtherDeductions);
|
||||
// Listen for changes in hold amounts
|
||||
document.addEventListener("holdAmountChanged", calculateFinalAmount);
|
||||
});
|
||||
|
||||
// Listen for changes in hold amounts
|
||||
document.addEventListener('holdAmountChanged', calculateFinalAmount);
|
||||
});
|
||||
|
||||
// Optional JS for auto-hiding flash
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('.alert').forEach(el => el.style.display = 'none');
|
||||
}, 5000);
|
||||
</script>
|
||||
|
||||
|
||||
</div>
|
||||
// Optional JS for auto-hiding flash
|
||||
setTimeout(() => {
|
||||
document
|
||||
.querySelectorAll(".alert")
|
||||
.forEach((el) => (el.style.display = "none"));
|
||||
}, 5000);
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -8,91 +9,104 @@
|
||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
|
||||
<div id="addForm" style="display: none;">
|
||||
<h2>Add Payment</h2>
|
||||
|
||||
<form action="/add_payment" method="POST" onsubmit="showSuccessAlert(event)">
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/>
|
||||
<div id="subcontractor_list" class="autocomplete-items"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="PMC_No">PMC No:</label><br>
|
||||
<select id="PMC_No" name="PMC_No" required>
|
||||
<option value="">Select PMC No</option>
|
||||
</select><br><br>
|
||||
|
||||
<label for="invoice_No">Invoice No:</label><br>
|
||||
<input type="number" step="0.01" id="invoice_No" name="invoice_No" ><br><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>
|
||||
|
||||
<label for="TDS_Percentage">TDS Percentage (%):</label><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>
|
||||
<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>
|
||||
<input type="number" step="0.01" id="total_amount" name="total_amount" required readonly><br><br>
|
||||
|
||||
|
||||
<label for="utr">UTR:</label><br>
|
||||
<input type="text" id="utr" name="utr"><br><br>
|
||||
|
||||
<button type="submit">Submit Payment</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="successPopup" class="success-popup">
|
||||
<i>✔</i> Payment added successfully!
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>Payment History</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
<table id="sortableTable" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable-header">Payment ID</th>
|
||||
<th class="sortable-header">PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>TDS Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for payment in payments %}
|
||||
<tr>
|
||||
<td>{{ payment[0] }}</td>
|
||||
<td>{{ payment[1] }}</td>
|
||||
<td>{{ payment[2] }}</td>
|
||||
<td>{{ payment[3] }}</td>
|
||||
<td>{{ payment[4] }}</td>
|
||||
<td>{{ payment[5] }}</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="/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>
|
||||
</tr>
|
||||
<!-- <tr>
|
||||
|
||||
<div id="addForm" style="display: none;">
|
||||
<h2>Add Payment</h2>
|
||||
|
||||
<form action="/add_payment" method="POST" onsubmit="showSuccessAlert(event)">
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off" />
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id" />
|
||||
<div id="subcontractor_list" class="autocomplete-items"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label for="PMC_No">PMC No:</label><br>
|
||||
<select id="PMC_No" name="PMC_No" required>
|
||||
<option value="">Select PMC No</option>
|
||||
</select><br><br>
|
||||
|
||||
<label for="invoice_No">Invoice No:</label><br>
|
||||
<input type="number" step="0.01" id="invoice_No" name="invoice_No"><br><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>
|
||||
|
||||
<label for="TDS_Percentage">TDS Percentage (%):</label><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>
|
||||
<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>
|
||||
<input type="number" step="0.01" id="total_amount" name="total_amount" required readonly><br><br>
|
||||
|
||||
|
||||
<label for="utr">UTR:</label><br>
|
||||
<input type="text" id="utr" name="utr"><br><br>
|
||||
|
||||
<button type="submit">Submit Payment</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="successPopup" class="success-popup">
|
||||
<i>✔</i> Payment added successfully!
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none;">
|
||||
<div class="search-container">
|
||||
<h2>Payment History</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
</div>
|
||||
<table id="sortableTable" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable-header">Payment ID</th>
|
||||
<th class="sortable-header">PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>TDS Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for payment in payments %}
|
||||
<tr>
|
||||
<td>{{ payment[0] }}</td>
|
||||
<td>{{ payment[1] }}</td>
|
||||
<td>{{ payment[2] }}</td>
|
||||
<td>{{ payment[3] }}</td>
|
||||
<td>{{ payment[4] }}</td>
|
||||
<td>{{ payment[5] }}</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="{{ 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>
|
||||
<td>{{ payment['Payment_Id'] }}</td>
|
||||
<td>{{ payment['PMC_No'] }}</td>
|
||||
<td>{{ payment['invoice_no'] }}</td>
|
||||
@@ -103,91 +117,91 @@
|
||||
<td><a href="/edit_payment/{{ payment['Payment_Id'] }}"><img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon"></a></td>
|
||||
<td><a href="/delete_payment/{{ payment['Payment_Id'] }}" 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> -->
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById("subcontractor").addEventListener("input", function () {
|
||||
const query = this.value;
|
||||
const list = document.getElementById("subcontractor_list");
|
||||
<script>
|
||||
document.getElementById("subcontractor").addEventListener("input", function () {
|
||||
const query = this.value;
|
||||
const list = document.getElementById("subcontractor_list");
|
||||
|
||||
if (query.length < 2) {
|
||||
list.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
if (query.length < 2) {
|
||||
list.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
list.innerHTML = '';
|
||||
data.results.forEach(item => {
|
||||
const div = document.createElement("div");
|
||||
div.setAttribute("data-id", item.id);
|
||||
div.textContent = item.name;
|
||||
list.appendChild(div);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
|
||||
const selectedId = e.target.getAttribute("data-id");
|
||||
const selectedName = e.target.textContent;
|
||||
|
||||
if (selectedId) {
|
||||
document.getElementById("subcontractor_id").value = selectedId;
|
||||
document.getElementById("subcontractor").value = selectedName;
|
||||
document.getElementById("subcontractor_list").innerHTML = ""; // hide the list
|
||||
|
||||
console.log("Contractor id is", selectedId);
|
||||
|
||||
// Fetch PMC numbers
|
||||
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Fetched PMC Nos:", data.pmc_nos);
|
||||
const pmcDropdown = document.getElementById("PMC_No");
|
||||
pmcDropdown.innerHTML = "";
|
||||
|
||||
const defaultOption = document.createElement("option");
|
||||
defaultOption.value = "";
|
||||
defaultOption.textContent = "Select PMC No";
|
||||
pmcDropdown.appendChild(defaultOption);
|
||||
|
||||
data.pmc_nos.forEach(pmc => {
|
||||
const option = document.createElement("option");
|
||||
option.value = pmc;
|
||||
option.textContent = pmc;
|
||||
pmcDropdown.appendChild(option);
|
||||
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
list.innerHTML = '';
|
||||
data.results.forEach(item => {
|
||||
const div = document.createElement("div");
|
||||
div.setAttribute("data-id", item.id);
|
||||
div.textContent = item.name;
|
||||
list.appendChild(div);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (data.pmc_nos.length === 0) {
|
||||
alert("No PMC Nos found for this subcontractor.");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error fetching PMC Nos:", error);
|
||||
alert("Failed to fetch PMC numbers.");
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
document.getElementById("subcontractor_list").addEventListener("click", function (e) {
|
||||
const selectedId = e.target.getAttribute("data-id");
|
||||
const selectedName = e.target.textContent;
|
||||
|
||||
<script>
|
||||
function calculateTDSAndTotal() {
|
||||
const amount = parseFloat(document.getElementById("Payment_Amount").value) || 0;
|
||||
const tdsPercent = parseFloat(document.getElementById("TDS_Percentage").value) || 0;
|
||||
if (selectedId) {
|
||||
document.getElementById("subcontractor_id").value = selectedId;
|
||||
document.getElementById("subcontractor").value = selectedName;
|
||||
document.getElementById("subcontractor_list").innerHTML = ""; // hide the list
|
||||
|
||||
const tdsAmount = (amount * tdsPercent / 100).toFixed(2);
|
||||
const totalAmount = (amount - tdsAmount).toFixed(2);
|
||||
console.log("Contractor id is", selectedId);
|
||||
|
||||
document.getElementById("TDS_Payment_Amount").value = tdsAmount;
|
||||
document.getElementById("total_amount").value = totalAmount;
|
||||
}
|
||||
</script>
|
||||
// Fetch PMC numbers
|
||||
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log("Fetched PMC Nos:", data.pmc_nos);
|
||||
const pmcDropdown = document.getElementById("PMC_No");
|
||||
pmcDropdown.innerHTML = "";
|
||||
|
||||
const defaultOption = document.createElement("option");
|
||||
defaultOption.value = "";
|
||||
defaultOption.textContent = "Select PMC No";
|
||||
pmcDropdown.appendChild(defaultOption);
|
||||
|
||||
data.pmc_nos.forEach(pmc => {
|
||||
const option = document.createElement("option");
|
||||
option.value = pmc;
|
||||
option.textContent = pmc;
|
||||
pmcDropdown.appendChild(option);
|
||||
});
|
||||
|
||||
if (data.pmc_nos.length === 0) {
|
||||
alert("No PMC Nos found for this subcontractor.");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error fetching PMC Nos:", error);
|
||||
alert("Failed to fetch PMC numbers.");
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function calculateTDSAndTotal() {
|
||||
const amount = parseFloat(document.getElementById("Payment_Amount").value) || 0;
|
||||
const tdsPercent = parseFloat(document.getElementById("TDS_Percentage").value) || 0;
|
||||
|
||||
const tdsAmount = (amount * tdsPercent / 100).toFixed(2);
|
||||
const totalAmount = (amount - tdsAmount).toFixed(2);
|
||||
|
||||
document.getElementById("TDS_Payment_Amount").value = tdsAmount;
|
||||
document.getElementById("total_amount").value = totalAmount;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script src="{{ url_for('static', filename='js/showSuccessAlert.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/showSuccessAlert.js') }}"></script>
|
||||
</body>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -1,99 +1,129 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% extends 'base.html' %} {% block content %}
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Village Management</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/village.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Village Management</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
href="{{ url_for('static', filename='css/style.css') }}"
|
||||
/>
|
||||
<script src="{{ url_for('static', filename='js/village.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Button Container to Center Buttons -->
|
||||
<div class="button-container">
|
||||
<!-- Button Container to Center Buttons -->
|
||||
<div class="button-container">
|
||||
<button id="addButton" class="action-button">Add</button>
|
||||
<button id="displayButton" class="action-button">Display</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="addForm" style="display: none;">
|
||||
<div id="addForm" style="display: none">
|
||||
<div class="container">
|
||||
<div class="form-block">
|
||||
<h2>Add a New Village</h2>
|
||||
<form id="villageForm" method="POST">
|
||||
<label for="state_Id">State:</label>
|
||||
<select id="state_Id" name="state_Id" required>
|
||||
<option value="" disabled selected>Select State</option>
|
||||
{% for state in states %}
|
||||
<option value="{{ state[0] }}">{{ state[1] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="district_Id">District:</label>
|
||||
<select id="district_Id" name="district_Id" required disabled>
|
||||
<option value="" disabled selected>Select District</option>
|
||||
</select>
|
||||
<div class="form-block">
|
||||
<h2>Add a New Village</h2>
|
||||
<form id="villageForm" method="POST">
|
||||
<label for="state_Id">State:</label>
|
||||
<select id="state_Id" name="state_Id" required>
|
||||
<option value="" disabled selected>Select State</option>
|
||||
{% for state in states %}
|
||||
<option value="{{ state[0] }}">{{ state[1] }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<label for="block_Id">Block:</label>
|
||||
<select id="block_Id" name="block_Id" required disabled>
|
||||
<option value="" disabled selected>Select Block</option>
|
||||
</select>
|
||||
<label for="district_Id">District:</label>
|
||||
<select id="district_Id" name="district_Id" required disabled>
|
||||
<option value="" disabled selected>Select District</option>
|
||||
</select>
|
||||
|
||||
<label for="Village_Name">Village Name:</label>
|
||||
<input type="text" id="Village_Name" name="Village_Name" placeholder="Enter Village Name" required>
|
||||
<span id="villageMessage"></span>
|
||||
<label for="block_Id">Block:</label>
|
||||
<select id="block_Id" name="block_Id" required disabled>
|
||||
<option value="" disabled selected>Select Block</option>
|
||||
</select>
|
||||
|
||||
<button type="submit" id="submitVillage" disabled>Add Village</button>
|
||||
</form>
|
||||
</div>
|
||||
<label for="Village_Name">Village Name:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="Village_Name"
|
||||
name="Village_Name"
|
||||
placeholder="Enter Village Name"
|
||||
required
|
||||
/>
|
||||
<span id="villageMessage"></span>
|
||||
|
||||
<button type="submit" id="submitVillage" disabled>Add Village</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="addTable" style="display: none;">
|
||||
<div id="addTable" style="display: none">
|
||||
<div class="search-container">
|
||||
<h2>Display Villages</h2>
|
||||
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()">
|
||||
<h2>Display Villages</h2>
|
||||
<input
|
||||
type="text"
|
||||
id="searchBar"
|
||||
placeholder="Searching..."
|
||||
onkeyup="searchTable()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<table id="sortableTable" border="1">
|
||||
<tr>
|
||||
<th>Village Sr No</th>
|
||||
<th class="sortable-header">
|
||||
Village Name
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span></th>
|
||||
<th class="sortable-header">Block Name
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span></th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
{% for village in villages %}
|
||||
<tr>
|
||||
<td>{{ village[0] }}</td>
|
||||
<td>{{ village[1] }}</td>
|
||||
<td>{{ village[2] }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('village.edit_village', village_id=village[0]) }}">
|
||||
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit"
|
||||
class="icon">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#"
|
||||
onclick="deleteVillage({{ village[0] }}); return false;">
|
||||
<tr>
|
||||
<th>Village Sr No</th>
|
||||
<th class="sortable-header">
|
||||
Village Name
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span>
|
||||
</th>
|
||||
<th class="sortable-header">
|
||||
Block Name
|
||||
<span class="sort-buttons">
|
||||
<span class="sort-asc">⬆️</span>
|
||||
<span class="sort-desc">⬇️</span>
|
||||
</span>
|
||||
</th>
|
||||
<th>Update</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
{% for village in villages %}
|
||||
<tr>
|
||||
<td>{{ village[0] }}</td>
|
||||
<td>{{ village[1] }}</td>
|
||||
<td>{{ village[2] }}</td>
|
||||
<td>
|
||||
<a
|
||||
href="{{ url_for('village.edit_village', village_id=village[0]) }}"
|
||||
>
|
||||
<img
|
||||
src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}"
|
||||
alt="Edit"
|
||||
class="icon"
|
||||
/>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="javascript:void(0);"
|
||||
onclick="deleteVillage({{ village[0] }}, this)">
|
||||
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
|
||||
alt="Delete" class="icon">
|
||||
class="icon">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</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>
|
||||
{% endblock %}
|
||||
|
||||
@@ -9,37 +9,37 @@
|
||||
<body>
|
||||
<h2>Edit GST Release</h2>
|
||||
|
||||
<form action="/edit_gst_release/{{ gst_release_data[0] }}" 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>-->
|
||||
<form action="/edit_gst_release/{{ gst_release_data.gst_release_id }}" method="POST">
|
||||
|
||||
<!-- PMC Number -->
|
||||
<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>
|
||||
<input type="number" step="0.01" id="invoice_No" name="invoice_No" value="{{ gst_release_data[2] }}"
|
||||
required><br><br>
|
||||
<!-- Invoice Number -->
|
||||
<label for="invoice_no">Invoice No:</label><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>
|
||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ gst_release_data[3] }}"
|
||||
required><br><br>
|
||||
<!-- Final Amount -->
|
||||
<label for="Final_Amount">Final Amount:</label><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>
|
||||
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ gst_release_data[4] }}"
|
||||
required><br><br>
|
||||
<!-- Total Amount -->
|
||||
<label for="Total_Amount">Total Amount:</label><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>
|
||||
<input type="number" step="0.01" id="total_amount" name="total_amount" value="{{ gst_release_data[5] }}"
|
||||
required><br><br>
|
||||
<!-- UTR -->
|
||||
<label for="UTR">UTR:</label><br>
|
||||
<input type="text" id="UTR" name="UTR" value="{{ gst_release_data.utr }}" readonly required><br><br>
|
||||
|
||||
<label for="utr">UTR:</label><br>
|
||||
<input type="text" id="utr" name="utr" value="{{ gst_release_data[6] }}"
|
||||
required readonly><br><br>
|
||||
<!-- Hidden Contractor ID -->
|
||||
<input type="hidden" id="Contractor_ID" name="Contractor_ID" value="{{ gst_release_data.contractor_id }}">
|
||||
|
||||
<button type="submit">Update GST Release</button>
|
||||
</form>
|
||||
|
||||
|
||||
</body>
|
||||
{% endblock %}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<title>Edit Hold Type</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
<body>
|
||||
<h2>Edit Hold Type</h2>
|
||||
<form id="updateHoldTypeForm">
|
||||
<input type="hidden" id="hold_type_id" value="{{ hold_type[0] }}">
|
||||
<form id="updateHoldTypeForm" method="POST">
|
||||
<input type="hidden" id="hold_type_id" value="{{ hold_type.hold_type_id }}">
|
||||
<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>
|
||||
<a href="{{ url_for('hold_types.add_hold_type') }}"></a>
|
||||
</form>
|
||||
@@ -37,7 +37,7 @@
|
||||
formData.append('hold_type', newHoldType);
|
||||
|
||||
$.ajax({
|
||||
url: '/update_hold_type/' + holdTypeId,
|
||||
url: '/edit_hold_type/' + holdTypeId,
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
@@ -54,9 +54,4 @@
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -2,168 +2,185 @@
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>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/style1.css') }}">
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="editForm">
|
||||
<h2>Edit Invoice</h2>
|
||||
<div id="editForm">
|
||||
<h2>Edit Invoice</h2>
|
||||
|
||||
<!-- Success Alert Box -->
|
||||
<div id="invoiceSuccessAlert" class="success-alert" style="display:none;">
|
||||
Invoice successfully updated!
|
||||
<!-- Success Alert Box -->
|
||||
<div id="invoiceSuccessAlert" class="success-alert" style="display:none;">
|
||||
Invoice successfully updated!
|
||||
</div>
|
||||
|
||||
<form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
|
||||
method="POST">
|
||||
|
||||
<!-- Subcontractor Field -->
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor"
|
||||
value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id"
|
||||
value="{{ invoice.Subcontractor_Id }}">
|
||||
<datalist id="subcontractor_list"></datalist>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Village and PMC No Fields -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="village">Village Name:</label>
|
||||
<input type="text" id="village" name="village" value="{{ invoice.Village_Name }}" required />
|
||||
<datalist id="village_list"></datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pmc_no">PMC No:</label>
|
||||
<input type="text" id="pmc_no" name="pmc_no" value="{{ invoice.PMC_No }}" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Work Type and Invoice Details -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="work_type">Work Type:</label>
|
||||
<input type="text" id="work_type" name="work_type" value="{{ invoice.Work_Type }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_details">Invoice Details:</label>
|
||||
<textarea id="invoice_details" name="invoice_details"
|
||||
required>{{ invoice.Invoice_Details }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Invoice No and Invoice Date -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="invoice_no">Invoice No:</label>
|
||||
<input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.invoice_no }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_date">Invoice Date:</label>
|
||||
<input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}"
|
||||
required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Amount Fields -->
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="basic_amount">Basic Amount:</label>
|
||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount"
|
||||
value="{{ invoice.Basic_Amount }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="debit_amount">Debit Amount:</label>
|
||||
<input type="number" step="0.01" id="debit_amount" name="debit_amount"
|
||||
value="{{ invoice.Debit_Amount }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="after_debit_amount">After Debit Amount:</label>
|
||||
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount"
|
||||
value="{{ invoice.After_Debit_Amount }}" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- GST, TDS, and Other Amounts -->
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="amount">Amount:</label>
|
||||
<input type="number" step="0.01" id="amount" name="amount" value="{{ invoice.Amount }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="gst_amount">GST Amount:</label>
|
||||
<input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}"
|
||||
required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="tds_amount">TDS Amount:</label>
|
||||
<input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}"
|
||||
required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SD, On Commission, Hydro Testing -->
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="sd_amount">SD Amount:</label>
|
||||
<input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}"
|
||||
required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="on_commission">On Commission:</label>
|
||||
<input type="number" step="0.01" id="on_commission" name="on_commission"
|
||||
value="{{ invoice.On_Commission }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="hydro_testing">Hydro Testing:</label>
|
||||
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing"
|
||||
value="{{ invoice.Hydro_Testing }}" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hold Amount Section -->
|
||||
<div id="hold_amount_container">
|
||||
{% set seen_types = [] %}
|
||||
{% for hold in invoice.hold_amounts %}
|
||||
{% if hold.hold_type not in seen_types %}
|
||||
{% set _ = seen_types.append(hold.hold_type) %}
|
||||
<div class="hold-amount-row">
|
||||
<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 />
|
||||
<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 />
|
||||
<button type="button" class="remove-hold-amount">Remove</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hold-row">
|
||||
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button>
|
||||
</div>
|
||||
|
||||
<!-- Final Amounts -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
||||
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount"
|
||||
value="{{ invoice.GST_SD_Amount }}" required />
|
||||
</div>
|
||||
<div>
|
||||
<label for="final_amount">Final Amount:</label>
|
||||
<input type="number" step="0.01" id="final_amount" name="final_amount"
|
||||
value="{{ invoice.Final_Amount }}" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button type="submit" class="button">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}" method="POST">
|
||||
|
||||
<!-- Subcontractor Field -->
|
||||
<div class="row1">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor"
|
||||
value="{{ invoice.Contractor_Name }}" placeholder="Type to search..." required>
|
||||
<input type="hidden" id="subcontractor_id" name="subcontractor_id" value="{{ invoice.Subcontractor_Id }}">
|
||||
<datalist id="subcontractor_list"></datalist>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Village and PMC No Fields -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="village">Village Name:</label>
|
||||
<input type="text" id="village" name="village" value="{{ invoice.Village_Name }}" required/>
|
||||
<datalist id="village_list"></datalist>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pmc_no">PMC No:</label>
|
||||
<input type="text" id="pmc_no" name="pmc_no" value="{{ invoice.PMC_No }}" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Work Type and Invoice Details -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="work_type">Work Type:</label>
|
||||
<input type="text" id="work_type" name="work_type" value="{{ invoice.Work_Type }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_details">Invoice Details:</label>
|
||||
<textarea id="invoice_details" name="invoice_details" required>{{ invoice.Invoice_Details }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Invoice No and Invoice Date -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="invoice_no">Invoice No:</label>
|
||||
<input type="text" id="invoice_no" name="invoice_no" value="{{ invoice.Invoice_No }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="invoice_date">Invoice Date:</label>
|
||||
<input type="date" id="invoice_date" name="invoice_date" value="{{ invoice.Invoice_Date }}" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Amount Fields -->
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="basic_amount">Basic Amount:</label>
|
||||
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ invoice.Basic_Amount }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="debit_amount">Debit Amount:</label>
|
||||
<input type="number" step="0.01" id="debit_amount" name="debit_amount" value="{{ invoice.Debit_Amount }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="after_debit_amount">After Debit Amount:</label>
|
||||
<input type="number" step="0.01" id="after_debit_amount" name="after_debit_amount" value="{{ invoice.After_Debit_Amount }}" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- GST, TDS, and Other Amounts -->
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="amount">Amount:</label>
|
||||
<input type="number" step="0.01" id="amount" name="amount" value="{{ invoice.Amount }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="gst_amount">GST Amount:</label>
|
||||
<input type="number" step="0.01" id="gst_amount" name="gst_amount" value="{{ invoice.GST_Amount }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="tds_amount">TDS Amount:</label>
|
||||
<input type="number" step="0.01" id="tds_amount" name="tds_amount" value="{{ invoice.TDS_Amount }}" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SD, On Commission, Hydro Testing -->
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="sd_amount">SD Amount:</label>
|
||||
<input type="number" step="0.01" id="sd_amount" name="sd_amount" value="{{ invoice.SD_Amount }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="on_commission">On Commission:</label>
|
||||
<input type="number" step="0.01" id="on_commission" name="on_commission" value="{{ invoice.On_Commission }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="hydro_testing">Hydro Testing:</label>
|
||||
<input type="number" step="0.01" id="hydro_testing" name="hydro_testing" value="{{ invoice.Hydro_Testing }}" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Hold Amount Section -->
|
||||
<div id="hold_amount_container">
|
||||
{% set seen_types = [] %}
|
||||
{% for hold in invoice.hold_amounts %}
|
||||
{% if hold.hold_type not in seen_types %}
|
||||
{% set _ = seen_types.append(hold.hold_type) %}
|
||||
<div class="hold-amount-row">
|
||||
<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/>
|
||||
<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/>
|
||||
<button type="button" class="remove-hold-amount">Remove</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hold-row">
|
||||
<button type="button" id="add_hold_amount" class="button">+ Add Hold Amount</button>
|
||||
</div>
|
||||
|
||||
<!-- Final Amounts -->
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="gst_sd_amount">GST SD Amount:</label>
|
||||
<input type="number" step="0.01" id="gst_sd_amount" name="gst_sd_amount" value="{{ invoice.GST_SD_Amount }}" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="final_amount">Final Amount:</label>
|
||||
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ invoice.Final_Amount }}" required/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<button type="submit" class="button">Update</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- JS for dynamic hold amount rows -->
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Add new hold amount row
|
||||
$("#add_hold_amount").click(function() {
|
||||
const index = $("#hold_amount_container .hold-amount-row").length;
|
||||
const newRow = `
|
||||
<!-- JS for dynamic hold amount rows -->
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
// Add new hold amount row
|
||||
$("#add_hold_amount").click(function () {
|
||||
const index = $("#hold_amount_container .hold-amount-row").length;
|
||||
const newRow = `
|
||||
<div class="hold-amount-row">
|
||||
<label for="hold_type_${index}">Hold Type:</label>
|
||||
<input type="text" id="hold_type_${index}" name="hold_type[]" required/>
|
||||
@@ -172,36 +189,38 @@ $(document).ready(function() {
|
||||
<button type="button" class="remove-hold-amount">Remove</button>
|
||||
</div>
|
||||
`;
|
||||
$("#hold_amount_container").append(newRow);
|
||||
});
|
||||
$("#hold_amount_container").append(newRow);
|
||||
});
|
||||
|
||||
// Remove hold amount row
|
||||
$(document).on("click", ".remove-hold-amount", function() {
|
||||
$(this).closest(".hold-amount-row").remove();
|
||||
});
|
||||
// Remove hold amount row
|
||||
$(document).on("click", ".remove-hold-amount", function () {
|
||||
$(this).closest(".hold-amount-row").remove();
|
||||
});
|
||||
|
||||
// Submit form via AJAX
|
||||
$("#invoiceForm").submit(function(e) {
|
||||
e.preventDefault();
|
||||
// Submit form via AJAX
|
||||
$("#invoiceForm").submit(function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: $(this).attr("action"),
|
||||
data: $(this).serialize(),
|
||||
success: function(response) {
|
||||
if(response.status === "success") {
|
||||
$("#invoiceSuccessAlert").fadeIn().delay(3000).fadeOut();
|
||||
alert("Invoice updated successfully!"); // <-- Popup alert
|
||||
}
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: $(this).attr("action"),
|
||||
data: $(this).serialize(),
|
||||
dataType: 'json', // ensure JSON is returned
|
||||
success: function (response) {
|
||||
if (response.status === "success") {
|
||||
alert("Invoice updated successfully!"); // <-- Popup alert
|
||||
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert("Error: " + xhr.responseJSON.message);
|
||||
}
|
||||
// ✅ Redirect to Add Invoice page (table part visible)
|
||||
window.location.href = "{{ url_for('invoice.add_invoice') }}#addTable";
|
||||
}
|
||||
},
|
||||
error: function (xhr) {
|
||||
alert("Error: " + xhr.responseJSON?.message || "Something went wrong!");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
{% endblock %}
|
||||
@@ -28,25 +28,17 @@
|
||||
|
||||
<button type="submit">Update Village</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Flash Message (Hidden, used for JS popup) -->
|
||||
<!-- Flash Messages (hidden, used for JS popup) -->
|
||||
<div id="flash-messages-container" style="display:none;">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div id="flash-message" data-category="{{ category }}" style="display:none;">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if messages %}
|
||||
{% for category, message in messages %}
|
||||
<div class="flash-message" data-category="{{ category }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.onload = function () {
|
||||
const flash = document.getElementById('flash-message');
|
||||
if (flash && flash.innerText.trim() !== "") {
|
||||
alert(flash.innerText);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
</body>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -9,332 +8,337 @@
|
||||
<!-- <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/subcontractor_report.css') }}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<h2>PMC Report</h2>
|
||||
<div class="container">
|
||||
<h2>PMC Report</h2>
|
||||
|
||||
<div class="info">
|
||||
<h2>Contractor Details</h2>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" value="{{ info.Contractor_Name }}"
|
||||
readonly/>
|
||||
<div class="info">
|
||||
<h2>Contractor Details</h2>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}"
|
||||
readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Address">Address :</label>
|
||||
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Address">Address :</label>
|
||||
<textarea id="Address" name="Address" readonly>{{ info.Address }}</textarea>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="PAN_No">PAN No :</label>
|
||||
<input type="text" id="PAN_No" name="PAN_No" value="{{ contInfo.PAN_No }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Mobile_No">Mobile Number :</label>
|
||||
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ contInfo.Mobile_No }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Email">Email :</label>
|
||||
<input type="text" id="Email" name="Email" value="{{ contInfo.Email }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="PAN_No">PAN No :</label>
|
||||
<input type="text" id="PAN_No" name="PAN_No" value="{{ info.PAN_No }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Mobile_No">Mobile Number :</label>
|
||||
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ info.Mobile_No }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Email">Email :</label>
|
||||
<input type="text" id="Email" name="Email" value="{{ info.Email }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="GST_Registration_Type">GST Registration Type :</label>
|
||||
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
|
||||
value="{{ info.GST_Registration_Type }}" readonly/>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="GST_Registration_Type">GST Registration Type :</label>
|
||||
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
|
||||
value="{{ contInfo.GST_Registration_Type }}" readonly />
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<label for="GST_No">GST No:</label>
|
||||
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="GST_No">GST No:</label>
|
||||
<input type="text" id="GST_No" name="GST_No" value="{{ info.GST_No }}" readonly/>
|
||||
<h2>PMC Report for PMC No: {{ contInfo.PMC_No}}</h2>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="State">State :</label>
|
||||
<input type="text" id="State" name="State" value="{{ contInfo.State_Name }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="District">District :</label>
|
||||
<input type="text" id="District" name="District" value="{{ contInfo.District_Name }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Block">Block :</label>
|
||||
<input type="text" id="Block" name="Block" value="{{ contInfo.Block_Name }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>PMC Report for PMC No: {{ info.PMC_No}}</h2>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="State">State :</label>
|
||||
<input type="text" id="State" name="State" value="{{ info.State_Name }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="District">District :</label>
|
||||
<input type="text" id="District" name="District" value="{{ info.District_Name }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Block">Block :</label>
|
||||
<input type="text" id="Block" name="Block" value="{{ info.Block_Name }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="PMC_No">PMC No:</label>
|
||||
<input type="text" id="PMC_No" name="PMC_No" value="{{ info.PMC_No }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Village_Name">Village Name :</label>
|
||||
<input type="text" id="Village_Name" name="Village_Name"
|
||||
value="{{ info.Village_Name.capitalize() }}" readonly/>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="PMC_No">PMC No:</label>
|
||||
<input type="text" id="PMC_No" name="PMC_No" value="{{ contInfo.PMC_No }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Village_Name">Village Name :</label>
|
||||
<input type="text" id="Village_Name" name="Village_Name"
|
||||
value="{{ contInfo.Village_Name.capitalize() }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Invoice Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Village Name</th>
|
||||
<th>Work Type</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Invoice Date</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST (18%)</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS (1%)</th>
|
||||
<th>SD (5%)</th>
|
||||
<th>On Commission</th>
|
||||
<th>Hydro Testing</th>
|
||||
<h3>Invoice Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Village Name</th>
|
||||
<th>Work Type</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Invoice Date</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST (18%)</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS (1%)</th>
|
||||
<th>SD (5%)</th>
|
||||
<th>On Commission</th>
|
||||
<th>Hydro Testing</th>
|
||||
|
||||
<!-- Dynamic Hold Types -->
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | reject('none') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{ hold }}</th>
|
||||
{% endfor %}
|
||||
<!-- Dynamic Hold Types -->
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | reject('none') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{ hold }}</th>
|
||||
{% endfor %}
|
||||
|
||||
<th>GST SD (18%)</th>
|
||||
<th>Final Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if invoices %}
|
||||
{% for invoice in invoices %}
|
||||
<tr>
|
||||
<td>{{ invoice.PMC_No }}</td>
|
||||
<td>{{ invoice.Village_Name.capitalize() }}</td>
|
||||
<td>{{ invoice.Work_Type }}</td>
|
||||
<td>{{ invoice.Invoice_Details }}</td>
|
||||
<td>{{ invoice.Invoice_Date }}</td>
|
||||
<td>{{ invoice.Invoice_No }}</td>
|
||||
<td>{{ invoice.Basic_Amount }}</td>
|
||||
<td>{{ invoice.Debit_Amount }}</td>
|
||||
<td>{{ invoice.After_Debit_Amount }}</td>
|
||||
<td>{{ invoice.GST_Amount }}</td>
|
||||
<td>{{ invoice.Amount }}</td>
|
||||
<td>{{ invoice.TDS_Amount }}</td>
|
||||
<td>{{ invoice.SD_Amount }}</td>
|
||||
<td>{{ invoice.On_Commission }}</td>
|
||||
<td>{{ invoice.Hydro_Testing }}</td>
|
||||
<th>GST SD (18%)</th>
|
||||
<th>Final Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if invoices %}
|
||||
{% for invoice in invoices %}
|
||||
<tr>
|
||||
<td>{{ invoice.PMC_No }}</td>
|
||||
<td>{{ invoice.Village_Name.capitalize() if invoice.Village_Name else '' }}</td>
|
||||
<td>{{ invoice.Work_Type }}</td>
|
||||
<td>{{ invoice.Invoice_Details }}</td>
|
||||
<td>{{ invoice.Invoice_Date }}</td>
|
||||
<td>{{ invoice.Invoice_No }}</td>
|
||||
<td>{{ invoice.Basic_Amount }}</td>
|
||||
<td>{{ invoice.Debit_Amount }}</td>
|
||||
<td>{{ invoice.After_Debit_Amount }}</td>
|
||||
<td>{{ invoice.GST_Amount }}</td>
|
||||
<td>{{ invoice.Amount }}</td>
|
||||
<td>{{ invoice.TDS_Amount }}</td>
|
||||
<td>{{ invoice.SD_Amount }}</td>
|
||||
<td>{{ invoice.On_Commission }}</td>
|
||||
<td>{{ invoice.Hydro_Testing }}</td>
|
||||
|
||||
<!-- Dynamic Hold Amounts -->
|
||||
{% for hold in hold_types %}
|
||||
<td>
|
||||
{% if invoice.hold_type == hold %}
|
||||
{{ invoice.hold_amount }}
|
||||
{% else %}
|
||||
0
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
|
||||
<td>{{ invoice.GST_SD_Amount }}</td>
|
||||
<td>{{ invoice.Final_Amount }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="6">Total</th>
|
||||
<th>{{total["sum_invo_basic_amt"]}}</th>
|
||||
<th>{{total["sum_invo_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_after_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_gst_amt"]}}</th>
|
||||
<th>{{total["sum_invo_amt"]}}</th>
|
||||
<th>{{total["sum_invo_tds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_ds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_on_commission"]}}</th>
|
||||
<th>{{total["sum_invo_hydro_test"]}}</th>
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{total["sum_invo_hold_amt"]}}</th>
|
||||
{% endfor %}
|
||||
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
|
||||
<th>{{total["sum_invo_final_amt"]}}</th>
|
||||
</tr>
|
||||
|
||||
<!-- Dynamic Hold Amounts -->
|
||||
{% for hold in hold_types %}
|
||||
<td>
|
||||
{% if invoice.hold_type == hold %}
|
||||
{{ invoice.hold_amount }}
|
||||
{% else %}
|
||||
0
|
||||
<tr>
|
||||
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Hold Release</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%if hold_release%}
|
||||
{%for hold in hold_release%}
|
||||
<tr>
|
||||
<td>{{ hold['PMC_No'] }}</td>
|
||||
<td>{{ hold['Invoice_No'] }}</td>
|
||||
<td>{{ hold['Invoice_Details'] }}</td>
|
||||
<td>{{ hold['Basic_Amount'] }}</td>
|
||||
<td>{{ hold['Total_Amount'] }}</td>
|
||||
<td>{{ hold['UTR'] }}</td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
{%else%}
|
||||
<tr>
|
||||
<td colspan="6" style="text-align:center;">No data present</td>
|
||||
</tr>
|
||||
{%endif%}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<td>{{ invoice.GST_SD_Amount }}</td>
|
||||
<td>{{ invoice.Final_Amount }}</td>
|
||||
</tr>
|
||||
<br>
|
||||
<h3>GST Release Note Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Final Amount</th>
|
||||
<th>Total_Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if gst_rel %}
|
||||
{% for gst in gst_rel %}
|
||||
<tr>
|
||||
<td>{{ gst.pmc_no }}</td>
|
||||
<td>{{ gst.Invoice_No }}</td>
|
||||
<td>{{ gst.Basic_Amount }}</td>
|
||||
<td>{{ gst.Final_Amount }}</td>
|
||||
<td>{{ gst.Total_Amount }}</td>
|
||||
<td>{{ gst.UTR }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="6">Total</th>
|
||||
<th>{{total["sum_invo_basic_amt"]}}</th>
|
||||
<th>{{total["sum_invo_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_after_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_gst_amt"]}}</th>
|
||||
<th>{{total["sum_invo_amt"]}}</th>
|
||||
<th>{{total["sum_invo_tds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_ds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_on_commission"]}}</th>
|
||||
<th>{{total["sum_invo_hydro_test"]}}</th>
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{total["sum_invo_hold_amt"]}}</th>
|
||||
{% endfor %}
|
||||
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
|
||||
<th>{{total["sum_invo_final_amt"]}}</th>
|
||||
</tr>
|
||||
<th>{{total["sum_gst_basic_amt"]}}</th>
|
||||
<th>{{total["sum_gst_final_amt"]}}</th>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">No GST release found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Hold Release</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{%if hold_release%}
|
||||
{%for hold in hold_release%}
|
||||
<tr>
|
||||
<td>{{ hold['PMC_No'] }}</td>
|
||||
<td>{{ hold['Invoice_No'] }}</td>
|
||||
<td>{{ hold['Invoice_Details'] }}</td>
|
||||
<td>{{ hold['Basic_Amount'] }}</td>
|
||||
<td>{{ hold['Total_Amount'] }}</td>
|
||||
<td>{{ hold['UTR'] }}</td>
|
||||
</tr>
|
||||
{%endfor%}
|
||||
{%else%}
|
||||
<tr>
|
||||
<td colspan="6" style="text-align:center;">No data present</td>
|
||||
</tr>
|
||||
{%endif%}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
<h3>GST Release Note Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Final Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if gst_rel %}
|
||||
{% for gst in gst_rel %}
|
||||
<tr>
|
||||
<td>{{ gst.pmc_no }}</td>
|
||||
<td>{{ gst.invoice_no }}</td>
|
||||
<td>{{ gst.basic_amount }}</td>
|
||||
<td>{{ gst.final_amount }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
|
||||
<th>{{total["sum_gst_basic_amt"]}}</th>
|
||||
<th>{{total["sum_gst_final_amt"]}}</th>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">No GST release found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<tr>
|
||||
<h3>Credit Details</h3>
|
||||
</tr>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST Amount</th>
|
||||
<th>Amount</th>
|
||||
<th>Final Amount</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST Amount</th>
|
||||
<th>Amount</th>
|
||||
<th>Final Amount</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
|
||||
</tr>
|
||||
|
||||
{% if credit_note %}
|
||||
{% for credit in credit_note %}
|
||||
<tr>
|
||||
<td>{{ credit["PMC_No"] }}</td>
|
||||
<td>{{ credit["Invoice_Details"] }}</td>
|
||||
<td>{{ credit["Basic_Amount"] }}</td>
|
||||
<td>{{ credit["Debit_Amount"] }}</td>
|
||||
<td>{{ credit["After_Debit_Amount"] }}</td>
|
||||
<td>{{ credit["GST_Amount"] }}</td>
|
||||
<td>{{ credit["Amount"] }}</td>
|
||||
<td>{{ credit["Final_Amount"] }}</td>
|
||||
<td>{{ credit["Payment_Amount"] }}</td>
|
||||
<td>{{ credit["Total_Amount"] }}</td>
|
||||
<td>{{ credit["UTR"] }}</td>
|
||||
{% if credit_note %}
|
||||
{% for credit in credit_note %}
|
||||
<tr>
|
||||
<td>{{ credit["PMC_No"] }}</td>
|
||||
<td>{{ credit["Invoice_Details"] }}</td>
|
||||
<td>{{ credit["Basic_Amount"] }}</td>
|
||||
<td>{{ credit["Debit_Amount"] }}</td>
|
||||
<td>{{ credit["After_Debit_Amount"] }}</td>
|
||||
<td>{{ credit["GST_Amount"] }}</td>
|
||||
<td>{{ credit["Amount"] }}</td>
|
||||
<td>{{ credit["Final_Amount"] }}</td>
|
||||
<td>{{ credit["Payment_Amount"] }}</td>
|
||||
<td>{{ credit["Total_Amount"] }}</td>
|
||||
<td>{{ credit["UTR"] }}</td>
|
||||
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="11">No Credit note found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="11">No Credit note found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</thead>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
<h3>Payment Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS Amount @ 1% on BASIC AMOUNT</th>
|
||||
<th>Total Amount Paid</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if payments %}
|
||||
{% for pay in payments %}
|
||||
<tr>
|
||||
<td>{{ pay.pmc_no }}</td>
|
||||
<td>{{ pay.invoice_no }}</td>
|
||||
<td>{{ pay.Payment_Amount }}</td>
|
||||
<td>{{ pay.TDS_Payment_Amount }}</td>
|
||||
<td>{{ pay.Total_amount }}</td>
|
||||
<td>{{ pay.utr}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
<th>{{total["sum_pay_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_tds_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_total_amt"]}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% else %}
|
||||
<br>
|
||||
<h3>Payment Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS Amount @ 1% on BASIC AMOUNT</th>
|
||||
<th>Total Amount Paid</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if invoices %}
|
||||
{% for pay in invoices %}
|
||||
<tr>
|
||||
<td>{{ pay.PMC_No }}</td>
|
||||
<td>{{ pay.invoice_no }}</td>
|
||||
<td>{{ pay.Payment_Amount }}</td>
|
||||
<td>{{ pay.TDS_Payment_Amount }}</td>
|
||||
<td>{{ pay.Total_Amount }}</td>
|
||||
<td>{{ pay.UTR}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
<th>{{total["sum_pay_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_tds_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_total_amt"]}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% else %}
|
||||
|
||||
<tr>
|
||||
<td colspan="6">No payment found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td colspan="6">No payment found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<a href="/download_pmc_report/{{ info.PMC_No}}">
|
||||
<button class="download-btn">Download PMC Report</button>
|
||||
</a>
|
||||
<a href="/download_pmc_report/{{ contInfo.PMC_No}}">
|
||||
<button class="download-btn">Download PMC Report</button>
|
||||
</a>
|
||||
</body>
|
||||
{% endblock %}
|
||||
@@ -1,5 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -7,102 +8,104 @@
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/report.css') }}">
|
||||
<script src="{{ url_for('static', filename='js/searchContractor.js') }}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="report" class="page">
|
||||
<h2>Search Contractor Report</h2>
|
||||
<div>
|
||||
<form id="search-form">
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="subcontractor_name">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor_name" name="subcontractor_name">
|
||||
<div id="report" class="page">
|
||||
<h2>Search Contractor Report</h2>
|
||||
<div>
|
||||
<form id="search-form">
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="subcontractor_name">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor_name" name="subcontractor_name">
|
||||
</div>
|
||||
<div>
|
||||
<label for="pmc_no">PMC No:</label>
|
||||
<input type="text" id="pmc_no" name="pmc_no">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="pmc_no">PMC No:</label>
|
||||
<input type="text" id="pmc_no" name="pmc_no">
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="state">State:</label>
|
||||
<input type="text" id="state" name="state">
|
||||
</div>
|
||||
<div>
|
||||
<label for="district">District:</label>
|
||||
<input type="text" id="district" name="district">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="state">State:</label>
|
||||
<input type="text" id="state" name="state">
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="block">Block:</label>
|
||||
<input type="text" id="block" name="block">
|
||||
</div>
|
||||
<div>
|
||||
<label for="village">Village:</label>
|
||||
<input type="text" id="village" name="village">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="district">District:</label>
|
||||
<input type="text" id="district" name="district">
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="year_from">Year From:</label>
|
||||
<input type="date" id="year_from" name="year_from">
|
||||
</div>
|
||||
<div>
|
||||
<label for="year_to">Year To:</label>
|
||||
<input type="date" id="year_to" name="year_to">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="block">Block:</label>
|
||||
<input type="text" id="block" name="block">
|
||||
</div>
|
||||
<div>
|
||||
<label for="village">Village:</label>
|
||||
<input type="text" id="village" name="village">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="year_from">Year From:</label>
|
||||
<input type="date" id="year_from" name="year_from">
|
||||
</div>
|
||||
<div>
|
||||
<label for="year_to">Year To:</label>
|
||||
<input type="date" id="year_to" name="year_to">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<button type="button" onclick="fetchData()">Search</button>
|
||||
</form>
|
||||
|
||||
<h2>Contractor List</h2>
|
||||
<table border="1" id="result-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable">Contractor Name
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th>PMC No</th>
|
||||
<th class="sortable">State
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th class="sortable">District
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th class="sortable">Block
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th class="sortable">Village
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Results will be dynamically populated -->
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Contractor List</h2>
|
||||
<table border="1" id="result-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sortable">Contractor Name
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th>PMC No</th>
|
||||
<th class="sortable">State
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th class="sortable">District
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th class="sortable">Block
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
<th class="sortable">Village
|
||||
<select>
|
||||
<option value="">🔽</option>
|
||||
<option value="asc">Ascending</option>
|
||||
<option value="desc">Descending</option>
|
||||
</select>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Results will be dynamically populated -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
{% endblock %}
|
||||
@@ -58,8 +58,9 @@
|
||||
|
||||
<!-- Hidden fields for other necessary information -->
|
||||
<input type="text" name="subcontractor_data" value="{{ subcontractor_data['Contractor_Id'] }}">
|
||||
<input type="text" name="state_data" value="{{ state_data['State_ID'] }}">
|
||||
<input type="text" name="district_data" value="{{ district_data['District_ID'] }}">
|
||||
<input type="text" name="state_data" value="{{ state_data['State_Id'] }}">
|
||||
<!-- <input type="text" name="district_data" value="{{ district_data['District_ID'] }}"> -->
|
||||
<input type="text" name="district_data" value="{{ district_data['District_id'] }}">
|
||||
<input type="text" name="block_data" value="{{ block_data['Block_Id'] }}">
|
||||
|
||||
<input type="text" name="file_info" value="{{ file_info }}">
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
|
||||
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -10,363 +8,343 @@
|
||||
<!-- <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/subcontractor_report.css') }}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Contractor Report</h2>
|
||||
<div class="container">
|
||||
<h2>Contractor Report</h2>
|
||||
|
||||
<div class="info">
|
||||
<h2>Contractor Details</h2>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}"
|
||||
readonly/>
|
||||
<div class="info">
|
||||
<h2>Contractor Details</h2>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="subcontractor">Subcontractor Name:</label>
|
||||
<input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}"
|
||||
readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Address">Address :</label>
|
||||
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Address">Address :</label>
|
||||
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="PAN_No">PAN No :</label>
|
||||
<input type="text" id="PAN_No" name="PAN_No" value="{{ contInfo.PAN_No }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Mobile_No">Mobile Number :</label>
|
||||
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ contInfo.Mobile_No }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Email">Email :</label>
|
||||
<input type="text" id="Email" name="Email" value="{{ contInfo.Email }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="GST_Registration_Type">GST Registration Type :</label>
|
||||
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
|
||||
value="{{ contInfo.GST_Registration_Type }}" readonly />
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<label for="GST_No">GST No:</label>
|
||||
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="State">State :</label>
|
||||
<input type="text" id="State" name="State" value="{{ contInfo.State_Name }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="District">District :</label>
|
||||
<input type="text" id="District" name="District" value="{{ contInfo.District_Name }}" readonly />
|
||||
</div>
|
||||
<div>
|
||||
<label for="Block">Block :</label>
|
||||
<input type="text" id="Block" name="Block" value="{{ contInfo.Block_Name }}" readonly />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="PAN_No">PAN No :</label>
|
||||
<input type="text" id="PAN_No" name="PAN_No" value="{{ contInfo.PAN_No }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Mobile_No">Mobile Number :</label>
|
||||
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ contInfo.Mobile_No }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Email">Email :</label>
|
||||
<input type="text" id="Email" name="Email" value="{{ contInfo.Email }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row2">
|
||||
<div>
|
||||
<label for="GST_Registration_Type">GST Registration Type :</label>
|
||||
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
|
||||
value="{{ contInfo.GST_Registration_Type }}" readonly/>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<label for="GST_No">GST No:</label>
|
||||
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row3">
|
||||
<div>
|
||||
<label for="State">State :</label>
|
||||
<input type="text" id="State" name="State" value="{{ contInfo.State_Name }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="District">District :</label>
|
||||
<input type="text" id="District" name="District" value="{{ contInfo.District_Name }}" readonly/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="Block">Block :</label>
|
||||
<input type="text" id="Block" name="Block" value="{{ contInfo.Block_Name }}" readonly/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Total</h3>
|
||||
<table class="total-table">
|
||||
<tr>
|
||||
<th colspan="2">{{current_date}}</th>
|
||||
</tr>
|
||||
<!-- <tr>-->
|
||||
<!-- <th>Total Hold Amounnt</th>-->
|
||||
<!-- <td>0</td>-->
|
||||
<!-- </tr>-->
|
||||
<tr>
|
||||
<th>Advance / Suplus</th>
|
||||
<td>{{total["sum_invo_final_amt"]+total["sum_gst_final_amt"]-total["sum_pay_total_amt"]}}</td>
|
||||
</tr>
|
||||
{% if hold_types %}
|
||||
<tr>
|
||||
{% for hold in hold_types %}
|
||||
<th>{{ hold.hold_type }}</th>
|
||||
<td>{{total["sum_invo_hold_amt"]}}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th>Amount With TDS</th>
|
||||
<td>{{total["sum_invo_tds_amt"]}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- {% if hold_types %}-->
|
||||
<!-- <h3>Hold Types</h3>-->
|
||||
<!-- <ul>-->
|
||||
<!-- {% for hold in hold_types %}-->
|
||||
<!-- <li>{{ hold.hold_type }}</li>-->
|
||||
<!-- {% endfor %}-->
|
||||
<!-- </ul>-->
|
||||
<!-- {% endif %}-->
|
||||
|
||||
|
||||
<h3>Invoice Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Village Name</th>
|
||||
<th>Work Type</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Invoice Date</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST (18%)</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS (1%)</th>
|
||||
<th>SD (5%)</th>
|
||||
<th>On Commission</th>
|
||||
<th>Hydro Testing</th>
|
||||
<!-- {% if hold_types %}-->
|
||||
<!-- <h3>Hold Types</h3>-->
|
||||
<!-- <ul>-->
|
||||
<!-- {% for hold in hold_types %}-->
|
||||
<!-- <li>{{ hold.hold_type }}</li>-->
|
||||
<!-- {% endfor %}-->
|
||||
<!-- </ul>-->
|
||||
<!-- {% endif %}-->
|
||||
|
||||
<!-- Dynamic Hold Types -->
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{ hold }}</th>
|
||||
{% endfor %}
|
||||
|
||||
<th>GST SD (18%)</th>
|
||||
<th>Final Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if invoices %}
|
||||
{% for invoice in invoices %}
|
||||
<tr>
|
||||
<td>{{ invoice.PMC_No }}</td>
|
||||
<td>{{ invoice.Village_Name.capitalize() }}</td>
|
||||
<td>{{ invoice.Work_Type }}</td>
|
||||
<td>{{ invoice.Invoice_Details }}</td>
|
||||
<td>{{ invoice.Invoice_Date }}</td>
|
||||
<td>{{ invoice.Invoice_No }}</td>
|
||||
<td>{{ invoice.Basic_Amount }}</td>
|
||||
<td>{{ invoice.Debit_Amount }}</td>
|
||||
<td>{{ invoice.After_Debit_Amount }}</td>
|
||||
<td>{{ invoice.GST_Amount }}</td>
|
||||
<td>{{ invoice.Amount }}</td>
|
||||
<td>{{ invoice.TDS_Amount }}</td>
|
||||
<td>{{ invoice.SD_Amount }}</td>
|
||||
<td>{{ invoice.On_Commission }}</td>
|
||||
<td>{{ invoice.Hydro_Testing }}</td>
|
||||
<h3>Invoice Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Village Name</th>
|
||||
<th>Work Type</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Invoice Date</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST (18%)</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS (1%)</th>
|
||||
<th>SD (5%)</th>
|
||||
<th>On Commission</th>
|
||||
<th>Hydro Testing</th>
|
||||
|
||||
<!-- Dynamic Hold Types -->
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{ hold }}</th>
|
||||
{% endfor %}
|
||||
|
||||
<th>GST SD (18%)</th>
|
||||
<th>Final Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if invoices %}
|
||||
{% for invoice in invoices %}
|
||||
<tr>
|
||||
<td>{{ invoice.PMC_No }}</td>
|
||||
<td>{{ invoice.Village_Name}}</td>
|
||||
<td>{{ invoice.Work_Type }}</td>
|
||||
<td>{{ invoice.Invoice_Details }}</td>
|
||||
<td>{{ invoice.Invoice_Date }}</td>
|
||||
<td>{{ invoice.Invoice_No }}</td>
|
||||
<td>{{ invoice.Basic_Amount }}</td>
|
||||
<td>{{ invoice.Debit_Amount }}</td>
|
||||
<td>{{ invoice.After_Debit_Amount }}</td>
|
||||
<td>{{ invoice.GST_Amount }}</td>
|
||||
<td>{{ invoice.Amount }}</td>
|
||||
<td>{{ invoice.TDS_Amount }}</td>
|
||||
<td>{{ invoice.SD_Amount }}</td>
|
||||
<td>{{ invoice.On_Commission }}</td>
|
||||
<td>{{ invoice.Hydro_Testing }}</td>
|
||||
|
||||
<!-- Dynamic Hold Amounts -->
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<td>
|
||||
{% if invoice.hold_type == hold %}
|
||||
{{ invoice.hold_amount }}
|
||||
{% else %}
|
||||
0.00
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
|
||||
<td>{{ invoice.GST_SD_Amount }}</td>
|
||||
<td>{{ invoice.Final_Amount }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
<tr>
|
||||
<th colspan="6">Total</th>
|
||||
<th>{{total["sum_invo_basic_amt"]}}</th>
|
||||
<th>{{total["sum_invo_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_after_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_gst_amt"]}}</th>
|
||||
<th>{{total["sum_invo_amt"]}}</th>
|
||||
<th>{{total["sum_invo_tds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_ds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_on_commission"]}}</th>
|
||||
<th>{{total["sum_invo_hydro_test"]}}</th>
|
||||
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{total["sum_invo_hold_amt"]}}</th>
|
||||
{% endfor %}
|
||||
|
||||
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
|
||||
<th>{{total["sum_invo_final_amt"]}}</th>
|
||||
</tr>
|
||||
|
||||
<!-- Dynamic Hold Amounts -->
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<td>
|
||||
{% if invoice.hold_type == hold %}
|
||||
{{ invoice.hold_amount }}
|
||||
{% else %}
|
||||
0.00
|
||||
<tr>
|
||||
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<td>{{ invoice.GST_SD_Amount }}</td>
|
||||
<td>{{ invoice.Final_Amount }}</td>
|
||||
</tr>
|
||||
<h3>Hold Release</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if hold_release %}
|
||||
{% for hold in hold_release %}
|
||||
<tr>
|
||||
<td>{{ hold['PMC_No'] }}</td>
|
||||
<td>{{ hold['Invoice_No'] }}</td>
|
||||
<td>{{ hold['Invoice_Details'] }}</td>
|
||||
<td>{{ hold['Basic_Amount'] }}</td>
|
||||
<td>{{ hold['Total_Amount'] }}</td>
|
||||
<td>{{ hold['UTR'] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6" style="text-align:center;">No data present</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
<tr>
|
||||
<th colspan="6">Total</th>
|
||||
<th>{{total["sum_invo_basic_amt"]}}</th>
|
||||
<th>{{total["sum_invo_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_after_debit_amt"]}}</th>
|
||||
<th>{{total["sum_invo_gst_amt"]}}</th>
|
||||
<th>{{total["sum_invo_amt"]}}</th>
|
||||
<th>{{total["sum_invo_tds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_ds_amt"]}}</th>
|
||||
<th>{{total["sum_invo_on_commission"]}}</th>
|
||||
<th>{{total["sum_invo_hydro_test"]}}</th>
|
||||
|
||||
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
|
||||
{% for hold in hold_types %}
|
||||
<th>{{total["sum_invo_hold_amt"]}}</th>
|
||||
{% endfor %}
|
||||
|
||||
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
|
||||
<th>{{total["sum_invo_final_amt"]}}</th>
|
||||
<h3>Credit Details</h3>
|
||||
</tr>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST Amount</th>
|
||||
<th>Amount</th>
|
||||
<th>Final Amount</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</tr>
|
||||
|
||||
<h3>Hold Release</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if hold_release %}
|
||||
{% for hold in hold_release %}
|
||||
<tr>
|
||||
<td>{{ hold['PMC_No'] }}</td>
|
||||
<td>{{ hold['Invoice_No'] }}</td>
|
||||
<td>{{ hold['Invoice_Details'] }}</td>
|
||||
<td>{{ hold['Basic_Amount'] }}</td>
|
||||
<td>{{ hold['Total_Amount'] }}</td>
|
||||
<td>{{ hold['UTR'] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="6" style="text-align:center;">No data present</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{% if credit_note %}
|
||||
{% for credit in credit_note %}
|
||||
<tr>
|
||||
<td>{{ credit["PMC_No"] }}</td>
|
||||
<td>{{ credit["Invoice_Details"] }}</td>
|
||||
<td>{{ credit["Basic_Amount"] }}</td>
|
||||
<td>{{ credit["Debit_Amount"] }}</td>
|
||||
<td>{{ credit["After_Debit_Amount"] }}</td>
|
||||
<td>{{ credit["GST_Amount"] }}</td>
|
||||
<td>{{ credit["Amount"] }}</td>
|
||||
<td>{{ credit["Final_Amount"] }}</td>
|
||||
<td>{{ credit["Payment_Amount"] }}</td>
|
||||
<td>{{ credit["Total_Amount"] }}</td>
|
||||
<td>{{ credit["UTR"] }}</td>
|
||||
|
||||
|
||||
<tr>
|
||||
<h3>Credit Details</h3>
|
||||
</tr>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice Details</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Debit</th>
|
||||
<th>After Debit Amt</th>
|
||||
<th>GST Amount</th>
|
||||
<th>Amount</th>
|
||||
<th>Final Amount</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tr>
|
||||
|
||||
{% if credit_note %}
|
||||
{% for credit in credit_note %}
|
||||
<tr>
|
||||
<td>{{ credit["PMC_No"] }}</td>
|
||||
<td>{{ credit["Invoice_Details"] }}</td>
|
||||
<td>{{ credit["Basic_Amount"] }}</td>
|
||||
<td>{{ credit["Debit_Amount"] }}</td>
|
||||
<td>{{ credit["After_Debit_Amount"] }}</td>
|
||||
<td>{{ credit["GST_Amount"] }}</td>
|
||||
<td>{{ credit["Amount"] }}</td>
|
||||
<td>{{ credit["Final_Amount"] }}</td>
|
||||
<td>{{ credit["Payment_Amount"] }}</td>
|
||||
<td>{{ credit["Total_Amount"] }}</td>
|
||||
<td>{{ credit["UTR"] }}</td>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="11">No Credit note found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="11">No Credit note found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</thead>
|
||||
</table>
|
||||
<h3>GST Release Note Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Final Amount</th>
|
||||
<th>Total Amount</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
|
||||
|
||||
</thead>
|
||||
</table>
|
||||
<h3>GST Release Note Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Basic Amount</th>
|
||||
<th>Final Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if gst_rel %}
|
||||
{% for gst in gst_rel %}
|
||||
<tr>
|
||||
<td>{{ gst.pmc_no }}</td>
|
||||
<td>{{ gst.Invoice_No }}</td>
|
||||
<td>{{ gst.Basic_Amount }}</td>
|
||||
<td>{{ gst.Final_Amount }}</td>
|
||||
<td>{{ gst.Total_Amount }}</td>
|
||||
<td>{{ gst.UTR }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
|
||||
<th>{{total["sum_gst_basic_amt"]}}</th>
|
||||
<th>{{total["sum_gst_final_amt"]}}</th>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">No GST release found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if gst_rel %}
|
||||
{% for gst in gst_rel %}
|
||||
<tr>
|
||||
<td>{{ gst.pmc_no }}</td>
|
||||
<td>{{ gst.invoice_no }}</td>
|
||||
<td>{{ gst.basic_amount }}</td>
|
||||
<td>{{ gst.final_amount }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
<br>
|
||||
<h3>Payment Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS Amount @ 1% on BASIC AMOUNT</th>
|
||||
<th>Total Amount Paid</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if invoices %}
|
||||
{% for pay in invoices %}
|
||||
<tr>
|
||||
<td>{{ pay.PMC_No }}</td>
|
||||
<td>{{ pay.invoice_no }}</td>
|
||||
<td>{{ pay.Payment_Amount }}</td>
|
||||
<td>{{ pay.TDS_Payment_Amount }}</td>
|
||||
<td>{{ pay.Total_Amount }}</td>
|
||||
<td>{{ pay.UTR}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
<th>{{total["sum_gst_basic_amt"]}}</th>
|
||||
<th>{{total["sum_gst_final_amt"]}}</th>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4">No GST release found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
<th>{{total["sum_pay_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_tds_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_total_amt"]}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% else %}
|
||||
|
||||
<tr>
|
||||
<td colspan="6">No payment found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<br>
|
||||
<h3>Payment Details</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>PMC No</th>
|
||||
<th>Invoice No</th>
|
||||
<th>Amount</th>
|
||||
<th>TDS Amount @ 1% on BASIC AMOUNT</th>
|
||||
<th>Total Amount Paid</th>
|
||||
<th>UTR</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if payments %}
|
||||
{% for pay in payments %}
|
||||
<tr>
|
||||
<td>{{ pay.pmc_no }}</td>
|
||||
<td>{{ pay.invoice_no }}</td>
|
||||
<td>{{ pay.Payment_Amount }}</td>
|
||||
<td>{{ pay.TDS_Payment_Amount }}</td>
|
||||
<td>{{ pay.Total_amount }}</td>
|
||||
<td>{{ pay.utr}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
<tr>
|
||||
<th colspan="2">Total</th>
|
||||
<th>{{total["sum_pay_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_tds_payment_amt"]}}</th>
|
||||
<th>{{total["sum_pay_total_amt"]}}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% else %}
|
||||
|
||||
<tr>
|
||||
<td colspan="6">No payment found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<a href="{{ url_for('report.download_report', contractor_id=contractor_id) }}" class="download-btn">Download Report</a>
|
||||
</div>
|
||||
<a href="{{ url_for('report.download_report', contractor_id=contractor_id) }}" class="download-btn">Download
|
||||
Report</a>
|
||||
</div>
|
||||
</body>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user