25 Commits

Author SHA1 Message Date
055b272703 change of gst rels detail proce calling add 2026-04-04 14:00:25 +05:30
73cd97f3c8 optimize and add new service of get report and download report. 2026-04-03 12:10:47 +05:30
0b72adef7d updated code by aakash 2026-03-30 11:36:16 +05:30
88e8771b51 add log file function 2026-03-24 16:56:23 +05:30
6c74b5d3bf Merge branch 'main' of https://gitea.lcepl.org/pjpatil12/Payment_Reconciliation into pankaj-dev 2026-03-24 16:29:32 +05:30
47ba78d72c search on table 2026-03-24 16:29:18 +05:30
1946a98d59 Merge pull request 'Invoice Add Edit and Delete Done' (#17) from swapnil-dev into main
Reviewed-on: #17
2026-03-24 10:51:43 +00:00
8f35e08429 Merge pull request 'GST Release Display Chages' (#16) from laxmi-dev into main
Reviewed-on: #16
Reviewed-by: Pankaj J Patil <pankajjpatil2001@gmail.com>
2026-03-24 10:51:05 +00:00
82bedc3117 Update activity.log 2026-03-24 10:49:06 +00:00
cb68e454bc Update .env 2026-03-24 10:47:05 +00:00
Swapnil9693
91b078a0c3 edit_invoice html removed 2026-03-24 16:16:43 +05:30
Swapnil9693
eb46929893 New invoice commit 2026-03-24 16:13:04 +05:30
675301df7f GST Release Display Chages 2026-03-24 16:08:37 +05:30
Swapnil9693
14e799a1d4 Inoive add update delete messages shown properly 2026-03-24 15:51:55 +05:30
8ab1b69033 Merge pull request 'hold type updated , delete done by prajkta' (#13) from pankaj-dev into main
Reviewed-on: #13
2026-03-24 09:51:42 +00:00
dbeec9962d hold type updated , delete done by prajkta 2026-03-24 15:19:38 +05:30
8750f268db Merge pull request 'Village Add, Edit and Delete Messages done' (#12) from swapnil-dev into main
Reviewed-on: #12
2026-03-24 09:47:16 +00:00
Swapnil9693
b78526ad9f Village Add, Edit and Delete Messages done 2026-03-24 13:41:00 +05:30
7146391c18 Merge pull request 'delete payment code updated by prajakta' (#11) from pankaj-dev into main
Reviewed-on: #11
2026-03-24 07:21:43 +00:00
94b5563d15 delete payment code updated by prajakta 2026-03-24 12:50:44 +05:30
937018dc16 Merge pull request 'add item crude' (#10) from pankaj-dev into main
Reviewed-on: #10
2026-03-24 07:07:31 +00:00
eda238c235 add itemcrude 2026-03-24 12:36:15 +05:30
f184d6cecc Merge pull request 'update block redirect added' (#9) from pankaj-dev into main
Reviewed-on: #9
2026-03-24 06:26:39 +00:00
e7646eee76 Merge pull request 'Village module delete issue resolved and also message shown in alert' (#8) from swapnil-dev into main
Reviewed-on: #8
2026-03-24 06:25:19 +00:00
64ca39944b update block redirect added 2026-03-24 11:47:57 +05:30
83 changed files with 3342 additions and 2982 deletions

Binary file not shown.

View File

View File

View File

@@ -6,7 +6,6 @@ from model.Log import LogHelper
auth_bp = Blueprint('auth', __name__) auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/login', methods=['GET', 'POST']) @auth_bp.route('/login', methods=['GET', 'POST'])
def login(): def login():

View File

@@ -1,5 +1,5 @@
import config import config
from flask import Blueprint, render_template, request, redirect, url_for, jsonify from flask import Blueprint, render_template, request, redirect, url_for, jsonify, flash
from flask_login import login_required from flask_login import login_required
from model.State import State from model.State import State
@@ -7,12 +7,12 @@ from model.Block import Block
from model.Utilities import HtmlHelper from model.Utilities import HtmlHelper
block_bp = Blueprint('block', __name__) block_bp = Blueprint('block', __name__)
block = Block()
# --- Add Block page ------- # --- Add Block page -------
@block_bp.route('/add_block', methods=['GET', 'POST']) @block_bp.route('/add_block', methods=['GET', 'POST'])
@login_required @login_required
def add_block(): def add_block():
block = Block() # block = Block()
if request.method == 'POST': if request.method == 'POST':
block.AddBlock(request) block.AddBlock(request)
@@ -62,7 +62,7 @@ def get_districts(state_id):
@login_required @login_required
def check_block(): def check_block():
block = Block() # block = Block()
return block.CheckBlock(request) return block.CheckBlock(request)
@@ -70,12 +70,19 @@ def check_block():
@login_required @login_required
def edit_block(block_id): def edit_block(block_id):
block = Block()
# block = Block()
if request.method == 'POST': if request.method == 'POST':
block.EditBlock(request, block_id) block.EditBlock(request, block_id)
return block.resultMessage block.resultMessage
if block.resultMessage:
flash("Block updated successfully!", "success")
return redirect(url_for('block.add_block'))
else:
flash(block.resultMessage, "error")
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor() cursor = connection.cursor()
@@ -83,7 +90,10 @@ def edit_block(block_id):
for rs in cursor.stored_results(): for rs in cursor.stored_results():
states = rs.fetchall() 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(): for rs in cursor.stored_results():
districts = rs.fetchall() districts = rs.fetchall()
@@ -104,7 +114,7 @@ def edit_block(block_id):
@login_required @login_required
def delete_block(block_id): def delete_block(block_id):
block = Block() # block = Block()
block.DeleteBlock(request, block_id) block.DeleteBlock(request, block_id)
return redirect(url_for('block.add_block')) return redirect(url_for('block.add_block'))

View File

@@ -5,12 +5,13 @@ from model.District import District
from model.State import State from model.State import State
district_bp = Blueprint('district', __name__) district_bp = Blueprint('district', __name__)
district = District()
# ------- District page -------- # ------- District page --------
@district_bp.route('/add_district', methods=['GET', 'POST']) @district_bp.route('/add_district', methods=['GET', 'POST'])
@login_required @login_required
def add_district(): def add_district():
district = District() # district = District()
if request.method == 'POST': if request.method == 'POST':
district.AddDistrict(request=request) district.AddDistrict(request=request)
@@ -32,7 +33,7 @@ def add_district():
@login_required @login_required
def check_district(): def check_district():
district = District() # district = District()
return district.CheckDistrict(request=request) return district.CheckDistrict(request=request)
@@ -41,7 +42,7 @@ def check_district():
@login_required @login_required
def delete_district(district_id): def delete_district(district_id):
district = District() # district = District()
district.DeleteDistrict(request=request, district_id=district_id) district.DeleteDistrict(request=request, district_id=district_id)
@@ -56,7 +57,7 @@ def delete_district(district_id):
@login_required @login_required
def edit_district(district_id): def edit_district(district_id):
district = District() # district = District()
state = State() state = State()
if request.method == 'POST': if request.method == 'POST':

View File

@@ -59,21 +59,21 @@ def show_table(filename):
try: try:
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
cursor.callproc('GetStateByName', [file_info['State']]) cursor.callproc('CheckStateExists', [file_info['State']])
for result in cursor.stored_results(): for result in cursor.stored_results():
state_data = result.fetchone() state_data = result.fetchone()
if not state_data: if not state_data:
errors.append(f"State '{file_info['State']}' is not valid. Please add it.") errors.append(f"State '{file_info['State']}' is not valid. Please add it.")
if state_data: 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(): for result in cursor.stored_results():
district_data = result.fetchone() district_data = result.fetchone()
if not district_data: if not district_data:
errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.") errors.append(f"District '{file_info['District']}' is not valid under state '{file_info['State']}'.")
if district_data: 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(): for result in cursor.stored_results():
block_data = result.fetchone() block_data = result.fetchone()
if not block_data: if not block_data:
@@ -84,7 +84,9 @@ def show_table(filename):
subcontractor_data = result.fetchone() subcontractor_data = result.fetchone()
if not subcontractor_data: 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() connection.commit()
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']]) cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
for result in cursor.stored_results(): for result in cursor.stored_results():
@@ -229,7 +231,7 @@ def save_data():
else: else:
work_type = " ".join(words[:work_pos + 1]) work_type = " ".join(words[:work_pos + 1])
if Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower(): 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: if block_id and village_name:
village_id = None village_id = None
cursor.callproc("GetVillageId", (block_id, village_name)) cursor.callproc("GetVillageId", (block_id, village_name))
@@ -242,11 +244,11 @@ def save_data():
for result in cursor.stored_results(): for result in cursor.stored_results():
result = result.fetchone() result = result.fetchone()
village_id = result[0] if result else None village_id = result[0] if result else None
print("village_id :", village_id) # print("village_id :", village_id)
print("block_id :", block_id) # print("block_id :", block_id)
print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, # 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, # Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount) # SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount)
args = ( args = (
PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No, PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
@@ -255,22 +257,39 @@ def save_data():
subcontractor_id, 0 subcontractor_id, 0
) )
print("All invoice Details ",args) # print("All invoice Details ",args)
# add subcontarctor id in invoice table
results = cursor.callproc('SaveInvoice', args) results = cursor.callproc('SaveInvoice', args)
invoice_id = results[-1] 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): if isinstance(hold_columns, str):
hold_columns = ast.literal_eval(hold_columns) hold_columns = ast.literal_eval(hold_columns)
if isinstance(hold_columns, list) and all(isinstance(hold, dict) for hold in hold_columns): if isinstance(hold_columns, list) and all(isinstance(hold, dict) for hold in hold_columns):
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_column_name = hold.get('column_name') # Get column name
hold_type_id = hold.get('hold_type_id') # Get hold_type_id hold_type_id = hold.get('hold_type_id') # Get hold_type_id
if hold_column_name: if hold_column_name:
hold_amount = entry.get( hold_amount = entry.get(
hold_column_name) # Get the value for that specific hold column hold_column_name) # Get the value for that specific hold column
if hold_amount is not None: 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 = { hold_join_data = {
"Contractor_Id": subcontractor_id, "Contractor_Id": subcontractor_id,
"Invoice_Id": invoice_id, "Invoice_Id": invoice_id,
@@ -288,9 +307,9 @@ def save_data():
else: else:
print("Hold columns data is not a valid list of dictionaries.") print("Hold columns data is not a valid list of dictionaries.")
#---------------------------------------------Credit Note--------------------------------------------------------------------------- #---------------------------------------------Credit Note---------------------------------------------------------------------------
elif any(keyword in Invoice_Details.lower() for keyword in ['credit note','logging report']): elif any(keyword in Invoice_Details.lower() for keyword in ['credit note','logging report','credit','Credit note Details']):
print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount, # 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) # After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No)
cursor.callproc( cursor.callproc(
'AddCreditNoteFromExcel', 'AddCreditNoteFromExcel',
[ [
@@ -311,56 +330,113 @@ def save_data():
'excess hold amount', 'excess hold amount',
'Multi to Single layer bill', 'Multi to Single layer bill',
'hold amount', 'hold amount',
'logging report' 'logging report',
'hold'
] ]
# Step 3: Matching condition # Step 3: Matching condition
if any(kw in normalized_details for kw in keywords): 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( cursor.callproc(
'AddHoldReleaseFromExcel', 'AddHoldReleaseFromExcel',
[PMC_No, Invoice_No, Invoice_Details, Basic_Amount, Final_Amount, UTR, subcontractor_id] [PMC_No, Invoice_No, Invoice_Details, Basic_Amount, Final_Amount, UTR, subcontractor_id]
) )
connection.commit() 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( elif Invoice_Details and any(
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']): 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) # print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
cursor.callproc( cursor.callproc(
'AddGSTReleaseFromExcel', 'AddGSTReleaseFromExcel',
[PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id] [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 ) # If no village/work detected, only PMC/Payment
cursor.callproc("SavePayment",(PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount, Total_Amount, UTR )) if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()):
if not village_id: # 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()):
village_id = None
cursor.callproc('InsertOrUpdateInPayment', ( # ---------- Only PMC / Payment rows ----------
PMC_No, if PMC_No and not Invoice_No and UTR :
village_id, # print("No village/work, using PMC only :", PMC_No)
work_type,
Invoice_Details, # check invoice exists
Invoice_Date, # cursor.execute(
Invoice_No, # "SELECT invoice_id FROM invoice WHERE PMC_No=%s ORDER BY invoice_id DESC LIMIT 1",
Basic_Amount, # (PMC_No,)
Debit_Amount, # )
After_Debit_Amount, # row = cursor.fetchone()
Amount, # invoice_id = row[0] if row else None
GST_Amount,
TDS_Amount, # # insert invoice if not exists
SD_Amount,
On_Commission, # if not invoice_id:
Hydro_Testing, print(" extra payment :", PMC_No,Total_Amount,UTR, subcontractor_id)
0,
GST_SD_Amount, # cursor.execute(
Final_Amount, # """
Payment_Amount, # INSERT INTO invoice (PMC_No,Contractor_Id) VALUES (%s, %s);
TDS_Payment_Amount, # """,
Total_Amount, # (PMC_No, subcontractor_id)
UTR, # )
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() connection.commit()
return jsonify({"success": "Data saved successfully!"}), 200 return jsonify({"success": "Data saved successfully!"}), 200
except Exception as e: except Exception as e:

View File

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

View File

@@ -5,32 +5,32 @@ from model.GST import GST
hold_bp = Blueprint("hold_types", __name__) hold_bp = Blueprint("hold_types", __name__)
hold = HoldTypes()
# ---------------- ADD HOLD TYPE ---------------- # ---------------- ADD HOLD TYPE ----------------
@hold_bp.route('/add_hold_type', methods=['GET','POST']) @hold_bp.route('/add_hold_type', methods=['GET','POST'])
@login_required @login_required
def add_hold_type(): def add_hold_type():
# hold = HoldTypes()
hold = HoldTypes()
if request.method == 'POST': if request.method == 'POST':
hold.AddHoldType(request) # ✅ hold.AddHoldType(request)
return hold.resultMessage # ✅ Always redirect to same page (NO JSON)
return redirect(url_for("hold_types.add_hold_type"))
hold_types = hold.GetAllHoldTypes() # ✅ # GET request → show data
hold_types = hold.GetAllHoldTypes()
return render_template( return render_template(
"add_hold_type.html", "add_hold_type.html",
Hold_Types_data=hold_types Hold_Types_data=hold_types
) )
# ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ---------------- # ---------------- CHECK HOLD TYPE (OPTIONAL LIKE BLOCK) ----------------
@hold_bp.route('/check_hold_type', methods=['POST']) @hold_bp.route('/check_hold_type', methods=['POST'])
@login_required @login_required
def check_hold_type(): def check_hold_type():
hold = HoldTypes() # hold = HoldTypes()
return hold.CheckHoldType(request) # if exists return hold.CheckHoldType(request) # if exists
@@ -39,7 +39,7 @@ def check_hold_type():
@login_required @login_required
def edit_hold_type(id): def edit_hold_type(id):
hold = HoldTypes() # hold = HoldTypes()
if request.method == 'POST': if request.method == 'POST':
hold.EditHoldType(request, id) # ✅ hold.EditHoldType(request, id) # ✅
@@ -58,7 +58,7 @@ def edit_hold_type(id):
@login_required @login_required
def delete_hold_type(id): def delete_hold_type(id):
hold = HoldTypes() # hold = HoldTypes()
hold.DeleteHoldType(request, id) # ✅ hold.DeleteHoldType(request, id) # ✅
return redirect(url_for("hold_types.add_hold_type")) return redirect(url_for("hold_types.add_hold_type"))

View File

@@ -1,6 +1,3 @@
# controllers/invoice_controller.py # controllers/invoice_controller.py
from flask import Blueprint, request, jsonify, render_template from flask import Blueprint, request, jsonify, render_template
@@ -40,7 +37,11 @@ def add_invoice():
village_id = village_result['Village_Id'] village_id = village_result['Village_Id']
invoice_id = insert_invoice(data, 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) insert_hold_types(data, invoice_id)
log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'") log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'")
@@ -83,7 +84,7 @@ def edit_invoice(invoice_id):
if request.method == 'POST': if request.method == 'POST':
data = request.form data = request.form
update_invoice(data, invoice_id) update_invoice(data, invoice_id)
update_inpayment(data) # update_inpayment(data)
log_action("Edit invoice", f"edited invoice '{invoice_id}'") log_action("Edit invoice", f"edited invoice '{invoice_id}'")
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200 return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200

View File

@@ -21,7 +21,6 @@ def activity_log():
end_date, end_date,
user_name user_name
) )
return render_template( return render_template(
"activity_log.html", "activity_log.html",
logs=filtered_logs, logs=filtered_logs,

View File

@@ -28,8 +28,8 @@ def add_payment():
utr = request.form['utr'] utr = request.form['utr']
LogHelper.log_action("Add Payment", f"User {current_user.id} Add Payment '{pmc_no}'") 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.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) # Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
return redirect(url_for('payment_bp.add_payment')) 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) Paymentmodel.call_update_payment_proc(payment_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
# Update inpayment # Update inpayment
connection = Paymentmodel.get_connection() # connection = Paymentmodel.get_connection()
cursor = connection.cursor() # cursor = connection.cursor()
cursor.callproc( # cursor.callproc('UpdateInpaymentByPMCInvoiceUTR',[amount, tds_amount, total_amount, pmc_no, invoice_no, utr])
'UpdateInpaymentByPMCInvoiceUTR',
[amount, tds_amount, total_amount, pmc_no, invoice_no, utr] # connection.commit()
) # cursor.close()
connection.commit() # connection.close()
cursor.close()
connection.close()
return redirect(url_for('payment_bp.add_payment')) return redirect(url_for('payment_bp.add_payment'))
return render_template('edit_payment.html', payment_data=payment_data) return render_template('edit_payment.html', payment_data=payment_data)
# ------------------- Delete Payment ------------------- # ------------------- Delete Payment -------------------
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['POST']) @payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET'])
@login_required @login_required
def delete_payment(payment_id): def delete_payment(payment_id):
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id) success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
if not success: if not success:
flash("Payment not found or failed to delete", "error") flash("Payment not found or failed to delete", "error")
else: else:

View File

@@ -1,40 +1,40 @@
from flask import Blueprint, render_template, send_from_directory # from flask import Blueprint, render_template, send_from_directory
from flask_login import login_required # 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 ---------------- # return render_template(
@pmc_report_bp.route("/pmc_report/<pmc_no>") # "pmc_report.html",
@login_required # info=data["info"],
def pmc_report(pmc_no): # invoices=data["invoices"],
data = PmcReport.get_pmc_report(pmc_no) # hold_types=data["hold_types"],
if not data: # gst_rel=data["gst_rel"],
return "No PMC found with this number", 404 # payments=data["payments"],
# credit_note=data["credit_note"],
# hold_release=data["hold_release"],
# total=data["total"]
# )
return render_template( # # ---------------- Contractor Download Report by pmc no ----------------
"pmc_report.html", # @pmc_report_bp.route("/download_pmc_report/<pmc_no>")
info=data["info"], # @login_required
invoices=data["invoices"], # def download_pmc_report(pmc_no):
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 ---------------- # result = PmcReport.download_pmc_report(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) # if not result:
# return "No contractor found for this PMC No", 404
if not result: # output_folder, file_name = result
return "No contractor found for this PMC No", 404
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)

View File

@@ -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 flask_login import login_required, current_user
from services.ReportService import ReportService
from model.Report import ReportHelper from model.Report import ReportHelper
from model.Log import LogHelper
report_bp = Blueprint("report", __name__) report_bp = Blueprint("report", __name__)
# ---------------- Report Page ---------------- # ---------------- Report Page ----------------
@report_bp.route("/report") @report_bp.route("/report")
@login_required @login_required
@@ -20,28 +17,45 @@ def report_page():
@login_required @login_required
def search_contractor(): 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) 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 ---------------- # ---------------- Contractor Report by contractor id ----------------
@report_bp.route('/contractor_report/<int:contractor_id>') @report_bp.route('/contractor_report/<int:contractor_id>')
@login_required @login_required
def contractor_report(contractor_id): def contractor_report(contractor_id):
data = ReportHelper.get_contractor_report(contractor_id) service = ReportService(contractor_id=contractor_id).load_data()
return render_template( return render_template(
'subcontractor_report.html', 'subcontractor_report.html',
contractor_id=contractor_id, 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 ---------------- # ---------------- Contractor Download Report by contractor id ----------------
@@ -49,5 +63,24 @@ def contractor_report(contractor_id):
@login_required @login_required
def download_report(contractor_id): 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)

View File

@@ -3,13 +3,13 @@ from flask_login import login_required
from model.State import State from model.State import State
state_bp = Blueprint('state', __name__) state_bp = Blueprint('state', __name__)
state = State()
# ----- State page ------ # ----- State page ------
@state_bp.route('/add_state', methods=['GET', 'POST']) @state_bp.route('/add_state', methods=['GET', 'POST'])
@login_required @login_required
def add_state(): def add_state():
state = State() # state = State()
if request.method == 'POST': if request.method == 'POST':
state.AddState(request=request) state.AddState(request=request)
@@ -24,7 +24,7 @@ def add_state():
@login_required @login_required
def check_state(): def check_state():
state = State() # state = State()
return state.CheckState(request=request) return state.CheckState(request=request)
@@ -33,7 +33,7 @@ def check_state():
@login_required @login_required
def deleteState(id): def deleteState(id):
state = State() # state = State()
state.DeleteState(request=request, id=id) state.DeleteState(request=request, id=id)
@@ -47,7 +47,7 @@ def deleteState(id):
@login_required @login_required
def editState(id): def editState(id):
state = State() # state = State()
if request.method == 'POST': if request.method == 'POST':

View File

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

View File

@@ -16,7 +16,7 @@ from controllers.payment_controller import payment_bp
from controllers.gst_release_controller import gst_release_bp from controllers.gst_release_controller import gst_release_bp
from controllers.excel_upload_controller import excel_bp from controllers.excel_upload_controller import excel_bp
from controllers.report_controller import report_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 controllers.hold_types_controller import hold_bp
from dotenv import load_dotenv from dotenv import load_dotenv
@@ -57,7 +57,7 @@ app.register_blueprint(payment_bp)
app.register_blueprint(gst_release_bp) app.register_blueprint(gst_release_bp)
app.register_blueprint(excel_bp) app.register_blueprint(excel_bp)
app.register_blueprint(report_bp) app.register_blueprint(report_bp)
app.register_blueprint(pmc_report_bp) # app.register_blueprint(pmc_report_bp)
app.register_blueprint(hold_bp) app.register_blueprint(hold_bp)
# ---------------- Run App ---------------- # ---------------- Run App ----------------

View File

@@ -1,16 +1,6 @@
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogData, LogHelper from model.Log import LogData, LogHelper
from model.ItemCRUD import ItemCRUD
import os
import config
import re
import mysql.connector
from mysql.connector import Error
from model.ItemCRUD import ItemCRUD, itemCRUDMapping
class Block: class Block:
@@ -22,9 +12,7 @@ class Block:
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
# ----------------------------------------------------------
# Add Block # Add Block
# ----------------------------------------------------------
def AddBlock(self, request): def AddBlock(self, request):
block = ItemCRUD(itemType=ItemCRUDType.Block) block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -37,17 +25,7 @@ class Block:
self.resultMessage = block.resultMessage self.resultMessage = block.resultMessage
return return
# ---------------------------------------------------------- # Get All Blocks
# 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
def GetAllBlocks(self, request): def GetAllBlocks(self, request):
block = ItemCRUD(itemType=ItemCRUDType.Block) block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -57,18 +35,8 @@ class Block:
self.resultMessage = block.resultMessage self.resultMessage = block.resultMessage
return blocksdata return blocksdata
# ----------------------------------------------------------
# Check Block Exists # 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): def CheckBlock(self, request):
block = ItemCRUD(itemType=ItemCRUDType.Block) block = ItemCRUD(itemType=ItemCRUDType.Block)
data = request.get_json(silent=True) or request.form data = request.get_json(silent=True) or request.form
@@ -85,24 +53,7 @@ class Block:
self.resultMessage = block.resultMessage self.resultMessage = block.resultMessage
return result return result
# ----------------------------------------------------------
# Get Block By ID # 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): def GetBlockByID(self, id):
block = ItemCRUD(itemType=ItemCRUDType.Block) block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -116,20 +67,8 @@ class Block:
self.resultMessage = block.resultMessage self.resultMessage = block.resultMessage
return blockdata return blockdata
# ----------------------------------------------------------
# Update Block # 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): def EditBlock(self, request, block_id):
block = ItemCRUD(itemType=ItemCRUDType.Block) block = ItemCRUD(itemType=ItemCRUDType.Block)
@@ -147,11 +86,10 @@ class Block:
self.isSuccess = block.isSuccess self.isSuccess = block.isSuccess
self.resultMessage = block.resultMessage self.resultMessage = block.resultMessage
return render_template('add_block.html') return
# ----------------------------------------------------------
# Delete Block # Delete Block
# ---------------------------------------------------------
def DeleteBlock(self,request, id): def DeleteBlock(self,request, id):
block = ItemCRUD(itemType=ItemCRUDType.Block) block = ItemCRUD(itemType=ItemCRUDType.Block)

View File

@@ -1,10 +1,5 @@
from mysql.connector import Error from mysql.connector import Error
import config import config
from datetime import datetime
class ContractorInfo: class ContractorInfo:
def __init__(self, contractor_id): def __init__(self, contractor_id):

View File

@@ -27,13 +27,27 @@ class FolderAndFile:
os.makedirs(folder, exist_ok=True) os.makedirs(folder, exist_ok=True)
return folder return folder
# ----------------------------- @staticmethod
# FILE PATH METHODS def get_logs_folder():
# ----------------------------- folder = os.path.join(current_app.root_path, "logs")
if not os.path.exists(folder):
os.makedirs(folder)
os.makedirs(folder, exist_ok=True)
return folder
# FILE PATH METHODS - download
@staticmethod @staticmethod
def get_download_path(filename): def get_download_path(filename):
return os.path.join(FolderAndFile.get_download_folder(), filename) return os.path.join(FolderAndFile.get_download_folder(), filename)
# FILE PATH METHODS - upload file
@staticmethod @staticmethod
def get_upload_path(filename): def get_upload_path(filename):
return os.path.join(FolderAndFile.get_upload_folder(), filename) return os.path.join(FolderAndFile.get_upload_folder(), filename)
# FILE PATH METHODS - activity log file
@staticmethod
def get_activity_log_path(filename):
return os.path.join(FolderAndFile.get_logs_folder(), filename)

View File

@@ -3,7 +3,6 @@ from model.ItemCRUD import ItemCRUD
from model.Utilities import ItemCRUDType from model.Utilities import ItemCRUDType
class HoldTypes: class HoldTypes:
"""CRUD operations for Hold Types using ItemCRUD"""
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
@@ -33,7 +32,7 @@ class HoldTypes:
self.isSuccess = hold.isSuccess self.isSuccess = hold.isSuccess
self.resultMessage = hold.resultMessage self.resultMessage = hold.resultMessage
# Convert tuple → dictionary # Convert tuple → dictionary
data = [] data = []
for row in rows: for row in rows:
data.append({ data.append({
@@ -51,7 +50,7 @@ class HoldTypes:
self.isSuccess = hold.isSuccess self.isSuccess = hold.isSuccess
self.resultMessage = hold.resultMessage self.resultMessage = hold.resultMessage
# Convert tuple → dictionary # Convert tuple → dictionary
if row: if row:
return { return {
"hold_type_id": row[0], "hold_type_id": row[0],

View File

@@ -66,27 +66,27 @@ def get_all_villages():
return fetch_all(cursor) return fetch_all(cursor)
return execute_db_operation(operation) return execute_db_operation(operation)
# ------------------- Invoice Functions ------------------- # ------------------- Invoice Functions -------------------
def insert_invoice(data, village_id): def insert_invoice(data, village_id):
def operation(cursor): def operation(cursor):
# Insert invoice # Insert invoice
cursor.callproc('InsertInvoice', [ # cursor.callproc('InsertInvoice', [
data.get('pmc_no'), # data.get('pmc_no'),
village_id, # village_id,
data.get('work_type'), # data.get('work_type'),
data.get('invoice_details'), # data.get('invoice_details'),
data.get('invoice_date'), # data.get('invoice_date'),
data.get('invoice_no'), # data.get('invoice_no'),
*get_numeric_values(data) # *get_numeric_values(data),
]) # data.get('subcontractor_id')
invoice_row = fetch_one(cursor)
if not invoice_row:
raise Exception("Invoice ID not returned")
invoice_id = invoice_row.get('invoice_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'), data.get('pmc_no'),
village_id, village_id,
data.get('work_type'), data.get('work_type'),
@@ -94,9 +94,27 @@ def insert_invoice(data, village_id):
data.get('invoice_date'), data.get('invoice_date'),
data.get('invoice_no'), data.get('invoice_no'),
*get_numeric_values(data), *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 invoice_id
return execute_db_operation(operation) return execute_db_operation(operation)
@@ -141,18 +159,18 @@ def update_invoice(data, invoice_id):
clear_results(cursor) clear_results(cursor)
execute_db_operation(operation) execute_db_operation(operation)
def update_inpayment(data): # def update_inpayment(data):
def operation(cursor): # def operation(cursor):
cursor.callproc('UpdateInpayment', [ # cursor.callproc('UpdateInpayment', [
data.get('work_type'), # data.get('work_type'),
data.get('invoice_details'), # data.get('invoice_details'),
data.get('invoice_date'), # data.get('invoice_date'),
*get_numeric_values(data), # *get_numeric_values(data),
data.get('pmc_no'), # data.get('pmc_no'),
data.get('invoice_no') # data.get('invoice_no')
]) # ])
clear_results(cursor) # clear_results(cursor)
execute_db_operation(operation) # execute_db_operation(operation)
def delete_invoice_data(invoice_id, user_id): def delete_invoice_data(invoice_id, user_id):
def operation(cursor): def operation(cursor):
@@ -173,22 +191,22 @@ def delete_invoice_data(invoice_id, user_id):
clear_results(cursor) clear_results(cursor)
# Delete inpayment # Delete inpayment
cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no)) # cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
clear_results(cursor) # clear_results(cursor)
execute_db_operation(operation) execute_db_operation(operation)
# ------------------- Subcontractor Functions ------------------- # ------------------- Subcontractor Functions -------------------
def assign_subcontractor(data, village_id): # def assign_subcontractor(data, village_id):
def operation(cursor): # def operation(cursor):
cursor.callproc('AssignSubcontractor', [ # cursor.callproc('AssignSubcontractor', [
data.get('pmc_no'), # data.get('pmc_no'),
data.get('subcontractor_id'), # data.get('subcontractor_id'),
village_id # village_id
]) # ])
clear_results(cursor) # clear_results(cursor)
execute_db_operation(operation) # execute_db_operation(operation)
# ------------------- Hold Types Functions ------------------- # ------------------- Hold Types Functions -------------------

View File

@@ -1,6 +1,3 @@
from flask_login import current_user from flask_login import current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogHelper from model.Log import LogHelper
@@ -9,7 +6,6 @@ import config
import re import re
import mysql.connector import mysql.connector
# ---------------------------------------------------------- # ----------------------------------------------------------
# Mapping Class # Mapping Class
# ---------------------------------------------------------- # ----------------------------------------------------------
@@ -26,10 +22,11 @@ class itemCRUDMapping:
self.name = "Hold Type" self.name = "Hold Type"
elif itemType is ItemCRUDType.Subcontractor: elif itemType is ItemCRUDType.Subcontractor:
self.name = "Subcontractor" self.name = "Subcontractor"
elif itemType.name == "GSTRelease":
self.name = "GSTRelease"
else: else:
self.name = "Item" self.name = "Item"
# ---------------------------------------------------------- # ----------------------------------------------------------
# Generic CRUD Class # Generic CRUD Class
# ---------------------------------------------------------- # ----------------------------------------------------------
@@ -38,7 +35,6 @@ class ItemCRUD:
def __init__(self, itemType): def __init__(self, itemType):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
self.response = {} # ✅ ADDED
self.itemCRUDType = itemType self.itemCRUDType = itemType
self.itemCRUDMapping = itemCRUDMapping(itemType) self.itemCRUDMapping = itemCRUDMapping(itemType)
@@ -60,14 +56,16 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.response = ResponseHandler.delete_success(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.delete_success(self.itemCRUDMapping.name), 200
)
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error deleting {self.itemCRUDMapping.name}: {e}") print(f"Error deleting {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.delete_failure(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.delete_failure(self.itemCRUDMapping.name), 500
)
finally: finally:
cursor.close() cursor.close()
@@ -81,8 +79,9 @@ class ItemCRUD:
connection = config.get_db_connection() connection = config.get_db_connection()
if not connection: if not connection:
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.add_failure(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.db_connection_failure(), 500
)
return return
cursor = connection.cursor() cursor = connection.cursor()
@@ -93,18 +92,57 @@ class ItemCRUD:
) )
try: try:
# SUBCONTRACTOR # ======================================================
if data: # GSTRelease MULTI-FIELD
cursor.callproc(storedprocfetch, (data['Contractor_Name'],)) # ======================================================
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 existing_item = None
for rs in cursor.stored_results(): for rs in cursor.stored_results():
existing_item = rs.fetchone() existing_item = rs.fetchone()
if existing_item: if existing_item:
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.already_exists(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
)
return return
cursor.callproc(storedprocadd, ( cursor.callproc(storedprocadd, (
@@ -118,19 +156,22 @@ class ItemCRUD:
data['GST_No'], data['GST_No'],
data['Contractor_password'] data['Contractor_password']
)) ))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.response = ResponseHandler.add_success(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
return 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.isSuccess = False
self.response = ResponseHandler.invalid_name(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
)
return return
if parentid is None: if parentid is None:
@@ -144,8 +185,9 @@ class ItemCRUD:
if existing_item: if existing_item:
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.already_exists(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
)
return return
if parentid is None: if parentid is None:
@@ -154,16 +196,17 @@ class ItemCRUD:
cursor.callproc(storedprocadd, (childname, parentid)) cursor.callproc(storedprocadd, (childname, parentid))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.response = ResponseHandler.add_success(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Database Error: {e}") print(f"Database Error: {e}")
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.add_failure(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.add_failure(self.itemCRUDMapping.name), 500
)
finally: finally:
cursor.close() cursor.close()
@@ -183,7 +226,33 @@ class ItemCRUD:
) )
try: 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, ( cursor.callproc(storedprocupdate, (
childid, childid,
data['Contractor_Name'], data['Contractor_Name'],
@@ -196,18 +265,19 @@ class ItemCRUD:
data['GST_No'], data['GST_No'],
data['Contractor_password'] data['Contractor_password']
)) ))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.response = ResponseHandler.update_success(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.update_success(self.itemCRUDMapping.name), 200
)
return return
if not re.match(RegEx.patternAlphabetOnly, childname): # ======================================================
# NORMAL SINGLE-FIELD
# ======================================================
if not re.match(RegEx.allPattern, childname):
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.update_failure(self.itemCRUDMapping.name) self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
self.resultMessage = self.response["message"]
return return
if parentid is None: if parentid is None:
@@ -216,16 +286,15 @@ class ItemCRUD:
cursor.callproc(storedprocupdate, (childid, parentid, childname)) cursor.callproc(storedprocupdate, (childid, parentid, childname))
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.response = ResponseHandler.update_success(self.itemCRUDMapping.name) self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message']
self.resultMessage = self.response["message"]
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error updating {self.itemCRUDMapping.name}: {e}") print(f"Error updating {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.update_failure(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.update_failure(self.itemCRUDMapping.name), 500
)
finally: finally:
cursor.close() cursor.close()
@@ -238,27 +307,22 @@ class ItemCRUD:
data = [] data = []
connection = config.get_db_connection() connection = config.get_db_connection()
if not connection: if not connection:
return [] return []
cursor = connection.cursor() cursor = connection.cursor()
try: try:
cursor.callproc(storedproc) cursor.callproc(storedproc)
for result in cursor.stored_results(): for result in cursor.stored_results():
data = result.fetchall() data = result.fetchall()
self.isSuccess = True self.isSuccess = True
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}") print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.response = ResponseHandler.fetch_failure(self.itemCRUDMapping.name) self.resultMessage = HtmlHelper.json_response(
self.resultMessage = self.response["message"] ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
)
return [] return []
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()
@@ -276,13 +340,10 @@ class ItemCRUD:
try: try:
cursor.callproc(storedproc, (id,)) cursor.callproc(storedproc, (id,))
for rs in cursor.stored_results(): for rs in cursor.stored_results():
data = rs.fetchone() data = rs.fetchone()
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}") print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()
@@ -290,7 +351,7 @@ class ItemCRUD:
return data return data
# ---------------------------------------------------------- # ----------------------------------------------------------
# CHECK ITEM (KEEP AS IS - API USE) # CHECK ITEM
# ---------------------------------------------------------- # ----------------------------------------------------------
def CheckItem(self, request, parentid, childname, storedprocfetch): def CheckItem(self, request, parentid, childname, storedprocfetch):
@@ -302,7 +363,7 @@ class ItemCRUD:
f"User {current_user.id} checked '{childname}'" f"User {current_user.id} checked '{childname}'"
) )
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.allPattern, childname):
return HtmlHelper.json_response( return HtmlHelper.json_response(
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400 ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
) )
@@ -331,7 +392,6 @@ class ItemCRUD:
return HtmlHelper.json_response( return HtmlHelper.json_response(
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500 ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
) )
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()

View File

@@ -1,29 +1,40 @@
import os import os
from datetime import datetime from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask import current_app
from flask_login import current_user
from datetime import datetime
from model.FolderAndFile import FolderAndFile
class LogHelper: class LogHelper:
@staticmethod @staticmethod
def log_action(action, details=""): def log_action(action, details=""):
"""Add a log entry.""" """Log user actions with timestamp, user, action, and details."""
log_data = LogData() logData = LogData()
log_data.add_log(action, details) logData.WriteLog(action, details="")
class LogData: class LogData:
filepath = ""
timestamp = None
def __init__(self): def __init__(self):
self.filepath = os.path.join(current_app.root_path, 'activity.log') self.filepath = FolderAndFile.get_activity_log_path('activity.log')
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.user = getattr(current_user, "cn", None) \ self.user = LogData.get_current_user()
or getattr(current_user, "username", None) \
or getattr(current_user, "sAMAccountName", "Unknown")
def add_log(self, action, details=""): @staticmethod
"""Create/Add a log entry.""" def get_current_user():
if hasattr(current_user, "cn") and current_user.cn:
return current_user.cn
elif hasattr(current_user, "username") and current_user.username:
return current_user.username
elif hasattr(current_user, "sAMAccountName") and current_user.sAMAccountName:
return current_user.sAMAccountName
return "Unknown"
def WriteLog(self, action, details=""):
"""Log user actions with timestamp, user, action, and details."""
with open(self.filepath, "a", encoding="utf-8") as f: with open(self.filepath, "a", encoding="utf-8") as f:
f.write( f.write(
f"Timestamp: {self.timestamp} | " f"Timestamp: {self.timestamp} | "
@@ -32,73 +43,41 @@ class LogData:
f"Details: {details}\n" f"Details: {details}\n"
) )
def get_all_logs(self): def GetActivitiesLog(self):
"""Read all logs."""
logs = [] logs = []
if os.path.exists(self.filepath): if os.path.exists(self.filepath):
with open(self.filepath, 'r', encoding="utf-8") as f: with open(self.filepath, 'r') as f:
for line in f: for line in f:
parts = line.strip().split(" | ") parts = line.strip().split(" | ")
if len(parts) == 4: if len(parts) == 4:
logs.append({ logs.append({
"timestamp": parts[0].split(":", 1)[1].strip(), "timestamp": parts[0].replace("Timestamp:", "").strip(),
"user": parts[1].split(":", 1)[1].strip(), "user": parts[1].replace("User:", "").strip(),
"action": parts[2].split(":", 1)[1].strip(), "action": parts[2].replace("Action:", "").strip(),
"details": parts[3].split(":", 1)[1].strip() "details": parts[3].replace("Details:", "").strip()
}) })
return logs return logs
def get_filtered_logs(self, start_date=None, end_date=None, user_name=None): def GetFilteredActivitiesLog(self, startDate, endDate, userName):
"""Filter logs by date and/or user.""" filtered_logs = self.GetActivitiesLog()
logs = self.get_all_logs()
# Filter by date # Date filter
if start_date or end_date: if startDate or endDate:
start_dt = datetime.strptime(start_date, "%Y-%m-%d") if start_date else datetime.min try:
end_dt = datetime.strptime(end_date, "%Y-%m-%d") if end_date else datetime.max start_dt = datetime.strptime(startDate, "%Y-%m-%d") if startDate else datetime.min
logs = [ end_dt = datetime.strptime(endDate, "%Y-%m-%d") if endDate else datetime.max
log for log in logs
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
]
# Filter by username filtered_logs = [
if user_name: log for log in filtered_logs
logs = [log for log in logs if user_name.lower() in log.get("user", "").lower()] if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
]
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"
)
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

View File

@@ -1,456 +1,137 @@
import openpyxl
from openpyxl.styles import Font, PatternFill
import config import config
from flask_login import current_user from flask_login import current_user
from model.Log import LogHelper from model.Log import LogHelper
from model.Report import ReportHelper from services.Generalservice import GeneralUse
from model.FolderAndFile import FolderAndFile from model.FolderAndFile import FolderAndFile
from model.Report import ReportHelper
class PmcReport: class PmcReport:
data=[]
@staticmethod # @staticmethod
def get_pmc_report(pmc_no): # def get_pmc_report(pmc_no):
connection = config.get_db_connection() # connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True) # 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,)) # # Extract hold_type_ids
# pmc_info = next(cursor.stored_results()).fetchone() # hold_type_ids = [ht['hold_type_id'] for ht in hold_types]
pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True)
if not pmc_info: # invoices = []
return None # 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"])) # gst_rel = GeneralUse.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
hold_types = next(cursor.stored_results()).fetchall()
# hold_release = GeneralUse.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
# 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 = 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) # payments = GeneralUse.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel)
# 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 ---------------- # return {
# cursor.callproc('GetHoldReleaseByPMC', [pmc_no]) # "info": pmc_info,
# hold_release = [] # "invoices": invoices,
# for result in cursor.stored_results(): # "hold_types": hold_types,
# hold_release = result.fetchall() # "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 # @staticmethod
# def download_pmc_report(pmc_no): # def download_pmc_report(pmc_no):
# connection = config.get_db_connection() # connection = config.get_db_connection()
# if not connection:
# return None
# cursor = connection.cursor(dictionary=True) # 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: # try:
# filename = f"PMC_Report_{pmc_no}.xlsx"
# cursor.callproc('GetContractorDetailsByPMC', [pmc_no]) # output_folder = FolderAndFile.get_download_folder()
# contractor_info = next(cursor.stored_results()).fetchone() # 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: # if not contractor_info:
# return None # return None
# cursor.callproc('GetHoldTypesByContractor', [contractor_info["Contractor_Id"]]) # hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor',[contractor_info["Contractor_Id"]])
# hold_types = next(cursor.stored_results()).fetchall()
# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} # hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
# cursor.callproc('GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) # invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None,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()
# credit_notes = GeneralUse.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no])
# credit_note_map = {} # credit_note_map = {}
# for cn in credit_notes: # 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) # credit_note_map.setdefault(key, []).append(cn)
# cursor.callproc('GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]]) # hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
# hold_amounts = next(cursor.stored_results()).fetchall()
# 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 = {} # hold_data = {}
# for h in hold_amounts: # for h in hold_amounts:
# hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] # hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
# cursor.callproc('GetAllPaymentsByPMC', [pmc_no]) # # ================= LOG =================
# all_payments = next(cursor.stored_results()).fetchall() # LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'")
# 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()
# ReportHelper.generate_excel(
# 0, contractor_info, invoices, hold_types, hold_data,
# credit_note_map,gst_release_map, output_file)
# return output_folder, filename # return output_folder, filename
# finally: # finally:
# cursor.close() # cursor.close()
# connection.close() # connection.close()

View File

@@ -2,9 +2,10 @@ import config
from datetime import datetime from datetime import datetime
from flask import send_file from flask import send_file
import openpyxl import openpyxl
from openpyxl.styles import Font from openpyxl.styles import Font, PatternFill
from model.FolderAndFile import FolderAndFile from model.FolderAndFile import FolderAndFile
from services.Generalservice import GeneralUse
class ReportHelper: class ReportHelper:
isSuccess = False isSuccess = False
@@ -16,30 +17,6 @@ class ReportHelper:
self.resultMessage = "" self.resultMessage = ""
self.data = [] 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 @staticmethod
def search_contractor(request): def search_contractor(request):
@@ -59,10 +36,7 @@ class ReportHelper:
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
try: try:
data = ReportHelper.execute_sp( data = GeneralUse.execute_sp(cursor,"search_contractor_info",[
cursor,
"search_contractor_info",
[
subcontractor_name or None, subcontractor_name or None,
pmc_no or None, pmc_no or None,
state or None, state or None,
@@ -71,8 +45,7 @@ class ReportHelper:
village or None, village or None,
year_from or None, year_from or None,
year_to or None year_to or None
] ])
)
except Exception as e: except Exception as e:
print(f"Error in search_contractor: {e}") print(f"Error in search_contractor: {e}")
@@ -84,192 +57,156 @@ class ReportHelper:
return data 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 @staticmethod
def download_report(contractor_id): def get_contractor_info(contractor_id):
try: from model.ContractorInfo import ContractorInfo
connection = config.get_db_connection() contractor = ContractorInfo(contractor_id)
cursor = connection.cursor(dictionary=True) return contractor.contInfo if contractor.contInfo else None
# -------- Contractor Info --------
contInfo = ReportHelper.execute_sp(cursor, 'GetContractorInfo', [contractor_id], True)
if not contInfo: # call this method for excel formate written
return "No contractor found", 404 @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 -------- # Contractor Info
cursor.callproc('FetchInvoicesByContractor', [contractor_id]) for field, value in contInfo.items():
sheet.append([field.replace("_", " "), value])
sheet.append([])
invoices = [] # Headers
for result in cursor.stored_results(): base_headers = ["PMC No", "Village", "Work Type", "Invoice Details", "Invoice Date", "Invoice No",
invoices.extend(result.fetchall()) "Basic Amount", "Debit", "After Debit Amount", "GST (18%)", "Amount", "TDS (1%)",
"SD (5%)", "On Commission", "Hydro Testing", "GST SD Amount"]
if not invoices: hold_headers = [ht['hold_type'] for ht in hold_types]
return "No invoice data found"
# -------- Create Workbook -------- payment_headers = ["Final Amount", "Payment Amount", "TDS Payment", "Total Paid", "UTR"]
workbook = openpyxl.Workbook()
sheet = workbook.active
sheet.title = "Contractor Report"
# ================= CONTRACTOR DETAILS ================= all_headers = base_headers + hold_headers + payment_headers
sheet.append(["SUB CONTRACTOR DETAILS"]) sheet.append(all_headers)
sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
sheet.append([])
sheet.append(["Name", contInfo.get("Contractor_Name") or ""]) for cell in sheet[sheet.max_row]:
sheet.append(["Mobile No", contInfo.get("Mobile_No") or ""]) cell.font = Font(bold=True)
sheet.append(["Email", contInfo.get("Email") or ""]) cell.fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid")
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([])
# ================= TABLE HEADERS ================= processed_gst_releases = set()
headers = [ appended_credit_keys = set()
"PMC No", "Village", "Invoice No", "Invoice Date", "Work Type","Invoice_Details", previous_pmc_no = None
"Basic Amount", "Debit Amount", "After Debit Amount",
"Amount", "GST Amount", "TDS Amount", "SD Amount", for inv in invoices:
"On Commission", "Hydro Testing", "Hold Amount", pmc_no = str(inv["PMC_No"]).strip()
"GST SD Amount", "Final Amount",
"Payment Amount", "TDS Payment", invoice_no = (
"Total Amount", "UTR" 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 ================= # Hold values
total_final = 0 invoice_holds = hold_data.get(inv["Invoice_Id"], {})
total_payment = 0 for ht_id in [ht['hold_type_id'] for ht in hold_types]:
total_amount = 0 row.append(invoice_holds.get(ht_id, ""))
for inv in invoices: # Payment values
row = [ row += [
inv.get("PMC_No"), inv.get("Final_Amount", ""),
inv.get("Village_Name"), inv.get("Payment_Amount", ""),
inv.get("invoice_no"), inv.get("TDS_Payment_Amount", ""),
inv.get("Invoice_Date"), inv.get("Total_Amount", ""),
inv.get("Work_Type"), inv.get("UTR", "")
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")
]
total_final += float(inv.get("Final_Amount") or 0) sheet.append(row)
total_payment += float(inv.get("Payment_Amount") or 0)
total_amount += float(inv.get("Total_Amount") or 0)
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 ================= gst_row += [""] * len(hold_headers)
sheet.append([])
sheet.append([
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"TOTAL",
total_final,
total_payment,
"",
total_amount,
""
])
# ================= AUTO WIDTH ================= gst_row += [
for column in sheet.columns: gr.get("Final_Amount", ""),
max_length = 0 "",
column_letter = column[0].column_letter "",
for cell in column: gr.get("Total_Amount", ""),
if cell.value: gr.get("UTR", "")
max_length = max(max_length, len(str(cell.value))) ]
sheet.column_dimensions[column_letter].width = max_length + 2
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)

View File

@@ -1,7 +1,6 @@
from model.Utilities import ItemCRUDType from model.Utilities import ItemCRUDType
from model.ItemCRUD import ItemCRUD from model.ItemCRUD import ItemCRUD
class Subcontractor: class Subcontractor:
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False

View File

@@ -8,10 +8,12 @@ class ItemCRUDType(Enum):
State = 4 State = 4
HoldType = 5 HoldType = 5
Subcontractor = 6 Subcontractor = 6
GSTRelease = 7
Invoice = 8
class RegEx: class RegEx:
patternAlphabetOnly = "^[A-Za-z ]+$" patternAlphabetOnly = r"^[A-Za-z ]+$"
allPattern = r"^(?!\s*$).+"
class ResponseHandler: class ResponseHandler:

View File

@@ -13,14 +13,14 @@ class Village:
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
self.response = {} # ✅ ADDED self.response = {}
self.village = ItemCRUD(itemType=ItemCRUDType.Village) self.village = ItemCRUD(itemType=ItemCRUDType.Village)
# 🔹 Helper: sync status # 🔹 Helper: sync status
def _set_status(self, village): def _set_status(self, village):
self.isSuccess = village.isSuccess self.isSuccess = village.isSuccess
# UPDATED (safe handling) # UPDATED (safe handling)
if hasattr(village, "response"): if hasattr(village, "response"):
self.response = village.response self.response = village.response
self.resultMessage = village.response.get("message", "") self.resultMessage = village.response.get("message", "")
@@ -37,7 +37,7 @@ class Village:
block_id, village_name = self._get_form_data(request) block_id, village_name = self._get_form_data(request)
if not village_name: if not village_name:
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED self.response = ResponseHandler.invalid_name("village")
self.resultMessage = self.response["message"] self.resultMessage = self.response["message"]
self.isSuccess = False self.isSuccess = False
return return
@@ -75,7 +75,7 @@ class Village:
block_id, village_name = self._get_form_data(request) block_id, village_name = self._get_form_data(request)
if not village_name: if not village_name:
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED self.response = ResponseHandler.invalid_name("village")
self.resultMessage = self.response["message"] self.resultMessage = self.response["message"]
self.isSuccess = False self.isSuccess = False
return None return None
@@ -113,7 +113,7 @@ class Village:
block_id, village_name = self._get_form_data(request) block_id, village_name = self._get_form_data(request)
if not village_name: if not village_name:
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED self.response = ResponseHandler.invalid_name("village")
self.resultMessage = self.response["message"] self.resultMessage = self.response["message"]
self.isSuccess = False self.isSuccess = False
return return
@@ -176,7 +176,7 @@ class Village:
print(f"Error fetching blocks: {e}") print(f"Error fetching blocks: {e}")
self.isSuccess = False self.isSuccess = False
# FIXED (removed jsonify response) # FIXED (removed jsonify response)
self.response = ResponseHandler.fetch_failure("block") self.response = ResponseHandler.fetch_failure("block")
self.resultMessage = self.response["message"] self.resultMessage = self.response["message"]

View File

@@ -1,120 +1,25 @@
# from flask import request # model/gst_release.py
# from model.ItemCRUD import ItemCRUD
# from model.Utilities import ItemCRUDType
# class GSTRelease:
# """CRUD operations for GST Release using ItemCRUD"""
# def __init__(self):
# self.isSuccess = False
# self.resultMessage = ""
# # ------------------- Add GST Release -------------------
# def AddGSTRelease(self, request):
# pmc_no = request.form.get('PMC_No', '').strip()
# invoice_no = request.form.get('invoice_No', '').strip()
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.AddItem(
# request=request,
# parentid=None,
# childname=f"{pmc_no}-{invoice_no}",
# storedprocfetch="CheckGSTReleaseExists",
# storedprocadd="AddGSTReleaseFromExcel" # your stored procedure handles extra fields
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# # ------------------- Get All GST Releases -------------------
# def GetAllGSTReleases(self):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# # Pass request=None for fetch
# rows = gst.GetAllData(request=None, storedproc="GetAllGSTReleases")
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# data = []
# for row in rows:
# data.append({
# "gst_release_id": row[0],
# "pmc_no": row[1],
# "invoice_no": row[2],
# "basic_amount": row[3],
# "final_amount": row[4],
# "total_amount": row[5],
# "utr": row[6],
# "contractor_id": row[7]
# })
# return data
# # ------------------- Get GST Release By ID -------------------
# def GetGSTReleaseByID(self, gst_release_id):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# row = gst.GetDataByID(gst_release_id, request=None, storedproc="GetGSTReleaseById")
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# if row:
# return {
# "gst_release_id": row[0],
# "pmc_no": row[1],
# "invoice_no": row[2],
# "basic_amount": row[3],
# "final_amount": row[4],
# "total_amount": row[5],
# "utr": row[6],
# "contractor_id": row[7]
# }
# return None
# # ------------------- Edit GST Release -------------------
# def EditGSTRelease(self, request, gst_release_id):
# pmc_no = request.form.get('PMC_No', '').strip()
# invoice_no = request.form.get('invoice_No', '').strip()
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.EditItem(
# request=request,
# childid=gst_release_id,
# parentid=None,
# childname=f"{pmc_no}-{invoice_no}",
# storedprocupdate="UpdateGSTRelease" # stored procedure handles extra fields
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# # ------------------- Delete GST Release -------------------
# def DeleteGSTRelease(self, gst_release_id):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.DeleteItem(
# itemID=gst_release_id,
# request=None,
# storedprocDelete="DeleteGSTReleaseById"
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
from flask import request, jsonify from flask import request, jsonify
from model.ItemCRUD import ItemCRUD from model.ItemCRUD import ItemCRUD
from model.Utilities import ItemCRUDType from model.Utilities import ItemCRUDType
class GSTRelease: class GSTRelease:
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
# ------------------- Add GST Release ------------------- # ------------------- Add GST Release -------------------
def AddGSTRelease(self, request): def AddGSTRelease(self, request):
try: try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# Print the full form data
print("===== DEBUG: FORM DATA =====")
for key, value in request.form.items():
print(f"{key} : {value}")
print("=============================")
data = { data = {
"PMC_No": request.form.get("PMC_No", "").strip(), "PMC_No": request.form.get("PMC_No", "").strip(),
"Invoice_No": request.form.get("Invoice_No", "").strip(), "Invoice_No": request.form.get("Invoice_No", "").strip(),
@@ -125,6 +30,11 @@ class GSTRelease:
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0) "Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
} }
print("===== DEBUG: PARSED DATA =====")
print(data)
print("==============================")
# Add GST Release
gst.AddItem( gst.AddItem(
request=request, request=request,
data=data, data=data,
@@ -132,6 +42,8 @@ class GSTRelease:
storedprocadd="AddGSTReleaseFromExcel" storedprocadd="AddGSTReleaseFromExcel"
) )
print(f"AddItem result: isSuccess={gst.isSuccess}, message={gst.resultMessage}")
self.isSuccess = gst.isSuccess self.isSuccess = gst.isSuccess
self.resultMessage = str(gst.resultMessage) self.resultMessage = str(gst.resultMessage)
@@ -142,20 +54,26 @@ class GSTRelease:
return jsonify({"success": self.isSuccess, "message": self.resultMessage}) return jsonify({"success": self.isSuccess, "message": self.resultMessage})
# ------------------- Edit GST Release -------------------
def EditGSTRelease(self, request, gst_release_id): def EditGSTRelease(self, request, gst_release_id):
try: try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# Map form inputs to stored procedure parameters
data = { data = {
"PMC_No": request.form.get("PMC_No", "").strip(), "p_pmc_no": request.form.get("PMC_No", "").strip(),
"Invoice_No": request.form.get("Invoice_No", "").strip(), "p_invoice_no": request.form.get("invoice_no", "").strip(),
"Basic_Amount": float(request.form.get("Basic_Amount", 0) or 0), "p_basic_amount": float(request.form.get("Basic_Amount", 0) or 0),
"Final_Amount": float(request.form.get("Final_Amount", 0) or 0), "p_final_amount": float(request.form.get("Final_Amount", 0) or 0),
"Total_Amount": float(request.form.get("Total_Amount", 0) or 0), "p_total_amount": float(request.form.get("Total_Amount", 0) or 0),
"UTR": request.form.get("UTR", "").strip() "p_utr": request.form.get("UTR", "").strip(),
"p_gst_release_id": gst_release_id
} }
print("===== DEBUG: UPDATE DATA =====")
print(data)
print("==============================")
# Call your stored procedure
gst.EditItem( gst.EditItem(
request=request, request=request,
childid=gst_release_id, childid=gst_release_id,
@@ -171,8 +89,6 @@ class GSTRelease:
self.isSuccess = False self.isSuccess = False
self.resultMessage = str(e) self.resultMessage = str(e)
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
# ------------------- Delete GST Release ------------------- # ------------------- Delete GST Release -------------------
def DeleteGSTRelease(self, gst_release_id): def DeleteGSTRelease(self, gst_release_id):
try: try:
@@ -198,7 +114,6 @@ class GSTRelease:
def GetAllGSTReleases(self): def GetAllGSTReleases(self):
try: try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
rows = gst.GetAllData(None, "GetAllGSTReleases") rows = gst.GetAllData(None, "GetAllGSTReleases")
data = [] data = []
@@ -224,7 +139,6 @@ class GSTRelease:
def GetGSTReleaseByID(self, gst_release_id): def GetGSTReleaseByID(self, gst_release_id):
try: try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById") row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById")
if row: if row:

View File

@@ -2,7 +2,6 @@ import config
import mysql.connector import mysql.connector
import config import config
import mysql.connector import mysql.connector
from enum import Enum
from model.Utilities import ItemCRUDType from model.Utilities import ItemCRUDType
class Paymentmodel: class Paymentmodel:
@@ -34,40 +33,44 @@ class Paymentmodel:
return payments return payments
@staticmethod @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() connection = Paymentmodel.get_connection()
if not connection: if not connection:
return False 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 cursor = None
def update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr):
connection = Paymentmodel.get_connection()
if not connection:
return False
try: try:
cursor = connection.cursor() 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() connection.commit()
return True return True
except mysql.connector.Error as e:
print(f"Error updating inpayment: {e}") except Exception as e:
print(e)
return False return False
finally: finally:
cursor.close() if cursor:
connection.close() cursor.close()
if connection:
connection.close()
@staticmethod @staticmethod
def fetch_payment_by_id(payment_id): def fetch_payment_by_id(payment_id):
@@ -133,9 +136,7 @@ class Paymentmodel:
# Delete payment # Delete payment
cursor.callproc("DeletePayment", (payment_id,)) cursor.callproc("DeletePayment", (payment_id,))
connection.commit() connection.commit()
# Reset inpayment fields
cursor.callproc("ResetInpayment", [pmc_no, invoice_no])
connection.commit()
return True, pmc_no, invoice_no return True, pmc_no, invoice_no
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error deleting payment: {e}") print(f"Error deleting payment: {e}")

View 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

179
services/ReportService.py Normal file
View File

@@ -0,0 +1,179 @@
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])
self.gst_release_raw = GeneralUse.execute_sp(cursor, 'GetGSTRelease', [self.contractor_id])
# ---------- 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])
self.gst_release_raw = GeneralUse.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [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.pmc_no, 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

@@ -3,7 +3,7 @@ $(document).ready(function () {
let holdType = $(this).val().replace(/^\s+/, ""); let holdType = $(this).val().replace(/^\s+/, "");
$(this).val(holdType); $(this).val(holdType);
let reg = /^[A-Za-z]/; let reg = /^.+$/; // all pattern allow
if (!reg.test(holdType)) { if (!reg.test(holdType)) {
$("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red"); $("#holdTypeMessage").text("Hold Type must start with a letter.").css("color", "red");

View File

@@ -1,62 +1,271 @@
// Subcontractor autocomplete functionality // $(document).ready(function () {
$(document).ready(function () { // // ===============================
$("#subcontractor").keyup(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(); let query = $(this).val();
if (query !== "") { if (query !== "") {
$.ajax({ $.ajax({
url: "/search_subcontractor", url: "/search_subcontractor",
method: "POST", method: "POST",
data: { query: query }, data: { query: query },
success: function (data) { success: function (data) {
$("#subcontractor_list").fadeIn().html(data); $("#subcontractor_list").fadeIn().html(data);
} }
}); });
} else { } else {
$("#subcontractor_list").fadeOut(); $("#subcontractor_list").fadeOut();
} }
}); });
$(document).on("click", "li", function () { $(document).on("click", "li", function () {
$("#subcontractor").val($(this).text()); $("#subcontractor").val($(this).text());
$("#subcontractor_id").val($(this).attr("data-id")); $("#subcontractor_id").val($(this).attr("data-id"));
$("#subcontractor_list").fadeOut(); $("#subcontractor_list").fadeOut();
});
}); });
// Success Alert: show alert and reload after 3 seconds // Focus
function showSuccessAlert() { if (document.getElementById('subcontractor')) {
const alertBox = document.getElementById("invoiceSuccessAlert"); document.getElementById('subcontractor').focus();
alertBox.classList.add("show");
setTimeout(() => {
alertBox.classList.remove("show");
// Reload page or redirect after alert hides
window.location.href = '/add_invoice';
}, 3000);
} }
// Submit form via AJAX // ===============================
$("#invoiceForm").on("submit", function (e) { // ADD INVOICE
e.preventDefault(); // ===============================
let formData = $(this).serialize(); if ($('#invoiceForm').length && window.location.href.includes('add_invoice')) {
$.ajax({ $("#invoiceForm").on("submit", function (e) {
url: '/add_invoice', e.preventDefault();
method: 'POST', let formData = $(this).serialize();
data: formData,
success: function (response) {
if(response.status === "success") {
showSuccessAlert();
} else {
alert(response.message);
}
},
error: function (xhr, status, error) {
alert("Submission failed: " + error);
}
});
});
$.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 () { $.ajax({
document.getElementById('subcontractor').focus(); 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
});

View File

@@ -1,43 +1,57 @@
$(document).ready(function () { document.addEventListener("DOMContentLoaded", function () {
function fetchResults() {
let formData = $('#search-form').serialize();
$.ajax({ const form = document.getElementById("search-form");
type: 'POST', const tableBody = document.querySelector("#result-table tbody");
url: '/search_contractor',
data: formData,
success: function (data) {
let tableBody = $('#result-table tbody');
tableBody.empty();
if (data.length === 0) { function fetchData(page = 1) {
tableBody.append('<tr><td colspan="6">No data found</td></tr>'); const formData = new FormData(form);
} else { formData.append("page", page);
data.forEach(function (row) {
tableBody.append(` fetch("/search_contractor", {
<tr> method: "POST",
<td><a href="/contractor_report/${row.Contractor_Id}" target="_blank">${row.Contractor_Name}</a></td> body: formData
<td><a href="/pmc_report/${row.PMC_No}" target="_blank">${row.PMC_No}</a></td> })
<td>${row.State_Name}</td> .then(res => res.json())
<td>${row.District_Name}</td> .then(res => {
<td>${row.Block_Name}</td> tableBody.innerHTML = "";
<td>${row.Village_Name}</td>
</tr> res.data.forEach(row => {
`);
}); const tr = document.createElement("tr");
}
}, tr.innerHTML = `
error: function (xhr) { <td class="contractor-link" data-id="${row.Contractor_Id}">
alert(xhr.responseJSON.error); ${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 () { if (e.target.classList.contains("pmc-link")) {
fetchResults(); const pmc = e.target.dataset.pmc;
}); window.location.href = `/pmc_report/${pmc}`;
}
}); });
window.onload = function () { fetchData();
document.getElementById('subcontractor_name').focus(); });
};

View File

@@ -1,26 +1,23 @@
// Search on table using search inpute options // Search on table using search inpute options
function searchTable() { function searchTable() {
let input = document.getElementById("searchBar").value.toLowerCase(); let input = document.getElementById("searchBar").value.toLowerCase();
let rows = document.querySelectorAll("table tbody tr"); let tables = document.querySelectorAll("table");
rows.forEach(row => { tables.forEach(table => {
let blockName = row.cells[1].textContent.toLowerCase(); let rows = table.querySelectorAll("tr");
let districtName = row.cells[2].textContent.toLowerCase();
let villageName = row.cells[3].textContent.toLowerCase();
if (blockName.includes(input) || districtName.includes(input)|| villageName.includes(input)) { rows.forEach((row, index) => {
row.style.display = ""; if (index === 0) return; // header skip
} else {
row.style.display = "none"; let text = row.textContent.toLowerCase();
}
row.style.display = text.includes(input) ? "" : "none";
});
}); });
} }
// Common Sorting Script for Tables // Common Sorting Script for Tables
function sortTable(n, dir) { function sortTable(n, dir) {
var table, rows, switching, i, x, y, shouldSwitch; var table, rows, switching, i, x, y, shouldSwitch;
@@ -57,14 +54,14 @@ function sortTable(n, dir) {
} }
// Attach sorting functionality to all sortable tables // Attach sorting functionality to all sortable tables
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
// Find all elements with the class "sortable-header" // Find all elements with the class "sortable-header"
var sortableHeaders = document.querySelectorAll(".sortable-header"); var sortableHeaders = document.querySelectorAll(".sortable-header");
sortableHeaders.forEach(function(header) { sortableHeaders.forEach(function (header) {
// Attach click event for ascending sort // Attach click event for ascending sort
if (header.querySelector(".sort-asc")) { if (header.querySelector(".sort-asc")) {
header.querySelector(".sort-asc").addEventListener("click", function() { header.querySelector(".sort-asc").addEventListener("click", function () {
var columnIndex = Array.from(header.parentNode.children).indexOf(header); var columnIndex = Array.from(header.parentNode.children).indexOf(header);
sortTable(columnIndex, "asc"); sortTable(columnIndex, "asc");
}); });
@@ -72,7 +69,7 @@ document.addEventListener("DOMContentLoaded", function() {
// Attach click event for descending sort // Attach click event for descending sort
if (header.querySelector(".sort-desc")) { if (header.querySelector(".sort-desc")) {
header.querySelector(".sort-desc").addEventListener("click", function() { header.querySelector(".sort-desc").addEventListener("click", function () {
var columnIndex = Array.from(header.parentNode.children).indexOf(header); var columnIndex = Array.from(header.parentNode.children).indexOf(header);
sortTable(columnIndex, "desc"); sortTable(columnIndex, "desc");
}); });
@@ -105,4 +102,31 @@ document.addEventListener("DOMContentLoaded", function () {
displayButton.classList.add("active-button"); displayButton.classList.add("active-button");
addButton.classList.remove("active-button"); addButton.classList.remove("active-button");
}); });
});
document.addEventListener("DOMContentLoaded", function () {
let tables = document.querySelectorAll("table");
tables.forEach(table => {
let header = table.querySelector("tr:first-child");
if (header) {
header.style.position = "sticky";
header.style.top = "0";
header.style.background = "#fff";
header.style.zIndex = "2";
}
if (!table.parentElement.classList.contains("table-wrapper")) {
let wrapper = document.createElement("div");
wrapper.classList.add("table-wrapper");
wrapper.style.maxHeight = "65vh"
wrapper.style.overflowY = "auto";
table.parentNode.insertBefore(wrapper, table);
wrapper.appendChild(table);
}
});
}); });

View File

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

View File

@@ -15,17 +15,21 @@
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm" style="display: none;"> <div id="addForm" style="display: none;">
<h2>Add GST Release</h2> <h2>Add GST Release</h2>
<form action="/add_gst_release" method="POST" onsubmit="showSuccessAlert(event)"> <form action="/add_gst_release" method="POST" onsubmit="showSuccessAlert(event)">
<div class="row1"> <div class="row1">
<div> <div>
<label for="subcontractor">Subcontractor Name:</label> <label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/> <!-- Text input for user-friendly autocomplete -->
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/> <input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/>
<div id="subcontractor_list" class="autocomplete-items"></div>
</div> <!-- 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> </div>
<label for="PMC_No">PMC No:</label><br> <label for="PMC_No">PMC No:</label><br>
@@ -37,19 +41,19 @@
</select><br><br> </select><br><br>
<label for="invoice_No">Invoice No:</label><br> <label for="invoice_No">Invoice No:</label><br>
<input type="text" id="invoice_No" name="invoice_No" required><br><br> <input type="text" id="invoice_No" name="Invoice_No" required><br><br>
<label for="basic_amount">Basic Amount:</label><br> <label for="basic_amount">Basic Amount:</label><br>
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required><br><br> <input type="number" step="0.01" id="basic_amount" name="Basic_Amount" placeholder="₹ - 00.00" required><br><br>
<label for="final_amount">Final Amount:</label><br> <label for="final_amount">Final Amount:</label><br>
<input type="number" step="0.01" id="final_amount" name="final_amount" placeholder="₹ - 00.00" required><br><br> <input type="number" step="0.01" id="final_amount" name="Final_Amount" placeholder="₹ - 00.00" required><br><br>
<label for="total_amount">Total Amount:</label><br> <label for="total_amount">Total Amount:</label><br>
<input type="number" step="0.01" id="total_amount" name="total_amount" placeholder="₹ - 00.00" required><br><br> <input type="number" step="0.01" id="total_amount" name="Total_Amount" placeholder="₹ - 00.00" required><br><br>
<label for="utr">UTR:</label><br> <label for="utr">UTR:</label><br>
<input type="text" id="utr" name="utr" required><br><br> <input type="text" id="utr" name="UTR" required><br><br>
<button type="submit">Submit GST Release</button> <button type="submit">Submit GST Release</button>
</form> </form>
@@ -68,96 +72,110 @@
{% endwith %} {% endwith %}
</div> </div>
<!-- GST Release History Table -->
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none;">
<div class="search-container"> <div class="search-container">
<h2>GST Release History</h2> <h2>GST Release History</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()"> <input type="text" id="searchBar" placeholder="Search..." onkeyup="searchTable()">
</div> </div>
<table id="sortableTable" border="1"> <table id="sortableTable" border="1">
<thead> <thead>
<tr> <tr>
<th class="sortable-header">GST_Release_Id</th> <th class="sortable-header">GST_Release_Id</th>
<th class="sortable-header">PMC_No</th> <th class="sortable-header">PMC_No</th>
<th>Invoice_No</th> <th>Invoice_No</th>
<th>Basic_Amount</th> <th>Basic_Amount</th>
<th>Final_Amount</th> <th>Final_Amount</th>
<th>Total_Amount</th> <th>Total_Amount</th>
<th>UTR</th> <th>UTR</th>
<th>Update</th> <th>Update</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for gst_rel in gst_releases %} {% for gst_rel in gst_releases %}
<tr> <tr>
<td>{{ gst_rel[0] }}</td> <td>{{ gst_rel.gst_release_id }}</td>
<td>{{ gst_rel[1] }}</td> <td>{{ gst_rel.pmc_no }}</td>
<td>{{ gst_rel[2] }}</td> <td>{{ gst_rel.invoice_no }}</td>
<td>{{ gst_rel[3] }}</td> <td>{{ gst_rel.basic_amount }}</td>
<td>{{ gst_rel[4] }}</td> <td>{{ gst_rel.final_amount }}</td>
<td>{{ gst_rel[5] }}</td> <td>{{ gst_rel.total_amount }}</td>
<td>{{ gst_rel[6] }}</td> <td>{{ gst_rel.utr }}</td>
<td> <td>
<a href="/edit_gst_release/{{ gst_rel[0] }}"> <a href="{{ url_for('gst_release_bp.edit_gst_release', gst_release_id=gst_rel.gst_release_id) }}">
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" <img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon">
class="icon"> </a>
</a> </td>
</td> <td>
<td> <a href="{{ url_for('gst_release_bp.delete_gst_release', gst_release_id=gst_rel.gst_release_id) }}"
<a href="/delete_gst_release/{{ gst_rel[0] }}" onclick="return confirm('Are you sure you want to delete this GST Release?')">
onclick="return confirm('Are you sure you want to delete this GST Release?')"> <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" </a>
class="icon"> </td>
</a> </tr>
</td> {% endfor %}
</tr>
{% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Handle subcontractor autocomplete
document.getElementById("subcontractor").addEventListener("input", function () { const subcontractorInput = document.getElementById("subcontractor");
const subcontractorIdInput = document.getElementById("subcontractor_id");
const subcontractorList = document.getElementById("subcontractor_list");
const pmcDropdown = document.getElementById("PMC_No");
const form = document.querySelector('form');
// --------------------------
// Subcontractor autocomplete
// --------------------------
subcontractorInput.addEventListener("input", function () {
const query = this.value; const query = this.value;
const list = document.getElementById("subcontractor_list");
if (query.length < 2) { if (query.length < 2) {
list.innerHTML = ''; subcontractorList.innerHTML = '';
subcontractorIdInput.value = ''; // reset hidden id
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>'; // reset PMC dropdown
return; return;
} }
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`) fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
list.innerHTML = ''; subcontractorList.innerHTML = '';
data.results.forEach(item => { data.results.forEach(item => {
const div = document.createElement("div"); const div = document.createElement("div");
div.setAttribute("data-id", item.id); div.setAttribute("data-id", item.id);
div.textContent = item.name; div.textContent = item.name;
list.appendChild(div); subcontractorList.appendChild(div);
}); });
}); });
}); });
// Handle subcontractor selection // --------------------------
document.getElementById("subcontractor_list").addEventListener("click", function (e) { // Subcontractor selection
// --------------------------
subcontractorList.addEventListener("click", function (e) {
const selectedId = e.target.getAttribute("data-id"); const selectedId = e.target.getAttribute("data-id");
const selectedName = e.target.textContent; const selectedName = e.target.textContent;
if (selectedId) { if (selectedId) {
document.getElementById("subcontractor_id").value = selectedId; // Set hidden field for backend
document.getElementById("subcontractor").value = selectedName; subcontractorIdInput.value = selectedId;
document.getElementById("subcontractor_list").innerHTML = "";
// Update PMC dropdown for selected subcontractor // Set text input to selected name
subcontractorInput.value = selectedName;
// Clear the autocomplete list
subcontractorList.innerHTML = "";
// Fetch and populate PMC dropdown
fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`) fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
const pmcDropdown = document.getElementById("PMC_No");
pmcDropdown.innerHTML = '<option value="">Select PMC No</option>'; pmcDropdown.innerHTML = '<option value="">Select PMC No</option>';
data.pmc_nos.forEach(pmc => { data.pmc_nos.forEach(pmc => {
const option = document.createElement("option"); const option = document.createElement("option");
option.value = pmc; option.value = pmc;
@@ -167,6 +185,22 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
} }
}); });
// --------------------------
// Form submit validation
// --------------------------
form.addEventListener('submit', function(e) {
if (!subcontractorIdInput.value) {
e.preventDefault();
alert("Please select a subcontractor from the list.");
subcontractorInput.focus();
} else if (!pmcDropdown.value) {
e.preventDefault();
alert("Please select a PMC No.");
pmcDropdown.focus();
}
});
}); });
</script> </script>

View File

@@ -1,59 +1,73 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<title>Manage Hold Types</title> <title>Manage Hold Types</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- <script src="{{ url_for('static', filename='js/hold_types.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') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
</head> </head>
<body> <body>
<div class="button-container"> <div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm"> <div id="addForm">
<h2>Add Hold Types</h2> <h2>Add Hold Types</h2>
<form id="holdTypeForm" method="POST" action="{{ url_for('hold_types.add_hold_type') }}"> <form id="holdTypeForm" method="POST" action="{{ url_for('hold_types.add_hold_type') }}">
<label>Enter Hold Amount Type:</label> <label>Enter Hold Amount Type:</label>
<input type="text" id="hold_type" name="hold_type" placeholder="Enter Type" required> <input type="text" id="hold_type" name="hold_type" placeholder="Enter Type" required>
<span id="holdTypeMessage"></span> <span id="holdTypeMessage"></span>
<button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button> <button type="submit" value="Add Hold Type" id="successPopup">Add Hold Type</button>
</form> </form>
</div> </div>
<div id="addTable" style="display: none;">
<div 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>
<a href="/">Back to Dashboard</a> <div id="addTable" style="display: none;">
</div> <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> </body>
{% endblock %} {% endblock %}

View File

@@ -1,176 +1,322 @@
{% extends 'base.html' %} {% extends 'base.html' %} {% block content %}
{% block content %}
<head xmlns="http://www.w3.org/1999/html"> <head xmlns="http://www.w3.org/1999/html">
<meta charset="UTF-8"/> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Add Invoice</title> <title>Add Invoice</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}"> <link
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script> rel="stylesheet"
<script src="{{ url_for('static', filename='js/holdAmount.js') }}"></script> type="text/css"
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> 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> </head>
<body> <body>
{% if success == 'true' %} {% if success == 'true' %}
<div class="alert alert-success alert-dismissible fade show mt-3" role="alert"> <div
class="alert alert-success alert-dismissible fade show mt-3"
role="alert"
>
✅ Invoice added successfully! ✅ Invoice added successfully!
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> <button
</div> type="button"
{% endif %} class="btn-close"
data-bs-dismiss="alert"
aria-label="Close"
<!-- Flash Messages --> ></button>
{% with messages = get_flashed_messages(with_categories=true) %} </div>
{% if messages %}
<div class="flash-messages">
{% for category, message in messages %}
<div class="alert {{ category }}">{{ message }}</div>
{% endfor %}
</div>
{% endif %} {% 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="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div> </div>
<div id="addForm" style="display: none;"> <div id="addForm" style="display: none">
<h2>Add Invoice</h2> <h2>Add Invoice</h2>
<form id="invoiceForm" action="{{ url_for('invoice.add_invoice') }}" method="POST"> <form
<div class="row1"> id="invoiceForm"
<div> action="{{ url_for('invoice.add_invoice') }}"
<label for="subcontractor">Subcontractor Name:</label> method="POST"
<input type="text" id="subcontractor" name="subcontractor" required autocomplete="off"/> >
<input type="hidden" id="subcontractor_id" name="subcontractor_id"/> <div class="row1">
<div id="subcontractor_list"></div> <div>
</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>
<div class="row2"> <div class="row2">
<div> <div>
<label for="village">Village Name:</label> <label for="village">Village Name:</label>
<select id="village" name="village" required> <select id="village" name="village" required>
<option value="">-- Select Village --</option> <option value="">-- Select Village --</option>
{% for village in villages %} {% for village in villages %}
<option value="{{ village.Village_Name }}">{{ village.Village_Name }}</option> <option value="{{ village.Village_Name }}">
{% endfor %} {{ village.Village_Name }}
</select> </option>
</div> {% endfor %}
<div> </select>
<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>
<div>
<div class="row2"> <label for="pmc_no">PMC No:</label>
<div> <input type="text" id="pmc_no" name="pmc_no" required />
<label for="work_type">Work Type:</label> <div id="pmc_no_list" class="autocomplete-list"></div>
<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> </div>
</div>
<div class="row2"> <div class="row2">
<div> <div>
<label for="invoice_no">Invoice No:</label> <label for="work_type">Work Type:</label>
<input type="text" id="invoice_no" name="invoice_no" required/> <input type="text" id="work_type" name="work_type" required />
</div>
<div>
<label for="invoice_date">Invoice Date:</label>
<input type="date" id="invoice_date" name="invoice_date" required/>
</div>
</div> </div>
<div>
<div class="row3"> <label for="invoice_details">Invoice Details:</label>
<div> <textarea
<label for="basic_amount">Basic Amount:</label> id="invoice_details"
<input type="number" step="0.01" id="basic_amount" name="basic_amount" placeholder="₹ - 00.00" required/> name="invoice_details"
</div> required
<div> ></textarea>
<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> </div>
</div>
<!-- Dynamically added hold amount fields --> <div class="row2">
<div id="hold_amount_container"></div> <div>
<label for="invoice_no">Invoice No:</label>
<div class="row2"> <input type="text" id="invoice_no" name="invoice_no" required />
<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> </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> </form>
</div> </div>
<div id="addTable" style="display: none;"> <div id="addTable" style="display: none">
<!-- Invoice Table Section --> <!-- Invoice Table Section -->
<div class="search-container"> <div class="search-container">
<h2>Invoice List</h2> <h2>Invoice List</h2>
<input type="text" id="searchBar" placeholder="Searching..." onkeyup="searchTable()"> <input
{% if invoices %} type="text"
<table class="invoice-table"> id="searchBar"
placeholder="Searching..."
onkeyup="searchTable()"
/>
{% if invoices %}
<table class="invoice-table">
<thead> <thead>
<tr> <tr>
<th>Invoice Id</th> <th>Invoice Id</th>
<th>SubContractor Name</th> <th>SubContractor Name</th>
<th>PMC No</th> <th>PMC No</th>
@@ -192,11 +338,11 @@
<th>Final Amount</th> <th>Final Amount</th>
<th>Update</th> <th>Update</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for invoice in invoices %} {% for invoice in invoices %}
<tr> <tr>
<td>{{ invoice.Invoice_Id }}</td> <td>{{ invoice.Invoice_Id }}</td>
<td>{{ invoice.Contractor_Name }}</td> <td>{{ invoice.Contractor_Name }}</td>
<td>{{ invoice.PMC_No }}</td> <td>{{ invoice.PMC_No }}</td>
@@ -217,62 +363,77 @@
<td>{{ invoice.GST_SD_Amount }}</td> <td>{{ invoice.GST_SD_Amount }}</td>
<td>{{ invoice.Final_Amount }}</td> <td>{{ invoice.Final_Amount }}</td>
<td> <td>
<!-- Edit --> <!-- Edit -->
<a href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"> <a
<img src="{{ url_for('static', filename='images/icons/pen_blue_icon.png') }}" alt="Edit" class="icon"> href="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}"
</a> >
<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>
<td> <td>
<!-- Delete --> <a
<a href="{{ url_for('invoice.delete_invoice_route', invoice_id=invoice.Invoice_Id) }}" onclick="return confirm('Are you sure?')"> href="javascript:void(0);"
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" class="icon"> onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
</a> >
<img
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
alt="Delete"
class="icon"
/>
</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %} {% else %}
<p>No invoices found.</p> <p>No invoices found.</p>
{% endif %} {% endif %}
</div> </div>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
// Get all the input fields // Get all the input fields
const basicAmount = document.getElementById('basic_amount'); const basicAmount = document.getElementById("basic_amount");
const debitAmount = document.getElementById('debit_amount'); const debitAmount = document.getElementById("debit_amount");
const afterDebitAmount = document.getElementById('after_debit_amount'); const afterDebitAmount = document.getElementById("after_debit_amount");
const amount = document.getElementById('amount'); const amount = document.getElementById("amount");
// Percentage fields // Percentage fields
const gstPercentage = document.getElementById('gst_percentage'); const gstPercentage = document.getElementById("gst_percentage");
const gstAmount = document.getElementById('gst_amount'); const gstAmount = document.getElementById("gst_amount");
const tdsPercentage = document.getElementById('tds_percentage'); const tdsPercentage = document.getElementById("tds_percentage");
const tdsAmount = document.getElementById('tds_amount'); const tdsAmount = document.getElementById("tds_amount");
const sdPercentage = document.getElementById('sd_percentage'); const sdPercentage = document.getElementById("sd_percentage");
const sdAmountInput = document.getElementById('sd_amount'); const sdAmountInput = document.getElementById("sd_amount");
const commissionPercentage = document.getElementById('commission_percentage'); const commissionPercentage = document.getElementById(
const onCommission = document.getElementById('on_commission'); "commission_percentage",
const hydroPercentage = document.getElementById('hydro_percentage'); );
const hydroTesting = document.getElementById('hydro_testing'); const onCommission = document.getElementById("on_commission");
const gstSdAmount = document.getElementById('gst_sd_amount'); const hydroPercentage = document.getElementById("hydro_percentage");
const finalAmount = document.getElementById('final_amount'); const hydroTesting = document.getElementById("hydro_testing");
const gstSdAmount = document.getElementById("gst_sd_amount");
const finalAmount = document.getElementById("final_amount");
// Calculate after debit amount when basic or debit amount changes // Calculate after debit amount when basic or debit amount changes
function calculateAfterDebitAmount() { function calculateAfterDebitAmount() {
const basic = parseFloat(basicAmount.value) || 0; const basic = parseFloat(basicAmount.value) || 0;
const debit = parseFloat(debitAmount.value) || 0; const debit = parseFloat(debitAmount.value) || 0;
const afterDebit = basic - debit; const afterDebit = basic - debit;
afterDebitAmount.value = afterDebit.toFixed(2); afterDebitAmount.value = afterDebit.toFixed(2);
calculateGST(); calculateGST();
} }
// Calculate GST and Amount // Calculate GST and Amount
function calculateGST() { function calculateGST() {
const baseAmount = parseFloat(afterDebitAmount.value) || 0; const baseAmount = parseFloat(afterDebitAmount.value) || 0;
if (gstPercentage.value) { if (gstPercentage.value) {
const gstPerc = parseFloat(gstPercentage.value) || 0; const gstPerc = parseFloat(gstPercentage.value) || 0;
const gstAmt = (baseAmount * gstPerc) / 100; const gstAmt = (baseAmount * gstPerc) / 100;
gstAmount.value = gstAmt.toFixed(2); gstAmount.value = gstAmt.toFixed(2);
@@ -280,91 +441,96 @@ document.addEventListener('DOMContentLoaded', function() {
// Calculate Amount (After Debit + GST) // Calculate Amount (After Debit + GST)
amount.value = (baseAmount + gstAmt).toFixed(2); amount.value = (baseAmount + gstAmt).toFixed(2);
} else { } else {
amount.value = baseAmount.toFixed(2); 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) // Calculate TDS
function calculateOtherDeductions() { if (tdsPercentage.value) {
const baseAmount = parseFloat(afterDebitAmount.value) || 0;
// Calculate TDS
if (tdsPercentage.value) {
const tdsPerc = parseFloat(tdsPercentage.value) || 0; const tdsPerc = parseFloat(tdsPercentage.value) || 0;
const tdsAmt = (baseAmount * tdsPerc) / 100; const tdsAmt = (baseAmount * tdsPerc) / 100;
tdsAmount.value = tdsAmt.toFixed(2); tdsAmount.value = tdsAmt.toFixed(2);
} }
// Calculate SD // Calculate SD
if (sdPercentage.value) { if (sdPercentage.value) {
const sdPerc = parseFloat(sdPercentage.value) || 0; const sdPerc = parseFloat(sdPercentage.value) || 0;
const sdAmt = (baseAmount * sdPerc) / 100; const sdAmt = (baseAmount * sdPerc) / 100;
sdAmountInput.value = sdAmt.toFixed(2); sdAmountInput.value = sdAmt.toFixed(2);
} }
// Calculate Commission // Calculate Commission
if (commissionPercentage.value) { if (commissionPercentage.value) {
const commPerc = parseFloat(commissionPercentage.value) || 0; const commPerc = parseFloat(commissionPercentage.value) || 0;
const commAmt = (baseAmount * commPerc) / 100; const commAmt = (baseAmount * commPerc) / 100;
onCommission.value = commAmt.toFixed(2); onCommission.value = commAmt.toFixed(2);
} }
// Calculate Hydro Testing // Calculate Hydro Testing
if (hydroPercentage.value) { if (hydroPercentage.value) {
const hydroPerc = parseFloat(hydroPercentage.value) || 0; const hydroPerc = parseFloat(hydroPercentage.value) || 0;
const hydroAmt = (baseAmount * hydroPerc) / 100; const hydroAmt = (baseAmount * hydroPerc) / 100;
hydroTesting.value = hydroAmt.toFixed(2); 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 // Get hold amounts
function calculateFinalAmount() { let totalHold = 0;
const amt = parseFloat(amount.value) || 0; document
const tds = parseFloat(tdsAmount.value) || 0; .querySelectorAll('input[name="hold_amount[]"]')
const sd = parseFloat(sdAmountInput.value) || 0; .forEach((input) => {
const commission = parseFloat(onCommission.value) || 0; totalHold += parseFloat(input.value) || 0;
const hydro = parseFloat(hydroTesting.value) || 0; });
const gstSd = parseFloat(gstSdAmount.value) || 0;
// Get hold amounts // Final Amount = Amount - TDS - SD - Commission - Hydro - GST SD - Hold Amounts
let totalHold = 0; const final = amt - tds - sd - commission - hydro - gstSd - totalHold;
document.querySelectorAll('input[name="hold_amount[]"]').forEach(input => { finalAmount.value = final.toFixed(2);
totalHold += parseFloat(input.value) || 0; }
});
// Final Amount = Amount - TDS - SD - Commission - Hydro - GST SD - Hold Amounts // Add event listeners
const final = amt - tds - sd - commission - hydro - gstSd - totalHold; basicAmount.addEventListener("input", calculateAfterDebitAmount);
finalAmount.value = final.toFixed(2); debitAmount.addEventListener("input", calculateAfterDebitAmount);
}
// Add event listeners // Percentage fields
basicAmount.addEventListener('input', calculateAfterDebitAmount); gstPercentage.addEventListener("input", calculateGST);
debitAmount.addEventListener('input', calculateAfterDebitAmount); tdsPercentage.addEventListener("input", calculateOtherDeductions);
sdPercentage.addEventListener("input", calculateOtherDeductions);
commissionPercentage.addEventListener(
"input",
calculateOtherDeductions,
);
hydroPercentage.addEventListener("input", calculateOtherDeductions);
// Percentage fields // Listen for changes in hold amounts
gstPercentage.addEventListener('input', calculateGST); document.addEventListener("holdAmountChanged", calculateFinalAmount);
tdsPercentage.addEventListener('input', calculateOtherDeductions); });
sdPercentage.addEventListener('input', calculateOtherDeductions);
commissionPercentage.addEventListener('input', calculateOtherDeductions);
hydroPercentage.addEventListener('input', calculateOtherDeductions);
// Listen for changes in hold amounts // Optional JS for auto-hiding flash
document.addEventListener('holdAmountChanged', calculateFinalAmount); setTimeout(() => {
}); document
.querySelectorAll(".alert")
// Optional JS for auto-hiding flash .forEach((el) => (el.style.display = "none"));
setTimeout(() => { }, 5000);
document.querySelectorAll('.alert').forEach(el => el.style.display = 'none'); </script>
}, 5000); </div>
</script>
</div>
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -1,5 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -8,91 +9,104 @@
<script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script> <script src="{{ url_for('static', filename='js/search_on_table.js') }}"></script>
<script src="{{ url_for('static', filename='js/invoice.js') }}"></script> <script src="{{ url_for('static', filename='js/invoice.js') }}"></script>
</head> </head>
<body> <body>
<div class="button-container"> <div class="button-container">
<button id="addButton" class="action-button">Add</button> <button id="addButton" class="action-button">Add</button>
<button id="displayButton" class="action-button">Display</button> <button id="displayButton" class="action-button">Display</button>
</div>
<div 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>&#10004;</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> </div>
<table id="sortableTable" border="1">
<thead> <div id="addForm" style="display: none;">
<tr> <h2>Add Payment</h2>
<th class="sortable-header">Payment ID</th>
<th class="sortable-header">PMC No</th> <form action="/add_payment" method="POST" onsubmit="showSuccessAlert(event)">
<th>Invoice No</th> <div class="row1">
<th>Payment Amount</th> <div>
<th>TDS Amount</th> <label for="subcontractor">Subcontractor Name:</label>
<th>Total Amount</th> <input type="text" id="subcontractor" name="subcontractor" required autocomplete="off" />
<th>UTR</th> <input type="hidden" id="subcontractor_id" name="subcontractor_id" />
<th>Update</th> <div id="subcontractor_list" class="autocomplete-items"></div>
<th>Delete</th> </div>
</tr> </div>
</thead>
<tbody> <label for="PMC_No">PMC No:</label><br>
{% for payment in payments %} <select id="PMC_No" name="PMC_No" required>
<tr> <option value="">Select PMC No</option>
<td>{{ payment[0] }}</td> </select><br><br>
<td>{{ payment[1] }}</td>
<td>{{ payment[2] }}</td> <label for="invoice_No">Invoice No:</label><br>
<td>{{ payment[3] }}</td> <input type="number" step="0.01" id="invoice_No" name="invoice_No"><br><br>
<td>{{ payment[4] }}</td>
<td>{{ payment[5] }}</td> <label for="Payment_Amount">Amount:</label><br>
<td>{{ payment[6] }}</td> <input type="number" step="0.01" id="Payment_Amount" name="Payment_Amount" required
<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> oninput="calculateTDSAndTotal()"><br><br>
<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> <label for="TDS_Percentage">TDS Percentage (%):</label><br>
<!-- <tr> <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>&#10004;</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['Payment_Id'] }}</td>
<td>{{ payment['PMC_No'] }}</td> <td>{{ payment['PMC_No'] }}</td>
<td>{{ payment['invoice_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="/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> <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> --> </tr> -->
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
<script> <script>
document.getElementById("subcontractor").addEventListener("input", function () { document.getElementById("subcontractor").addEventListener("input", function () {
const query = this.value; const query = this.value;
const list = document.getElementById("subcontractor_list"); const list = document.getElementById("subcontractor_list");
if (query.length < 2) { if (query.length < 2) {
list.innerHTML = ''; list.innerHTML = '';
return; return;
} }
fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`) fetch(`/search_subcontractor?query=${encodeURIComponent(query)}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
list.innerHTML = ''; list.innerHTML = '';
data.results.forEach(item => { data.results.forEach(item => {
const div = document.createElement("div"); const div = document.createElement("div");
div.setAttribute("data-id", item.id); div.setAttribute("data-id", item.id);
div.textContent = item.name; div.textContent = item.name;
list.appendChild(div); 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);
}); });
});
if (data.pmc_nos.length === 0) { document.getElementById("subcontractor_list").addEventListener("click", function (e) {
alert("No PMC Nos found for this subcontractor."); const selectedId = e.target.getAttribute("data-id");
} const selectedName = e.target.textContent;
})
.catch(error => {
console.error("Error fetching PMC Nos:", error);
alert("Failed to fetch PMC numbers.");
});
}
});
</script>
<script> if (selectedId) {
function calculateTDSAndTotal() { document.getElementById("subcontractor_id").value = selectedId;
const amount = parseFloat(document.getElementById("Payment_Amount").value) || 0; document.getElementById("subcontractor").value = selectedName;
const tdsPercent = parseFloat(document.getElementById("TDS_Percentage").value) || 0; document.getElementById("subcontractor_list").innerHTML = ""; // hide the list
const tdsAmount = (amount * tdsPercent / 100).toFixed(2); console.log("Contractor id is", selectedId);
const totalAmount = (amount - tdsAmount).toFixed(2);
document.getElementById("TDS_Payment_Amount").value = tdsAmount; // Fetch PMC numbers
document.getElementById("total_amount").value = totalAmount; fetch(`/get_pmc_nos_by_subcontractor/${encodeURIComponent(selectedId)}`)
} .then(response => response.json())
</script> .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> </body>
{% endblock %} {% endblock %}

View File

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

View File

@@ -9,37 +9,37 @@
<body> <body>
<h2>Edit GST Release</h2> <h2>Edit GST Release</h2>
<form action="/edit_gst_release/{{ gst_release_data[0] }}" method="POST"> <form action="/edit_gst_release/{{ gst_release_data.gst_release_id }}" method="POST">
<!-- <label for="invoice_id">Invoice Id:</label><br>-->
<!-- <input type="number" id="invoice_id" name="invoice_id" value="{{ gst_release_data[0] }}" required><br><br>-->
<!-- PMC Number -->
<label for="PMC_No">PMC No :</label><br> <label for="PMC_No">PMC No :</label><br>
<input type="number" id="PMC_No" name="PMC_No" value="{{ gst_release_data[1] }}" required><br><br> <input type="text" id="PMC_No" name="PMC_No" value="{{ gst_release_data.pmc_no }}" required><br><br>
<label for="invoice_No">Invoice No:</label><br> <!-- Invoice Number -->
<input type="number" step="0.01" id="invoice_No" name="invoice_No" value="{{ gst_release_data[2] }}" <label for="invoice_no">Invoice No:</label><br>
required><br><br> <input type="text" id="invoice_no" name="invoice_no" value="{{ gst_release_data.invoice_no }}" required><br><br>
<!-- Basic Amount -->
<label for="Basic_Amount">Basic Amount:</label><br>
<input type="number" step="0.01" id="Basic_Amount" name="Basic_Amount" value="{{ gst_release_data.basic_amount }}" required><br><br>
<label for="basic_amount">Basic Amount:</label><br> <!-- Final Amount -->
<input type="number" step="0.01" id="basic_amount" name="basic_amount" value="{{ gst_release_data[3] }}" <label for="Final_Amount">Final Amount:</label><br>
required><br><br> <input type="number" step="0.01" id="Final_Amount" name="Final_Amount" value="{{ gst_release_data.final_amount }}" required><br><br>
<label for="final_amount">Final Amount:</label><br> <!-- Total Amount -->
<input type="number" step="0.01" id="final_amount" name="final_amount" value="{{ gst_release_data[4] }}" <label for="Total_Amount">Total Amount:</label><br>
required><br><br> <input type="number" step="0.01" id="Total_Amount" name="Total_Amount" value="{{ gst_release_data.total_amount }}" required><br><br>
<label for="total_amount">Total Amount:</label><br> <!-- UTR -->
<input type="number" step="0.01" id="total_amount" name="total_amount" value="{{ gst_release_data[5] }}" <label for="UTR">UTR:</label><br>
required><br><br> <input type="text" id="UTR" name="UTR" value="{{ gst_release_data.utr }}" readonly required><br><br>
<label for="utr">UTR:</label><br> <!-- Hidden Contractor ID -->
<input type="text" id="utr" name="utr" value="{{ gst_release_data[6] }}" <input type="hidden" id="Contractor_ID" name="Contractor_ID" value="{{ gst_release_data.contractor_id }}">
required readonly><br><br>
<button type="submit">Update GST Release</button> <button type="submit">Update GST Release</button>
</form> </form>
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<title>Edit Hold Type</title> <title>Edit Hold Type</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
@@ -10,10 +10,10 @@
<body> <body>
<h2>Edit Hold Type</h2> <h2>Edit Hold Type</h2>
<form id="updateHoldTypeForm"> <form id="updateHoldTypeForm" method="POST">
<input type="hidden" id="hold_type_id" value="{{ hold_type[0] }}"> <input type="hidden" id="hold_type_id" value="{{ hold_type.hold_type_id }}">
<label for="edit_hold_type">Hold Type:</label> <label for="edit_hold_type">Hold Type:</label>
<input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type[1] }}" required> <input type="text" id="edit_hold_type" name="hold_type" value="{{ hold_type.hold_type }}" required>
<button type="submit">Update</button> <button type="submit">Update</button>
<a href="{{ url_for('hold_types.add_hold_type') }}"></a> <a href="{{ url_for('hold_types.add_hold_type') }}"></a>
</form> </form>
@@ -37,7 +37,7 @@
formData.append('hold_type', newHoldType); formData.append('hold_type', newHoldType);
$.ajax({ $.ajax({
url: '/update_hold_type/' + holdTypeId, url: '/edit_hold_type/' + holdTypeId,
method: 'POST', method: 'POST',
data: formData, data: formData,
processData: false, processData: false,
@@ -54,9 +54,4 @@
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}

View File

@@ -2,168 +2,185 @@
{% block content %} {% block content %}
<head> <head>
<meta charset="UTF-8"/> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Edit Invoice</title> <title>Edit Invoice</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/invoice.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style1.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style1.css') }}">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head> </head>
<body> <body>
<div id="editForm"> <div id="editForm">
<h2>Edit Invoice</h2> <h2>Edit Invoice</h2>
<!-- Success Alert Box --> <!-- Success Alert Box -->
<div id="invoiceSuccessAlert" class="success-alert" style="display:none;"> <div id="invoiceSuccessAlert" class="success-alert" style="display:none;">
Invoice successfully updated! 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> </div>
<form id="invoiceForm" action="{{ url_for('invoice.edit_invoice', invoice_id=invoice.Invoice_Id) }}" method="POST"> <!-- JS for dynamic hold amount rows -->
<script>
<!-- Subcontractor Field --> $(document).ready(function () {
<div class="row1"> // Add new hold amount row
<div> $("#add_hold_amount").click(function () {
<label for="subcontractor">Subcontractor Name:</label> const index = $("#hold_amount_container .hold-amount-row").length;
<input class="form-control" list="subcontractor_list" id="subcontractor" name="subcontractor" const newRow = `
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 = `
<div class="hold-amount-row"> <div class="hold-amount-row">
<label for="hold_type_${index}">Hold Type:</label> <label for="hold_type_${index}">Hold Type:</label>
<input type="text" id="hold_type_${index}" name="hold_type[]" required/> <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> <button type="button" class="remove-hold-amount">Remove</button>
</div> </div>
`; `;
$("#hold_amount_container").append(newRow); $("#hold_amount_container").append(newRow);
}); });
// Remove hold amount row // Remove hold amount row
$(document).on("click", ".remove-hold-amount", function() { $(document).on("click", ".remove-hold-amount", function () {
$(this).closest(".hold-amount-row").remove(); $(this).closest(".hold-amount-row").remove();
}); });
// Submit form via AJAX // Submit form via AJAX
$("#invoiceForm").submit(function(e) { $("#invoiceForm").submit(function (e) {
e.preventDefault(); e.preventDefault();
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: $(this).attr("action"), url: $(this).attr("action"),
data: $(this).serialize(), data: $(this).serialize(),
success: function(response) { dataType: 'json', // ensure JSON is returned
if(response.status === "success") { success: function (response) {
$("#invoiceSuccessAlert").fadeIn().delay(3000).fadeOut(); if (response.status === "success") {
alert("Invoice updated successfully!"); // <-- Popup alert alert("Invoice updated successfully!"); // <-- Popup alert
}
}, // ✅ Redirect to Add Invoice page (table part visible)
error: function(xhr) { window.location.href = "{{ url_for('invoice.add_invoice') }}#addTable";
alert("Error: " + xhr.responseJSON.message); }
} },
error: function (xhr) {
alert("Error: " + xhr.responseJSON?.message || "Something went wrong!");
}
});
});
}); });
}); </script>
});
</script>
</body> </body>
{% endblock %} {% endblock %}

View File

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

View File

@@ -34,7 +34,7 @@
<a href="/logout">Logout</a> <a href="/logout">Logout</a>
</div> </div>
<div class="sidebar"> <div class="sidebar">
<img src="https://lceplpmprod.btltech.xyz/assets/images/lcpl.png" alt="logo-image" class="logo"> <img src="http://lceplpmprod.btltech.xyz/assets/images/lcpl.png" alt="logo-image" class="logo">
<ul class="nav-menu"> <ul class="nav-menu">
<li class="nav-item"> <li class="nav-item">
@@ -136,7 +136,7 @@
<div class="card"> <div class="card">
<h2>Work Order</h2> <h2>Work Order</h2>
<!-- <a class="btn" href="/add_work_order">Go ➜</a> --> <!-- <a class="btn" href="/add_work_order">Go ➜</a> -->
<a class="btn">Go ➜</a> <a class="btn">Go ➜</a>
</div> </div>
<!-- <div class="card"> <!-- <div class="card">
<h2>Purchase Order</h2> <h2>Purchase Order</h2>

View File

@@ -1,7 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -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/style.css') }}">-->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h2>PMC Report</h2> <h2>PMC Report</h2>
<div class="info"> <div class="info">
<h2>Contractor Details</h2> <h2>Contractor Details</h2>
<div class="row2"> <div class="row2">
<div> <div>
<label for="subcontractor">Subcontractor Name:</label> <label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" value="{{ info.Contractor_Name }}" <input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}"
readonly/> readonly />
</div>
<div>
<label for="Address">Address :</label>
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea>
</div>
</div> </div>
<div> <div class="row3">
<label for="Address">Address :</label> <div>
<textarea id="Address" name="Address" readonly>{{ info.Address }}</textarea> <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> <div class="row2">
<div class="row3"> <div>
<div> <label for="GST_Registration_Type">GST Registration Type :</label>
<label for="PAN_No">PAN No :</label> <input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
<input type="text" id="PAN_No" name="PAN_No" value="{{ info.PAN_No }}" readonly/> value="{{ contInfo.GST_Registration_Type }}" 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>
<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>
<div> <h2>PMC Report for PMC No: {{ contInfo.PMC_No}}</h2>
<label for="GST_No">GST No:</label> <div class="row3">
<input type="text" id="GST_No" name="GST_No" value="{{ info.GST_No }}" readonly/> <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> <div class="row2">
<h2>PMC Report for PMC No: {{ info.PMC_No}}</h2> <div>
<div class="row3"> <label for="PMC_No">PMC No:</label>
<div> <input type="text" id="PMC_No" name="PMC_No" value="{{ contInfo.PMC_No }}" readonly />
<label for="State">State :</label> </div>
<input type="text" id="State" name="State" value="{{ info.State_Name }}" readonly/> <div>
</div> <label for="Village_Name">Village Name :</label>
<div> <input type="text" id="Village_Name" name="Village_Name"
<label for="District">District :</label> value="{{ contInfo.Village_Name.capitalize() }}" readonly />
<input type="text" id="District" name="District" value="{{ info.District_Name }}" readonly/> </div>
</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> </div>
</div> </div>
</div> </div>
</div>
<h3>Invoice Details</h3> <h3>Invoice Details</h3>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>PMC No</th> <th>PMC No</th>
<th>Village Name</th> <th>Village Name</th>
<th>Work Type</th> <th>Work Type</th>
<th>Invoice Details</th> <th>Invoice Details</th>
<th>Invoice Date</th> <th>Invoice Date</th>
<th>Invoice No</th> <th>Invoice No</th>
<th>Basic Amount</th> <th>Basic Amount</th>
<th>Debit</th> <th>Debit</th>
<th>After Debit Amt</th> <th>After Debit Amt</th>
<th>GST (18%)</th> <th>GST (18%)</th>
<th>Amount</th> <th>Amount</th>
<th>TDS (1%)</th> <th>TDS (1%)</th>
<th>SD (5%)</th> <th>SD (5%)</th>
<th>On Commission</th> <th>On Commission</th>
<th>Hydro Testing</th> <th>Hydro Testing</th>
<!-- Dynamic Hold Types --> <!-- Dynamic Hold Types -->
{% set hold_types = invoices | map(attribute='hold_type') | reject('none') | unique | list %} {% set hold_types = invoices | map(attribute='hold_type') | reject('none') | unique | list %}
{% for hold in hold_types %} {% for hold in hold_types %}
<th>{{ hold }}</th> <th>{{ hold }}</th>
{% endfor %} {% endfor %}
<th>GST SD (18%)</th> <th>GST SD (18%)</th>
<th>Final Amount</th> <th>Final Amount</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% if invoices %} {% if invoices %}
{% for invoice in invoices %} {% for invoice in invoices %}
<tr> <tr>
<td>{{ invoice.PMC_No }}</td> <td>{{ invoice.PMC_No }}</td>
<td>{{ invoice.Village_Name.capitalize() }}</td> <td>{{ invoice.Village_Name.capitalize() if invoice.Village_Name else '' }}</td>
<td>{{ invoice.Work_Type }}</td> <td>{{ invoice.Work_Type }}</td>
<td>{{ invoice.Invoice_Details }}</td> <td>{{ invoice.Invoice_Details }}</td>
<td>{{ invoice.Invoice_Date }}</td> <td>{{ invoice.Invoice_Date }}</td>
<td>{{ invoice.Invoice_No }}</td> <td>{{ invoice.invoice_no }}</td>
<td>{{ invoice.Basic_Amount }}</td> <td>{{ invoice.Basic_Amount }}</td>
<td>{{ invoice.Debit_Amount }}</td> <td>{{ invoice.Debit_Amount }}</td>
<td>{{ invoice.After_Debit_Amount }}</td> <td>{{ invoice.After_Debit_Amount }}</td>
<td>{{ invoice.GST_Amount }}</td> <td>{{ invoice.GST_Amount }}</td>
<td>{{ invoice.Amount }}</td> <td>{{ invoice.Amount }}</td>
<td>{{ invoice.TDS_Amount }}</td> <td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td> <td>{{ invoice.SD_Amount }}</td>
<td>{{ invoice.On_Commission }}</td> <td>{{ invoice.On_Commission }}</td>
<td>{{ invoice.Hydro_Testing }}</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 %} {% else %}
0 <tr>
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
</tr>
{% endif %} {% endif %}
</td> </tbody>
{% endfor %} </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> <br>
<td>{{ invoice.Final_Amount }}</td> <h3>GST Release Note Details</h3>
</tr> <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 %} <th>{{total["sum_gst_basic_amt"]}}</th>
<tr> <th>{{total["sum_gst_final_amt"]}}</th>
<th colspan="6">Total</th> </tr>
<th>{{total["sum_invo_basic_amt"]}}</th> {% else %}
<th>{{total["sum_invo_debit_amt"]}}</th> <tr>
<th>{{total["sum_invo_after_debit_amt"]}}</th> <td colspan="4">No GST release found.</td>
<th>{{total["sum_invo_gst_amt"]}}</th> </tr>
<th>{{total["sum_invo_amt"]}}</th> {% endif %}
<th>{{total["sum_invo_tds_amt"]}}</th> </tbody>
<th>{{total["sum_invo_ds_amt"]}}</th> </table>
<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>
{% else %}
<tr> <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> <h3>Credit Details</h3>
</tr> </tr>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>PMC No</th> <th>PMC No</th>
<th>Invoice Details</th> <th>Invoice Details</th>
<th>Basic Amount</th> <th>Basic Amount</th>
<th>Debit</th> <th>Debit</th>
<th>After Debit Amt</th> <th>After Debit Amt</th>
<th>GST Amount</th> <th>GST Amount</th>
<th>Amount</th> <th>Amount</th>
<th>Final Amount</th> <th>Final Amount</th>
<th>Payment Amount</th> <th>Payment Amount</th>
<th>Total Amount</th> <th>Total Amount</th>
<th>UTR</th> <th>UTR</th>
</tr> </tr>
{% if credit_note %} {% if credit_note %}
{% for credit in credit_note %} {% for credit in credit_note %}
<tr> <tr>
<td>{{ credit["PMC_No"] }}</td> <td>{{ credit["PMC_No"] }}</td>
<td>{{ credit["Invoice_Details"] }}</td> <td>{{ credit["Invoice_Details"] }}</td>
<td>{{ credit["Basic_Amount"] }}</td> <td>{{ credit["Basic_Amount"] }}</td>
<td>{{ credit["Debit_Amount"] }}</td> <td>{{ credit["Debit_Amount"] }}</td>
<td>{{ credit["After_Debit_Amount"] }}</td> <td>{{ credit["After_Debit_Amount"] }}</td>
<td>{{ credit["GST_Amount"] }}</td> <td>{{ credit["GST_Amount"] }}</td>
<td>{{ credit["Amount"] }}</td> <td>{{ credit["Amount"] }}</td>
<td>{{ credit["Final_Amount"] }}</td> <td>{{ credit["Final_Amount"] }}</td>
<td>{{ credit["Payment_Amount"] }}</td> <td>{{ credit["Payment_Amount"] }}</td>
<td>{{ credit["Total_Amount"] }}</td> <td>{{ credit["Total_Amount"] }}</td>
<td>{{ credit["UTR"] }}</td> <td>{{ credit["UTR"] }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
{% else %} {% else %}
<tr> <tr>
<td colspan="11">No Credit note found.</td> <td colspan="11">No Credit note found.</td>
</tr> </tr>
{% endif %} {% endif %}
</thead> </thead>
</table> </table>
<br> <br>
<h3>Payment Details</h3> <h3>Payment Details</h3>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>PMC No</th> <th>PMC No</th>
<th>Invoice No</th> <th>Invoice No</th>
<th>Amount</th> <th>Amount</th>
<th>TDS Amount @ 1% on BASIC AMOUNT</th> <th>TDS Amount @ 1% on BASIC AMOUNT</th>
<th>Total Amount Paid</th> <th>Total Amount Paid</th>
<th>UTR</th> <th>UTR</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% if payments %} {% if invoices %}
{% for pay in payments %} {% for pay in invoices %}
<tr> <tr>
<td>{{ pay.pmc_no }}</td> <td>{{ pay.PMC_No }}</td>
<td>{{ pay.invoice_no }}</td> <td>{{ pay.invoice_no }}</td>
<td>{{ pay.Payment_Amount }}</td> <td>{{ pay.Payment_Amount }}</td>
<td>{{ pay.TDS_Payment_Amount }}</td> <td>{{ pay.TDS_Payment_Amount }}</td>
<td>{{ pay.Total_amount }}</td> <td>{{ pay.Total_Amount }}</td>
<td>{{ pay.utr}}</td> <td>{{ pay.UTR}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr> <tr>
<th colspan="2">Total</th> <th colspan="2">Total</th>
<th>{{total["sum_pay_payment_amt"]}}</th> <th>{{total["sum_pay_payment_amt"]}}</th>
<th>{{total["sum_pay_tds_payment_amt"]}}</th> <th>{{total["sum_pay_tds_payment_amt"]}}</th>
<th>{{total["sum_pay_total_amt"]}}</th> <th>{{total["sum_pay_total_amt"]}}</th>
<th></th> <th></th>
</tr> </tr>
{% else %} {% else %}
<tr> <tr>
<td colspan="6">No payment found.</td> <td colspan="6">No payment found.</td>
</tr> </tr>
{% endif %} {% endif %}
</tbody> </tbody>
</table> </table>
<a href="/download_pmc_report/{{ info.PMC_No}}"> <a href="/download_pmc_report/{{ contInfo.PMC_No}}">
<button class="download-btn">Download PMC Report</button> <button class="download-btn">Download PMC Report</button>
</a> </a>
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -1,5 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -7,102 +8,104 @@
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/report.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/report.css') }}">
<script src="{{ url_for('static', filename='js/searchContractor.js') }}"></script> <script src="{{ url_for('static', filename='js/searchContractor.js') }}"></script>
</head> </head>
<body> <body>
<div id="report" class="page"> <div id="report" class="page">
<h2>Search Contractor Report</h2> <h2>Search Contractor Report</h2>
<div> <div>
<form id="search-form"> <form id="search-form">
<div class="row2"> <div class="row2">
<div> <div>
<label for="subcontractor_name">Subcontractor Name:</label> <label for="subcontractor_name">Subcontractor Name:</label>
<input type="text" id="subcontractor_name" name="subcontractor_name"> <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>
<div> <div class="row2">
<label for="pmc_no">PMC No:</label> <div>
<input type="text" id="pmc_no" name="pmc_no"> <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> <div class="row2">
<div class="row2"> <div>
<div> <label for="block">Block:</label>
<label for="state">State:</label> <input type="text" id="block" name="block">
<input type="text" id="state" name="state"> </div>
<div>
<label for="village">Village:</label>
<input type="text" id="village" name="village">
</div>
</div> </div>
<div> <div class="row2">
<label for="district">District:</label> <div>
<input type="text" id="district" name="district"> <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> <button type="button" onclick="fetchData()">Search</button>
<div class="row2"> </form>
<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>
<h2>Contractor List</h2> <h2>Contractor List</h2>
<table border="1" id="result-table"> <table border="1" id="result-table">
<thead> <thead>
<tr> <tr>
<th class="sortable">Contractor Name <th class="sortable">Contractor Name
<select> <select>
<option value="">🔽</option> <option value="">🔽</option>
<option value="asc">Ascending</option> <option value="asc">Ascending</option>
<option value="desc">Descending</option> <option value="desc">Descending</option>
</select> </select>
</th> </th>
<th>PMC No</th> <th>PMC No</th>
<th class="sortable">State <th class="sortable">State
<select> <select>
<option value="">🔽</option> <option value="">🔽</option>
<option value="asc">Ascending</option> <option value="asc">Ascending</option>
<option value="desc">Descending</option> <option value="desc">Descending</option>
</select> </select>
</th> </th>
<th class="sortable">District <th class="sortable">District
<select> <select>
<option value="">🔽</option> <option value="">🔽</option>
<option value="asc">Ascending</option> <option value="asc">Ascending</option>
<option value="desc">Descending</option> <option value="desc">Descending</option>
</select> </select>
</th> </th>
<th class="sortable">Block <th class="sortable">Block
<select> <select>
<option value="">🔽</option> <option value="">🔽</option>
<option value="asc">Ascending</option> <option value="asc">Ascending</option>
<option value="desc">Descending</option> <option value="desc">Descending</option>
</select> </select>
</th> </th>
<th class="sortable">Village <th class="sortable">Village
<select> <select>
<option value="">🔽</option> <option value="">🔽</option>
<option value="asc">Ascending</option> <option value="asc">Ascending</option>
<option value="desc">Descending</option> <option value="desc">Descending</option>
</select> </select>
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<!-- Results will be dynamically populated --> <!-- Results will be dynamically populated -->
</tbody> </tbody>
</table> </table>
</div>
</div> </div>
</div>
</body> </body>
{% endblock %} {% endblock %}

View File

@@ -58,8 +58,9 @@
<!-- Hidden fields for other necessary information --> <!-- Hidden fields for other necessary information -->
<input type="text" name="subcontractor_data" value="{{ subcontractor_data['Contractor_Id'] }}"> <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="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="district_data" value="{{ district_data['District_id'] }}">
<input type="text" name="block_data" value="{{ block_data['Block_Id'] }}"> <input type="text" name="block_data" value="{{ block_data['Block_Id'] }}">
<input type="text" name="file_info" value="{{ file_info }}"> <input type="text" name="file_info" value="{{ file_info }}">

View File

@@ -1,8 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% block content %}
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -10,363 +8,345 @@
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">--> <!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">-->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}"> <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}">
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h2>Contractor Report</h2> <h2>Contractor Report</h2>
<div class="info"> <div class="info">
<h2>Contractor Details</h2> <h2>Contractor Details</h2>
<div class="row2"> <div class="row2">
<div> <div>
<label for="subcontractor">Subcontractor Name:</label> <label for="subcontractor">Subcontractor Name:</label>
<input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}" <input type="text" id="subcontractor" name="subcontractor" value="{{ contInfo.Contractor_Name }}"
readonly/> readonly />
</div>
<div>
<label for="Address">Address :</label>
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea>
</div>
</div> </div>
<div> <div class="row3">
<label for="Address">Address :</label> <div>
<textarea id="Address" name="Address" readonly>{{ contInfo.Address }}</textarea> <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> <div class="row2">
<div class="row3"> <div>
<div> <label for="GST_Registration_Type">GST Registration Type :</label>
<label for="PAN_No">PAN No :</label> <input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
<input type="text" id="PAN_No" name="PAN_No" value="{{ contInfo.PAN_No }}" readonly/> value="{{ contInfo.GST_Registration_Type }}" 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>
<div> <div class="row3">
<label for="GST_No">GST No:</label> <div>
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly/> <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> </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"> <!-- {% if hold_types %}
<tr> <h3>Hold Types</h3>
<th colspan="2">{{current_date}}</th> <ul>
</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 %} {% for hold in hold_types %}
<th>{{ hold.hold_type }}</th> <li>{{ hold.hold_type }}</li>
<td>{{total["sum_invo_hold_amt"]}}</td>
{% endfor %} {% endfor %}
</tr> </ul>
{% endif %} {% 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> <h3>Invoice Details</h3>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>PMC No</th> <th>PMC No</th>
<th>Village Name</th> <th>Village Name</th>
<th>Work Type</th> <th>Work Type</th>
<th>Invoice Details</th> <th>Invoice Details</th>
<th>Invoice Date</th> <th>Invoice Date</th>
<th>Invoice No</th> <th>Invoice No</th>
<th>Basic Amount</th> <th>Basic Amount</th>
<th>Debit</th> <th>Debit</th>
<th>After Debit Amt</th> <th>After Debit Amt</th>
<th>GST (18%)</th> <th>GST (18%)</th>
<th>Amount</th> <th>Amount</th>
<th>TDS (1%)</th> <th>TDS (1%)</th>
<th>SD (5%)</th> <th>SD (5%)</th>
<th>On Commission</th> <th>On Commission</th>
<th>Hydro Testing</th> <th>Hydro Testing</th>
<!-- Dynamic Hold Types --> <!-- Dynamic Hold Types -->
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %} {% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %} {% for hold in hold_types %}
<th>{{ hold }}</th> <th>{{ hold }}</th>
{% endfor %} {% endfor %}
<th>GST SD (18%)</th> <th>GST SD (18%)</th>
<th>Final Amount</th> <th>Final Amount</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% if invoices %} {% if invoices %}
{% for invoice in invoices %} {% for invoice in invoices %}
<tr> <tr>
<td>{{ invoice.PMC_No }}</td> <td>{{ invoice.PMC_No }}</td>
<td>{{ invoice.Village_Name.capitalize() }}</td> <td>{{ invoice.Village_Name}}</td>
<td>{{ invoice.Work_Type }}</td> <td>{{ invoice.Work_Type }}</td>
<td>{{ invoice.Invoice_Details }}</td> <td>{{ invoice.Invoice_Details }}</td>
<td>{{ invoice.Invoice_Date }}</td> <td>{{ invoice.Invoice_Date }}</td>
<td>{{ invoice.Invoice_No }}</td> <td>{{ invoice.invoice_no }}</td>
<td>{{ invoice.Basic_Amount }}</td> <td>{{ invoice.Basic_Amount }}</td>
<td>{{ invoice.Debit_Amount }}</td> <td>{{ invoice.Debit_Amount }}</td>
<td>{{ invoice.After_Debit_Amount }}</td> <td>{{ invoice.After_Debit_Amount }}</td>
<td>{{ invoice.GST_Amount }}</td> <td>{{ invoice.GST_Amount }}</td>
<td>{{ invoice.Amount }}</td> <td>{{ invoice.Amount }}</td>
<td>{{ invoice.TDS_Amount }}</td> <td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td> <td>{{ invoice.SD_Amount }}</td>
<td>{{ invoice.On_Commission }}</td> <td>{{ invoice.On_Commission }}</td>
<td>{{ invoice.Hydro_Testing }}</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>
<td>hold.</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 %} {% else %}
0.00 <tr>
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
</tr>
{% endif %} {% endif %}
</td> </tbody>
{% endfor %} </table>
<td>{{ invoice.GST_SD_Amount }}</td> <h3>Hold Release</h3>
<td>{{ invoice.Final_Amount }}</td> <table>
</tr> <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> <tr>
<th colspan="6">Total</th> <h3>Credit Details</h3>
<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> </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>
<tr>
<td colspan="{{ 17 + hold_types|length }}">No invoices found.</td>
</tr>
{% endif %}
</tbody>
</table>
<h3>Hold Release</h3> {% if credit_note %}
<table> {% for credit in credit_note %}
<thead> <tr>
<tr> <td>{{ credit["PMC_No"] }}</td>
<th>PMC No</th> <td>{{ credit["Invoice_Details"] }}</td>
<th>Invoice No</th> <td>{{ credit["Basic_Amount"] }}</td>
<th>Invoice Details</th> <td>{{ credit["Debit_Amount"] }}</td>
<th>Basic Amount</th> <td>{{ credit["After_Debit_Amount"] }}</td>
<th>Total Amount</th> <td>{{ credit["GST_Amount"] }}</td>
<th>UTR</th> <td>{{ credit["Amount"] }}</td>
</tr> <td>{{ credit["Final_Amount"] }}</td>
</thead> <td>{{ credit["Payment_Amount"] }}</td>
<tbody> <td>{{ credit["Total_Amount"] }}</td>
{% if hold_release %} <td>{{ credit["UTR"] }}</td>
{% 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>
<tr> </tr>
<h3>Credit Details</h3> {% endfor %}
</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> {% else %}
<tr>
{% if credit_note %} <td colspan="11">No Credit note found.</td>
{% for credit in credit_note %} </tr>
<tr> {% endif %}
<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> </thead>
{% endfor %} </table>
{% else %} <h3>GST Release Note Details</h3>
<tr> <table>
<td colspan="11">No Credit note found.</td> <thead>
</tr> <tr>
{% endif %} <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> </thead>
</table> <tbody>
<h3>GST Release Note Details</h3> {% if gst_rel %}
<table> {% for gst in gst_rel %}
<thead> <tr>
<tr> <td>{{ gst.pmc_no }}</td>
<th>PMC No</th> <td>{{ gst.Invoice_No }}</td>
<th>Invoice No</th> <td>{{ gst.Basic_Amount }}</td>
<th>Basic Amount</th> <td>{{ gst.Final_Amount }}</td>
<th>Final Amount</th> <td>{{ gst.Total_Amount }}</td>
</tr> <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> <br>
<tbody> <h3>Payment Details</h3>
{% if gst_rel %} <table>
{% for gst in gst_rel %} <thead>
<tr> <tr>
<td>{{ gst.pmc_no }}</td> <th>PMC No</th>
<td>{{ gst.invoice_no }}</td> <th>Invoice No</th>
<td>{{ gst.basic_amount }}</td> <th>Amount</th>
<td>{{ gst.final_amount }}</td> <th>TDS Amount @ 1% on BASIC AMOUNT</th>
</tr> <th>Total Amount Paid</th>
{% endfor %} <th>UTR</th>
<tr> </tr>
<th colspan="2">Total</th> </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> <tr>
<th>{{total["sum_gst_final_amt"]}}</th> <th colspan="2">Total</th>
</tr> <th>{{total["sum_pay_payment_amt"]}}</th>
{% else %} <th>{{total["sum_pay_tds_payment_amt"]}}</th>
<tr> <th>{{total["sum_pay_total_amt"]}}</th>
<td colspan="4">No GST release found.</td> <th></th>
</tr> </tr>
{% endif %} {% else %}
</tbody>
</table> <tr>
<td colspan="6">No payment found.</td>
</tr>
{% endif %}
</tbody>
</table>
<br> <a href="{{ url_for('report.download_report', contractor_id=contractor_id) }}" class="download-btn">Download
<h3>Payment Details</h3> Report</a>
<table> </div>
<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>
</body> </body>
{% endblock %} {% endblock %}