2 Commits

5 changed files with 392 additions and 516 deletions

View File

@@ -1,98 +1,101 @@
# controllers/invoice_controller.py # 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 *
from model.Log import LogHelper from model.Log import LogHelper
invoice_bp = Blueprint('invoice', __name__) invoice_bp = Blueprint('invoice', __name__)
# -------------------------------- Add Invoice --------------------------------- # ------------------------------- Helpers -------------------------------
@invoice_bp.route('/add_invoice', methods=['GET', 'POST']) def handle_exception(func):
@login_required """Decorator to handle exceptions and return JSON error responses."""
def add_invoice(): def wrapper(*args, **kwargs):
if request.method == 'POST':
try: try:
village_name = request.form.get('village') return func(*args, **kwargs)
village_result = get_village_id(village_name)
if not village_result:
return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400
village_id = village_result['Village_Id']
data = request.form
invoice_id = insert_invoice(data, village_id)
assign_subcontractor(data, village_id)
insert_hold_types(data, invoice_id)
LogHelper.log_action("Add invoice", f"User {current_user.id} Added invoice '{data.get('pmc_no')}'")
return jsonify({"status": "success", "message": "Invoice added successfully"}), 201
except Exception as e: except Exception as e:
return jsonify({"status": "error", "message": str(e)}), 500 return jsonify({"status": "error", "message": str(e)}), 500
wrapper.__name__ = func.__name__
return wrapper
def log_action(action: str, detail: str):
LogHelper.log_action(action, f"User {current_user.id} {detail}")
# ------------------------------- Add Invoice -------------------------------
@invoice_bp.route('/add_invoice', methods=['GET', 'POST'])
@login_required
@handle_exception
def add_invoice():
if request.method == 'POST':
data = request.form
village_name = data.get('village')
village_result = get_village_id(village_name)
if not village_result:
return jsonify({"status": "error", "message": f"Village '{village_name}' not found"}), 400
village_id = village_result['Village_Id']
invoice_id = insert_invoice(data, village_id)
assign_subcontractor(data, village_id)
insert_hold_types(data, invoice_id)
log_action("Add invoice", f"added invoice '{data.get('pmc_no')}'")
return jsonify({"status": "success", "message": "Invoice added successfully"}), 201
invoices = get_all_invoice_details() invoices = get_all_invoice_details()
villages = get_all_villages() villages = get_all_villages()
return render_template('add_invoice.html', invoices=invoices, villages=villages) return render_template('add_invoice.html', invoices=invoices, villages=villages)
# ------------------- Search Subcontractor ------------------- # ------------------------------- Search Subcontractor -------------------------------
@invoice_bp.route('/search_subcontractor', methods=['POST']) @invoice_bp.route('/search_subcontractor', methods=['POST'])
@login_required @login_required
@handle_exception
def search_subcontractor(): def search_subcontractor():
sub_query = request.form.get("query") query = request.form.get("query", "").strip()
results = search_contractors(sub_query) results = search_contractors(query)
if not results: if not results:
return "<li>No subcontractor found</li>" return "<li>No subcontractor found</li>"
output = "".join( return "".join(f"<li data-id='{r['Contractor_Id']}'>{r['Contractor_Name']}</li>" for r in results)
f"<li data-id='{row['Contractor_Id']}'>{row['Contractor_Name']}</li>"
for row in results
)
return output
# ------------------- Get Hold Types ------------------- # ------------------------------- Get Hold Types -------------------------------
@invoice_bp.route('/get_hold_types', methods=['GET']) @invoice_bp.route('/get_hold_types', methods=['GET'])
@login_required @login_required
@handle_exception
def get_hold_types(): def get_hold_types():
hold_types = get_all_hold_types() hold_types = get_all_hold_types()
LogHelper.log_action("Get hold type", f"User {current_user.id} Get hold type '{hold_types}'") log_action("Get hold type", f"retrieved hold types '{hold_types}'")
return jsonify(hold_types) return jsonify(hold_types)
# ------------------- Edit Invoice ------------------- # ------------------------------- Edit Invoice -------------------------------
@invoice_bp.route('/edit_invoice/<int:invoice_id>', methods=['GET', 'POST']) @invoice_bp.route('/edit_invoice/<int:invoice_id>', methods=['GET', 'POST'])
@login_required @login_required
@handle_exception
def edit_invoice(invoice_id): def edit_invoice(invoice_id):
if request.method == 'POST': if request.method == 'POST':
data = request.form data = request.form
update_invoice(data, invoice_id) update_invoice(data, invoice_id)
update_inpayment(data) update_inpayment(data)
log_action("Edit invoice", f"edited invoice '{invoice_id}'")
LogHelper.log_action("Edit invoice", f"User {current_user.id} Edit invoice '{invoice_id}'")
return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200 return jsonify({"status": "success", "message": "Invoice updated successfully"}), 200
invoice = get_invoice_by_id(invoice_id) invoice = get_invoice_by_id(invoice_id)
return render_template('edit_invoice.html', invoice=invoice) return render_template('edit_invoice.html', invoice=invoice)
# ------------------- Delete Invoice ------------------- # ------------------------------- Delete Invoice -------------------------------
@invoice_bp.route('/delete_invoice/<int:invoice_id>', methods=['GET']) @invoice_bp.route('/delete_invoice/<int:invoice_id>', methods=['GET'])
@login_required @login_required
@handle_exception
def delete_invoice_route(invoice_id): def delete_invoice_route(invoice_id):
try: delete_invoice_data(invoice_id, current_user.id)
delete_invoice_data(invoice_id, current_user.id) log_action("Delete invoice", f"deleted invoice '{invoice_id}'")
LogHelper.log_action("Delete Invoice", f"User {current_user.id} deleted Invoice '{invoice_id}'") return jsonify({"status": "success", "message": f"Invoice {invoice_id} deleted successfully."})
return jsonify({
"message": f"Invoice {invoice_id} deleted successfully.",
"status": "success"
})
except Exception as e:
return jsonify({
"message": str(e),
"status": "error"
}), 500

