final payment reconciliation

This commit is contained in:
2026-04-06 10:46:47 +05:30
parent 0ca1749757
commit 5ae1fbe320
24 changed files with 766 additions and 638 deletions

View File

@@ -12,7 +12,6 @@ block = Block()
@block_bp.route('/add_block', methods=['GET', 'POST'])
@login_required
def add_block():
# block = Block()
if request.method == 'POST':
block.AddBlock(request)
@@ -30,7 +29,7 @@ def add_block():
)
# ✅ NEW ROUTE (FIX FOR DISTRICT FETCH)
# get district
@block_bp.route('/get_districts/<int:state_id>')
@login_required
def get_districts(state_id):
@@ -62,7 +61,6 @@ def get_districts(state_id):
@login_required
def check_block():
# block = Block()
return block.CheckBlock(request)
@@ -70,8 +68,6 @@ def check_block():
@login_required
def edit_block(block_id):
# block = Block()
if request.method == 'POST':
block.EditBlock(request, block_id)
block.resultMessage
@@ -111,7 +107,6 @@ def edit_block(block_id):
@login_required
def delete_block(block_id):
# block = Block()
block.DeleteBlock(request, block_id)
return redirect(url_for('block.add_block'))

View File

@@ -84,8 +84,6 @@ def show_table(filename):
subcontractor_data = result.fetchone()
if not subcontractor_data:
# cursor.callproc('InsertSubcontractor', [file_info['Subcontractor']])
# connection.commit()
cursor.callproc('SaveContractor', [file_info.get('Subcontractor'),None,None,None,None,None,None,None,None])
connection.commit()
cursor.callproc('GetSubcontractorByName', [file_info['Subcontractor']])
@@ -252,7 +250,7 @@ def save_data():
subcontractor_id, 0
)
# print("All invoice Details ",args)
# add subcontarctor id in invoice table
results = cursor.callproc('SaveInvoice', args)
invoice_id = results[-1]
@@ -261,16 +259,16 @@ def save_data():
"SavePayment",
(
PMC_No,
Invoice_No, # required
Invoice_No,
Payment_Amount,
TDS_Payment_Amount,
Total_Amount,
UTR,
invoice_id # last
invoice_id
)
)
# print("invoice id from the excel ", invoice_id)
if isinstance(hold_columns, str):
hold_columns = ast.literal_eval(hold_columns)
if isinstance(hold_columns, list) and all(isinstance(hold, dict) for hold in hold_columns):
@@ -282,7 +280,7 @@ def save_data():
hold_amount = entry.get(
hold_column_name) # Get the value for that specific hold column
if hold_amount is not None:
# print(f"Processing hold type: {hold_column_name}, Hold Amount: {hold_amount}")
hold_join_data = {
"Contractor_Id": subcontractor_id,
"Invoice_Id": invoice_id,
@@ -299,8 +297,7 @@ def save_data():
print(f"Invalid hold entry: {hold}")
else:
print("Hold columns data is not a valid list of dictionaries.")
#---------------------------------------------Credit Note---------------------------------------------------------------------------
# elif any(keyword in Invoice_Details.lower() for keyword in ['credit note ','credit note details','logging report']):
#-----------------------------------Credit Note----------------------------------------------------------------
elif any(keyword in Invoice_Details.lower() for keyword in ['credit', 'logging report']):
cursor.callproc(
'AddCreditNoteFromExcel',
@@ -310,7 +307,7 @@ def save_data():
subcontractor_id, Invoice_No
]
)
#-----------------------------------------------Hold Amount----------------------------------------------------------------------
#---------------------------------------Hold Amount-----------------------------------------------------------
# Step 1: Normalize Invoice_Details: lowercase, trim, remove extra spaces
normalized_details = re.sub(r'\s+', ' ', Invoice_Details.strip()).lower()
# Step 2: Define lowercase keywords
@@ -328,8 +325,7 @@ def save_data():
if any(kw in normalized_details for kw in keywords):
cursor.callproc(
'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()
#------------------------------------------------------------------------------------------------------------------
elif Invoice_Details and any(
@@ -341,13 +337,9 @@ def save_data():
# --------------------------------------
# If no village/work detected, only PMC/Payment
if not (Invoice_Details and 'village' in Invoice_Details.lower() and 'work' in Invoice_Details.lower()):
# ---------- Only PMC / Payment rows ----------
if PMC_No and not Invoice_No and UTR :
print(" extra payment :", PMC_No,Total_Amount,UTR, subcontractor_id)
cursor.callproc("insertExtrapaymet",(PMC_No, subcontractor_id))
for result in cursor.stored_results():
row = result.fetchone()
@@ -357,7 +349,7 @@ def save_data():
"SavePayment",
(
PMC_No,
Invoice_No, # required
Invoice_No,
Payment_Amount,
TDS_Payment_Amount,
Total_Amount,
@@ -375,4 +367,3 @@ def save_data():
cursor.close()
connection.close()
return render_template('index.html')
# ---------------------- Report --------------------------------

View File

@@ -10,11 +10,9 @@ hold = HoldTypes()
@hold_bp.route('/add_hold_type', methods=['GET','POST'])
@login_required
def add_hold_type():
# hold = HoldTypes()
if request.method == 'POST':
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"))
# GET request → show data
@@ -30,7 +28,6 @@ def add_hold_type():
@login_required
def check_hold_type():
# hold = HoldTypes()
return hold.CheckHoldType(request) # if exists
@@ -39,13 +36,11 @@ def check_hold_type():
@login_required
def edit_hold_type(id):
# hold = HoldTypes()
if request.method == 'POST':
hold.EditHoldType(request, id) # ✅
hold.EditHoldType(request, id)
return hold.resultMessage
hold_data = hold.GetHoldTypeByID(id) # ✅
hold_data = hold.GetHoldTypeByID(id)
return render_template(
"edit_hold_type.html",
@@ -58,9 +53,7 @@ def edit_hold_type(id):
@login_required
def delete_hold_type(id):
# hold = HoldTypes()
hold.DeleteHoldType(request, id) # ✅
hold.DeleteHoldType(request, id)
return redirect(url_for("hold_types.add_hold_type"))

View File

@@ -1,5 +1,3 @@
# controllers/invoice_controller.py
from flask import Blueprint, request, jsonify, render_template
from flask_login import login_required, current_user
from model.Invoice import *
@@ -37,7 +35,6 @@ def add_invoice():
village_id = village_result['Village_Id']
invoice_id = insert_invoice(data, village_id)
# assign_subcontractor(data, village_id)
insert_hold_types(data, invoice_id)
@@ -81,7 +78,6 @@ def edit_invoice(invoice_id):
if request.method == 'POST':
data = request.form
update_invoice(data, invoice_id)
# update_inpayment(data)
log_action("Edit invoice", f"edited invoice '{invoice_id}'")
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200

View File

@@ -29,7 +29,6 @@ def add_payment():
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.update_inpayment(subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr)
return redirect(url_for('payment_bp.add_payment'))

View File

@@ -1,11 +1,9 @@
from flask import Blueprint, render_template, send_from_directory,send_file
from flask_login import login_required
# from model.PmcReport import PmcReport
from model.UnifiedReportService import UnifiedReportService
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):
@@ -18,15 +16,15 @@ def pmc_report(pmc_no):
info=data["info"],
invoices=data["invoices"],
hold_types=data["hold_types"],
hold_data=data["hold_data"], # <-- add this line
hold_data=data["hold_data"],
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 ----------------
# ---------------- Contractor Download Report by pmc no ----------------
@pmc_report_bp.route("/download_pmc_report/<pmc_no>")
@login_required
def download_pmc_report(pmc_no):

View File

@@ -5,7 +5,7 @@ from model.Report import ReportHelper
from model.Log import LogHelper
import os
from model.UnifiedReportService import UnifiedReportService
# DOWNLOAD_FOLDER = "static/download"
report_bp = Blueprint("report", __name__)
@@ -33,7 +33,6 @@ def search_contractor():
return jsonify(data)
# ---------------- Contractor Report by contractor id ----------------
@report_bp.route('/contractor_report/<int:contractor_id>')
@login_required
def contractor_report(contractor_id):
@@ -47,8 +46,7 @@ def contractor_report(contractor_id):
**data
)
# # ---------------- Contractor Download Report by contractor id ----------------
# ---------------- Contractor Download Report by contractor id ----------------
@report_bp.route('/download_report/<int:contractor_id>')
def download_report(contractor_id):

View File

@@ -4,13 +4,11 @@ from model.State import State
state_bp = Blueprint('state', __name__)
state = State()
# ----- State page ------
@state_bp.route('/add_state', methods=['GET', 'POST'])
@login_required
def add_state():
# state = State()
if request.method == 'POST':
state.AddState(request=request)
return state.resultMessage
@@ -24,8 +22,6 @@ def add_state():
@login_required
def check_state():
# state = State()
return state.CheckState(request=request)
# ----- State delete by state id ------
@@ -33,8 +29,6 @@ def check_state():
@login_required
def deleteState(id):
# state = State()
state.DeleteState(request=request, id=id)
if not state.isSuccess:
@@ -47,8 +41,6 @@ def deleteState(id):
@login_required
def editState(id):
# state = State()
if request.method == 'POST':
state.EditState(request=request, id=id)

View File

@@ -15,7 +15,6 @@ subcontractor_bp = Blueprint('subcontractor', __name__)
def subcontract():
sub = Subcontractor()
# ---------------- GET ----------------
if request.method == 'GET':
subcontractor = sub.GetAllSubcontractors(request)

View File

@@ -1,7 +1,3 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required
@@ -18,8 +14,6 @@ village = Village()
@login_required
def add_village():
# village = Village()
if request.method == 'POST':
village.AddVillage(request=request)
return village.resultMessage
@@ -79,17 +73,17 @@ def get_blocks(district_id):
@village_bp.route('/check_village', methods=['POST'])
@login_required
def check_village():
# village = Village()
return village.CheckVillage(request=request)
@village_bp.route('/delete_village/<int:village_id>')
@login_required
def delete_village(village_id):
# village = Village()
village.DeleteVillage(request=request, village_id=village_id)
# ✅ Convert resultMessage to string if it's a Response or tuple
# resultMessage to string if it's a Response or tuple
raw_msg = village.resultMessage
if isinstance(raw_msg, tuple):
@@ -112,8 +106,6 @@ def delete_village(village_id):
@login_required
def edit_village(village_id):
# village = Village()
if request.method == 'POST':
village.EditVillage(request=request, village_id=village_id)
@@ -135,7 +127,6 @@ def edit_village(village_id):
)
else:
# ✅ FIXED HERE (removed request)
village_data = village.GetVillageByID(id=village_id)
if not village.isSuccess:

View File

@@ -9591,3 +9591,173 @@ Timestamp: 2026-04-04 14:29:44 | User: Unknown | Action: Search Contractor | Det
Timestamp: 2026-04-04 14:35:59 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 14:35:59 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 14:36:00 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 14:59:22 | User: Unknown | Action: Login | Details:
Timestamp: 2026-04-04 15:29:49 | User: Unknown | Action: Login | Details:
Timestamp: 2026-04-04 15:30:06 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-04 15:30:23 | User: Unknown | Action: Add Hold Type | Details:
Timestamp: 2026-04-04 15:30:39 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-04 15:31:15 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:31:23 | User: Unknown | Action: Add Hold Type | Details:
Timestamp: 2026-04-04 15:31:39 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-04 15:31:41 | User: Unknown | Action: Add State | Details:
Timestamp: 2026-04-04 15:31:52 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:31:53 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:31:54 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:31:55 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:31:55 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:31:55 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:31:56 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:32:00 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:32:02 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:32:09 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:32:10 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:32:10 | User: Unknown | Action: Add Item | Details:
Timestamp: 2026-04-04 15:32:20 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-04 15:32:21 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-04 15:32:21 | User: Unknown | Action: Add Block | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:29 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:32:37 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:32:39 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:36:58 | User: Unknown | Action: Login | Details:
Timestamp: 2026-04-04 15:37:34 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-04 15:37:52 | User: Unknown | Action: Add Hold Type | Details:
Timestamp: 2026-04-04 15:37:59 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:38:02 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:39:23 | User: Unknown | Action: Edit Payment | Details:
Timestamp: 2026-04-04 15:39:39 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:39:40 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:39:41 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:40:24 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:40:24 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:40:26 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:42:08 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:42:09 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:43:28 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-04 15:43:44 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-04 15:43:45 | User: Unknown | Action: Add State | Details:
Timestamp: 2026-04-04 15:43:57 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-04 15:44:11 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:44:12 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-04 15:44:12 | User: Unknown | Action: Add Item | Details:
Timestamp: 2026-04-04 15:44:29 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-04 15:44:30 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-04 15:44:30 | User: Unknown | Action: Add Block | Details:
Timestamp: 2026-04-04 15:44:44 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-04 15:44:50 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:51 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-04 15:44:57 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:44:57 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:44:58 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:45:27 | User: Unknown | Action: Edit Payment | Details:
Timestamp: 2026-04-04 15:45:36 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:45:36 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-04 15:45:38 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:22:00 | User: Unknown | Action: Login | Details:
Timestamp: 2026-04-06 10:22:10 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-06 10:22:11 | User: Unknown | Action: Add State | Details:
Timestamp: 2026-04-06 10:22:21 | User: Unknown | Action: Edit State | Details:
Timestamp: 2026-04-06 10:22:27 | User: Unknown | Action: Delete State | Details:
Timestamp: 2026-04-06 10:22:33 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-06 10:22:36 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-06 10:22:37 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-06 10:22:39 | User: Unknown | Action: Check State | Details:
Timestamp: 2026-04-06 10:22:40 | User: Unknown | Action: Add State | Details:
Timestamp: 2026-04-06 10:22:54 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-06 10:22:54 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-06 10:22:56 | User: Unknown | Action: Add Item | Details:
Timestamp: 2026-04-06 10:23:07 | User: Unknown | Action: Edit Item | Details:
Timestamp: 2026-04-06 10:23:13 | User: Unknown | Action: Delete Item | Details:
Timestamp: 2026-04-06 10:23:18 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-06 10:23:18 | User: Unknown | Action: Check Item | Details:
Timestamp: 2026-04-06 10:23:19 | User: Unknown | Action: Add Item | Details:
Timestamp: 2026-04-06 10:23:44 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-06 10:23:44 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-06 10:23:46 | User: Unknown | Action: Add Block | Details:
Timestamp: 2026-04-06 10:24:01 | User: Unknown | Action: Edit Block | Details:
Timestamp: 2026-04-06 10:24:06 | User: Unknown | Action: Delete Block | Details:
Timestamp: 2026-04-06 10:24:14 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-06 10:24:14 | User: Unknown | Action: Check Block | Details:
Timestamp: 2026-04-06 10:24:15 | User: Unknown | Action: Add Block | Details:
Timestamp: 2026-04-06 10:24:33 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-04-06 10:24:33 | User: Unknown | Action: Check Village | Details:
Timestamp: 2026-04-06 10:24:34 | User: Unknown | Action: Add Village | Details:
Timestamp: 2026-04-06 10:24:46 | User: Unknown | Action: Edit Village | Details:
Timestamp: 2026-04-06 10:24:53 | User: Unknown | Action: Delete Village | Details:
Timestamp: 2026-04-06 10:25:21 | User: Unknown | Action: Add Subcontractor | Details:
Timestamp: 2026-04-06 10:25:31 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-04-06 10:25:52 | User: Unknown | Action: Add invoice | Details:
Timestamp: 2026-04-06 10:25:57 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-04-06 10:26:22 | User: Unknown | Action: Edit invoice | Details:
Timestamp: 2026-04-06 10:26:24 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-04-06 10:27:37 | User: Unknown | Action: Add Payment | Details:
Timestamp: 2026-04-06 10:28:11 | User: Unknown | Action: Add GSTRelease | Details:
Timestamp: 2026-04-06 10:28:11 | User: Unknown | Action: Add GST Release | Details:
Timestamp: 2026-04-06 10:28:45 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:28:47 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:30:41 | User: Unknown | Action: Edit Payment | Details:
Timestamp: 2026-04-06 10:30:51 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:30:52 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:32:30 | User: Unknown | Action: Upload Excel File | Details:
Timestamp: 2026-04-06 10:32:50 | User: Unknown | Action: Add Hold Type | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:32:57 | User: Unknown | Action: Data saved | Details:
Timestamp: 2026-04-06 10:33:04 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:33:06 | User: Unknown | Action: Search Contractor | Details:
Timestamp: 2026-04-06 10:37:23 | User: Unknown | Action: Get hold type | Details:
Timestamp: 2026-04-06 10:37:36 | User: Unknown | Action: Delete invoice | Details:
Timestamp: 2026-04-06 10:37:55 | User: Unknown | Action: Delete Payment | Details:
Timestamp: 2026-04-06 10:38:07 | User: Unknown | Action: Delete GSTRelease | Details:
Timestamp: 2026-04-06 10:38:07 | User: Unknown | Action: Delete GST Release | Details:
Timestamp: 2026-04-06 10:39:39 | User: Unknown | Action: Get hold type | Details:

View File

@@ -1,14 +1,4 @@
from flask import Blueprint, render_template, request, redirect, url_for, jsonify
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogData, LogHelper
import os
import config
import re
import mysql.connector
from mysql.connector import Error
from model.ItemCRUD import ItemCRUD, itemCRUDMapping

View File

@@ -1,6 +1,5 @@
from mysql.connector import Error
import config
from datetime import datetime
class ContractorInfo:
@@ -24,39 +23,39 @@ class ContractorInfo:
if connection.is_connected():
connection.close()
# def fetchalldata(self):
# """Fetch hold types and invoices for contractor."""
# data = {}
# try:
# connection = config.get_db_connection()
# with connection.cursor(dictionary=True, buffered=True) as cursor:
# # Fetch Hold Types
# cursor.callproc('GetHoldAmountsAndHoldTypeByCtr', [self.ID])
# hold_types = []
# for result in cursor.stored_results():
# hold_types = result.fetchall()
# hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
# data['hold_types'] = hold_type_map
def fetchalldata(self):
"""Fetch hold types and invoices for contractor."""
data = {}
try:
connection = config.get_db_connection()
with connection.cursor(dictionary=True, buffered=True) as cursor:
# Fetch Hold Types
cursor.callproc('GetHoldAmountsAndHoldTypeByCtr', [self.ID])
hold_types = []
for result in cursor.stored_results():
hold_types = result.fetchall()
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types}
data['hold_types'] = hold_type_map
# # Fetch Invoices
# cursor.callproc('GetInvoicesByContractor', [self.ID])
# invoices = []
# for result in cursor.stored_results():
# invoices = result.fetchall()
# Fetch Invoices
cursor.callproc('GetInvoicesByContractor', [self.ID])
invoices = []
for result in cursor.stored_results():
invoices = result.fetchall()
# # Remove duplicate invoices
# seen_ids = set()
# unique_invoices = []
# for inv in invoices:
# if inv['Invoice_Id'] not in seen_ids:
# seen_ids.add(inv['Invoice_Id'])
# unique_invoices.append(inv)
# data['invoices'] = unique_invoices
# Remove duplicate invoices
seen_ids = set()
unique_invoices = []
for inv in invoices:
if inv['Invoice_Id'] not in seen_ids:
seen_ids.add(inv['Invoice_Id'])
unique_invoices.append(inv)
data['invoices'] = unique_invoices
# except Error as e:
# print(f"Error fetching contractor data: {e}")
# finally:
# if connection.is_connected():
# connection.close()
except Error as e:
print(f"Error fetching contractor data: {e}")
finally:
if connection.is_connected():
connection.close()
# return data
return data

