From 1054d1f7e5aff7cb0993ba7919fe1e49ed8217f9 Mon Sep 17 00:00:00 2001 From: Swapnil9693 Date: Wed, 26 Nov 2025 14:28:15 +0530 Subject: [PATCH] Initial commit --- MAIN2.PY | 26 -- main.py | 49 ++- main1.py | 933 ------------------------------------------------------- 3 files changed, 18 insertions(+), 990 deletions(-) delete mode 100644 MAIN2.PY delete mode 100644 main1.py diff --git a/MAIN2.PY b/MAIN2.PY deleted file mode 100644 index 394fb24..0000000 --- a/MAIN2.PY +++ /dev/null @@ -1,26 +0,0 @@ -from flask import Blueprint, request, jsonify, send_file, current_app, render_template -from datetime import datetime -import ast -import os - -from db import DB # Your existing DB wrapper - - -# ============================================================= -# Base Service (common DB operations) -# ============================================================= -class BaseService: - def __init__(self): - self.db = DB() - - def fetch_all(self, proc, params=None): - return self.db.fetch_all_proc(proc, params) - - def fetch_one(self, proc, params=None): - return self.db.fetch_one_proc(proc, params) - - def execute_proc(self, proc, params=None): - return self.db.exec_proc(proc, params) - - def get_conn(self): - return self.db.get_connection() diff --git a/main.py b/main.py index 19be04e..8c49acb 100644 --- a/main.py +++ b/main.py @@ -568,8 +568,7 @@ def edit_district(district_id): # Retrieve all states for dropdown try: - # cursor.execute("SELECT State_ID, State_Name FROM states") - # states = cursor.fetchall() + cursor.callproc("GetAllStates") for res in cursor.stored_results(): states = res.fetchall() @@ -580,8 +579,7 @@ def edit_district(district_id): # Retrieve district info try: - # cursor.execute("SELECT District_Name, State_Id FROM districts WHERE District_id = %s", (district_id,)) - # districtdata = cursor.fetchone() + cursor.callproc("GetDistrictDataByID", (district_id,)) for rs in cursor.stored_results(): districtdata = rs.fetchone() @@ -596,8 +594,7 @@ def edit_district(district_id): state_id = request.form['state_Id'] try: - # cursor.execute( "UPDATE districts SET District_Name = %s, State_Id = %s WHERE District_id = %s", - # (district_name, state_id, district_id) ) + cursor.callproc("UpdateDistrict", (district_id, state_id, district_name,)) connection.commit() @@ -622,8 +619,7 @@ def add_block(): if connection: cursor = connection.cursor() try: - # cursor.execute("SELECT State_ID, State_Name FROM states") - # states = cursor.fetchall() + cursor.callproc("GetAllStates") for res in cursor.stored_results(): states = res.fetchall() @@ -640,9 +636,7 @@ def add_block(): return json_response(ResponseHandler.invalid_name("block"), 400) try: - # cursor.execute("SELECT * FROM blocks WHERE Block_Name = %s AND District_id = %s", - # (block_name, district_id)) - # existing_block = cursor.fetchone() + cursor.callproc("GetBlockByNameAndDistrict", (block_name, district_id,)) for rs in cursor.stored_results(): existing_block = rs.fetchone() @@ -766,7 +760,7 @@ def delete_block(block_id): if connection: cursor = connection.cursor() try: - # cursor.execute("DELETE FROM blocks WHERE Block_Id = %s", (block_id,)) + cursor.callproc("DeleteBlock", (block_id,)) log_action("Delete Block", f"User {current_user.id} Deleted block '{block_id}'") connection.commit() @@ -906,8 +900,7 @@ def check_village(): if not block_id or not village_name: return json_response({'status': 'error', 'message': 'Block and Village Name are required!'}, 400) - # cursor.execute("SELECT * FROM villages WHERE Village_Name = %s AND Block_Id = %s", (village_name, block_id)) - # existing_village = cursor.fetchone() + cursor.callproc("GetVillageByNameAndBlocks", (village_name, block_id)) for rs in cursor.stored_results(): existing_village = rs.fetchone() @@ -975,11 +968,11 @@ def delete_village(village_id): cursor = connection.cursor() try: - # cursor.execute("DELETE FROM villages WHERE Village_Id = %s", (village_id,)) + cursor.callproc("DeleteVillage", (village_id,)) log_action("Delete villages", f"User {current_user.id} Deletedvillages '{village_id}'") connection.commit() - # return json_response(ResponseHandler.delete_success("village"), 200) + except mysql.connector.Error as e: print(f"Error: {e}") return json_response(ResponseHandler.add_failure("village"), 500) @@ -1074,8 +1067,7 @@ def add_invoice(): hold_count = 0 for hold_type, hold_amount in zip(hold_types, hold_amounts): - # cursor.execute("SELECT hold_type_id FROM hold_types WHERE hold_type = %s", (hold_type,)) - # hold_type_result = cursor.fetchone() + cursor.callproc('GetHoldTypeIdByName', [hold_type]) for result in cursor.stored_results(): hold_type_result = result.fetchone() @@ -1175,7 +1167,7 @@ def get_hold_types(): return jsonify(hold_types) except mysql.connector.Error as e: return ResponseHandler.fetch_failure({str(e)}), 500 - # return jsonify({"status": "error", "message": f"Failed to fetch hold types: {str(e)}"}), 500 + finally: cursor.close() connection.close() @@ -1334,7 +1326,7 @@ def delete_invoice(invoice_id): try: cursor = connection.cursor() - # cursor.execute("DELETE FROM invoice WHERE Invoice_Id = %s", (invoice_id,)) + cursor.callproc("DeleteInvoice", (invoice_id,)) log_action("Delete invoice", f"User {current_user.id} Delete invoice'{ invoice_id}'") @@ -2118,8 +2110,7 @@ def save_data(): SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount, subcontractor_id, 0 ) - # for result in cursor.stored_results(): - # invoice_id = result.fetchone()['invoice_id'] + print("All invoice Details ",args) results = cursor.callproc('SaveInvoice', args) @@ -2207,7 +2198,7 @@ def save_data(): elif Invoice_Details and any( keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']): print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id) - #cursor.callproc("SaveGSTRelease", (PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR)) + cursor.execute( """INSERT INTO gst_release (PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, Contractor_Id) VALUES (%s,%s, %s, %s, %s, %s, %s)""", (PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id)) @@ -2223,7 +2214,7 @@ def save_data(): connection.commit() return jsonify({"success": "Data saved successfully!"}), 200 - # return render_template('uploadExcelFile.html') + except Exception as e: connection.rollback() return jsonify({"error": f"An unexpected error occurred: {e}"}), 500 @@ -2865,10 +2856,7 @@ def pmc_report(pmc_no): ORDER BY invoice_no ASC """, (pmc_no,)) payments = cursor.fetchall() - # cursor.callproc('GetPaymentByPMC', [pmc_no]) - # - # for result in cursor.stored_results(): - # payments = result.fetchall() + total_pay_amount = sum(row.get('Payment_Amount', 0) or 0 for row in payments) total_pay_total = sum(row.get('Total_amount', 0) or 0 for row in payments) @@ -3319,8 +3307,7 @@ def delete_hold_type(id): cursor = connection.cursor() try: - # cursor.execute("SELECT * FROM hold_types WHERE hold_type_id = %s", (id,)) - # hold_type = cursor.fetchone() + cursor.callproc("GetHoldTypesById", (id,)) for hold in cursor.stored_results(): hold_type = hold.fetchone() @@ -3329,7 +3316,7 @@ def delete_hold_type(id): return jsonify({'status': 'error', 'message': 'Hold Type not found.'}), 404 # Proceed with deletion - # cursor.execute("DELETE FROM hold_types WHERE hold_type_id = %s", (id,)) + cursor.callproc("DeleteHoldType", (id,)) connection.commit() return jsonify(ResponseHandler.delete_success('Hold Type')) diff --git a/main1.py b/main1.py deleted file mode 100644 index d8a00ff..0000000 --- a/main1.py +++ /dev/null @@ -1,933 +0,0 @@ -# PART 1 of main.py -# Imports, DB helper, app init, auth/login, logging & small helpers - -from decimal import Decimal -from datetime import datetime -import os -import re -import logging -from logging.handlers import RotatingFileHandler - -from flask import ( - Flask, render_template, request, redirect, url_for, send_from_directory, - flash, jsonify, json, session, current_app -) -from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user -import mysql.connector -from mysql.connector import Error -import config -import openpyxl -import ast -import pandas as pd -from openpyxl.styles import Font -from ldap3 import Server, Connection, ALL, SUBTREE -from ldap3.core.exceptions import LDAPBindError - -# --------------------------- -# App and Login manager init -# --------------------------- -app = Flask(__name__) -app.secret_key = os.environ.get('FLASK_SECRET_KEY', '9f2a1b8c4d6e7f0123456789abcdef01') - -login_manager = LoginManager() -login_manager.init_app(app) -login_manager.login_view = 'login' - -# --------------------------- -# DB helper (dictionary cursor) -# --------------------------- -class DB: - """ - Lightweight DB helper to call stored procedures with dictionary=True cursors. - Usage: - db = DB() - rows = db.fetch_all_proc('GetAllStates') - single = db.fetch_one_proc('GetStateByID', [id]) - db.exec_proc('SaveState', [state_name]) - db.close() - """ - def __init__(self): - self.conn = None - self.cursor = None - try: - self.conn = config.get_db_connection() - except Exception as e: - # Keep None and let callers handle connection absence - self.conn = None - app.logger.exception("DB connection failed: %s", e) - - def _ensure_cursor(self, dict_mode=True): - if not self.conn: - raise mysql.connector.Error("No DB connection") - self.cursor = self.conn.cursor(dictionary=dict_mode) - - def fetch_all_proc(self, proc_name, params=None): - try: - self._ensure_cursor(dict_mode=True) - self.cursor.callproc(proc_name, params or []) - results = [] - for res in self.cursor.stored_results(): - results = res.fetchall() - return results - finally: - self.close_cursor() - - def fetch_one_proc(self, proc_name, params=None): - rows = self.fetch_all_proc(proc_name, params) - return rows[0] if rows else None - - def exec_proc(self, proc_name, params=None): - try: - self._ensure_cursor(dict_mode=True) - self.cursor.callproc(proc_name, params or []) - # advance through any results to avoid unread result issues - for _ in self.cursor.stored_results(): - pass - if self.conn: - self.conn.commit() - finally: - self.close_cursor() - - def close_cursor(self): - try: - if self.cursor: - self.cursor.close() - except Exception: - pass - self.cursor = None - - def close(self): - self.close_cursor() - try: - if self.conn: - self.conn.close() - except Exception: - pass - self.conn = None - -# --------------------------- -# ResponseHandler (centralized messages) -# --------------------------- -class ResponseHandler: - @staticmethod - def invalid_name(entity): - return {'status': 'error', 'message': f'Invalid {entity} name. Only letters and spaces are allowed!'} - - @staticmethod - def already_exists(entity): - return {'status': 'exists', 'message': f'{entity.capitalize()} already exists!'} - - @staticmethod - def add_success(entity): - return {'status': 'success', 'message': f'{entity.capitalize()} added successfully!'} - - @staticmethod - def add_failure(entity): - return {'status': 'error', 'message': f'Failed to add {entity}.'} - - @staticmethod - def is_available(entity): - return {'status': 'available', 'message': f'{entity.capitalize()} name is available!'} - - @staticmethod - def delete_success(entity): - return {'status': 'success', 'message': f'{entity.capitalize()} deleted successfully!'} - - @staticmethod - def delete_failure(entity): - return {'status': 'error', 'message': f'Failed to delete {entity}.'} - - @staticmethod - def update_success(entity): - return {'status': 'success', 'message': f'{entity.capitalize()} updated successfully!'} - - @staticmethod - def update_failure(entity): - return {'status': 'error', 'message': f'Failed to update {entity}.'} - - @staticmethod - def fetch_failure(entity): - return {'status': 'error', 'message': f'Failed to fetch {entity}.'} - -# JSON response helper -def json_response(message_obj, status_code=200): - return jsonify(message_obj), status_code - -# --------------------------- -# Logging helper -# --------------------------- -if not app.debug: - log_file = os.path.join(app.root_path, 'app.log') - handler = RotatingFileHandler(log_file, maxBytes=5*1024*1024, backupCount=2) - handler.setLevel(logging.INFO) - formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]') - handler.setFormatter(formatter) - app.logger.addHandler(handler) - -def log_action(action, details=""): - """Write a user action to activity.log with timestamp and user info.""" - try: - log_file = os.path.join(current_app.root_path, 'activity.log') - except RuntimeError: - # current_app not available (like unit tests). Use app.root_path fallback. - log_file = os.path.join(app.root_path, 'activity.log') - - timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - user = "Unknown" - try: - if current_user and hasattr(current_user, "id"): - user = getattr(current_user, "id", "Unknown") - elif session.get('username'): - user = session.get('username') - except Exception: - pass - - try: - with open(log_file, "a", encoding="utf-8") as f: - f.write(f"Timestamp: {timestamp} | User: {user} | Action: {action} | Details: {details}\n") - except Exception: - app.logger.exception("Failed to write activity log.") - -# --------------------------- -# Simple User class for flask-login -# --------------------------- -class User(UserMixin): - def __init__(self, id, cn=None, username=None, sAMAccountName=None): - self.id = id - self.cn = cn - self.username = username - self.sAMAccountName = sAMAccountName - -@login_manager.user_loader -def load_user(user_id): - # Minimal loader: return User object with id. - return User(user_id) - -# --------------------------- -# Constants & simple validators -# --------------------------- -STR_NAME_PATTERN = r"^[A-Za-z\s]+$" - -def is_valid_name(value): - return bool(re.match(STR_NAME_PATTERN, value.strip())) if value else False - -# --------------------------- -# Basic Routes: index, login, logout -# --------------------------- -@app.route('/') -@login_required -def index(): - return render_template('index.html') - -@app.route('/login', methods=['GET', 'POST']) -def login(): - """ - Login supports: - - static admin/admin123 fallback - - LDAP bind if not static - """ - if request.method == 'POST': - username = request.form.get('username', '').strip() - password = request.form.get('password', '') - - # static fallback - if username == 'admin' and password == 'admin123': - session['username'] = username - login_user(User(username)) - log_action('Login', f"Static admin logged in: {username}") - return redirect(url_for('index')) - - ldap_user_dn = f"uid={username},ou=users,dc=lcepl,dc=org" - try: - conn = Connection(Server('ldap://localhost:389', get_info=ALL), user=ldap_user_dn, password=password, auto_bind=True) - session['username'] = username - login_user(User(username)) - log_action('Login', f"LDAP login: {username}") - conn.unbind() - return redirect(url_for('index')) - except LDAPBindError: - flash('Invalid credentials.', 'danger') - except Exception as e: - app.logger.exception("LDAP error during login") - flash(f'LDAP error: {str(e)}', 'danger') - - return render_template('login.html') - -@app.route('/logout') -@login_required -def logout(): - try: - user_id = getattr(current_user, 'id', 'Unknown') - except Exception: - user_id = session.get('username', 'Unknown') - log_action('Logout', f"User {user_id} logged out") - logout_user() - flash('You have been logged out.', 'info') - return redirect(url_for('login')) - -# --------------------------- -# Activity log viewer -# --------------------------- -@app.route('/activity_log', methods=['GET', 'POST']) -@login_required -def activity_log(): - logs = [] - log_file = os.path.join(current_app.root_path, 'activity.log') - if os.path.exists(log_file): - with open(log_file, 'r', encoding='utf-8') as f: - for line in f: - parts = line.strip().split(" | ") - if len(parts) == 4: - logs.append({ - "timestamp": parts[0].replace("Timestamp:", "").strip(), - "user": parts[1].replace("User:", "").strip(), - "action": parts[2].replace("Action:", "").strip(), - "details": parts[3].replace("Details:", "").strip() - }) - - # Filters - start_date = request.values.get("start_date") - end_date = request.values.get("end_date") - username = request.values.get("username") - - filtered_logs = logs - # date filter - if start_date or end_date: - try: - start_dt = datetime.strptime(start_date, "%Y-%m-%d") if start_date else datetime.min - end_dt = datetime.strptime(end_date, "%Y-%m-%d") if end_date else datetime.max - end_dt = end_dt.replace(hour=23, minute=59, second=59) - filtered_logs = [ - log for log in filtered_logs - if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt - ] - except Exception: - app.logger.exception("activity_log date filter parse error") - - if username: - filtered_logs = [log for log in filtered_logs if username.lower() in log["user"].lower()] - - return render_template('activity_log.html', logs=filtered_logs, start_date=start_date, end_date=end_date, username=username) - -# PART 2 of main.py -# -------------------------------------------- -# STATE, DISTRICT, BLOCK, VILLAGE MANAGEMENT -# -------------------------------------------- - -# ---------------- STATE ---------------- -@app.route('/add_state', methods=['GET', 'POST']) -@login_required -def add_state(): - db = DB() - - if request.method == 'POST': - state_name = request.form['state_Name'].strip() - - if not is_valid_name(state_name): - db.close() - return json_response(ResponseHandler.invalid_name("state"), 400) - - existing = db.fetch_one_proc('CheckStateExists', [state_name]) - if existing: - db.close() - return json_response(ResponseHandler.already_exists("state"), 409) - - db.exec_proc('SaveState', [state_name]) - log_action('Add State', f"State added: {state_name}") - db.close() - return json_response(ResponseHandler.add_success("state"), 200) - - statedata = db.fetch_all_proc('GetAllStates') - db.close() - return render_template('add_state.html', statedata=statedata) - - -@app.route('/delete_state/', methods=['POST']) -@login_required -def delete_state(id): - db = DB() - try: - db.exec_proc('DeleteState', [id]) - log_action('Delete State', f"Deleted state id={id}") - return json_response(ResponseHandler.delete_success("state")) - except Exception as e: - app.logger.exception("DeleteState failed: %s", e) - return json_response(ResponseHandler.delete_failure("state"), 500) - finally: - db.close() - - -@app.route('/update_state/', methods=['POST']) -@login_required -def update_state(id): - db = DB() - state_name = request.form.get('state_Name', '').strip() - - if not is_valid_name(state_name): - db.close() - return json_response(ResponseHandler.invalid_name("state"), 400) - - try: - db.exec_proc('UpdateStateById', [id, state_name]) - log_action('Update State', f"Updated state id={id}, name={state_name}") - return json_response(ResponseHandler.update_success("state")) - except Exception as e: - app.logger.exception("UpdateState failed: %s", e) - return json_response(ResponseHandler.update_failure("state"), 500) - finally: - db.close() - - -# ---------------- DISTRICT ---------------- -@app.route('/add_district', methods=['GET', 'POST']) -@login_required -def add_district(): - db = DB() - - if request.method == 'POST': - state_id = request.form.get('state_id') - district_name = request.form.get('district_Name', '').strip() - - if not is_valid_name(district_name): - db.close() - return json_response(ResponseHandler.invalid_name("district"), 400) - - existing = db.fetch_one_proc('CheckDistrictExists', [state_id, district_name]) - if existing: - db.close() - return json_response(ResponseHandler.already_exists("district"), 409) - - db.exec_proc('SaveDistrict', [state_id, district_name]) - log_action('Add District', f"District added: {district_name} (state_id={state_id})") - db.close() - return json_response(ResponseHandler.add_success("district"), 200) - - statedata = db.fetch_all_proc('GetAllStates') - districtdata = db.fetch_all_proc('GetAllDistricts') - db.close() - return render_template('add_district.html', statedata=statedata, districtdata=districtdata) - - -@app.route('/delete_district/', methods=['POST']) -@login_required -def delete_district(id): - db = DB() - try: - db.exec_proc('DeleteDistrict', [id]) - log_action('Delete District', f"Deleted district id={id}") - return json_response(ResponseHandler.delete_success("district")) - except Exception as e: - app.logger.exception("DeleteDistrict failed: %s", e) - return json_response(ResponseHandler.delete_failure("district"), 500) - finally: - db.close() - - -@app.route('/update_district/', methods=['POST']) -@login_required -def update_district(id): - db = DB() - state_id = request.form.get('state_id') - district_name = request.form.get('district_Name', '').strip() - - if not is_valid_name(district_name): - db.close() - return json_response(ResponseHandler.invalid_name("district"), 400) - - try: - db.exec_proc('UpdateDistrictById', [id, state_id, district_name]) - log_action('Update District', f"Updated district id={id}, name={district_name}") - return json_response(ResponseHandler.update_success("district")) - except Exception as e: - app.logger.exception("UpdateDistrict failed: %s", e) - return json_response(ResponseHandler.update_failure("district"), 500) - finally: - db.close() - - -# ---------------- BLOCK ---------------- -@app.route('/add_block', methods=['GET', 'POST']) -@login_required -def add_block(): - db = DB() - - if request.method == 'POST': - district_id = request.form.get('district_id') - block_name = request.form.get('block_Name', '').strip() - - if not is_valid_name(block_name): - db.close() - return json_response(ResponseHandler.invalid_name("block"), 400) - - existing = db.fetch_one_proc('CheckBlockExists', [district_id, block_name]) - if existing: - db.close() - return json_response(ResponseHandler.already_exists("block"), 409) - - db.exec_proc('SaveBlock', [district_id, block_name]) - log_action('Add Block', f"Block added: {block_name} (district_id={district_id})") - db.close() - return json_response(ResponseHandler.add_success("block"), 200) - - districtdata = db.fetch_all_proc('GetAllDistricts') - blockdata = db.fetch_all_proc('GetAllBlocks') - db.close() - return render_template('add_block.html', districtdata=districtdata, blockdata=blockdata) - - -@app.route('/delete_block/', methods=['POST']) -@login_required -def delete_block(id): - db = DB() - try: - db.exec_proc('DeleteBlock', [id]) - log_action('Delete Block', f"Deleted block id={id}") - return json_response(ResponseHandler.delete_success("block")) - except Exception as e: - app.logger.exception("DeleteBlock failed: %s", e) - return json_response(ResponseHandler.delete_failure("block"), 500) - finally: - db.close() - - -@app.route('/update_block/', methods=['POST']) -@login_required -def update_block(id): - db = DB() - district_id = request.form.get('district_id') - block_name = request.form.get('block_Name', '').strip() - - if not is_valid_name(block_name): - db.close() - return json_response(ResponseHandler.invalid_name("block"), 400) - - try: - db.exec_proc('UpdateBlockById', [id, district_id, block_name]) - log_action('Update Block', f"Updated block id={id}, name={block_name}") - return json_response(ResponseHandler.update_success("block")) - except Exception as e: - app.logger.exception("UpdateBlock failed: %s", e) - return json_response(ResponseHandler.update_failure("block"), 500) - finally: - db.close() - - -# ---------------- VILLAGE ---------------- -@app.route('/add_village', methods=['GET', 'POST']) -@login_required -def add_village(): - db = DB() - - if request.method == 'POST': - block_id = request.form.get('block_id') - village_name = request.form.get('village_Name', '').strip() - - if not is_valid_name(village_name): - db.close() - return json_response(ResponseHandler.invalid_name("village"), 400) - - existing = db.fetch_one_proc('CheckVillageExists', [block_id, village_name]) - if existing: - db.close() - return json_response(ResponseHandler.already_exists("village"), 409) - - db.exec_proc('SaveVillage', [block_id, village_name]) - log_action('Add Village', f"Village added: {village_name} (block_id={block_id})") - db.close() - return json_response(ResponseHandler.add_success("village"), 200) - - blockdata = db.fetch_all_proc('GetAllBlocks') - villagedata = db.fetch_all_proc('GetAllVillages') - db.close() - return render_template('add_village.html', blockdata=blockdata, villagedata=villagedata) - - -@app.route('/delete_village/', methods=['POST']) -@login_required -def delete_village(id): - db = DB() - try: - db.exec_proc('DeleteVillage', [id]) - log_action('Delete Village', f"Deleted village id={id}") - return json_response(ResponseHandler.delete_success("village")) - except Exception as e: - app.logger.exception("DeleteVillage failed: %s", e) - return json_response(ResponseHandler.delete_failure("village"), 500) - finally: - db.close() - - -@app.route('/update_village/', methods=['POST']) -@login_required -def update_village(id): - db = DB() - block_id = request.form.get('block_id') - village_name = request.form.get('village_Name', '').strip() - - if not is_valid_name(village_name): - db.close() - return json_response(ResponseHandler.invalid_name("village"), 400) - - try: - db.exec_proc('UpdateVillageById', [id, block_id, village_name]) - log_action('Update Village', f"Updated village id={id}, name={village_name}") - return json_response(ResponseHandler.update_success("village")) - except Exception as e: - app.logger.exception("UpdateVillage failed: %s", e) - return json_response(ResponseHandler.update_failure("village"), 500) - finally: - db.close() - -# ----------------------------------- -# INVOICE ENTRY -# ----------------------------------- - -@app.route('/invoice_entry', methods=['GET', 'POST']) -@login_required -def invoice_entry(): - db = DB() - - if request.method == 'POST': - inv_no = request.form['Invoice_No'].strip() - inv_date = request.form['Invoice_Date'] - state_id = request.form['state'] - district_id = request.form['district'] - block_id = request.form['block'] - village_id = request.form['village'] - subcontractor_id = request.form['subcontractor'] - work_type_id = request.form['work_type'] - final_amount = request.form['Final_Amount'] - - # Check duplicate invoice number - exists = db.fetch_one_proc("CheckInvoiceExists", [inv_no]) - if exists: - db.close() - return json_response(ResponseHandler.already_exists("invoice"), 409) - - db.exec_proc("InsertInvoice", [ - inv_no, inv_date, - state_id, district_id, block_id, village_id, - subcontractor_id, work_type_id, final_amount - ]) - db.close() - - log_action("Add Invoice", f"Invoice: {inv_no}") - return json_response(ResponseHandler.add_success("invoice"), 200) - - # GET REQUEST → Load dropdown data - statedata = db.fetch_all_proc("GetAllStates") - districtdata = db.fetch_all_proc("GetDistrictDetails") - blockdata = db.fetch_all_proc("GetBlockDetails") - villagedata = db.fetch_all_proc("GetVillageDetails") - subcontractordata = db.fetch_all_proc("GetSubcontractorDetails") - worktypedata = db.fetch_all_proc("GetWorkTypeDetails") - invoicedata = db.fetch_all_proc("GetInvoiceDetails") - db.close() - - return render_template('invoice_entry.html', - statedata=statedata, districtdata=districtdata, - blockdata=blockdata, villagedata=villagedata, - subcontractordata=subcontractordata, - worktypedata=worktypedata, - invoicedata=invoicedata) - - -@app.route('/delete_invoice/', methods=['POST']) -@login_required -def delete_invoice(id): - db = DB() - db.exec_proc("DeleteInvoice", [id]) - db.close() - - log_action("Delete Invoice", f"Invoice ID: {id}") - return json_response(ResponseHandler.delete_success("invoice"), 200) - - -@app.route('/update_invoice', methods=['POST']) -@login_required -def update_invoice(): - invoice_id = request.form['invoice_id'] - inv_no = request.form['Invoice_No'].strip() - inv_date = request.form['Invoice_Date'] - state_id = request.form['state'] - district_id = request.form['district'] - block_id = request.form['block'] - village_id = request.form['village'] - subcontractor_id = request.form['subcontractor'] - work_type_id = request.form['work_type'] - final_amount = request.form['Final_Amount'] - - db = DB() - db.exec_proc("UpdateInvoice", [ - invoice_id, inv_no, inv_date, - state_id, district_id, block_id, village_id, - subcontractor_id, work_type_id, final_amount - ]) - db.close() - - log_action("Update Invoice", f"Invoice ID {invoice_id}") - return json_response(ResponseHandler.update_success("invoice"), 200) - - -# ----------------------------------- -# HOLD ENTRY -# ----------------------------------- - -@app.route('/hold_entry', methods=['GET', 'POST']) -@login_required -def hold_entry(): - db = DB() - - if request.method == 'POST': - invoice_id = request.form['invoice'] - hold_type_id = request.form['hold_type'] - remarks = request.form['Remarks'].strip() - - db.exec_proc("InsertHold", [invoice_id, hold_type_id, remarks]) - db.close() - log_action("Add Hold", f"Invoice ID: {invoice_id}") - return json_response(ResponseHandler.add_success("hold"), 200) - - invoicedata = db.fetch_all_proc("GetInvoiceDetails") - holdtypedata = db.fetch_all_proc("GetHoldTypeDetails") - holddata = db.fetch_all_proc("GetHoldDetails") - db.close() - - return render_template('hold_entry.html', - invoicedata=invoicedata, - holdtypedata=holdtypedata, - holddata=holddata) - - -@app.route('/delete_hold/', methods=['POST']) -@login_required -def delete_hold(id): - db = DB() - db.exec_proc("DeleteHold", [id]) - db.close() - - log_action("Delete Hold", f"Hold ID: {id}") - return json_response(ResponseHandler.delete_success("hold"), 200) - - -# ----------------------------------- -# PAYMENT ENTRY -# ----------------------------------- - -@app.route('/payment_entry', methods=['GET', 'POST']) -@login_required -def payment_entry(): - db = DB() - - if request.method == 'POST': - invoice_id = request.form['invoice'] - payment_date = request.form['Payment_Date'] - payment_amt = request.form['Payment_Amount'] - tds_amt = request.form['TDS_Payment_Amount'] - total = request.form['Total_amount'] - utr = request.form['utr'].strip() - - db.exec_proc("InsertPayment", [ - invoice_id, payment_date, payment_amt, tds_amt, total, utr - ]) - db.close() - - log_action("Add Payment", f"Invoice ID: {invoice_id}") - return json_response(ResponseHandler.add_success("payment"), 200) - - invoicedata = db.fetch_all_proc("GetInvoiceDetails") - paymentdata = db.fetch_all_proc("GetPaymentDetails") - db.close() - - return render_template('payment_entry.html', - invoicedata=invoicedata, - paymentdata=paymentdata) - - -@app.route('/delete_payment/', methods=['POST']) -@login_required -def delete_payment(id): - db = DB() - db.exec_proc("DeletePayment", [id]) - db.close() - - log_action("Delete Payment", f"Payment ID: {id}") - return json_response(ResponseHandler.delete_success("payment"), 200) - -# ----------------------------------- -# SUBCONTRACTOR MANAGEMENT -# ----------------------------------- - -@app.route('/add_subcontractor', methods=['GET', 'POST']) -@login_required -def add_subcontractor(): - db = DB() - - if request.method == 'POST': - subcontractor_name = request.form['subcontractor_Name'].strip() - mobile_no = request.form['Mobile_No'].strip() - - if not subcontractor_name: - return json_response(ResponseHandler.invalid_name("subcontractor"), 400) - - exists = db.fetch_one_proc("CheckSubcontractorExists", [subcontractor_name]) - if exists: - db.close() - return json_response(ResponseHandler.already_exists("subcontractor"), 409) - - db.exec_proc("SaveSubcontractor", [subcontractor_name, mobile_no]) - db.close() - log_action("Add Subcontractor", f"Name: {subcontractor_name}") - return json_response(ResponseHandler.add_success("subcontractor"), 200) - - subcontractordata = db.fetch_all_proc("GetSubcontractorDetails") - db.close() - return render_template('add_subcontractor.html', subcontractordata=subcontractordata) - - -@app.route('/delete_subcontractor/', methods=['POST']) -@login_required -def delete_subcontractor(id): - db = DB() - db.exec_proc("DeleteSubcontractor", [id]) - db.close() - log_action("Delete Subcontractor", f"ID: {id}") - return json_response(ResponseHandler.delete_success("subcontractor"), 200) - - -@app.route('/update_subcontractor', methods=['POST']) -@login_required -def update_subcontractor(): - subcontractor_id = request.form['subcontractor_id'] - subcontractor_name = request.form['subcontractor_Name'].strip() - mobile_no = request.form['Mobile_No'].strip() - - db = DB() - db.exec_proc("UpdateSubcontractor", [subcontractor_id, subcontractor_name, mobile_no]) - db.close() - log_action("Update Subcontractor", f"ID {subcontractor_id}") - return json_response(ResponseHandler.update_success("subcontractor"), 200) - - -# ----------------------------------- -# WORK TYPE MANAGEMENT -# ----------------------------------- - -@app.route('/add_work_type', methods=['GET', 'POST']) -@login_required -def add_work_type(): - db = DB() - - if request.method == 'POST': - work_type_name = request.form['worktype_Name'].strip() - - if not is_valid_name(work_type_name): - return json_response(ResponseHandler.invalid_name("work type"), 400) - - exists = db.fetch_one_proc("CheckWorkTypeExists", [work_type_name]) - if exists: - db.close() - return json_response(ResponseHandler.already_exists("work type"), 409) - - db.exec_proc("SaveWorkType", [work_type_name]) - db.close() - - log_action("Add Work Type", f"Name: {work_type_name}") - return json_response(ResponseHandler.add_success("work type"), 200) - - worktypedata = db.fetch_all_proc("GetWorkTypeDetails") - db.close() - return render_template('add_work_type.html', worktypedata=worktypedata) - - -@app.route('/delete_work_type/', methods=['POST']) -@login_required -def delete_work_type(id): - db = DB() - db.exec_proc("DeleteWorkType", [id]) - db.close() - log_action("Delete Work Type", f"ID: {id}") - return json_response(ResponseHandler.delete_success("work type"), 200) - - -@app.route('/update_work_type', methods=['POST']) -@login_required -def update_work_type(): - work_type_id = request.form['worktype_id'] - work_type_name = request.form['worktype_Name'].strip() - - if not is_valid_name(work_type_name): - return json_response(ResponseHandler.invalid_name("work type"), 400) - - db = DB() - db.exec_proc("UpdateWorkTypeById", [work_type_id, work_type_name]) - db.close() - log_action("Update Work Type", f"ID {work_type_id}") - return json_response(ResponseHandler.update_success("work type"), 200) - - -# ----------------------------------- -# EXCEL BULK UPLOAD (INVOICE) -# ----------------------------------- - -@app.route('/upload_excel', methods=['GET', 'POST']) -@login_required -def upload_excel(): - if request.method == 'POST': - file = request.files.get("file") - if not file: - flash("No file selected.", "danger") - return redirect(url_for("upload_excel")) - - filepath = os.path.join(app.root_path, "uploads", file.filename) - os.makedirs(os.path.dirname(filepath), exist_ok=True) - file.save(filepath) - - workbook = openpyxl.load_workbook(filepath) - sheet = workbook.active - - db = DB() - for row in sheet.iter_rows(min_row=2, values_only=True): - inv_no, inv_date, state, district, block, village, subcontractor, work_type, amount = row - db.exec_proc("InsertInvoiceBulk", [ - inv_no, inv_date, state, district, block, village, subcontractor, work_type, amount - ]) - db.close() - - log_action("Bulk Invoice Upload", f"File: {file.filename}") - flash("Excel uploaded successfully!", "success") - return redirect(url_for("invoice_entry")) - - return render_template('uploadExcelFile.html') - - -# ----------------------------------- -# REPORTS -# ----------------------------------- - -@app.route('/report', methods=['GET', 'POST']) -@login_required -def report(): - db = DB() - statedata = db.fetch_all_proc("GetAllStates") - subcontractordata = db.fetch_all_proc( "GetSubcontractorDetails", - ["1=1", "{}"] ) - db.close() - return render_template('report.html', statedata=statedata, subcontractordata=subcontractordata) - - -@app.route('/view_report', methods=['POST']) -@login_required -def view_report(): - state_id = request.form.get("state", "") - subcontractor_id = request.form.get("subcontractor", "") - - db = DB() - reportdata = db.fetch_all_proc("GetReportData", [state_id, subcontractor_id]) - db.close() - - log_action("Generate Report", f"State {state_id}, Subcontractor {subcontractor_id}") - return render_template("report_table.html", reportdata=reportdata) - -if __name__ == "__main__": - app.run(host='0.0.0.0', port=5000, debug=True)