pankaj-dev #20

Merged
pjpatil12 merged 2 commits from pankaj-dev into main 2026-04-03 06:43:43 +00:00
27 changed files with 1416 additions and 1292 deletions
Showing only changes of commit 73cd97f3c8 - Show all commits

View File

@@ -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,8 +70,8 @@ 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)
block.resultMessage block.resultMessage
@@ -90,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()
@@ -111,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():
@@ -152,17 +154,19 @@ def show_table(filename):
) )
# save Excel data # save Excel data
@excel_bp.route('/save_data', methods=['POST']) @excel_bp.route('/save_data', methods=['POST'])
def save_data(): def save_data():
# Extract form data # Extract form data
subcontractor_id = request.form.get("subcontractor_data") subcontractor_id = request.form.get("subcontractor_data")
state_id = request.form.get("state_data")
district_id = request.form.get("district_data")
block_id = request.form.get("block_data") block_id = request.form.get("block_data")
variables = request.form.getlist('variables[]')
hold_columns = request.form.get("hold_columns") hold_columns = request.form.get("hold_columns")
hold_counter = request.form.get("hold_counter")
if not data: if not data:
return jsonify({"error": "No data provided to save"}), 400 return jsonify({"error": "No data provided to save"}), 400
if data: if data:
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor() cursor = connection.cursor()
@@ -172,7 +176,7 @@ def save_data():
"PMC_No": entry.get("PMC_No"), "PMC_No": entry.get("PMC_No"),
"Invoice_Details": entry.get("Invoice_Details", ''), "Invoice_Details": entry.get("Invoice_Details", ''),
"Work_Type": 'none', "Work_Type": 'none',
"In oice_Date": entry.get("Invoice_Date").strftime('%Y-%m-%d') if entry.get( "Invoice_Date": entry.get("Invoice_Date").strftime('%Y-%m-%d') if entry.get(
"Invoice_Date") else None, "Invoice_Date") else None,
"Invoice_No": entry.get("Invoice_No", ''), "Invoice_No": entry.get("Invoice_No", ''),
"Basic_Amount": entry.get("Basic_Amount", 0.00), "Basic_Amount": entry.get("Basic_Amount", 0.00),
@@ -227,6 +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)
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))
@@ -239,7 +244,12 @@ 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("block_id :", block_id)
# print("invoice :", PMC_No, village_id, work_type, Invoice_Details, Invoice_Date, Invoice_No,
# Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
# SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount)
args = ( 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,
Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount, Basic_Amount, Debit_Amount, After_Debit_Amount, Amount, GST_Amount, TDS_Amount,
@@ -247,24 +257,39 @@ def save_data():
subcontractor_id, 0 subcontractor_id, 0
) )
# 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("**************************************************************")
print(invoice_id)
cursor.callproc("SavePayment",( PMC_No, Invoice_No, Payment_Amount, TDS_Payment_Amount,Total_Amount, UTR,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}")
hold_column_name = hold.get('column_name') hold_column_name = hold.get('column_name') # Get column name
hold_type_id = hold.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) 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}")
hold_join_data = { hold_join_data = {
"Contractor_Id": subcontractor_id, "Contractor_Id": subcontractor_id,
"Invoice_Id": invoice_id, "Invoice_Id": invoice_id,
@@ -281,9 +306,10 @@ def save_data():
print(f"Invalid hold entry: {hold}") print(f"Invalid hold entry: {hold}")
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']):
# print("Credit note found:", PMC_No, Invoice_No, Basic_Amount, Debit_Amount, Final_Amount,
# After_Debit_Amount, GST_Amount, Amount, Final_Amount, Payment_Amount, Total_Amount, UTR, Invoice_No)
cursor.callproc( cursor.callproc(
'AddCreditNoteFromExcel', 'AddCreditNoteFromExcel',
[ [
@@ -292,7 +318,7 @@ def save_data():
subcontractor_id, Invoice_No subcontractor_id, Invoice_No
] ]
) )
#--------------------------Hold Amount------------------------------------------------- #-----------------------------------------------Hold Amount----------------------------------------------------------------------
# Step 1: Normalize Invoice_Details: lowercase, trim, remove extra spaces # Step 1: Normalize Invoice_Details: lowercase, trim, remove extra spaces
normalized_details = re.sub(r'\s+', ' ', Invoice_Details.strip()).lower() normalized_details = re.sub(r'\s+', ' ', Invoice_Details.strip()).lower()
# Step 2: Define lowercase keywords # Step 2: Define lowercase keywords
@@ -308,13 +334,13 @@ def save_data():
] ]
# 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', 'gst release note']): keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'gst release note']):
@@ -324,33 +350,51 @@ def save_data():
[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 no village/work detected, only PMC/Payment # If no village/work detected, only PMC/Payment
if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()): if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()):
# if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower() and 'gst' in Invoice_Details.lower() and 'gst release note' in Invoice_Details.lower() and 'release' in Invoice_Details.lower()):
# ---------- Only PMC / Payment rows ---------- # ---------- Only PMC / Payment rows ----------
if PMC_No and not Invoice_No and UTR : if PMC_No and not Invoice_No and UTR :
# print("No village/work, using PMC only :", PMC_No)
# check invoice exists
# cursor.execute(
# "SELECT invoice_id FROM invoice WHERE PMC_No=%s ORDER BY invoice_id DESC LIMIT 1",
# (PMC_No,)
# )
# row = cursor.fetchone()
# invoice_id = row[0] if row else None
# # insert invoice if not exists
# if not invoice_id:
print(" extra payment :", PMC_No,Total_Amount,UTR, subcontractor_id)
cursor.execute( # cursor.execute(
""" # """
INSERT INTO invoice (PMC_No,Contractor_Id) VALUES (%s, %s); # INSERT INTO invoice (PMC_No,Contractor_Id) VALUES (%s, %s);
""", # """,
(PMC_No, subcontractor_id) # (PMC_No, subcontractor_id)
) # )
connection.commit() # 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()
invoice_id = row[0] if row else None
# 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 # insert payment
cursor.callproc( cursor.callproc(
"SavePayment", "SavePayment",
( (
PMC_No, PMC_No,
Invoice_No, Invoice_No, # required
Payment_Amount, Payment_Amount,
TDS_Payment_Amount, TDS_Payment_Amount,
Total_Amount, Total_Amount,
@@ -358,7 +402,40 @@ def save_data():
invoice_id 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:
@@ -368,3 +445,4 @@ def save_data():
cursor.close() cursor.close()
connection.close() connection.close()
return render_template('index.html') return render_template('index.html')
# ---------------------- Report --------------------------------

View File

@@ -1,10 +1,10 @@
# routes/gst_release_routes.py
from flask import Blueprint, render_template, request, redirect, url_for, flash 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
gst_release_bp = Blueprint('gst_release_bp', __name__) gst_release_bp = Blueprint('gst_release_bp', __name__)
gst_service = GSTRelease() gst_service = GSTRelease()
# ---------------- ADD GST RELEASE ---------------- # ---------------- ADD GST RELEASE ----------------

View File

@@ -5,16 +5,16 @@ 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)
# Always redirect to same page (NO JSON) # Always redirect to same page (NO JSON)
return redirect(url_for("hold_types.add_hold_type")) return redirect(url_for("hold_types.add_hold_type"))
# GET request → show data # GET request → show data
@@ -30,7 +30,7 @@ def add_hold_type():
@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,13 +39,13 @@ 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) # ✅
return hold.resultMessage return hold.resultMessage
hold_data = hold.GetHoldTypeByID(id) hold_data = hold.GetHoldTypeByID(id) # ✅
return render_template( return render_template(
"edit_hold_type.html", "edit_hold_type.html",
@@ -58,8 +58,8 @@ 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,3 +1,5 @@
# controllers/invoice_controller.py
from flask import Blueprint, request, jsonify, render_template from flask import Blueprint, request, jsonify, render_template
from flask_login import login_required, current_user from flask_login import login_required, current_user
from model.Invoice import * from model.Invoice import *
@@ -35,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')}'")
@@ -78,6 +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)
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

@@ -29,6 +29,7 @@ def add_payment():
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(subcontractor_id,pmc_no, invoice_no, amount, tds_amount, total_amount, utr) Paymentmodel.insert_payment(subcontractor_id,pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
# Paymentmodel.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
return redirect(url_for('payment_bp.add_payment')) return redirect(url_for('payment_bp.add_payment'))
@@ -70,15 +71,14 @@ def edit_payment(payment_id):
LogHelper.log_action("Edit Payment", f"User {current_user.id} Edit Payment '{pmc_no}'") LogHelper.log_action("Edit Payment", f"User {current_user.id} Edit Payment '{pmc_no}'")
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)
connection = Paymentmodel.get_connection() # Update inpayment
cursor = connection.cursor() # connection = Paymentmodel.get_connection()
cursor.callproc( # cursor = connection.cursor()
'UpdateInpaymentByPMCInvoiceUTR', # cursor.callproc('UpdateInpaymentByPMCInvoiceUTR',[amount, tds_amount, total_amount, pmc_no, invoice_no, utr])
[amount, tds_amount, total_amount, pmc_no, invoice_no, utr]
) # connection.commit()
connection.commit() # cursor.close()
cursor.close() # connection.close()
connection.close()
return redirect(url_for('payment_bp.add_payment')) return redirect(url_for('payment_bp.add_payment'))

View File

@@ -1,41 +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,12 +1,10 @@
from flask import Blueprint, render_template, request, jsonify,send_file 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
@@ -19,36 +17,70 @@ 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 ----------------
@report_bp.route('/download_report/<int:contractor_id>') @report_bp.route('/download_report/<int:contractor_id>')
@login_required
def download_report(contractor_id): def download_report(contractor_id):
output_file, error = ReportHelper.create_contractor_report(contractor_id)
service = ReportService(contractor_id=contractor_id).load_data()
file, error = service.download_excel()
if error: if error:
return error, 404 return error, 404
return send_file(output_file, as_attachment=True) 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

@@ -3,12 +3,17 @@ from flask_login import login_required
from model.Subcontractor import Subcontractor from model.Subcontractor import Subcontractor
from model.Utilities import HtmlHelper, ResponseHandler from model.Utilities import HtmlHelper, ResponseHandler
subcontractor_bp = Blueprint('subcontractor', __name__) subcontractor_bp = Blueprint('subcontractor', __name__)
# ----------------------------------------------------------
# LIST + ADD # LIST + ADD
# ----------------------------------------------------------
@subcontractor_bp.route('/subcontractor', methods=['GET', 'POST']) @subcontractor_bp.route('/subcontractor', methods=['GET', 'POST'])
@login_required @login_required
def subcontract(): def subcontract():
sub = Subcontractor() sub = Subcontractor()
# ---------------- GET ---------------- # ---------------- GET ----------------
@@ -26,22 +31,27 @@ def subcontract():
if request.method == 'POST': if request.method == 'POST':
sub.AddSubcontractor(request) sub.AddSubcontractor(request)
if not sub.isSuccess: if not sub.isSuccess:
return HtmlHelper.json_response( return HtmlHelper.json_response(
ResponseHandler.add_failure("Subcontractor"), 500 ResponseHandler.add_failure("Subcontractor"), 500
) )
# Reload list after insert
subcontractor = sub.GetAllSubcontractors(request) subcontractor = sub.GetAllSubcontractors(request)
return render_template('add_subcontractor.html', subcontractor=subcontractor) return render_template('add_subcontractor.html', subcontractor=subcontractor)
# ----------------------------------------------------------
# EDIT # EDIT
# ----------------------------------------------------------
@subcontractor_bp.route('/edit_subcontractor/<int:id>', methods=['GET', 'POST']) @subcontractor_bp.route('/edit_subcontractor/<int:id>', methods=['GET', 'POST'])
@login_required @login_required
def edit_subcontractor(id): def edit_subcontractor(id):
sub = Subcontractor() sub = Subcontractor()
# Fetch data # Fetch data
subcontractor = sub.GetSubcontractorByID(id) subcontractor = sub.GetSubcontractorByID(id)
@@ -65,7 +75,9 @@ def edit_subcontractor(id):
return render_template('edit_subcontractor.html', subcontractor=subcontractor) return render_template('edit_subcontractor.html', subcontractor=subcontractor)
# ----------------------------------------------------------
# DELETE # DELETE
# ----------------------------------------------------------
@subcontractor_bp.route('/deleteSubContractor/<int:id>', methods=['GET', 'POST']) @subcontractor_bp.route('/deleteSubContractor/<int:id>', methods=['GET', 'POST'])
@login_required @login_required
def deleteSubContractor(id): def deleteSubContractor(id):

View File

@@ -1,3 +1,7 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required from flask_login import login_required
@@ -7,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)
@@ -75,24 +79,25 @@ 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)
@village_bp.route('/delete_village/<int:village_id>') @village_bp.route('/delete_village/<int:village_id>')
@login_required @login_required
def delete_village(village_id): def delete_village(village_id):
village = Village() # village = Village()
village.DeleteVillage(request=request, village_id=village_id) village.DeleteVillage(request=request, village_id=village_id)
# Convert resultMessage to string if it's a Response or tuple # Convert resultMessage to string if it's a Response or tuple
raw_msg = village.resultMessage raw_msg = village.resultMessage
if isinstance(raw_msg, tuple): if isinstance(raw_msg, tuple):
# e.g., (<Response ...>, 200)
msg = "Village deleted successfully!" msg = "Village deleted successfully!"
elif hasattr(raw_msg, 'get_data'): elif hasattr(raw_msg, 'get_data'):
# Flask Response object # Flask Response object
msg = raw_msg.get_data(as_text=True) msg = raw_msg.get_data(as_text=True) # get raw text
else: else:
# fallback # fallback
msg = str(raw_msg) if raw_msg else "Village deleted successfully!" msg = str(raw_msg) if raw_msg else "Village deleted successfully!"
@@ -107,7 +112,7 @@ def delete_village(village_id):
@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':
@@ -130,6 +135,7 @@ def edit_village(village_id):
) )
else: else:
# ✅ FIXED HERE (removed request)
village_data = village.GetVillageByID(id=village_id) village_data = village.GetVillageByID(id=village_id)
if not village.isSuccess: if not village.isSuccess:

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,11 +1,12 @@
import os import os
from flask import current_app from flask import current_app
# -----------------------------
# BASE FOLDER Class
# -----------------------------
class FolderAndFile: class FolderAndFile:
# -----------------------------
# BASE FOLDER METHODS
# -----------------------------
@staticmethod @staticmethod
def get_download_folder(): def get_download_folder():
folder = os.path.join(current_app.root_path, "static", "downloads") folder = os.path.join(current_app.root_path, "static", "downloads")