View File

@@ -33,7 +33,7 @@ class HoldTypes:
self.isSuccess = hold.isSuccess
self.resultMessage = hold.resultMessage
# Convert tuple → dictionary
# Convert tuple → dictionary
data = []
for row in rows:
data.append({
@@ -51,7 +51,7 @@ class HoldTypes:
self.isSuccess = hold.isSuccess
self.resultMessage = hold.resultMessage
#Convert tuple → dictionary
#Convert tuple → dictionary
if row:
return {
"hold_type_id": row[0],

View File

@@ -1,11 +1,4 @@
import config
from datetime import datetime
from flask import send_file
import openpyxl
from openpyxl.styles import Font, PatternFill
from model.excel import excel
from model.FolderAndFile import FolderAndFile
class ReportHelper:
isSuccess = False

View File

@@ -6,18 +6,18 @@ from decimal import Decimal
class UnifiedReportService:
# Static variable to cache report data
_cached_report_data = None
_cached_contractor_id = None
_cached_pmc_no = None
# _cached_report_data = None
# _cached_contractor_id = None
# _cached_pmc_no = None
@staticmethod
def get_report(contractor_id=None, pmc_no=None):
# If cached and same request, return cached data
if (UnifiedReportService._cached_report_data and
contractor_id == UnifiedReportService._cached_contractor_id and
pmc_no == UnifiedReportService._cached_pmc_no):
return UnifiedReportService._cached_report_data
# if (UnifiedReportService._cached_report_data and
# contractor_id == UnifiedReportService._cached_contractor_id and
# pmc_no == UnifiedReportService._cached_pmc_no):
# return UnifiedReportService._cached_report_data
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True)
@@ -42,25 +42,16 @@ class UnifiedReportService:
# ================= INVOICES =================
if pmc_no:
invoices = ReportHelper.execute_sp(cursor,'GetInvoicesByContractorOrPMCNo',[None, pmc_no]) or []
credit_notes = ReportHelper.execute_sp(cursor,'NewGetCreditNotesByPMCNo',[pmc_no]) or []
gst_rel = ReportHelper.execute_sp(cursor,'GetGSTReleaseDetailsByPMC',[pmc_no]) or []
payments = ReportHelper.execute_sp(cursor,'GetPaymentsByPMC',[pmc_no]) or []
else:
invoices = ReportHelper.execute_sp(cursor,'GetInvoicesByContractorOrPMCNo',[contractor_id, None]) or []
credit_notes = ReportHelper.execute_sp(cursor,'GetCreditNotesByContractor',[contractor_id]) or []
gst_rel = ReportHelper.execute_sp(cursor,'GstReleasesByContractorId',[contractor_id]) or []
payments = ReportHelper.execute_sp(cursor,'GetPayments',[contractor_id]) or []
print(payments)
# ================= HOLD AMOUNTS =================
hold_amounts = ReportHelper.execute_sp(cursor,'GetHoldAmountsByContractor',[contractor_id]) or []
@@ -99,9 +90,11 @@ class UnifiedReportService:
"sum_gst_final_amt": sum(r.get("Final_Amount", 0) or 0 for r in gst_rel),
"sum_gst_total_amt": sum(r.get("Total_Amount", 0) or 0 for r in gst_rel),
"sum_pay_total_amt": sum(Decimal(r.get("Total_amount") or 0) for r in payments),
"sum_pay_payment_amt": sum(Decimal(r.get("Payment_Amount") or 0) for r in payments), # same as above if you want
"sum_pay_payment_amt": sum(Decimal(r.get("Payment_Amount") or 0) for r in payments),
"sum_pay_tds_payment_amt": sum(Decimal(r.get("TDS_Payment_Amount") or 0) for r in payments),
"sum_credit_basic_amt": sum(Decimal(c.get("Basic_Amount") or 0) for c in credit_notes),
"sum_credit_final_amt": sum(Decimal(c.get("Final_Amount") or 0) for c in credit_notes),
"sum_credit_total_amt": sum(Decimal(c.get("Total_Amount") or 0) for c in credit_notes),
}
# Prepare final report
@@ -119,10 +112,10 @@ class UnifiedReportService:
"total": total
}
# Cache the report
UnifiedReportService._cached_report_data = report_data
UnifiedReportService._cached_contractor_id = contractor_id
UnifiedReportService._cached_pmc_no = pmc_no
# # Cache the report
# UnifiedReportService._cached_report_data = report_data
# UnifiedReportService._cached_contractor_id = contractor_id
# UnifiedReportService._cached_pmc_no = pmc_no
return report_data
@@ -155,6 +148,7 @@ class UnifiedReportService:
report_data["credit_note_map"],
report_data["gst_release_map"],
report_data["payments"],
report_data["total"],
output_file
)