View File

@@ -1,8 +1,11 @@
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
import config import config
from model.Village import Village from model.Village import Village
from model.State import State from model.State import State
@@ -23,7 +26,6 @@ def add_village():
state = State() state = State()
states = state.GetAllStates(request=request) states = state.GetAllStates(request=request)
villages = village.GetAllVillages(request=request) villages = village.GetAllVillages(request=request)
return render_template( return render_template(
@@ -42,7 +44,6 @@ def get_districts(state_id):
cursor = connection.cursor() cursor = connection.cursor()
cursor.callproc("GetDistrictByStateID", [state_id]) cursor.callproc("GetDistrictByStateID", [state_id])
districts = [] districts = []
for rs in cursor.stored_results(): for rs in cursor.stored_results():
@@ -51,15 +52,7 @@ def get_districts(state_id):
cursor.close() cursor.close()
connection.close() connection.close()
district_list = [] return jsonify([{"id": d[0], "name": d[1]} for d in districts])
for d in districts:
district_list.append({
"id": d[0],
"name": d[1]
})
return jsonify(district_list)
# ------------------------- Fetch Blocks ------------------------- # ------------------------- Fetch Blocks -------------------------
@@ -71,7 +64,6 @@ def get_blocks(district_id):
cursor = connection.cursor() cursor = connection.cursor()
cursor.callproc("GetBlocksByDistrictID", [district_id]) cursor.callproc("GetBlocksByDistrictID", [district_id])
blocks = [] blocks = []
for rs in cursor.stored_results(): for rs in cursor.stored_results():
@@ -80,22 +72,13 @@ def get_blocks(district_id):
cursor.close() cursor.close()
connection.close() connection.close()
block_list = [] return jsonify([{"id": b[0], "name": b[1]} for b in blocks])
for b in blocks:
block_list.append({
"id": b[0],
"name": b[1]
})
return jsonify(block_list)
# ------------------------- Check Village ------------------------- # ------------------------- Check Village -------------------------
@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)
@@ -106,14 +89,9 @@ def check_village():
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)
if not village.isSuccess: flash(village.resultMessage, "success" if village.isSuccess else "error")
flash(village.resultMessage, "error")
else:
flash(village.resultMessage, "success")
return redirect(url_for('village.add_village')) return redirect(url_for('village.add_village'))
@@ -135,8 +113,8 @@ def edit_village(village_id):
else: else:
flash(village.resultMessage, "error") flash(village.resultMessage, "error")
village_data = village.GetVillageByID(request=request, id=village_id) village_data = village.GetVillageByID(id=village_id) or []
blocks = village.GetAllBlocks(request=request) blocks = village.GetAllBlocks() or []
return render_template( return render_template(
'edit_village.html', 'edit_village.html',
@@ -145,23 +123,17 @@ def edit_village(village_id):
) )
else: else:
# ✅ FIXED HERE (removed request)
village_data = village.GetVillageByID(request=request, id=village_id) village_data = village.GetVillageByID(id=village_id)
if not village.isSuccess: if not village.isSuccess:
flash(village.resultMessage, "error") flash(village.resultMessage, "error")
return redirect(url_for('village.add_village')) return redirect(url_for('village.add_village'))
blocks = village.GetAllBlocks(request=request) blocks = village.GetAllBlocks() or []
if village_data is None:
village_data = []
if blocks is None:
blocks = []
return render_template( return render_template(
'edit_village.html', 'edit_village.html',
village_data=village_data, village_data=village_data or [],
blocks=blocks blocks=blocks
) )