View File

@@ -10,7 +10,7 @@ class GST:
invoices_rows = invoice_crud.GetAllData(storedproc="GetAllInvoicesBasic") invoices_rows = invoice_crud.GetAllData(storedproc="GetAllInvoicesBasic")
if not invoice_crud.isSuccess: if not invoice_crud.isSuccess:
return [] return [] # Could also log invoice_crud.resultMessage
invoices = [ invoices = [
dict( dict(
@@ -25,16 +25,16 @@ class GST:
gst_rows = gst_crud.GetAllData(storedproc="GetAllGSTReleasesBasic") gst_rows = gst_crud.GetAllData(storedproc="GetAllGSTReleasesBasic")
if not gst_crud.isSuccess: if not gst_crud.isSuccess:
return [] return [] # Could also log gst_crud.resultMessage
gst_invoice_nos = { gst_invoice_nos = {
g[2] g[2] # Invoice_No is at index 2
for g in gst_rows for g in gst_rows
if g[2] if g[2]
} }
gst_basic_amounts = { gst_basic_amounts = {
float(g[3]) float(g[3]) # Basic_Amount at index 3
for g in gst_rows for g in gst_rows
if g[3] is not None if g[3] is not None
} }

View File

@@ -1,4 +1,6 @@
import config import config
import mysql.connector
# ------------------- Helper Functions ------------------- # ------------------- Helper Functions -------------------
def clear_results(cursor): def clear_results(cursor):
@@ -69,7 +71,22 @@ def get_all_villages():
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'),
# 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')
# ])
# 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'),
@@ -77,14 +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
]) ])
invoice_row = fetch_one(cursor) invoice_id = None
if not invoice_row: for result in cursor.stored_results():
raise Exception("Invoice ID not returned") row = result.fetchone()
invoice_id = invoice_row.get('invoice_id') 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)
@@ -129,6 +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 operation(cursor):
# cursor.callproc('UpdateInpayment', [
# data.get('work_type'),
# data.get('invoice_details'),
# data.get('invoice_date'),
# *get_numeric_values(data),
# data.get('pmc_no'),
# data.get('invoice_no')
# ])
# clear_results(cursor)
# execute_db_operation(operation)
def delete_invoice_data(invoice_id, user_id): def delete_invoice_data(invoice_id, user_id):
def operation(cursor): def operation(cursor):
@@ -140,24 +182,31 @@ def delete_invoice_data(invoice_id, user_id):
if not record: if not record:
raise Exception("Invoice not found") raise Exception("Invoice not found")
# Use exact DB keys
pmc_no = record['PMC_No']
invoice_no = record['Invoice_No']
# Delete invoice # Delete invoice
cursor.callproc("DeleteInvoice", (invoice_id,)) cursor.callproc("DeleteInvoice", (invoice_id,))
clear_results(cursor) clear_results(cursor)
# Delete inpayment
# cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
# 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,275 +1,137 @@
import openpyxl
from openpyxl.styles import Font
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()
cursor = connection.cursor(dictionary=True, buffered=True)
try: # connection = config.get_db_connection()
pmc_info = ReportHelper.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no], True) # cursor = connection.cursor(dictionary=True, buffered=True)
if not pmc_info: # try:
return None # 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("Get_pmc_hold_types", (pmc_no, pmc_info["Contractor_Id"])) # # Extract hold_type_ids
hold_types = next(cursor.stored_results()).fetchall() # hold_type_ids = [ht['hold_type_id'] for ht in hold_types]
# Extract hold_type_ids # invoices = []
hold_type_ids = [ht['hold_type_id'] for ht in hold_types] # 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()
invoices = [] # gst_rel = GeneralUse.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no])
hold_amount_total = 0
if hold_type_ids: # hold_release = GeneralUse.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
hold_type_ids_str = ",".join(map(str, hold_type_ids))
cursor.callproc( # credit_note = GeneralUse.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
'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: # payments = GeneralUse.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
hold_amount_total = sum(row.get('hold_amount', 0) or 0 for row in invoices)
# 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)
# }
total_invo_final = sum(row.get('Final_Amount', 0) or 0 for row in invoices) # 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
# }
# GST RELEASE # finally:
gst_rel = ReportHelper.execute_sp(cursor, 'GetGSTReleaseByPMC', [pmc_no]) # cursor.close()
# connection.close()
total_gst_basic = sum(row.get('basic_amount', 0) or 0 for row in gst_rel)
total_gst_final = sum(row.get('final_amount', 0) or 0 for row in gst_rel)
# ---------------- HOLD RELEASE ----------------
hold_release = ReportHelper.execute_sp(cursor, 'GetHoldReleaseByPMC', [pmc_no])
# ---------------- CREDIT NOTE ----------------
credit_note = ReportHelper.execute_sp(cursor, 'GetCreditNoteByPMC', [pmc_no])
# ---------------- PAYMENTS ----------------
payments = ReportHelper.execute_sp(cursor, 'GetPaymentsByPMC', [pmc_no])
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 # @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: # if not connection:
return None # return None
cursor = connection.cursor(dictionary=True) # cursor = connection.cursor(dictionary=True)
try:
filename = f"PMC_Report_{pmc_no}.xlsx"
output_folder = FolderAndFile.get_download_folder() # try:
output_file = FolderAndFile.get_download_path(filename) # filename = f"PMC_Report_{pmc_no}.xlsx"
# ================= DATA FETCH ============= # output_folder = FolderAndFile.get_download_folder()
contractor_info = ReportHelper.execute_sp(cursor, 'GetContractorDetailsByPMC', [pmc_no]) # output_file = FolderAndFile.get_download_path(filename)
contractor_info = contractor_info[0] if contractor_info else None # contractor_info = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [pmc_no])
if not contractor_info: # contractor_info = contractor_info[0] if contractor_info else None
return None # print("contractor_info:::",contractor_info)
hold_types = ReportHelper.execute_sp(cursor, 'GetHoldTypesByContractor',[contractor_info["Contractor_Id"]]) # if not contractor_info:
# return None
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} # hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor',[contractor_info["Contractor_Id"]])
invoices = ReportHelper.execute_sp(cursor, 'GetInvoicesAndGstReleaseByPmcNo', [pmc_no]) # hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
credit_notes = ReportHelper.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no]) # invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None,pmc_no])
hold_amounts = ReportHelper.execute_sp(cursor, 'GetHoldAmountsByContractor',[contractor_info["Contractor_Id"]]) # credit_notes = GeneralUse.execute_sp(cursor, 'NewGetCreditNotesByPMCNo', [pmc_no])
# credit_note_map = {}
# for cn in credit_notes:
# key = (str(cn['PMC_No']).strip())
# credit_note_map.setdefault(key, []).append(cn)
gst_releases = ReportHelper.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no]) # hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [contractor_info["Contractor_Id"]])
# ================= DATA MAPPING ================= # gst_releases = GeneralUse.execute_sp(cursor, 'GetGSTReleaseDetailsByPMC', [pmc_no])
hold_data = {} # gst_release_map = {}
for h in hold_amounts: # for gr in gst_releases:
hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount'] # key = (str(gr['PMC_No']).strip())
# gst_release_map.setdefault(key, []).append(gr)
credit_note_map = {} # # ================= DATA MAPPING =================
for cn in credit_notes: # hold_data = {}
pmc = cn.get("PMC_No") # for h in hold_amounts:
if pmc: # hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
credit_note_map.setdefault(pmc, []).append(cn)
gst_map = {}
for gst in gst_releases:
pmc = gst.get("PMC_No")
if pmc:
gst_map.setdefault(pmc, []).append(gst)
# ================= LOG ================= # # ================= LOG =================
LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'") # LogHelper.log_action("Download PMC Report",f"User {current_user.id} Download PMC Report '{pmc_no}'")
# ================= EXCEL ================= # ReportHelper.generate_excel(
workbook = openpyxl.Workbook() # 0, contractor_info, invoices, hold_types, hold_data,
sheet = workbook.active # credit_note_map,gst_release_map, output_file)
sheet.title = "PMC Report"
# return output_folder, filename
# HEADER INFO # finally:
sheet.append(["", "", "Laxmi Civil Engineering Services PVT. LTD."]) # cursor.close()
sheet.append(["Contractor Name", contractor_info["Contractor_Name"]]) # connection.close()
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)
for cell in sheet[sheet.max_row]:
cell.font = Font(bold=True)
# ================= INVOICE ROWS =================
for inv in invoices:
row = [
pmc_no,
inv.get("Village_Name", ""),
inv.get("Work_Type", ""),
inv.get("Invoice_Details", ""),
inv.get("Invoice_Date", ""),
inv.get("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", "")
]
# HOLD DATA
invoice_holds = hold_data.get(inv.get("Invoice_Id"), {})
for ht_id in hold_type_map.keys():
row.append(invoice_holds.get(ht_id, ""))
# PAYMENT DATA
row += [
inv.get("Final_Amount", ""),
inv.get("Payment_Amount", ""),
inv.get("TDS_Payment_Amount", ""),
inv.get("Total_Amount", ""),
inv.get("UTR", "")
]
row += ["", ""]
sheet.append(row)
# ================= CREDIT NOTE ROWS =================
for pmc, cn_list in credit_note_map.items():
for cn in cn_list:
cn_row = [
pmc_no,
"", "", "Credit Note",
"", cn.get("Invoice_No", ""),
cn.get("Basic_Amount", ""),
"", "", "", "", "", "", "", "", "", "", ""
]
cn_row += [""] * len(hold_headers)
cn_row += [
cn.get("Final_Amount", ""),
cn.get("Total_Amount", ""),
cn.get("UTR", "")
]
sheet.append(cn_row)
# ================= GST RELEASE ROWS =================
for gst in gst_releases:
gst_row = [
gst.get("PMC_No", ""),
"", "", "GST Release Note",
"", gst.get("Invoice_No", ""),
gst.get("Basic_Amount", ""),
"", "", "", "", "", "", "", "", ""
]
gst_row += [""] * len(hold_headers)
gst_row += [
gst.get("Final_Amount", ""),
"",
"",
gst.get("Total_Amount", ""),
gst.get("UTR", "")
]
sheet.append(gst_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
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()

View File

@@ -1,11 +1,11 @@
import config import config
from datetime import datetime from datetime import datetime
from flask import send_file from flask import send_file
import os
import openpyxl import openpyxl
from openpyxl.styles import Font, PatternFill 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
@@ -17,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):
@@ -60,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,
@@ -72,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}")
@@ -85,69 +57,6 @@ 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 get_contractor_info(contractor_id): def get_contractor_info(contractor_id):
@@ -156,10 +65,11 @@ class ReportHelper:
return contractor.contInfo if contractor.contInfo else None return contractor.contInfo if contractor.contInfo else None
# call this method for excel formate written
@staticmethod @staticmethod
def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data, def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data,
credit_note_map, gst_release_map, output_file): credit_note_map, gst_release_map, output_file):
workbook = openpyxl.Workbook() workbook = openpyxl.Workbook()
sheet = workbook.active sheet = workbook.active
sheet.title = "Contractor Report" sheet.title = "Contractor Report"
@@ -196,8 +106,7 @@ class ReportHelper:
inv["invoice_no"].replace(" ", "") if inv["invoice_no"] else "" inv["invoice_no"].replace(" ", "") if inv["invoice_no"] else ""
if inv["invoice_no"] not in (None, "", 0) if inv["invoice_no"] not in (None, "", 0)
else "" else ""
) )
key = (pmc_no) key = (pmc_no)
# Yellow separator # Yellow separator
@@ -284,7 +193,13 @@ class ReportHelper:
cn_row += [""] * len(hold_headers) cn_row += [""] * len(hold_headers)
cn_row += [cn.get("Final_Amount", ""),"","",cn.get("Total_Amount", ""),cn.get("UTR", "")] cn_row += [
cn.get("Final_Amount", ""),
"",
"",
cn.get("Total_Amount", ""),
cn.get("UTR", "")
]
sheet.append(cn_row) sheet.append(cn_row)
@@ -294,53 +209,4 @@ class ReportHelper:
workbook.save(output_file) workbook.save(output_file)
@staticmethod
def create_contractor_report(contractor_id):
fileName = f"Contractor_Report_{contractor_id}.xlsx"
output_file = FolderAndFile.get_download_path(filename=fileName)
# Fetch Data
contInfo = ReportHelper.get_contractor_info(contractor_id)
if not contInfo:
return None, "No contractor found"
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True)
hold_types = ReportHelper.execute_sp(cursor, 'HoldTypesByContractorId', [contractor_id])
invoices = ReportHelper.execute_sp(cursor, 'FetchInvoicesByContractor', [contractor_id])
hold_amounts = ReportHelper.execute_sp(cursor, 'HoldAmountsByContractorId', [contractor_id])
hold_data = {}
for h in hold_amounts:
hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
# -------- Credit Note MAP --------
credit_note_raw = ReportHelper.execute_sp(cursor, 'GetCreditNotesByContractor', [contractor_id])
credit_note_map = {}
for cn in credit_note_raw:
key = (
str(cn['PMC_No']).strip()
)
credit_note_map.setdefault(key, []).append(cn)
# -------- GST MAP --------
gst_release_raw = ReportHelper.execute_sp(cursor, 'GstReleasesByContractorId', [contractor_id])
gst_release_map = {}
for gr in gst_release_raw:
key = (
str(gr['PMC_No']).strip()
)
gst_release_map.setdefault(key, []).append(gr)
# Generate Excel
ReportHelper.generate_excel(
contractor_id, contInfo, invoices, hold_types, hold_data,
credit_note_map, gst_release_map, output_file
)
return output_file, None