View File

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

View File

@@ -1,28 +1,13 @@
import openpyxl
from openpyxl.styles import Font, PatternFill
import config
from flask_login import current_user
from model.Log import LogHelper
# from model.Report import ReportHelper
from model.FolderAndFile import FolderAndFile
class excel:
@staticmethod
# def generate_excel(contractor_id, contInfo, invoices, hold_types, hold_data,
# credit_note_map, gst_release_map, output_file):
def generate_excel(
contractor_id,
info,
invoices,
hold_types,
hold_data,
credit_note_map,
gst_release_map,
payments,
output_file
):
def generate_excel(contractor_id,info, invoices, hold_types, hold_data, credit_note_map, gst_release_map, payments,total,output_file):
workbook = openpyxl.Workbook()
sheet = workbook.active
@@ -62,7 +47,6 @@ class excel:
else ""
)
# key = (pmc_no, invoice_no)
key = (pmc_no)
# Yellow separator
@@ -161,5 +145,43 @@ class excel:
appended_credit_keys.add(key)
# total calculation
hold_totals = {ht['hold_type_id']: 0 for ht in hold_types}
for inv in invoices:
invoice_holds = hold_data.get(inv["Invoice_Id"], {})
for ht_id in hold_totals:
hold_totals[ht_id] += invoice_holds.get(ht_id, 0) or 0
totalrow = ["Total","-","-","-","-","-",total.get('sum_invo_basic_amt', 0)+total.get('sum_gst_basic_amt')+ total.get('sum_credit_basic_amt'),
total.get('sum_invo_debit_amt', 0), total.get('sum_invo_after_debit_amt', 0),total.get('sum_invo_gst_amt', 0),total.get('sum_invo_amt', 0),
total.get('sum_invo_tds_amt', 0),total.get('sum_invo_ds_amt', 0),total.get('sum_invo_on_commission', 0), total.get('sum_invo_hydro_test', 0),
total.get('sum_invo_gst_sd_amt', 0)]
for ht in hold_types:
totalrow.append(hold_totals.get(ht['hold_type_id'], 0))
totalrow += [ total.get('sum_invo_final_amt', 0)+ total.get('sum_gst_final_amt', 0) + total.get('sum_credit_final_amt', 0),"","",
total.get('sum_pay_total_amt', 0)+ total.get('sum_gst_total_amt', 0) + total.get('sum_credit_total_amt', 0)]
sheet.append(totalrow)
# Apply style (color + bold)
for cell in sheet[sheet.max_row]:
cell.fill = PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid") # Yellow
cell.font = Font(bold=True)
# summary report
sheet.append([""])
sheet.append([""])
sheet.append(["","","Summary Report","",""])
summary1 = ["", "Advance / Suplus" , total.get('sum_pay_total_amt', 0)+ total.get('sum_gst_total_amt', 0) + total.get('sum_credit_total_amt', 0)]
summary2 = ["", "Hold Amt", total["sum_invo_hold_amt"]]
summary3 = ["", "Amount With TDS", total["sum_invo_tds_amt"]]
sheet.append(summary1)
sheet.append(summary2)
sheet.append(summary3)
# SAVE ONCE AT END
workbook.save(output_file)

