Initial commit
This commit is contained in:
26
MAIN2.PY
26
MAIN2.PY
@@ -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()
|
|
||||||
49
main.py
49
main.py
@@ -568,8 +568,7 @@ def edit_district(district_id):
|
|||||||
|
|
||||||
# Retrieve all states for dropdown
|
# Retrieve all states for dropdown
|
||||||
try:
|
try:
|
||||||
# cursor.execute("SELECT State_ID, State_Name FROM states")
|
|
||||||
# states = cursor.fetchall()
|
|
||||||
cursor.callproc("GetAllStates")
|
cursor.callproc("GetAllStates")
|
||||||
for res in cursor.stored_results():
|
for res in cursor.stored_results():
|
||||||
states = res.fetchall()
|
states = res.fetchall()
|
||||||
@@ -580,8 +579,7 @@ def edit_district(district_id):
|
|||||||
|
|
||||||
# Retrieve district info
|
# Retrieve district info
|
||||||
try:
|
try:
|
||||||
# cursor.execute("SELECT District_Name, State_Id FROM districts WHERE District_id = %s", (district_id,))
|
|
||||||
# districtdata = cursor.fetchone()
|
|
||||||
cursor.callproc("GetDistrictDataByID", (district_id,))
|
cursor.callproc("GetDistrictDataByID", (district_id,))
|
||||||
for rs in cursor.stored_results():
|
for rs in cursor.stored_results():
|
||||||
districtdata = rs.fetchone()
|
districtdata = rs.fetchone()
|
||||||
@@ -596,8 +594,7 @@ def edit_district(district_id):
|
|||||||
state_id = request.form['state_Id']
|
state_id = request.form['state_Id']
|
||||||
|
|
||||||
try:
|
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,))
|
cursor.callproc("UpdateDistrict", (district_id, state_id, district_name,))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
@@ -622,8 +619,7 @@ def add_block():
|
|||||||
if connection:
|
if connection:
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
try:
|
try:
|
||||||
# cursor.execute("SELECT State_ID, State_Name FROM states")
|
|
||||||
# states = cursor.fetchall()
|
|
||||||
cursor.callproc("GetAllStates")
|
cursor.callproc("GetAllStates")
|
||||||
for res in cursor.stored_results():
|
for res in cursor.stored_results():
|
||||||
states = res.fetchall()
|
states = res.fetchall()
|
||||||
@@ -640,9 +636,7 @@ def add_block():
|
|||||||
return json_response(ResponseHandler.invalid_name("block"), 400)
|
return json_response(ResponseHandler.invalid_name("block"), 400)
|
||||||
|
|
||||||
try:
|
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,))
|
cursor.callproc("GetBlockByNameAndDistrict", (block_name, district_id,))
|
||||||
for rs in cursor.stored_results():
|
for rs in cursor.stored_results():
|
||||||
existing_block = rs.fetchone()
|
existing_block = rs.fetchone()
|
||||||
@@ -766,7 +760,7 @@ def delete_block(block_id):
|
|||||||
if connection:
|
if connection:
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
try:
|
try:
|
||||||
# cursor.execute("DELETE FROM blocks WHERE Block_Id = %s", (block_id,))
|
|
||||||
cursor.callproc("DeleteBlock", (block_id,))
|
cursor.callproc("DeleteBlock", (block_id,))
|
||||||
log_action("Delete Block", f"User {current_user.id} Deleted block '{block_id}'")
|
log_action("Delete Block", f"User {current_user.id} Deleted block '{block_id}'")
|
||||||
connection.commit()
|
connection.commit()
|
||||||
@@ -906,8 +900,7 @@ def check_village():
|
|||||||
if not block_id or not village_name:
|
if not block_id or not village_name:
|
||||||
return json_response({'status': 'error', 'message': 'Block and Village Name are required!'}, 400)
|
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))
|
cursor.callproc("GetVillageByNameAndBlocks", (village_name, block_id))
|
||||||
for rs in cursor.stored_results():
|
for rs in cursor.stored_results():
|
||||||
existing_village = rs.fetchone()
|
existing_village = rs.fetchone()
|
||||||
@@ -975,11 +968,11 @@ def delete_village(village_id):
|
|||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# cursor.execute("DELETE FROM villages WHERE Village_Id = %s", (village_id,))
|
|
||||||
cursor.callproc("DeleteVillage", (village_id,))
|
cursor.callproc("DeleteVillage", (village_id,))
|
||||||
log_action("Delete villages", f"User {current_user.id} Deletedvillages '{village_id}'")
|
log_action("Delete villages", f"User {current_user.id} Deletedvillages '{village_id}'")
|
||||||
connection.commit()
|
connection.commit()
|
||||||
# return json_response(ResponseHandler.delete_success("village"), 200)
|
|
||||||
except mysql.connector.Error as e:
|
except mysql.connector.Error as e:
|
||||||
print(f"Error: {e}")
|
print(f"Error: {e}")
|
||||||
return json_response(ResponseHandler.add_failure("village"), 500)
|
return json_response(ResponseHandler.add_failure("village"), 500)
|
||||||
@@ -1074,8 +1067,7 @@ def add_invoice():
|
|||||||
hold_count = 0
|
hold_count = 0
|
||||||
|
|
||||||
for hold_type, hold_amount in zip(hold_types, hold_amounts):
|
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])
|
cursor.callproc('GetHoldTypeIdByName', [hold_type])
|
||||||
for result in cursor.stored_results():
|
for result in cursor.stored_results():
|
||||||
hold_type_result = result.fetchone()
|
hold_type_result = result.fetchone()
|
||||||
@@ -1175,7 +1167,7 @@ def get_hold_types():
|
|||||||
return jsonify(hold_types)
|
return jsonify(hold_types)
|
||||||
except mysql.connector.Error as e:
|
except mysql.connector.Error as e:
|
||||||
return ResponseHandler.fetch_failure({str(e)}), 500
|
return ResponseHandler.fetch_failure({str(e)}), 500
|
||||||
# return jsonify({"status": "error", "message": f"Failed to fetch hold types: {str(e)}"}), 500
|
|
||||||
finally:
|
finally:
|
||||||
cursor.close()
|
cursor.close()
|
||||||
connection.close()
|
connection.close()
|
||||||
@@ -1334,7 +1326,7 @@ def delete_invoice(invoice_id):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
# cursor.execute("DELETE FROM invoice WHERE Invoice_Id = %s", (invoice_id,))
|
|
||||||
|
|
||||||
cursor.callproc("DeleteInvoice", (invoice_id,))
|
cursor.callproc("DeleteInvoice", (invoice_id,))
|
||||||
log_action("Delete invoice", f"User {current_user.id} Delete invoice'{ 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,
|
SD_Amount, On_Commission, Hydro_Testing, GST_SD_Amount, Final_Amount,
|
||||||
subcontractor_id, 0
|
subcontractor_id, 0
|
||||||
)
|
)
|
||||||
# for result in cursor.stored_results():
|
|
||||||
# invoice_id = result.fetchone()['invoice_id']
|
|
||||||
print("All invoice Details ",args)
|
print("All invoice Details ",args)
|
||||||
results = cursor.callproc('SaveInvoice', args)
|
results = cursor.callproc('SaveInvoice', args)
|
||||||
|
|
||||||
@@ -2207,7 +2198,7 @@ def save_data():
|
|||||||
elif Invoice_Details and any(
|
elif Invoice_Details and any(
|
||||||
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']):
|
keyword in Invoice_Details.lower() for keyword in ['gst', 'release', 'note']):
|
||||||
print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
|
print("Gst rels :", PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR, subcontractor_id)
|
||||||
#cursor.callproc("SaveGSTRelease", (PMC_No, Invoice_No, Basic_Amount, Final_Amount,Total_Amount,UTR))
|
|
||||||
cursor.execute(
|
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)""",
|
"""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))
|
(PMC_No, Invoice_No, Basic_Amount, Final_Amount, Total_Amount, UTR, subcontractor_id))
|
||||||
@@ -2223,7 +2214,7 @@ def save_data():
|
|||||||
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
return jsonify({"success": "Data saved successfully!"}), 200
|
return jsonify({"success": "Data saved successfully!"}), 200
|
||||||
# return render_template('uploadExcelFile.html')
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
connection.rollback()
|
connection.rollback()
|
||||||
return jsonify({"error": f"An unexpected error occurred: {e}"}), 500
|
return jsonify({"error": f"An unexpected error occurred: {e}"}), 500
|
||||||
@@ -2865,10 +2856,7 @@ def pmc_report(pmc_no):
|
|||||||
ORDER BY invoice_no ASC
|
ORDER BY invoice_no ASC
|
||||||
""", (pmc_no,))
|
""", (pmc_no,))
|
||||||
payments = cursor.fetchall()
|
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_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)
|
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()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# cursor.execute("SELECT * FROM hold_types WHERE hold_type_id = %s", (id,))
|
|
||||||
# hold_type = cursor.fetchone()
|
|
||||||
cursor.callproc("GetHoldTypesById", (id,))
|
cursor.callproc("GetHoldTypesById", (id,))
|
||||||
for hold in cursor.stored_results():
|
for hold in cursor.stored_results():
|
||||||
hold_type = hold.fetchone()
|
hold_type = hold.fetchone()
|
||||||
@@ -3329,7 +3316,7 @@ def delete_hold_type(id):
|
|||||||
return jsonify({'status': 'error', 'message': 'Hold Type not found.'}), 404
|
return jsonify({'status': 'error', 'message': 'Hold Type not found.'}), 404
|
||||||
|
|
||||||
# Proceed with deletion
|
# Proceed with deletion
|
||||||
# cursor.execute("DELETE FROM hold_types WHERE hold_type_id = %s", (id,))
|
|
||||||
cursor.callproc("DeleteHoldType", (id,))
|
cursor.callproc("DeleteHoldType", (id,))
|
||||||
connection.commit()
|
connection.commit()
|
||||||
return jsonify(ResponseHandler.delete_success('Hold Type'))
|
return jsonify(ResponseHandler.delete_success('Hold Type'))
|
||||||
|
|||||||
933
main1.py
933
main1.py
@@ -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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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/<int:id>', 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)
|
|
||||||
Reference in New Issue
Block a user