View File

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

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

177
services/ReportService.py Normal file
View File

@@ -0,0 +1,177 @@
import config
from model.FolderAndFile import FolderAndFile
from services.Generalservice import GeneralUse
from model.Report import ReportHelper
from decimal import Decimal
def safe_decimal(value):
if value is None:
return Decimal(0)
return Decimal(value)
class ReportService:
def __init__(self, contractor_id=None, pmc_no=None):
self.contractor_id = contractor_id
self.pmc_no = pmc_no
self.contInfo = None
self.hold_types = []
self.invoices = []
self.hold_amounts = []
self.hold_data = {}
self.credit_note_raw = []
self.credit_note_map = {}
self.gst_release_raw = []
self.gst_release_map = {}
self.output_file = None
# ---------------- LOAD DATA ----------------
def load_data(self):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True)
try:
# ---------- CONTRACTOR ----------
if self.contractor_id:
self.contInfo = GeneralUse.execute_sp(cursor, 'GetContractorInfo', [self.contractor_id], True)
self.hold_types = GeneralUse.execute_sp(cursor, 'HoldTypesByContractorId', [self.contractor_id])
self.invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [self.contractor_id, None])
# ---------- PMC ----------
elif self.pmc_no:
self.contInfo = GeneralUse.execute_sp(cursor, 'GetContractorInfoByPmcNo', [self.pmc_no], True)
self.contractor_id = self.contInfo["Contractor_Id"]
self.hold_types = GeneralUse.execute_sp(cursor, 'GetHoldTypesByContractor', [self.contractor_id])
self.invoices = GeneralUse.execute_sp(cursor, 'GetInvoicesByContractorOrPMCNo', [None, self.pmc_no])
# ---------- COMMON ----------
self.hold_amounts = GeneralUse.execute_sp(cursor, 'GetHoldAmountsByContractor', [self.contractor_id])
self.credit_note_raw = GeneralUse.execute_sp(cursor, 'GetCreditNotesByContractor', [self.contractor_id])
self.gst_release_raw = GeneralUse.execute_sp(cursor, 'GetGSTRelease', [self.contractor_id])
self.prepare_maps()
self.total = self.calculate_totals()
finally:
cursor.close()
connection.close()
return self
# ---------------- MAPS ----------------
def prepare_maps(self):
# HOLD MAP
for h in self.hold_amounts:
self.hold_data.setdefault(h['Invoice_Id'], {})[h['hold_type_id']] = h['hold_amount']
# CREDIT MAP
for cn in self.credit_note_raw:
key = str(cn.get('PMC_No') or cn.get('pmc_no')).strip()
self.credit_note_map.setdefault(key, []).append(cn)
# GST MAP (FIXED)
for gr in self.gst_release_raw:
pmc_value = gr.get('PMC_No') or gr.get('pmc_no') or gr.get('PMC_NO')
if not pmc_value:
continue # skip if missing
key = str(pmc_value).strip()
self.gst_release_map.setdefault(key, []).append(gr)
# ---------------- calculate total ----------------
def calculate_totals(self):
total = {
"sum_invo_basic_amt": Decimal(0),
"sum_invo_debit_amt": Decimal(0),
"sum_invo_after_debit_amt": Decimal(0),
"sum_invo_gst_amt": Decimal(0),
"sum_invo_amt": Decimal(0),
"sum_invo_tds_amt": Decimal(0),
"sum_invo_ds_amt": Decimal(0),
"sum_invo_on_commission": Decimal(0),
"sum_invo_hydro_test": Decimal(0),
"sum_invo_hold_amt": Decimal(0),
"sum_invo_gst_sd_amt": Decimal(0),
"sum_invo_final_amt": Decimal(0),
"sum_gst_basic_amt": Decimal(0),
"sum_gst_final_amt": Decimal(0),
"sum_pay_payment_amt": Decimal(0),
"sum_pay_tds_payment_amt": Decimal(0),
"sum_pay_total_amt": Decimal(0)
}
# ---------- INVOICE ----------
for inv in self.invoices:
total["sum_invo_basic_amt"] += safe_decimal(inv.get("Basic_Amount"))
total["sum_invo_debit_amt"] += safe_decimal(inv.get("Debit_Amount"))
total["sum_invo_after_debit_amt"] += safe_decimal(inv.get("After_Debit_Amount"))
total["sum_invo_gst_amt"] += safe_decimal(inv.get("GST_Amount"))
total["sum_invo_amt"] += safe_decimal(inv.get("Amount"))
total["sum_invo_tds_amt"] += safe_decimal(inv.get("TDS_Amount"))
total["sum_invo_ds_amt"] += safe_decimal(inv.get("SD_Amount"))
total["sum_invo_on_commission"] += safe_decimal(inv.get("On_Commission"))
total["sum_invo_hydro_test"] += safe_decimal(inv.get("Hydro_Testing"))
total["sum_invo_gst_sd_amt"] += safe_decimal(inv.get("GST_SD_Amount"))
total["sum_invo_final_amt"] += safe_decimal(inv.get("Final_Amount"))
total["sum_invo_hold_amt"] += safe_decimal(inv.get("hold_amount"))
# ---------- GST ----------
for gst in self.gst_release_raw:
total["sum_gst_basic_amt"] += safe_decimal(gst.get("basic_amount"))
total["sum_gst_final_amt"] += safe_decimal(gst.get("final_amount"))
# ---------- PAYMENTS ----------
if hasattr(self, "payments"):
for pay in self.payments:
total["sum_pay_payment_amt"] += safe_decimal(pay.get("Payment_Amount"))
total["sum_pay_tds_payment_amt"] += safe_decimal(pay.get("TDS_Payment_Amount"))
total["sum_pay_total_amt"] += safe_decimal(pay.get("Total_amount"))
return total
# ---------------- WEB DATA ----------------
def get_web_data(self):
return {
"contInfo": self.contInfo,
"invoices": self.invoices,
"hold_types": self.hold_types,
"credit_note": self.credit_note_raw,
"gst_rel": self.gst_release_raw,
"total": self.total
}
# ---------------- DOWNLOAD ----------------
def download_excel(self):
if not self.contInfo:
return None, "No data found"
filename = f"Report_{self.contractor_id or self.pmc_no}.xlsx"
self.output_file = FolderAndFile.get_download_path(filename=filename)
ReportHelper.generate_excel(
self.contractor_id or 0,
self.contInfo,
self.invoices,
self.hold_types,
self.hold_data,
self.credit_note_map,
self.gst_release_map,
self.output_file
)
return self.output_file, None

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

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,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() if invoice.Village_Name else '' }}</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,343 @@
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">--> <!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/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 class="row2">
<div>
<label for="GST_Registration_Type">GST Registration Type :</label>
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
value="{{ contInfo.GST_Registration_Type }}" readonly />
</div>
<div>
<label for="GST_No">GST No:</label>
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly />
</div>
</div>
<div class="row3">
<div>
<label for="State">State :</label>
<input type="text" id="State" name="State" value="{{ contInfo.State_Name }}" readonly />
</div>
<div>
<label for="District">District :</label>
<input type="text" id="District" name="District" value="{{ contInfo.District_Name }}" readonly />
</div>
<div>
<label for="Block">Block :</label>
<input type="text" id="Block" name="Block" value="{{ contInfo.Block_Name }}" readonly />
</div>
</div> </div>
</div> </div>
<div class="row3">
<div>
<label for="PAN_No">PAN No :</label>
<input type="text" id="PAN_No" name="PAN_No" value="{{ contInfo.PAN_No }}" readonly/>
</div>
<div>
<label for="Mobile_No">Mobile Number :</label>
<input type="text" id="Mobile_No" name="Mobile_No" value="{{ contInfo.Mobile_No }}" readonly/>
</div>
<div>
<label for="Email">Email :</label>
<input type="text" id="Email" name="Email" value="{{ contInfo.Email }}" readonly/>
</div>
</div>
<div class="row2">
<div>
<label for="GST_Registration_Type">GST Registration Type :</label>
<input type="text" id="GST_Registration_Type" name="GST_Registration_Type"
value="{{ contInfo.GST_Registration_Type }}" readonly/>
</div>
<div>
<label for="GST_No">GST No:</label>
<input type="text" id="GST_No" name="GST_No" value="{{ contInfo.GST_No }}" readonly/>
</div>
</div>
<div class="row3">
<div>
<label for="State">State :</label>
<input type="text" id="State" name="State" value="{{ contInfo.State_Name }}" readonly/>
</div>
<div>
<label for="District">District :</label>
<input type="text" id="District" name="District" value="{{ contInfo.District_Name }}" readonly/>
</div>
<div>
<label for="Block">Block :</label>
<input type="text" id="Block" name="Block" value="{{ contInfo.Block_Name }}" readonly/>
</div>
</div>
</div>
<h3>Total</h3>
<table class="total-table">
<tr>
<th colspan="2">{{current_date}}</th>
</tr>
<!-- <tr>-->
<!-- <th>Total Hold Amounnt</th>-->
<!-- <td>0</td>-->
<!-- </tr>-->
<tr>
<th>Advance / Suplus</th>
<td>{{total["sum_invo_final_amt"]+total["sum_gst_final_amt"]-total["sum_pay_total_amt"]}}</td>
</tr>
{% if hold_types %}
<tr>
{% for hold in hold_types %}
<th>{{ hold.hold_type }}</th>
<td>{{total["sum_invo_hold_amt"]}}</td>
{% endfor %}
</tr>
{% endif %}
<tr>
<th>Amount With TDS</th>
<td>{{total["sum_invo_tds_amt"]}}</td>
</tr>
</table>
<!-- {% if hold_types %}-->
<!-- <h3>Hold Types</h3>-->
<!-- <ul>-->
<!-- {% for hold in hold_types %}-->
<!-- <li>{{ hold.hold_type }}</li>-->
<!-- {% endfor %}-->
<!-- </ul>-->
<!-- {% endif %}-->
<h3>Invoice Details</h3> <!-- {% if hold_types %}-->
<table> <!-- <h3>Hold Types</h3>-->
<thead> <!-- <ul>-->
<tr> <!-- {% for hold in hold_types %}-->
<th>PMC No</th> <!-- <li>{{ hold.hold_type }}</li>-->
<th>Village Name</th> <!-- {% endfor %}-->
<th>Work Type</th> <!-- </ul>-->
<th>Invoice Details</th> <!-- {% endif %}-->
<th>Invoice Date</th>
<th>Invoice No</th>
<th>Basic Amount</th>
<th>Debit</th>
<th>After Debit Amt</th>
<th>GST (18%)</th>
<th>Amount</th>
<th>TDS (1%)</th>
<th>SD (5%)</th>
<th>On Commission</th>
<th>Hydro Testing</th>
<!-- Dynamic Hold Types -->
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<th>{{ hold }}</th>
{% endfor %}
<th>GST SD (18%)</th> <h3>Invoice Details</h3>
<th>Final Amount</th> <table>
</tr> <thead>
</thead> <tr>
<tbody> <th>PMC No</th>
{% if invoices %} <th>Village Name</th>
{% for invoice in invoices %} <th>Work Type</th>
<tr> <th>Invoice Details</th>
<td>{{ invoice.PMC_No }}</td> <th>Invoice Date</th>
<td>{{ invoice.Village_Name.capitalize() }}</td> <th>Invoice No</th>
<td>{{ invoice.Work_Type }}</td> <th>Basic Amount</th>
<td>{{ invoice.Invoice_Details }}</td> <th>Debit</th>
<td>{{ invoice.Invoice_Date }}</td> <th>After Debit Amt</th>
<td>{{ invoice.Invoice_No }}</td> <th>GST (18%)</th>
<td>{{ invoice.Basic_Amount }}</td> <th>Amount</th>
<td>{{ invoice.Debit_Amount }}</td> <th>TDS (1%)</th>
<td>{{ invoice.After_Debit_Amount }}</td> <th>SD (5%)</th>
<td>{{ invoice.GST_Amount }}</td> <th>On Commission</th>
<td>{{ invoice.Amount }}</td> <th>Hydro Testing</th>
<td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td> <!-- Dynamic Hold Types -->
<td>{{ invoice.On_Commission }}</td> {% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
<td>{{ invoice.Hydro_Testing }}</td> {% for hold in hold_types %}
<th>{{ hold }}</th>
{% endfor %}
<th>GST SD (18%)</th>
<th>Final Amount</th>
</tr>
</thead>
<tbody>
{% if invoices %}
{% for invoice in invoices %}
<tr>
<td>{{ invoice.PMC_No }}</td>
<td>{{ invoice.Village_Name}}</td>
<td>{{ invoice.Work_Type }}</td>
<td>{{ invoice.Invoice_Details }}</td>
<td>{{ invoice.Invoice_Date }}</td>
<td>{{ invoice.Invoice_No }}</td>
<td>{{ invoice.Basic_Amount }}</td>
<td>{{ invoice.Debit_Amount }}</td>
<td>{{ invoice.After_Debit_Amount }}</td>
<td>{{ invoice.GST_Amount }}</td>
<td>{{ invoice.Amount }}</td>
<td>{{ invoice.TDS_Amount }}</td>
<td>{{ invoice.SD_Amount }}</td>
<td>{{ invoice.On_Commission }}</td>
<td>{{ invoice.Hydro_Testing }}</td>
<!-- Dynamic Hold Amounts -->
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<td>
{% if invoice.hold_type == hold %}
{{ invoice.hold_amount }}
{% else %}
0.00
{% endif %}
</td>
{% endfor %}
<td>{{ invoice.GST_SD_Amount }}</td>
<td>{{ invoice.Final_Amount }}</td>
</tr>
{% endfor %}
<tr>
<th colspan="6">Total</th>
<th>{{total["sum_invo_basic_amt"]}}</th>
<th>{{total["sum_invo_debit_amt"]}}</th>
<th>{{total["sum_invo_after_debit_amt"]}}</th>
<th>{{total["sum_invo_gst_amt"]}}</th>
<th>{{total["sum_invo_amt"]}}</th>
<th>{{total["sum_invo_tds_amt"]}}</th>
<th>{{total["sum_invo_ds_amt"]}}</th>
<th>{{total["sum_invo_on_commission"]}}</th>
<th>{{total["sum_invo_hydro_test"]}}</th>
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<th>{{total["sum_invo_hold_amt"]}}</th>
{% endfor %}
<th>{{total["sum_invo_gst_sd_amt"]}}</th>
<th>{{total["sum_invo_final_amt"]}}</th>
</tr>
<!-- Dynamic Hold Amounts -->
{% set hold_types = invoices | map(attribute='hold_type') | unique | list %}
{% for hold in hold_types %}
<td>
{% if invoice.hold_type == hold %}
{{ invoice.hold_amount }}
{% else %} {% 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>
<h3>GST Release Note Details</h3>
{% else %} <table>
<tr> <thead>
<td colspan="11">No Credit note found.</td> <tr>
</tr> <th>PMC No</th>
{% endif %} <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 %}