View File

@@ -14,12 +14,6 @@ class GSTRelease:
try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# Print the full form data
print("===== DEBUG: FORM DATA =====")
for key, value in request.form.items():
print(f"{key} : {value}")
print("=============================")
data = {
"PMC_No": request.form.get("PMC_No", "").strip(),
"Invoice_No": request.form.get("Invoice_No", "").strip(),
@@ -30,10 +24,6 @@ class GSTRelease:
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
}
print("===== DEBUG: PARSED DATA =====")
print(data)
print("==============================")
# Add GST Release
gst.AddItem(
request=request,
@@ -42,8 +32,6 @@ class GSTRelease:
storedprocadd="AddGSTReleaseFromExcel"
)
print(f"AddItem result: isSuccess={gst.isSuccess}, message={gst.resultMessage}")
self.isSuccess = gst.isSuccess
self.resultMessage = str(gst.resultMessage)
@@ -69,10 +57,6 @@ class GSTRelease:
"p_gst_release_id": gst_release_id
}
print("===== DEBUG: UPDATE DATA =====")
print(data)
print("==============================")
# Call your stored procedure
gst.EditItem(
request=request,

View File

@@ -16,6 +16,7 @@ form {
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
margin: auto;
gap: 15px;
}

View File

@@ -376,10 +376,12 @@
</a>
</td>
<td>
<a
<!-- <a
href="javascript:void(0);"
onclick="deleteInvoice({{ invoice.Invoice_Id }}, this)"
>
> -->
<a href="javascript:void(0);"
onclick="deleteInvoice('{{ invoice.Invoice_Id }}', this)">
<img
src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
alt="Delete"

View File

@@ -106,7 +106,7 @@
</td>
<td>
<a href="javascript:void(0);"
onclick="deleteVillage({{ village[0] }}, this)">
onclick="deleteVillage('{{ village[0] }}', this)">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
class="icon">
</a>

View File

@@ -1,7 +1,6 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -9,6 +8,7 @@
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">-->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}">
</head>
<body>
<div class="container">
@@ -82,6 +82,30 @@
</div>
</div>
<table class="total-table">
<tr>
<th colspan="2">Summary</th>
</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>
<th>
{% for hold in hold_types %}
{{ hold.hold_type }} ||
{% endfor %}
</th>
<td colspan="{{hold_types|length }}">{{total["sum_invo_hold_amt"]}}</td>
</tr>
{% endif %}
<tr>
<th>Amount With TDS</th>
<td>{{total["sum_invo_tds_amt"]}}</td>
</tr>
</table>
<h3>Invoice Details</h3>
<table border="1" cellpadding="5" cellspacing="0">
@@ -155,9 +179,9 @@
<th>{{ total.get('sum_invo_on_commission', 0) }}</th>
<th>{{ total.get('sum_invo_hydro_test', 0) }}</th>
{% for ht in hold_types %}
<th>{{ total.sum_invo_hold_amt }}</th>
{% endfor %}
{% if hold_types %}
<th colspan="{{hold_types|length }}">{{ total.sum_invo_hold_amt}}</th>
{% endif %}
<th>{{ total.get('sum_invo_gst_sd_amt', 0) }}</th>
<th>{{ total.sum_invo_final_amt }}</th>
@@ -187,17 +211,15 @@
<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.UTR}}</td></TD>
<td>{{gst.UTR}}</td>
</TD>
</tr>
{% endfor %}
<tr>