View File

@@ -1,72 +1,65 @@
import mysql.connector
from mysql.connector import Error from mysql.connector import Error
import config import config
import openpyxl
import os
import re
import ast
from datetime import datetime from datetime import datetime
class ContractorInfo: class ContractorInfo:
ID = "" def __init__(self, contractor_id):
contInfo = None self.ID = contractor_id
def __init__(self, id): self.contInfo = None
self.ID = id
print(id)
self.fetchData() self.fetchData()
def fetchData(self): def fetchData(self):
"""Fetch basic contractor info by ID."""
try: try:
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True) with connection.cursor(dictionary=True, buffered=True) as cursor:
cursor.callproc('GetContractorInfoById', [self.ID]) cursor.callproc('GetContractorInfoById', [self.ID])
for result in cursor.stored_results(): # Get the first result set
self.contInfo = result.fetchone() for result in cursor.stored_results():
self.contInfo = result.fetchone()
print(self.contInfo,flush=True) except Error as e:
print(f"Error fetching contractor info: {e}")
finally: finally:
cursor.close() if connection.is_connected():
connection.close() connection.close()
def fetchalldata(self): def fetchalldata(self):
"""Fetch hold types and invoices for contractor."""
data = {}
try: try:
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True, buffered=True) with connection.cursor(dictionary=True, buffered=True) as cursor:
print("here", flush=True) # Fetch Hold Types
cursor.callproc('GetHoldTypesByContractor', [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
# ---------------- Hold Types ---------------- # Fetch Invoices
cursor = connection.cursor(dictionary=True) cursor.callproc('GetInvoicesByContractor', [self.ID])
invoices = []
for result in cursor.stored_results():
invoices = result.fetchall()
cursor.callproc('GetHoldTypesByContractor', [self.ID]) # Remove duplicate invoices
seen_ids = set()
hold_types = [] unique_invoices = []
for result in cursor.stored_results(): for inv in invoices:
hold_types = result.fetchall() if inv['Invoice_Id'] not in seen_ids:
hold_type_map = {ht['hold_type_id']: ht['hold_type'] for ht in hold_types} seen_ids.add(inv['Invoice_Id'])
unique_invoices.append(inv)
# ---------------- Invoices ---------------- data['invoices'] = unique_invoices
cursor = connection.cursor(dictionary=True)
cursor.callproc('GetInvoicesByContractor', [self.ID])
invoices = []
for result in cursor.stored_results():
invoices = result.fetchall()
# Remove duplicate invoices
invoice_ids_seen = set()
unique_invoices = []
for inv in invoices:
if inv["Invoice_Id"] not in invoice_ids_seen:
invoice_ids_seen.add(inv["Invoice_Id"])
unique_invoices.append(inv)
invoices = unique_invoices
except Error as e:
print(f"Error fetching contractor data: {e}")
finally: finally:
cursor.close() if connection.is_connected():
connection.close() connection.close()
return data

View File

@@ -1,35 +1,76 @@
import config import config
import mysql.connector import mysql.connector
# ------------------- Helper ------------------- # ------------------- Helper Functions -------------------
def clear_results(cursor): def clear_results(cursor):
"""Consume all stored results to prevent cursor issues."""
for r in cursor.stored_results(): for r in cursor.stored_results():
r.fetchall() r.fetchall()
def fetch_one(cursor):
"""Fetch first row from stored results."""
for result in cursor.stored_results():
return result.fetchone()
return None
# ------------------- Get Village Id ------------------- def fetch_all(cursor):
def get_village_id(village_name): """Fetch all rows from stored results."""
data = []
for result in cursor.stored_results():
data.extend(result.fetchall())
return data
def get_numeric_values(data):
"""Return numeric fields for invoices safely."""
return [
float(data.get('basic_amount') or 0),
float(data.get('debit_amount') or 0),
float(data.get('after_debit_amount') or 0),
float(data.get('amount') or 0),
float(data.get('gst_amount') or 0),
float(data.get('tds_amount') or 0),
float(data.get('sd_amount') or 0),
float(data.get('on_commission') or 0),
float(data.get('hydro_testing') or 0),
float(data.get('gst_sd_amount') or 0),
float(data.get('final_amount') or 0),
]
def execute_db_operation(operation_func):
"""General DB operation wrapper with commit/rollback."""
connection = config.get_db_connection() connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
cursor.callproc("GetVillageIdByName", (village_name,))
village_result = None
for rs in cursor.stored_results():
village_result = rs.fetchone()
cursor.close()
connection.close()
return village_result
# ------------------- Insert Invoice -------------------
def insert_invoice(data, village_id):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
try: try:
# 1. Insert Invoice result = operation_func(cursor)
connection.commit()
return result
except Exception:
connection.rollback()
raise
finally:
cursor.close()
connection.close()
# ------------------- Village Functions -------------------
def get_village_id(village_name):
def operation(cursor):
cursor.callproc("GetVillageIdByName", (village_name,))
return fetch_one(cursor)
return execute_db_operation(operation)
def get_all_villages():
def operation(cursor):
cursor.callproc("GetAllVillages")
return fetch_all(cursor)
return execute_db_operation(operation)
# ------------------- Invoice Functions -------------------
def insert_invoice(data, village_id):
def operation(cursor):
# Insert invoice
cursor.callproc('InsertInvoice', [ cursor.callproc('InsertInvoice', [
data.get('pmc_no'), data.get('pmc_no'),
village_id, village_id,
@@ -37,29 +78,14 @@ def insert_invoice(data, village_id):
data.get('invoice_details'), data.get('invoice_details'),
data.get('invoice_date'), data.get('invoice_date'),
data.get('invoice_no'), data.get('invoice_no'),
float(data.get('basic_amount') or 0), *get_numeric_values(data)
float(data.get('debit_amount') or 0),
float(data.get('after_debit_amount') or 0),
float(data.get('amount') or 0),
float(data.get('gst_amount') or 0),
float(data.get('tds_amount') or 0),
float(data.get('sd_amount') or 0),
float(data.get('on_commission') or 0),
float(data.get('hydro_testing') or 0),
float(data.get('gst_sd_amount') or 0),
float(data.get('final_amount') or 0)
]) ])
invoice_row = fetch_one(cursor)
invoice_id = None if not invoice_row:
for result in cursor.stored_results():
row = result.fetchone()
if row:
invoice_id = row.get('invoice_id')
if not invoice_id:
raise Exception("Invoice ID not returned") raise Exception("Invoice ID not returned")
invoice_id = invoice_row.get('invoice_id')
# 2. Insert Inpayment # Insert inpayment
cursor.callproc('InsertInpayment', [ cursor.callproc('InsertInpayment', [
data.get('pmc_no'), data.get('pmc_no'),
village_id, village_id,
@@ -67,221 +93,41 @@ def insert_invoice(data, village_id):
data.get('invoice_details'), data.get('invoice_details'),
data.get('invoice_date'), data.get('invoice_date'),
data.get('invoice_no'), data.get('invoice_no'),
float(data.get('basic_amount') or 0), *get_numeric_values(data),
float(data.get('debit_amount') or 0),
float(data.get('after_debit_amount') or 0),
float(data.get('amount') or 0),
float(data.get('gst_amount') or 0),
float(data.get('tds_amount') or 0),
float(data.get('sd_amount') or 0),
float(data.get('on_commission') or 0),
float(data.get('hydro_testing') or 0),
float(data.get('gst_sd_amount') or 0),
float(data.get('final_amount') or 0),
data.get('subcontractor_id') data.get('subcontractor_id')
]) ])
clear_results(cursor) clear_results(cursor)
connection.commit()
return invoice_id return invoice_id
except Exception as e: return execute_db_operation(operation)
connection.rollback()
raise e
finally:
cursor.close()
connection.close()
# ------------------- Assign Subcontractor -------------------
def assign_subcontractor(data, village_id):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
try:
cursor.callproc('AssignSubcontractor', [
data.get('pmc_no'),
data.get('subcontractor_id'),
village_id
])
clear_results(cursor)
connection.commit()
except Exception as e:
connection.rollback()
raise e
finally:
cursor.close()
connection.close()
# ------------------- Insert Hold Types -------------------
def insert_hold_types(data, invoice_id):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
try:
hold_types = data.getlist('hold_type[]')
hold_amounts = data.getlist('hold_amount[]')
for hold_type, hold_amount in zip(hold_types, hold_amounts):
if not hold_type:
continue
cursor.callproc('GetHoldTypeIdByName', [hold_type])
hold_type_result = None
for result in cursor.stored_results():
hold_type_result = result.fetchone()
if not hold_type_result:
cursor.callproc('InsertHoldType', [hold_type, 0])
cursor.execute("SELECT @_InsertHoldType_1")
hold_type_id = cursor.fetchone()[0]
else:
hold_type_id = hold_type_result['hold_type_id']
hold_amount = float(hold_amount or 0)
cursor.callproc('InsertInvoiceSubcontractorHold', [
data.get('subcontractor_id'),
invoice_id,
hold_type_id,
hold_amount
])
clear_results(cursor)
connection.commit()
except Exception as e:
connection.rollback()
raise e
finally:
cursor.close()
connection.close()
# ------------------- Get All Invoices -------------------
def get_all_invoice_details(): def get_all_invoice_details():
connection = config.get_db_connection() def operation(cursor):
cursor = connection.cursor(dictionary=True) cursor.callproc('GetAllInvoiceDetails')
return fetch_all(cursor)
return execute_db_operation(operation)
cursor.callproc('GetAllInvoiceDetails')
invoices = []
for result in cursor.stored_results():
invoices = result.fetchall()
cursor.close()
connection.close()
return invoices
# ------------------- Get All Villages -------------------
def get_all_villages():
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
cursor.callproc("GetAllVillages")
villages = []
for result in cursor.stored_results():
villages = result.fetchall()
cursor.close()
connection.close()
return villages
# ------------------- Search Contractors -------------------
def search_contractors(sub_query):
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
cursor.callproc('SearchContractorsByName', [sub_query])
results = []
for result in cursor.stored_results():
results = result.fetchall()
cursor.close()
connection.close()
return results
# ------------------- Get All Hold Types -------------------
def get_all_hold_types():
connection = config.get_db_connection()
cursor = connection.cursor(dictionary=True)
cursor.callproc("GetAllHoldTypes")
hold_types = []
for result in cursor.stored_results():
hold_types = result.fetchall()
cursor.close()
connection.close()
return hold_types
# ------------------- Get Invoice By Id -------------------
def get_invoice_by_id(invoice_id): def get_invoice_by_id(invoice_id):
connection = config.get_db_connection() def operation(cursor):
cursor = connection.cursor(dictionary=True) cursor.callproc('GetInvoiceDetailsById', [invoice_id])
invoice = fetch_one(cursor)
cursor.callproc('GetInvoiceDetailsById', [invoice_id]) cursor.callproc('GetHoldAmountsByInvoiceId', [invoice_id])
invoice = None hold_amounts = fetch_all(cursor)
for result in cursor.stored_results(): if invoice:
invoice = result.fetchone() invoice["hold_amounts"] = hold_amounts
return invoice
return execute_db_operation(operation)
cursor.callproc('GetHoldAmountsByInvoiceId', [invoice_id])
hold_amounts = []
for result in cursor.stored_results():
hold_amounts = result.fetchall()
if invoice:
invoice["hold_amounts"] = hold_amounts
cursor.close()
connection.close()
return invoice
# ------------------- Update Invoice -------------------
def update_invoice(data, invoice_id): def update_invoice(data, invoice_id):
connection = config.get_db_connection() def operation(cursor):
cursor = connection.cursor(dictionary=True)
try:
cursor.callproc("GetVillageIdByName", (data.get('village'),)) cursor.callproc("GetVillageIdByName", (data.get('village'),))
village = None village = fetch_one(cursor)
if not village:
for rs in cursor.stored_results(): raise Exception("Village not found")
village = rs.fetchone()
village_id = village['Village_Id'] village_id = village['Village_Id']
numeric = [
float(data.get('basic_amount') or 0),
float(data.get('debit_amount') or 0),
float(data.get('after_debit_amount') or 0),
float(data.get('amount') or 0),
float(data.get('gst_amount') or 0),
float(data.get('tds_amount') or 0),
float(data.get('sd_amount') or 0),
float(data.get('on_commission') or 0),
float(data.get('hydro_testing') or 0),
float(data.get('gst_sd_amount') or 0),
float(data.get('final_amount') or 0),
]
cursor.callproc('UpdateInvoice', [ cursor.callproc('UpdateInvoice', [
data.get('pmc_no'), data.get('pmc_no'),
village_id, village_id,
@@ -289,91 +135,101 @@ def update_invoice(data, invoice_id):
data.get('invoice_details'), data.get('invoice_details'),
data.get('invoice_date'), data.get('invoice_date'),
data.get('invoice_no'), data.get('invoice_no'),
*numeric, *get_numeric_values(data),
invoice_id invoice_id
]) ])
clear_results(cursor) clear_results(cursor)
execute_db_operation(operation)
connection.commit()
except Exception as e:
connection.rollback()
raise e
finally:
cursor.close()
connection.close()
# ------------------- Update Inpayment -------------------
def update_inpayment(data): def update_inpayment(data):
connection = config.get_db_connection() def operation(cursor):
cursor = connection.cursor(dictionary=True)
try:
numeric = [
float(data.get('basic_amount') or 0),
float(data.get('debit_amount') or 0),
float(data.get('after_debit_amount') or 0),
float(data.get('amount') or 0),
float(data.get('gst_amount') or 0),
float(data.get('tds_amount') or 0),
float(data.get('sd_amount') or 0),
float(data.get('on_commission') or 0),
float(data.get('hydro_testing') or 0),
float(data.get('gst_sd_amount') or 0),
float(data.get('final_amount') or 0),
]
cursor.callproc('UpdateInpayment', [ cursor.callproc('UpdateInpayment', [
data.get('work_type'), data.get('work_type'),
data.get('invoice_details'), data.get('invoice_details'),
data.get('invoice_date'), data.get('invoice_date'),
*numeric, *get_numeric_values(data),
data.get('pmc_no'), data.get('pmc_no'),
data.get('invoice_no') data.get('invoice_no')
]) ])
clear_results(cursor) clear_results(cursor)
execute_db_operation(operation)
connection.commit()
except Exception as e:
connection.rollback()
raise e
finally:
cursor.close()
connection.close()
# ------------------- Delete Invoice -------------------
def delete_invoice_data(invoice_id, user_id): def delete_invoice_data(invoice_id, user_id):
connection = config.get_db_connection() def operation(cursor):
cursor = connection.cursor(dictionary=True) # Fetch PMC and Invoice_No from DB
cursor.callproc('GetInvoicePMCById', (invoice_id,))
try:
cursor.callproc('GetInvoicePMCById', [invoice_id])
record = {} record = {}
for result in cursor.stored_results(): for result in cursor.stored_results():
record = result.fetchone() or {} record = result.fetchone() or {}
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
cursor.callproc("DeleteInvoice", (invoice_id,)) cursor.callproc("DeleteInvoice", (invoice_id,))
clear_results(cursor) clear_results(cursor)
cursor.callproc( # Delete inpayment
'DeleteInpaymentByPMCInvoice', cursor.callproc('DeleteInpaymentByPMCInvoice', (pmc_no, invoice_no))
[record['PMC_No'], record['invoice_no']] clear_results(cursor)
)
connection.commit() execute_db_operation(operation)
except Exception as e:
connection.rollback()
raise e
finally: # ------------------- Subcontractor Functions -------------------
cursor.close() def assign_subcontractor(data, village_id):
connection.close() def operation(cursor):
cursor.callproc('AssignSubcontractor', [
data.get('pmc_no'),
data.get('subcontractor_id'),
village_id
])
clear_results(cursor)
execute_db_operation(operation)
# ------------------- Hold Types Functions -------------------
def insert_hold_types(data, invoice_id):
def operation(cursor):
hold_types = data.getlist('hold_type[]')
hold_amounts = data.getlist('hold_amount[]')
for hold_type, hold_amount in zip(hold_types, hold_amounts):
if not hold_type:
continue
cursor.callproc('GetHoldTypeIdByName', [hold_type])
hold_type_result = fetch_one(cursor)
if not hold_type_result:
cursor.callproc('InsertHoldType', [hold_type, 0])
cursor.execute("SELECT @_InsertHoldType_1")
hold_type_id = cursor.fetchone()[0]
else:
hold_type_id = hold_type_result['hold_type_id']
cursor.callproc('InsertInvoiceSubcontractorHold', [
data.get('subcontractor_id'),
invoice_id,
hold_type_id,
float(hold_amount or 0)
])
clear_results(cursor)
execute_db_operation(operation)
def get_all_hold_types():
def operation(cursor):
cursor.callproc("GetAllHoldTypes")
return fetch_all(cursor)
return execute_db_operation(operation)
# ------------------- Contractor Functions -------------------
def search_contractors(sub_query):
def operation(cursor):
cursor.callproc('SearchContractorsByName', [sub_query])
return fetch_all(cursor)
return execute_db_operation(operation)

View File

@@ -1,14 +1,7 @@
# return blocks
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogData, LogHelper
import config import config
import mysql.connector import mysql.connector
from mysql.connector import Error
from model.ItemCRUD import ItemCRUD from model.ItemCRUD import ItemCRUD
@@ -19,103 +12,162 @@ class Village:
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
self.village = ItemCRUD(itemType=ItemCRUDType.Village)
# 🔹 Helper: sync status
def _set_status(self, village):
self.isSuccess = village.isSuccess
self.resultMessage = village.resultMessage
# 🔹 Helper: get request data
def _get_form_data(self, request):
block_id = request.form.get('block_Id')
village_name = request.form.get('Village_Name', '').strip()
return block_id, village_name
def AddVillage(self, request): def AddVillage(self, request):
village = ItemCRUD(itemType=ItemCRUDType.Village) block_id, village_name = self._get_form_data(request)
block_id = request.form.get('block_Id') if not village_name:
village_name = request.form.get('Village_Name', '').strip() self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return
village.AddItem(request=request, parentid=block_id, childname=village_name, storedprocfetch="GetVillageByNameAndBlock", storedprocadd="SaveVillage" ) try:
self.isSuccess = village.isSuccess self.village.AddItem(
self.resultMessage = village.resultMessage request=request,
return parentid=block_id,
#self.isSuccess = False childname=village_name,
storedprocfetch="GetVillageByNameAndBlock",
storedprocadd="SaveVillage"
)
self._set_status(self.village)
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
def GetAllVillages(self, request): def GetAllVillages(self, request):
village = ItemCRUD(itemType=ItemCRUDType.Village)
villagesdata = village.GetAllData(request=request, storedproc="GetAllVillages")
self.isSuccess = village.isSuccess
self.resultMessage = village.resultMessage
return villagesdata
try:
villagesdata = self.village.GetAllData(
request=request,
storedproc="GetAllVillages"
)
self._set_status(self.village)
return villagesdata
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
return []
def CheckVillage(self, request): def CheckVillage(self, request):
village = ItemCRUD(itemType=ItemCRUDType.Village) block_id, village_name = self._get_form_data(request)
block_id = request.form.get('block_Id')
village_name = request.form.get('Village_Name', '').strip() if not village_name:
result = village.CheckItem(request=request, parentid=block_id, childname=village_name, storedprocfetch="GetVillageByNameAndBlocks") self.isSuccess = False
self.isSuccess = village.isSuccess self.resultMessage = "Village name cannot be empty"
self.resultMessage = village.resultMessage return None
return result
try:
result = self.village.CheckItem(
request=request,
parentid=block_id,
childname=village_name,
storedprocfetch="GetVillageByNameAndBlocks"
)
self._set_status(self.village)
return result
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
return None
def DeleteVillage(self, request, village_id): def DeleteVillage(self, request, village_id):
village = ItemCRUD(itemType=ItemCRUDType.Village) try:
self.village.DeleteItem(
request=request,
itemID=village_id,
storedprocDelete="DeleteVillage"
)
self._set_status(self.village)
village.DeleteItem(request=request, itemID=village_id, storedprocDelete="DeleteVillage" ) except Exception as e:
self.isSuccess = village.isSuccess self.isSuccess = False
self.resultMessage = village.resultMessage self.resultMessage = str(e)
return
def EditVillage(self, request, village_id): def EditVillage(self, request, village_id):
corsor=None block_id, village_name = self._get_form_data(request)
village = ItemCRUD(itemType=ItemCRUDType.Village)
block_id = request.form.get('block_Id') if not village_name:
village_name = request.form.get('Village_Name', '').strip()
village.EditItem(request=request,childid=village_id,parentid=block_id,childname=village_name,storedprocupdate="UpdateVillage" )
self.isSuccess = village.isSuccess
self.resultMessage = village.resultMessage
return
# def GetVillageByID(self, request, id):
# village = ItemCRUD(itemType=ItemCRUDType.Village)
# villagedetailsdata = village.GetAllData(request=request, storedproc="GetVillageDetailsById")
# self.isSuccess = village.isSuccess
# self.resultMessage = village.resultMessage
# return villagedetailsdata
def GetVillageByID(self, request, id):
village = ItemCRUD(itemType=ItemCRUDType.Village)
villagedetailsdata = village.GetDataByID(id=id,storedproc="GetVillageDetailsById")
if villagedetailsdata:
self.isSuccess = True
else:
self.isSuccess = False self.isSuccess = False
self.resultMessage = "Village not found" self.resultMessage = "Village name cannot be empty"
return
return villagedetailsdata try:
self.village.EditItem(
request=request,
childid=village_id,
parentid=block_id,
childname=village_name,
storedprocupdate="UpdateVillage"
)
self._set_status(self.village)
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
def GetAllBlocks(self, request): def GetVillageByID(self, id):
try:
villagedetailsdata = self.village.GetDataByID(
id=id,
storedproc="GetVillageDetailsById"
)
if villagedetailsdata:
self.isSuccess = True
else:
self.isSuccess = False
self.resultMessage = "Village not found"
return villagedetailsdata
except Exception as e:
self.isSuccess = False
self.resultMessage = str(e)
return None
def GetAllBlocks(self):
blocks = [] blocks = []
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
connection = config.get_db_connection()
connection = config.get_db_connection()
if not connection: if not connection:
return [] return []
cursor = connection.cursor()
try: try:
cursor.callproc('GetAllBlocks') with connection.cursor() as cursor:
for result in cursor.stored_results(): cursor.callproc('GetAllBlocks')
blocks = result.fetchall()
for result in cursor.stored_results():
blocks.extend(result.fetchall())
self.isSuccess = True self.isSuccess = True
return blocks
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching blocks: {e}") print(f"Error fetching blocks: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response(ResponseHandler.fetch_failure("block"), 500) self.resultMessage = HtmlHelper.json_response(
finally: ResponseHandler.fetch_failure("block"), 500
cursor.close() )
connection.close() return []
return blocks finally:
connection.close()