View File

@@ -1,8 +1,6 @@
{% extends 'base.html' %}
{% block content %}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -10,6 +8,7 @@
<!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">-->
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/subcontractor_report.css') }}">
</head>
<body>
<div class="container">
<h2>Contractor Report</h2>
@@ -72,22 +71,21 @@
<h3>Total</h3>
<table class="total-table">
<tr>
<th colspan="2">{{current_date}}</th>
<th colspan="2">Summary</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>
<th>
{% for hold in hold_types %}
<th>{{ hold.hold_type }}</th>
<td>{{total["sum_invo_hold_amt"]}}</td>
{{ hold.hold_type }} ||
{% endfor %}
</th>
<td colspan="{{hold_types|length }}">{{total["sum_invo_hold_amt"]}}</td>
</tr>
{% endif %}
<tr>
@@ -270,7 +268,8 @@
<td>{{ gst.Basic_Amount }}</td>
<td>{{ gst.Final_Amount }}</td>
<td>{{gst.Total_Amount}}</td>
<td>{{gst.UTR}}</td></TD>
<td>{{gst.UTR}}</td>
</TD>
</tr>
{% endfor %}
@@ -342,7 +341,8 @@
</table>
<a href="{{ url_for('report.download_report', contractor_id=contractor_id) }}" class="download-btn">Download Report</a>
<a href="{{ url_for('report.download_report', contractor_id=contractor_id) }}" class="download-btn">Download
Report</a>
</div>
</body>
{% endblock %}