11 Commits

60 changed files with 1416 additions and 8784 deletions

2
.env
View File

@@ -2,7 +2,7 @@ Secret_Key = 9f2a1b8c4d6e7f0123456789abcdef01
MYSQL_HOST=127.0.0.1 MYSQL_HOST=127.0.0.1
MYSQL_USER=root MYSQL_USER=root
MYSQL_PASSWORD=root MYSQL_PASSWORD=tiger
MYSQL_DB=test MYSQL_DB=test
DEFAULT_USERNAME=admin DEFAULT_USERNAME=admin

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
venv/
*.pyc
__pycache__/
static/downloads/
static/uploads/

Binary file not shown.

File diff suppressed because it is too large Load Diff

114
app.log
View File

@@ -1,114 +0,0 @@
2025-02-15 11:07:16,100 - INFO - Logging is set up.
2025-02-15 11:07:16,100 - INFO - Logging is set up.
2025-02-15 11:07:16,131 - WARNING - * Debugger is active!
2025-02-15 11:07:16,131 - WARNING - * Debugger is active!
2025-02-15 11:07:16,137 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:07:16,137 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:13:26,290 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET / HTTP/1.1" 200 -
2025-02-15 11:13:26,290 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET / HTTP/1.1" 200 -
2025-02-15 11:13:26,315 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/css/index.css HTTP/1.1" 304 -
2025-02-15 11:13:26,315 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/css/index.css HTTP/1.1" 304 -
2025-02-15 11:13:26,504 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:13:26,504 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:13:26,626 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/js/validateFileInput.js HTTP/1.1" 304 -
2025-02-15 11:13:26,626 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/js/validateFileInput.js HTTP/1.1" 304 -
2025-02-15 11:13:26,633 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/js/searchContractor.js HTTP/1.1" 304 -
2025-02-15 11:13:26,633 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /static/js/searchContractor.js HTTP/1.1" 304 -
2025-02-15 11:13:26,950 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /favicon.ico HTTP/1.1" 404 -
2025-02-15 11:13:26,950 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:26] "GET /favicon.ico HTTP/1.1" 404 -
2025-02-15 11:13:28,623 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET / HTTP/1.1" 200 -
2025-02-15 11:13:28,623 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET / HTTP/1.1" 200 -
2025-02-15 11:13:28,933 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/css/index.css HTTP/1.1" 304 -
2025-02-15 11:13:28,933 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/css/index.css HTTP/1.1" 304 -
2025-02-15 11:13:28,952 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/js/validateFileInput.js HTTP/1.1" 304 -
2025-02-15 11:13:28,952 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/js/validateFileInput.js HTTP/1.1" 304 -
2025-02-15 11:13:28,954 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/js/searchContractor.js HTTP/1.1" 304 -
2025-02-15 11:13:28,955 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:13:28,954 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/js/searchContractor.js HTTP/1.1" 304 -
2025-02-15 11:13:28,955 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:28] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:13:31,608 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:13:31,608 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:13:31,639 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:13:31,639 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:13:31,649 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:13:31,649 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:13:31,967 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:13:31,967 - INFO - 127.0.0.1 - - [15/Feb/2025 11:13:31] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:15:01,349 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:01] "POST /check_state HTTP/1.1" 409 -
2025-02-15 11:15:01,349 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:01] "POST /check_state HTTP/1.1" 409 -
2025-02-15 11:15:21,783 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:21] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:21,783 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:21] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,127 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,127 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,151 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,151 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,391 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,391 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,440 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:22,440 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:22] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:15:24,266 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:24] "POST /add_state HTTP/1.1" 200 -
2025-02-15 11:15:24,266 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:24] "POST /add_state HTTP/1.1" 200 -
2025-02-15 11:15:25,418 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:15:25,418 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:15:25,716 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:15:25,716 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:15:25,749 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:15:25,749 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:15:25,752 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:15:25,752 - INFO - 127.0.0.1 - - [15/Feb/2025 11:15:25] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:46,338 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:16:46,338 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:16:48,798 - INFO - Logging is set up.
2025-02-15 11:16:48,798 - INFO - Logging is set up.
2025-02-15 11:16:48,843 - WARNING - * Debugger is active!
2025-02-15 11:16:48,843 - WARNING - * Debugger is active!
2025-02-15 11:16:48,847 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:16:48,847 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:16:52,045 - DEBUG - Fetched state data successfully.
2025-02-15 11:16:52,045 - DEBUG - Fetched state data successfully.
2025-02-15 11:16:52,054 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:16:52,054 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:16:52,076 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:16:52,076 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:16:52,078 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:52,078 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:52,377 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:52,377 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:52] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:54,758 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:54] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:16:54,758 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:54] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:16:54,992 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:54] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:16:54,992 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:54] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:16:55,016 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:55] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:16:55,016 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:55] "POST /check_state HTTP/1.1" 200 -
2025-02-15 11:16:55,669 - INFO - State 'sss' added successfully.
2025-02-15 11:16:55,669 - INFO - 'State 'sss added successfully.
2025-02-15 11:16:55,670 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:55] "POST /add_state HTTP/1.1" 200 -
2025-02-15 11:16:55,670 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:55] "POST /add_state HTTP/1.1" 200 -
2025-02-15 11:16:57,235 - DEBUG - Fetched state data successfully.
2025-02-15 11:16:57,235 - DEBUG - Fetched state data successfully.
2025-02-15 11:16:57,239 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:16:57,239 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /add_state HTTP/1.1" 200 -
2025-02-15 11:16:57,263 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:16:57,263 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /static/css/style.css HTTP/1.1" 304 -
2025-02-15 11:16:57,483 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:57,483 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /static/images/icons/pen_blue_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:57,567 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:16:57,567 - INFO - 127.0.0.1 - - [15/Feb/2025 11:16:57] "GET /static/images/icons/bin_red_icon.png HTTP/1.1" 304 -
2025-02-15 11:20:55,547 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:20:55,547 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:20:56,800 - INFO - Logging is set up.
2025-02-15 11:20:56,800 - INFO - Logging is set up.
2025-02-15 11:20:56,835 - WARNING - * Debugger is active!
2025-02-15 11:20:56,835 - WARNING - * Debugger is active!
2025-02-15 11:20:56,837 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:20:56,837 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:21:04,060 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:21:04,060 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:21:05,429 - INFO - Logging is set up.
2025-02-15 11:21:05,429 - INFO - Logging is set up.
2025-02-15 11:21:05,461 - WARNING - * Debugger is active!
2025-02-15 11:21:05,461 - WARNING - * Debugger is active!
2025-02-15 11:21:05,463 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:21:05,463 - INFO - * Debugger PIN: 558-213-972
2025-02-15 11:21:17,911 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading
2025-02-15 11:21:17,911 - INFO - * Detected change in 'C:\\Users\\ADMIN\\PycharmProjects\\ManagementApplicationt\\main.py', reloading

View File

@@ -1,37 +1,28 @@
import config
from flask import Blueprint, render_template, request, redirect, url_for, jsonify from flask import Blueprint, render_template, request, redirect, url_for, jsonify
from flask_login import login_required from flask_login import login_required
import config from model.State import State
import mysql.connector
from model.Block import Block from model.Block import Block
from model.Utilities import HtmlHelper from model.Utilities import HtmlHelper
block_bp = Blueprint('block', __name__) block_bp = Blueprint('block', __name__)
# --- Add Block page -------
@block_bp.route('/add_block', methods=['GET', 'POST']) @block_bp.route('/add_block', methods=['GET', 'POST'])
@login_required @login_required
def add_block(): def add_block():
block = Block() block = Block()
if request.method == 'POST': if request.method == 'POST':
block.AddBlock(request) block.AddBlock(request)
return block.resultMessage return block.resultMessage
connection = config.get_db_connection() state = State()
cursor = connection.cursor() states = state.GetAllStates(request=request)
cursor.callproc("GetAllStates")
for rs in cursor.stored_results():
states = rs.fetchall()
block_data = block.GetAllBlocks(request) block_data = block.GetAllBlocks(request)
cursor.close()
connection.close()
return render_template( return render_template(
'add_block.html', 'add_block.html',
states=states, states=states,

View File

@@ -6,11 +6,10 @@ from model.State import State
district_bp = Blueprint('district', __name__) district_bp = Blueprint('district', __name__)
# ------- District page --------
@district_bp.route('/add_district', methods=['GET', 'POST']) @district_bp.route('/add_district', methods=['GET', 'POST'])
@login_required @login_required
def add_district(): def add_district():
district = District() district = District()
if request.method == 'POST': if request.method == 'POST':
@@ -28,7 +27,7 @@ def add_district():
states=states states=states
) )
# ------- District check --------
@district_bp.route('/check_district', methods=['POST']) @district_bp.route('/check_district', methods=['POST'])
@login_required @login_required
def check_district(): def check_district():
@@ -37,7 +36,7 @@ def check_district():
return district.CheckDistrict(request=request) return district.CheckDistrict(request=request)
# ------- District delete by district id --------
@district_bp.route('/delete_district/<int:district_id>') @district_bp.route('/delete_district/<int:district_id>')
@login_required @login_required
def delete_district(district_id): def delete_district(district_id):
@@ -52,6 +51,7 @@ def delete_district(district_id):
return redirect(url_for('district.add_district')) return redirect(url_for('district.add_district'))
# ------- District update by district id --------
@district_bp.route('/edit_district/<int:district_id>', methods=['GET', 'POST']) @district_bp.route('/edit_district/<int:district_id>', methods=['GET', 'POST'])
@login_required @login_required
def edit_district(district_id): def edit_district(district_id):

View File

@@ -1,28 +1,16 @@
import os import config
import ast import ast
import re import re
from flask_login import login_required
import openpyxl import openpyxl
from flask import Blueprint, request, render_template, redirect, url_for, jsonify, current_app
from flask_login import current_user from flask_login import current_user
from flask_login import login_required
from flask import Blueprint, request, render_template, redirect, url_for, jsonify
from model.Log import LogHelper from model.Log import LogHelper
import config
from model.FolderAndFile import FolderAndFile from model.FolderAndFile import FolderAndFile
excel_bp = Blueprint('excel', __name__) excel_bp = Blueprint('excel', __name__)
# Default folder in case config not set
# DEFAULT_UPLOAD_FOLDER = 'uploads'
# def get_upload_folder():
# """Returns the upload folder from Flask config or default, ensures it exists."""
# folder = current_app.config.get('UPLOAD_FOLDER', DEFAULT_UPLOAD_FOLDER)
# if not os.path.exists(folder):
# os.makedirs(folder)
# return folder
# ---------------- Upload Excel File ---------------- # ---------------- Upload Excel File ----------------
@excel_bp.route('/upload_excel_file', methods=['GET', 'POST']) @excel_bp.route('/upload_excel_file', methods=['GET', 'POST'])
@login_required @login_required
@@ -30,9 +18,6 @@ def upload():
if request.method == 'POST': if request.method == 'POST':
file = request.files.get('file') file = request.files.get('file')
if file and file.filename.endswith('.xlsx'): if file and file.filename.endswith('.xlsx'):
# upload_folder = get_upload_folder()
# filepath = os.path.join(upload_folder, file.filename)
filepath =FolderAndFile.get_upload_path(file.filename) filepath =FolderAndFile.get_upload_path(file.filename)
file.save(filepath) file.save(filepath)
@@ -42,6 +27,7 @@ def upload():
f"User {current_user.id} Upload Excel File '{file.filename}'" f"User {current_user.id} Upload Excel File '{file.filename}'"
) )
return redirect(url_for('excel.show_table', filename=file.filename)) return redirect(url_for('excel.show_table', filename=file.filename))
return render_template('uploadExcelFile.html') return render_template('uploadExcelFile.html')
@@ -51,7 +37,6 @@ def show_table(filename):
global data global data
data = [] data = []
# filepath = os.path.join(get_upload_folder(), filename)
filepath = FolderAndFile.get_upload_path(filename) filepath = FolderAndFile.get_upload_path(filename)
wb = openpyxl.load_workbook(filepath, data_only=True) wb = openpyxl.load_workbook(filepath, data_only=True)
sheet = wb.active sheet = wb.active

View File

@@ -1,70 +1,46 @@
from flask import Blueprint, render_template, request, redirect, url_for, jsonify from flask import Blueprint, render_template, request, redirect, url_for
from flask_login import login_required, current_user from flask_login import login_required
from model.gst_release import GSTReleasemodel from model.gst_release import GSTRelease
from model.Log import LogHelper from model.Log import LogHelper
from flask import flash, current_app
gst_release_bp = Blueprint('gst_release_bp', __name__) gst_release_bp = Blueprint('gst_release_bp', __name__)
gst_service = GSTRelease()
# ------------------- Add GST Release ------------------- # ---------------- ADD GST RELEASE ----------------
@gst_release_bp.route('/add_gst_release', methods=['GET', 'POST']) @gst_release_bp.route('/add_gst_release', methods=['GET', 'POST'])
@login_required @login_required
def add_gst_release(): def add_gst_release():
gst_releases_dict = GSTReleasemodel.fetch_all_gst_releases()
gst_releases = [
[
g['GST_Release_Id'], g['PMC_No'], g['invoice_no'],
g['Basic_Amount'], g['Final_Amount'], g['Total_Amount'], g['UTR']
] for g in gst_releases_dict
] if gst_releases_dict else []
if request.method == 'POST': if request.method == 'POST':
pmc_no = request.form['PMC_No'] gst_service.AddGSTRelease(request)
invoice_no = request.form['invoice_No'] LogHelper.log_action("Add GST Release", f"User added GST release")
basic_amount = request.form['basic_amount'] flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
final_amount = request.form['final_amount']
total_amount = request.form['total_amount']
utr = request.form['utr']
contractor_id = request.form['subcontractor_id']
LogHelper.log_action("Add GST Release", f"User {current_user.id} added GST release '{pmc_no}'")
GSTReleasemodel.insert_gst_release(pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr, contractor_id)
return redirect(url_for('gst_release_bp.add_gst_release')) return redirect(url_for('gst_release_bp.add_gst_release'))
return render_template('add_gst_release.html', gst_releases=gst_releases, invoices=[]) gst_releases = gst_service.GetAllGSTReleases()
return render_template('add_gst_release.html', gst_releases=gst_releases)
# ---------------- EDIT GST RELEASE ----------------
# ------------------- Edit GST Release -------------------
@gst_release_bp.route('/edit_gst_release/<int:gst_release_id>', methods=['GET', 'POST']) @gst_release_bp.route('/edit_gst_release/<int:gst_release_id>', methods=['GET', 'POST'])
@login_required @login_required
def edit_gst_release(gst_release_id): def edit_gst_release(gst_release_id):
gst_release_data = GSTReleasemodel.fetch_gst_release_by_id(gst_release_id) gst_data = gst_service.GetGSTReleaseByID(gst_release_id)
if not gst_release_data: if not gst_data:
return "GST Release not found", 404 return "GST Release not found", 404
if request.method == 'POST': if request.method == 'POST':
pmc_no = request.form['PMC_No'] gst_service.EditGSTRelease(request, gst_release_id)
invoice_no = request.form['invoice_No'] LogHelper.log_action("Edit GST Release", f"User edited GST release")
basic_amount = request.form['basic_amount'] flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
final_amount = request.form['final_amount']
total_amount = request.form['total_amount']
utr = request.form['utr']
LogHelper.log_action("Edit GST Release", f"User {current_user.id} edited GST release '{pmc_no}'")
GSTReleasemodel.update_gst_release(gst_release_id, pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr)
return redirect(url_for('gst_release_bp.add_gst_release')) return redirect(url_for('gst_release_bp.add_gst_release'))
return render_template('edit_gst_release.html', gst_release_data=gst_release_data, invoices=[]) return render_template('edit_gst_release.html', gst_release_data=gst_data)
# ---------------- DELETE GST RELEASE ----------------
# ------------------- Delete GST Release -------------------
@gst_release_bp.route('/delete_gst_release/<int:gst_release_id>', methods=['GET', 'POST']) @gst_release_bp.route('/delete_gst_release/<int:gst_release_id>', methods=['GET', 'POST'])
@login_required @login_required
def delete_gst_release(gst_release_id): def delete_gst_release(gst_release_id):
success, utr = GSTReleasemodel.delete_gst_release(gst_release_id) gst_service.DeleteGSTRelease(gst_release_id) # remove request
if not success: LogHelper.log_action("Delete GST Release", f"User deleted GST release")
return jsonify({"message": "GST Release not found or failed to delete", "status": "error"}), 404 flash(gst_service.resultMessage, 'success' if gst_service.isSuccess else 'error')
return redirect(url_for('gst_release_bp.add_gst_release'))
LogHelper.log_action("Delete GST Release", f"User {current_user.id} deleted GST release '{gst_release_id}'")
return jsonify({"message": f"GST Release {gst_release_id} deleted successfully.", "status": "success"}), 200

View File

@@ -1,4 +1,4 @@
from flask import Blueprint, render_template, request, redirect, url_for, jsonify from flask import Blueprint, render_template, request, redirect, url_for, jsonify, flash
from flask_login import login_required, current_user from flask_login import login_required, current_user
from model.payment import Paymentmodel from model.payment import Paymentmodel
from model.Log import LogHelper from model.Log import LogHelper
@@ -88,16 +88,14 @@ def edit_payment(payment_id):
# ------------------- Delete Payment ------------------- # ------------------- Delete Payment -------------------
@payment_bp.route('/delete_payment/<int:payment_id>', methods=['GET', 'POST']) @payment_bp.route('/delete_payment/<int:payment_id>', methods=['POST'])
@login_required @login_required
def delete_payment(payment_id): def delete_payment(payment_id):
success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id) success, pmc_no, invoice_no = Paymentmodel.delete_payment(payment_id)
if not success: if not success:
return jsonify({"message": "Payment not found or failed to delete", "status": "error"}), 404 flash("Payment not found or failed to delete", "error")
else:
LogHelper.log_action("Delete Payment", f"User {current_user.id} deleted Payment '{payment_id}'") LogHelper.log_action("Delete Payment", f"User {current_user.id} deleted Payment '{payment_id}'")
flash(f"Payment ID {payment_id} deleted successfully.", "success")
return jsonify({ return redirect(url_for('payment_bp.add_payment'))
"message": f"Payment ID {payment_id} deleted successfully.",
"status": "success"
}), 200

View File

@@ -1,9 +1,11 @@
from flask import Blueprint, render_template, send_from_directory from flask import Blueprint, render_template, send_from_directory
from flask_login import login_required, current_user from flask_login import login_required
from model.PmcReport import PmcReport from model.PmcReport import PmcReport
pmc_report_bp = Blueprint("pmc_report", __name__) pmc_report_bp = Blueprint("pmc_report", __name__)
# ---------------- Contractor Report by pmc no ----------------
@pmc_report_bp.route("/pmc_report/<pmc_no>") @pmc_report_bp.route("/pmc_report/<pmc_no>")
@login_required @login_required
def pmc_report(pmc_no): def pmc_report(pmc_no):
@@ -23,6 +25,7 @@ def pmc_report(pmc_no):
total=data["total"] total=data["total"]
) )
# ---------------- Contractor Download Report by pmc no ----------------
@pmc_report_bp.route("/download_pmc_report/<pmc_no>") @pmc_report_bp.route("/download_pmc_report/<pmc_no>")
@login_required @login_required
def download_pmc_report(pmc_no): def download_pmc_report(pmc_no):

View File

@@ -1,13 +1,8 @@
from flask import Blueprint, render_template, request, jsonify, send_file from flask import Blueprint, render_template, request, jsonify
from flask_login import login_required, current_user from flask_login import login_required, current_user
from model.Report import ReportHelper from model.Report import ReportHelper
from model.Log import LogHelper from model.Log import LogHelper
import config
import os
import openpyxl
from openpyxl.styles import Font
from model.ContractorInfo import ContractorInfo
from model.FolderAndFile import FolderAndFile
report_bp = Blueprint("report", __name__) report_bp = Blueprint("report", __name__)
@@ -36,7 +31,7 @@ def search_contractor():
return jsonify(data) return jsonify(data)
# ---------------- Contractor Report ---------------- # ---------------- Contractor Report by contractor id ----------------
@report_bp.route('/contractor_report/<int:contractor_id>') @report_bp.route('/contractor_report/<int:contractor_id>')
@login_required @login_required
def contractor_report(contractor_id): def contractor_report(contractor_id):
@@ -49,145 +44,10 @@ def contractor_report(contractor_id):
**data **data
) )
# ---------------- Contractor Download Report by contractor id ----------------
@report_bp.route('/download_report/<int:contractor_id>') @report_bp.route('/download_report/<int:contractor_id>')
@login_required @login_required
def download_report(contractor_id): def download_report(contractor_id):
return ReportHelper().download_report(contractor_id=contractor_id) return ReportHelper().download_report(contractor_id=contractor_id)
# @report_bp.route('/download_report/<int:contractor_id>')
# @login_required
# def download_report(contractor_id):
# try:
# connection = config.get_db_connection()
# cursor = connection.cursor(dictionary=True)
# # -------- Contractor Info --------
# contractor = ContractorInfo(contractor_id)
# contInfo = contractor.contInfo
# if not contInfo:
# return "No contractor found", 404
# # -------- Invoice Data --------
# cursor.callproc('FetchInvoicesByContractor', [contractor_id])
# invoices = []
# for result in cursor.stored_results():
# invoices.extend(result.fetchall())
# if not invoices:
# return "No invoice data found"
# # -------- Create Workbook --------
# workbook = openpyxl.Workbook()
# sheet = workbook.active
# sheet.title = "Contractor Report"
# # ================= CONTRACTOR DETAILS =================
# sheet.append(["SUB CONTRACTOR DETAILS"])
# sheet.cell(row=sheet.max_row, column=1).font = Font(bold=True)
# sheet.append([])
# sheet.append(["Name", contInfo.get("Contractor_Name") or ""])
# sheet.append(["Mobile No", contInfo.get("Mobile_No") or ""])
# sheet.append(["Email", contInfo.get("Email") or ""])
# sheet.append(["Village", contInfo.get("Village_Name") or ""])
# sheet.append(["Block", contInfo.get("Block_Name") or ""])
# sheet.append(["District", contInfo.get("District_Name") or ""])
# sheet.append(["State", contInfo.get("State_Name") or ""])
# sheet.append(["Address", contInfo.get("Address") or ""])
# sheet.append(["GST No", contInfo.get("GST_No") or ""])
# sheet.append(["PAN No", contInfo.get("PAN_No") or ""])
# sheet.append([])
# sheet.append([])
# # ================= TABLE HEADERS =================
# headers = [
# "PMC No", "Village", "Invoice No", "Invoice Date", "Work Type","Invoice_Details",
# "Basic Amount", "Debit Amount", "After Debit Amount",
# "Amount", "GST Amount", "TDS Amount", "SD Amount",
# "On Commission", "Hydro Testing", "Hold Amount",
# "GST SD Amount", "Final Amount",
# "Payment Amount", "TDS Payment",
# "Total Amount", "UTR"
# ]
# sheet.append(headers)
# for col in range(1, len(headers) + 1):
# sheet.cell(row=sheet.max_row, column=col).font = Font(bold=True)
# # ================= DATA =================
# total_final = 0
# total_payment = 0
# total_amount = 0
# for inv in invoices:
# row = [
# inv.get("PMC_No"),
# inv.get("Village_Name"),
# inv.get("invoice_no"),
# inv.get("Invoice_Date"),
# inv.get("Work_Type"),
# inv.get("Invoice_Details"),
# inv.get("Basic_Amount"),
# inv.get("Debit_Amount"),
# inv.get("After_Debit_Amount"),
# inv.get("Amount"),
# inv.get("GST_Amount"),
# inv.get("TDS_Amount"),
# inv.get("SD_Amount"),
# inv.get("On_Commission"),
# inv.get("Hydro_Testing"),
# inv.get("Hold_Amount"),
# inv.get("GST_SD_Amount"),
# inv.get("Final_Amount"),
# inv.get("Payment_Amount"),
# inv.get("TDS_Payment_Amount"),
# inv.get("Total_Amount"),
# inv.get("UTR")
# ]
# total_final += float(inv.get("Final_Amount") or 0)
# total_payment += float(inv.get("Payment_Amount") or 0)
# total_amount += float(inv.get("Total_Amount") or 0)
# sheet.append(row)
# # ================= TOTAL ROW =================
# sheet.append([])
# sheet.append([
# "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
# "TOTAL",
# total_final,
# total_payment,
# "",
# total_amount,
# ""
# ])
# # ================= AUTO WIDTH =================
# for column in sheet.columns:
# max_length = 0
# column_letter = column[0].column_letter
# for cell in column:
# if cell.value:
# max_length = max(max_length, len(str(cell.value)))
# sheet.column_dimensions[column_letter].width = max_length + 2
# # ================= SAVE FILE =================
# # output_folder = "downloads"
# # os.makedirs(output_folder, exist_ok=True)
# # filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx"
# # output_file = os.path.join(output_folder, filename)
# filename = f"Contractor_Report_{contInfo.get('Contractor_Name')}.xlsx"
# output_file = FolderAndFile.get_download_path(filename)
# workbook.save(output_file)
# return send_file(output_file, as_attachment=True)
# except Exception as e:
# return str(e)

View File

@@ -4,7 +4,7 @@ from model.State import State
state_bp = Blueprint('state', __name__) state_bp = Blueprint('state', __name__)
# ----- State page ------
@state_bp.route('/add_state', methods=['GET', 'POST']) @state_bp.route('/add_state', methods=['GET', 'POST'])
@login_required @login_required
def add_state(): def add_state():
@@ -19,7 +19,7 @@ def add_state():
return render_template('add_state.html', statedata=statedata) return render_template('add_state.html', statedata=statedata)
# ----- State check ------
@state_bp.route('/check_state', methods=['POST']) @state_bp.route('/check_state', methods=['POST'])
@login_required @login_required
def check_state(): def check_state():
@@ -28,21 +28,21 @@ def check_state():
return state.CheckState(request=request) return state.CheckState(request=request)
# ----- State delete by state id ------
@state_bp.route('/delete_state/<int:id>') @state_bp.route('/delete_state/<int:id>')
@login_required @login_required
def deleteState(id): def deleteState(id):
state = State() state = State()
msg = state.DeleteState(request=request, id=id) state.DeleteState(request=request, id=id)
if not state.isSuccess: if not state.isSuccess:
return state.resultMessage return state.resultMessage
else: else:
return redirect(url_for('state.add_state')) return redirect(url_for('state.add_state'))
# ----- State update by state id ------
@state_bp.route('/edit_state/<int:id>', methods=['GET', 'POST']) @state_bp.route('/edit_state/<int:id>', methods=['GET', 'POST'])
@login_required @login_required
def editState(id): def editState(id):

View File

@@ -1,34 +1,11 @@
from flask import Blueprint, render_template, request, redirect, url_for, jsonify from flask import Blueprint, render_template, request, redirect, url_for, jsonify
from flask_login import login_required from flask_login import login_required
from model.Subcontractor import Subcontractor from model.Subcontractor import Subcontractor
from model.Utilities import HtmlHelper, ResponseHandler
subcontractor_bp = Blueprint('subcontractor', __name__) subcontractor_bp = Blueprint('subcontractor', __name__)
# ----------------------------------------------------------
# Helpers (unchanged)
# ----------------------------------------------------------
class HtmlHelper:
@staticmethod
def json_response(data, status=200):
return jsonify(data), status
class ResponseHandler:
@staticmethod
def fetch_failure(entity):
return {"status": "error", "message": f"Failed to fetch {entity}"}
@staticmethod
def add_failure(entity):
return {"status": "error", "message": f"Failed to add {entity}"}
@staticmethod
def update_failure(entity):
return {"status": "error", "message": f"Failed to update {entity}"}
@staticmethod
def delete_failure(entity):
return {"status": "error", "message": f"Failed to delete {entity}"}
# ---------------------------------------------------------- # ----------------------------------------------------------
# LIST + ADD # LIST + ADD

View File

@@ -1,7 +1,3 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json
from flask import current_app
from datetime import datetime
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType

View File

@@ -1,20 +1,6 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json from model.Utilities import ItemCRUDType
from flask import current_app
from datetime import datetime
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogData, LogHelper
import os
import config
import re
import mysql.connector
from mysql.connector import Error
from model.ItemCRUD import ItemCRUD from model.ItemCRUD import ItemCRUD
class District: class District:
isSuccess = False isSuccess = False
@@ -24,7 +10,7 @@ class District:
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
# edit district
def EditDistrict(self, request, district_id): def EditDistrict(self, request, district_id):
district = ItemCRUD(itemType=ItemCRUDType.District) district = ItemCRUD(itemType=ItemCRUDType.District)
@@ -36,7 +22,7 @@ class District:
self.resultMessage = district.resultMessage self.resultMessage = district.resultMessage
return return
# add district
def AddDistrict(self, request): def AddDistrict(self, request):
district = ItemCRUD(ItemCRUDType.District) district = ItemCRUD(ItemCRUDType.District)
@@ -50,7 +36,7 @@ class District:
return return
# get all district data
def GetAllDistricts(self, request): def GetAllDistricts(self, request):
district = ItemCRUD(itemType=ItemCRUDType.District) district = ItemCRUD(itemType=ItemCRUDType.District)
districtsdata = district.GetAllData(request=request, storedproc="GetAllDistricts") districtsdata = district.GetAllData(request=request, storedproc="GetAllDistricts")
@@ -58,7 +44,7 @@ class District:
self.resultMessage = district.resultMessage self.resultMessage = district.resultMessage
return districtsdata return districtsdata
# check district validation
def CheckDistrict(self, request): def CheckDistrict(self, request):
district = ItemCRUD(itemType=ItemCRUDType.District) district = ItemCRUD(itemType=ItemCRUDType.District)
district_name = request.json.get('district_Name', '').strip() district_name = request.json.get('district_Name', '').strip()
@@ -68,13 +54,7 @@ class District:
self.resultMessage = district.resultMessage self.resultMessage = district.resultMessage
return result return result
# get district by district id
# def GetDistrictByID(self, request,district_id):
# district = ItemCRUD(itemType=ItemCRUDType.District)
# districtdata = district.GetAllData(id=district_id,storedproc="GetDistrictDataByID")
# self.isSuccess = district.isSuccess
# self.resultMessage = district.resultMessage
# return districtdata
def GetDistrictByID(self, request, district_id): def GetDistrictByID(self, request, district_id):
district = ItemCRUD(itemType=ItemCRUDType.District) district = ItemCRUD(itemType=ItemCRUDType.District)
@@ -92,7 +72,7 @@ class District:
return districtdata return districtdata
#Delete District # Delete District by district id
def DeleteDistrict(self, request, district_id): def DeleteDistrict(self, request, district_id):
district = ItemCRUD(itemType=ItemCRUDType.District) district = ItemCRUD(itemType=ItemCRUDType.District)
district.DeleteItem(request=request,itemID=district_id,storedprocDelete="DeleteDistrict") district.DeleteItem(request=request,itemID=district_id,storedprocDelete="DeleteDistrict")

View File

@@ -1,55 +1,51 @@
import config from model.ItemCRUD import ItemCRUD
from model.Utilities import ItemCRUDType
class GST: class GST:
@staticmethod @staticmethod
def get_unreleased_gst(): def get_unreleased_gst():
# Use ItemCRUD for Invoices
invoice_crud = ItemCRUD(itemType=ItemCRUDType.Invoice)
invoices_rows = invoice_crud.GetAllData(storedproc="GetAllInvoicesBasic")
connection = config.get_db_connection() if not invoice_crud.isSuccess:
cursor = connection.cursor(dictionary=True) return [] # Could also log invoice_crud.resultMessage
try: invoices = [
# ----------- Invoices ----------- dict(
cursor.callproc('GetAllInvoicesBasic') Invoice_No=row[1],
invoices = [] GST_SD_Amount=float(row[2]) if row[2] is not None else 0
for result in cursor.stored_results(): )
invoices = result.fetchall() for row in invoices_rows
]
# Use ItemCRUD for GST Releases
gst_crud = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
gst_rows = gst_crud.GetAllData(storedproc="GetAllGSTReleasesBasic")
# ----------- GST Releases ----------- if not gst_crud.isSuccess:
cursor.callproc('GetAllGSTReleasesBasic') return [] # Could also log gst_crud.resultMessage
gst_releases = []
for result in cursor.stored_results():
gst_releases = result.fetchall()
gst_invoice_nos = { gst_invoice_nos = {
g['Invoice_No'] g[2] # Invoice_No is at index 2
for g in gst_releases for g in gst_rows
if g['Invoice_No'] if g[2]
} }
gst_basic_amounts = { gst_basic_amounts = {
float(g['Basic_Amount']) float(g[3]) # Basic_Amount at index 3
for g in gst_releases for g in gst_rows
if g['Basic_Amount'] is not None if g[3] is not None
} }
# Filter unreleased invoices
unreleased = [] unreleased = []
for inv in invoices: for inv in invoices:
match_by_invoice = inv['Invoice_No'] in gst_invoice_nos match_by_invoice = inv['Invoice_No'] in gst_invoice_nos
match_by_gst_amount = inv['GST_SD_Amount'] in gst_basic_amounts
match_by_gst_amount = float(
inv.get('GST_SD_Amount') or 0
) in gst_basic_amounts
if not (match_by_invoice or match_by_gst_amount): if not (match_by_invoice or match_by_gst_amount):
unreleased.append(inv) unreleased.append(inv)
return unreleased return unreleased
finally:
cursor.close()
connection.close()

View File

@@ -1,3 +1,364 @@
# from flask_login import current_user
# from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
# from model.Log import LogHelper
# import config
# import re
# import mysql.connector
# # ----------------------------------------------------------
# # Mapping Class
# # ----------------------------------------------------------
# class itemCRUDMapping:
# def __init__(self, itemType):
# if itemType is ItemCRUDType.Village:
# self.name = "Village"
# elif itemType is ItemCRUDType.Block:
# self.name = "Block"
# elif itemType is ItemCRUDType.State:
# self.name = "State"
# elif itemType is ItemCRUDType.HoldType:
# self.name = "Hold Type"
# elif itemType is ItemCRUDType.Subcontractor:
# self.name = "Subcontractor"
# else:
# self.name = "Item"
# # ----------------------------------------------------------
# # Generic CRUD Class
# # ----------------------------------------------------------
# class ItemCRUD:
# def __init__(self, itemType):
# self.isSuccess = False
# self.resultMessage = ""
# self.itemCRUDType = itemType
# self.itemCRUDMapping = itemCRUDMapping(itemType)
# # ----------------------------------------------------------
# # DELETE
# # ----------------------------------------------------------
# def DeleteItem(self, request, itemID, storedprocDelete):
# connection = config.get_db_connection()
# cursor = connection.cursor()
# LogHelper.log_action(
# f"Delete {self.itemCRUDMapping.name}",
# f"User {current_user.id} deleted {self.itemCRUDMapping.name} '{itemID}'"
# )
# try:
# cursor.callproc(storedprocDelete, (itemID,))
# connection.commit()
# self.isSuccess = True
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.delete_success(self.itemCRUDMapping.name), 200
# )
# except mysql.connector.Error as e:
# print(f"Error deleting {self.itemCRUDMapping.name}: {e}")
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.delete_failure(self.itemCRUDMapping.name), 500
# )
# finally:
# cursor.close()
# connection.close()
# # ----------------------------------------------------------
# # ADD
# # ----------------------------------------------------------
# def AddItem(self, request, parentid=None, childname=None, storedprocfetch=None, storedprocadd=None, data=None):
# connection = config.get_db_connection()
# if not connection:
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.db_connection_failure(), 500
# )
# return
# cursor = connection.cursor()
# LogHelper.log_action(
# f"Add {self.itemCRUDMapping.name}",
# f"User {current_user.id} adding '{childname if childname else (data.get('Contractor_Name') if data else '')}'"
# )
# try:
# # ======================================================
# # SUBCONTRACTOR (MULTI-FIELD)
# # ======================================================
# if data:
# # Duplicate check
# cursor.callproc(storedprocfetch, (data['Contractor_Name'],))
# existing_item = None
# for rs in cursor.stored_results():
# existing_item = rs.fetchone()
# if existing_item:
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
# )
# return
# # Insert
# cursor.callproc(storedprocadd, (
# data['Contractor_Name'],
# data['Address'],
# data['Mobile_No'],
# data['PAN_No'],
# data['Email'],
# data['Gender'],
# data['GST_Registration_Type'],
# data['GST_No'],
# data['Contractor_password']
# ))
# connection.commit()
# self.isSuccess = True
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.add_success(self.itemCRUDMapping.name), 200
# )
# return
# # ======================================================
# # NORMAL (Village / Block / State)
# # ======================================================
# if not re.match(RegEx.patternAlphabetOnly, childname):
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
# )
# return
# # Duplicate check
# if parentid is None:
# cursor.callproc(storedprocfetch, (childname,))
# else:
# cursor.callproc(storedprocfetch, (childname, parentid))
# existing_item = None
# for rs in cursor.stored_results():
# existing_item = rs.fetchone()
# if existing_item:
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
# )
# return
# # Insert
# if parentid is None:
# cursor.callproc(storedprocadd, (childname,))
# else:
# cursor.callproc(storedprocadd, (childname, parentid))
# connection.commit()
# self.isSuccess = True
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.add_success(self.itemCRUDMapping.name), 200
# )
# except mysql.connector.Error as e:
# print(f"Database Error: {e}")
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.add_failure(self.itemCRUDMapping.name), 500
# )
# finally:
# cursor.close()
# connection.close()
# # ----------------------------------------------------------
# # EDIT
# # ----------------------------------------------------------
# def EditItem(self, request, childid, parentid=None, childname=None, storedprocupdate=None, data=None):
# connection = config.get_db_connection()
# cursor = connection.cursor()
# LogHelper.log_action(
# f"Edit {self.itemCRUDMapping.name}",
# f"User {current_user.id} edited '{childid}'"
# )
# try:
# # ======================================================
# # SUBCONTRACTOR (MULTI-FIELD)
# # ======================================================
# if data:
# cursor.callproc(storedprocupdate, (
# childid,
# data['Contractor_Name'],
# data['Address'],
# data['Mobile_No'],
# data['PAN_No'],
# data['Email'],
# data['Gender'],
# data['GST_Registration_Type'],
# data['GST_No'],
# data['Contractor_password']
# ))
# connection.commit()
# self.isSuccess = True
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.update_success(self.itemCRUDMapping.name), 200
# )
# return
# # ======================================================
# # NORMAL
# # ======================================================
# if not re.match(RegEx.patternAlphabetOnly, childname):
# self.isSuccess = False
# self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message']
# return
# if parentid is None:
# cursor.callproc(storedprocupdate, (childid, childname))
# else:
# cursor.callproc(storedprocupdate, (childid, parentid, childname))
# connection.commit()
# self.isSuccess = True
# self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message']
# except mysql.connector.Error as e:
# print(f"Error updating {self.itemCRUDMapping.name}: {e}")
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.update_failure(self.itemCRUDMapping.name), 500
# )
# finally:
# cursor.close()
# connection.close()
# # ----------------------------------------------------------
# # GET ALL
# # ----------------------------------------------------------
# def GetAllData(self, request, storedproc):
# data = []
# connection = config.get_db_connection()
# if not connection:
# return []
# cursor = connection.cursor()
# try:
# cursor.callproc(storedproc)
# for result in cursor.stored_results():
# data = result.fetchall()
# self.isSuccess = True
# except mysql.connector.Error as e:
# print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
# )
# return []
# finally:
# cursor.close()
# connection.close()
# return data
# # ----------------------------------------------------------
# # GET BY ID
# # ----------------------------------------------------------
# def GetDataByID(self, id, storedproc):
# data = None
# connection = config.get_db_connection()
# cursor = connection.cursor()
# try:
# cursor.callproc(storedproc, (id,))
# for rs in cursor.stored_results():
# data = rs.fetchone()
# except mysql.connector.Error as e:
# print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
# finally:
# cursor.close()
# connection.close()
# return data
# # ----------------------------------------------------------
# # CHECK ITEM
# # ----------------------------------------------------------
# def CheckItem(self, request, parentid, childname, storedprocfetch):
# connection = config.get_db_connection()
# cursor = connection.cursor()
# LogHelper.log_action(
# f"Check {self.itemCRUDMapping.name}",
# f"User {current_user.id} checked '{childname}'"
# )
# if not re.match(RegEx.patternAlphabetOnly, childname):
# return HtmlHelper.json_response(
# ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400
# )
# try:
# if parentid is None:
# cursor.callproc(storedprocfetch, (childname,))
# else:
# cursor.callproc(storedprocfetch, (childname, parentid))
# existing_item = None
# for rs in cursor.stored_results():
# existing_item = rs.fetchone()
# if existing_item:
# return HtmlHelper.json_response(
# ResponseHandler.already_exists(self.itemCRUDMapping.name), 409
# )
# return HtmlHelper.json_response(
# ResponseHandler.is_available(self.itemCRUDMapping.name), 200
# )
# except mysql.connector.Error as e:
# print(f"Error checking {self.itemCRUDMapping.name}: {e}")
# return HtmlHelper.json_response(
# ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500
# )
# finally:
# cursor.close()
# connection.close()
from flask_login import current_user from flask_login import current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogHelper from model.Log import LogHelper
@@ -35,6 +396,7 @@ class ItemCRUD:
def __init__(self, itemType): def __init__(self, itemType):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
self.response = {} # ✅ ADDED
self.itemCRUDType = itemType self.itemCRUDType = itemType
self.itemCRUDMapping = itemCRUDMapping(itemType) self.itemCRUDMapping = itemCRUDMapping(itemType)
@@ -56,16 +418,14 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.delete_success(self.itemCRUDMapping.name)
ResponseHandler.delete_success(self.itemCRUDMapping.name), 200 self.resultMessage = self.response["message"]
)
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error deleting {self.itemCRUDMapping.name}: {e}") print(f"Error deleting {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.delete_failure(self.itemCRUDMapping.name)
ResponseHandler.delete_failure(self.itemCRUDMapping.name), 500 self.resultMessage = self.response["message"]
)
finally: finally:
cursor.close() cursor.close()
@@ -79,9 +439,8 @@ class ItemCRUD:
connection = config.get_db_connection() connection = config.get_db_connection()
if not connection: if not connection:
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.add_failure(self.itemCRUDMapping.name)
ResponseHandler.db_connection_failure(), 500 self.resultMessage = self.response["message"]
)
return return
cursor = connection.cursor() cursor = connection.cursor()
@@ -92,12 +451,8 @@ class ItemCRUD:
) )
try: try:
# ====================================================== # SUBCONTRACTOR
# SUBCONTRACTOR (MULTI-FIELD)
# ======================================================
if data: if data:
# Duplicate check
cursor.callproc(storedprocfetch, (data['Contractor_Name'],)) cursor.callproc(storedprocfetch, (data['Contractor_Name'],))
existing_item = None existing_item = None
@@ -106,12 +461,10 @@ class ItemCRUD:
if existing_item: if existing_item:
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.already_exists(self.itemCRUDMapping.name)
ResponseHandler.already_exists(self.itemCRUDMapping.name), 409 self.resultMessage = self.response["message"]
)
return return
# Insert
cursor.callproc(storedprocadd, ( cursor.callproc(storedprocadd, (
data['Contractor_Name'], data['Contractor_Name'],
data['Address'], data['Address'],
@@ -127,22 +480,17 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.add_success(self.itemCRUDMapping.name)
ResponseHandler.add_success(self.itemCRUDMapping.name), 200 self.resultMessage = self.response["message"]
)
return return
# ====================================================== # NORMAL
# NORMAL (Village / Block / State)
# ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.patternAlphabetOnly, childname):
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.invalid_name(self.itemCRUDMapping.name)
ResponseHandler.invalid_name(self.itemCRUDMapping.name), 400 self.resultMessage = self.response["message"]
)
return return
# Duplicate check
if parentid is None: if parentid is None:
cursor.callproc(storedprocfetch, (childname,)) cursor.callproc(storedprocfetch, (childname,))
else: else:
@@ -154,12 +502,10 @@ class ItemCRUD:
if existing_item: if existing_item:
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.already_exists(self.itemCRUDMapping.name)
ResponseHandler.already_exists(self.itemCRUDMapping.name), 409 self.resultMessage = self.response["message"]
)
return return
# Insert
if parentid is None: if parentid is None:
cursor.callproc(storedprocadd, (childname,)) cursor.callproc(storedprocadd, (childname,))
else: else:
@@ -168,17 +514,14 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.add_success(self.itemCRUDMapping.name)
self.resultMessage = self.response["message"]
ResponseHandler.add_success(self.itemCRUDMapping.name), 200
)
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Database Error: {e}") print(f"Database Error: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.add_failure(self.itemCRUDMapping.name)
ResponseHandler.add_failure(self.itemCRUDMapping.name), 500 self.resultMessage = self.response["message"]
)
finally: finally:
cursor.close() cursor.close()
@@ -198,9 +541,6 @@ class ItemCRUD:
) )
try: try:
# ======================================================
# SUBCONTRACTOR (MULTI-FIELD)
# ======================================================
if data: if data:
cursor.callproc(storedprocupdate, ( cursor.callproc(storedprocupdate, (
childid, childid,
@@ -218,17 +558,14 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.update_success(self.itemCRUDMapping.name)
ResponseHandler.update_success(self.itemCRUDMapping.name), 200 self.resultMessage = self.response["message"]
)
return return
# ======================================================
# NORMAL
# ======================================================
if not re.match(RegEx.patternAlphabetOnly, childname): if not re.match(RegEx.patternAlphabetOnly, childname):
self.isSuccess = False self.isSuccess = False
self.resultMessage = ResponseHandler.update_failure(self.itemCRUDMapping.name)['message'] self.response = ResponseHandler.update_failure(self.itemCRUDMapping.name)
self.resultMessage = self.response["message"]
return return
if parentid is None: if parentid is None:
@@ -239,14 +576,14 @@ class ItemCRUD:
connection.commit() connection.commit()
self.isSuccess = True self.isSuccess = True
self.resultMessage = ResponseHandler.update_success(self.itemCRUDMapping.name)['message'] self.response = ResponseHandler.update_success(self.itemCRUDMapping.name)
self.resultMessage = self.response["message"]
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error updating {self.itemCRUDMapping.name}: {e}") print(f"Error updating {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.update_failure(self.itemCRUDMapping.name)
ResponseHandler.update_failure(self.itemCRUDMapping.name), 500 self.resultMessage = self.response["message"]
)
finally: finally:
cursor.close() cursor.close()
@@ -276,9 +613,8 @@ class ItemCRUD:
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error fetching {self.itemCRUDMapping.name}: {e}") print(f"Error fetching {self.itemCRUDMapping.name}: {e}")
self.isSuccess = False self.isSuccess = False
self.resultMessage = HtmlHelper.json_response( self.response = ResponseHandler.fetch_failure(self.itemCRUDMapping.name)
ResponseHandler.fetch_failure(self.itemCRUDMapping.name), 500 self.resultMessage = self.response["message"]
)
return [] return []
finally: finally:
@@ -312,7 +648,7 @@ class ItemCRUD:
return data return data
# ---------------------------------------------------------- # ----------------------------------------------------------
# CHECK ITEM # CHECK ITEM (KEEP AS IS - API USE)
# ---------------------------------------------------------- # ----------------------------------------------------------
def CheckItem(self, request, parentid, childname, storedprocfetch): def CheckItem(self, request, parentid, childname, storedprocfetch):

View File

@@ -1,39 +1,29 @@
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, jsonify, json
from flask import current_app
from datetime import datetime
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
import os import os
from datetime import datetime
from flask import current_app
from flask_login import current_user
class LogHelper: class LogHelper:
@staticmethod @staticmethod
def log_action(action, details=""): def log_action(action, details=""):
"""Log user actions with timestamp, user, action, and details.""" """Add a log entry."""
logData = LogData() log_data = LogData()
logData.WriteLog(action, details="") log_data.add_log(action, details)
class LogData: class LogData:
filepath = ""
timestamp = None
def __init__(self): def __init__(self):
self.filepath = os.path.join(current_app.root_path, 'activity.log') self.filepath = os.path.join(current_app.root_path, 'activity.log')
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.user = getattr(current_user, "cn", None) \
or getattr(current_user, "username", None) \
or getattr(current_user, "sAMAccountName", "Unknown")
if hasattr(current_user, "cn") and current_user.cn:
self.user = current_user.cn
elif hasattr(current_user, "username") and current_user.username:
self.user = current_user.username
elif hasattr(current_user, "sAMAccountName") and current_user.sAMAccountName:
self.user = current_user.sAMAccountName
else:
self.user = "Unknown"
def WriteLog(self, action, details=""):
"""Log user actions with timestamp, user, action, and details."""
def add_log(self, action, details=""):
"""Create/Add a log entry."""
with open(self.filepath, "a", encoding="utf-8") as f: with open(self.filepath, "a", encoding="utf-8") as f:
f.write( f.write(
f"Timestamp: {self.timestamp} | " f"Timestamp: {self.timestamp} | "
@@ -42,46 +32,73 @@ class LogData:
f"Details: {details}\n" f"Details: {details}\n"
) )
def get_all_logs(self):
def GetActivitiesLog(self): """Read all logs."""
logs = [] logs = []
if os.path.exists(self.filepath): if os.path.exists(self.filepath):
with open(self.filepath, 'r') as f: with open(self.filepath, 'r', encoding="utf-8") as f:
for line in f: for line in f:
parts = line.strip().split(" | ") parts = line.strip().split(" | ")
if len(parts) == 4: if len(parts) == 4:
logs.append({ logs.append({
"timestamp": parts[0].replace("Timestamp:", "").strip(), "timestamp": parts[0].split(":", 1)[1].strip(),
"user": parts[1].replace("User:", "").strip(), "user": parts[1].split(":", 1)[1].strip(),
"action": parts[2].replace("Action:", "").strip(), "action": parts[2].split(":", 1)[1].strip(),
"details": parts[3].replace("Details:", "").strip() "details": parts[3].split(":", 1)[1].strip()
}) })
return logs return logs
def GetFilteredActivitiesLog(self, startDate, endDate, userName): def get_filtered_logs(self, start_date=None, end_date=None, user_name=None):
"""Filter logs by date and/or user."""
logs = self.get_all_logs()
filtered_logs = self.GetActivitiesLog() # Filter by date
if start_date or end_date:
# Date filter start_dt = datetime.strptime(start_date, "%Y-%m-%d") if start_date else datetime.min
if startDate or endDate: end_dt = datetime.strptime(end_date, "%Y-%m-%d") if end_date else datetime.max
try: logs = [
start_dt = datetime.strptime(startDate, "%Y-%m-%d") if startDate else datetime.min log for log in logs
end_dt = datetime.strptime(endDate, "%Y-%m-%d") if endDate else datetime.max
filtered_logs = [
log for log in filtered_logs
if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt if start_dt <= datetime.strptime(log["timestamp"], "%Y-%m-%d %H:%M:%S") <= end_dt
] ]
# Filter by username
if user_name:
logs = [log for log in logs if user_name.lower() in log.get("user", "").lower()]
except Exception as e: return logs
print("Date filter error:", e)
#Why catching all exceptions? Need to handle specific exceptions def update_log(self, index, action=None, details=None):
"""Update a specific log entry by index (0-based)."""
logs = self.get_all_logs()
if 0 <= index < len(logs):
if action:
logs[index]["action"] = action
if details:
logs[index]["details"] = details
self._rewrite_logs_file(logs)
return True
return False
def delete_log(self, index):
"""Delete a specific log entry by index (0-based)."""
logs = self.get_all_logs()
if 0 <= index < len(logs):
logs.pop(index)
self._rewrite_logs_file(logs)
return True
return False
# ------------------- INTERNAL HELPER -------------------
def _rewrite_logs_file(self, logs):
"""Overwrite the log file with current logs."""
with open(self.filepath, "w", encoding="utf-8") as f:
for log in logs:
f.write(
f"Timestamp: {log['timestamp']} | "
f"User: {log['user']} | "
f"Action: {log['action']} | "
f"Details: {log['details']}\n"
)
# Username filter
if userName:
filtered_logs = [log for log in filtered_logs if userName.lower() in log["user"].lower()]
return filtered_logs

View File

@@ -1,13 +1,9 @@
from flask import request, redirect, url_for
from flask_login import current_user
from model.Utilities import RegEx, ResponseHandler, HtmlHelper, ItemCRUDType
from model.Log import LogHelper
from model.ItemCRUD import ItemCRUD
import config import config
import re
import mysql.connector import mysql.connector
from flask import request, redirect, url_for
from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
from model.ItemCRUD import ItemCRUD
class State: class State:
@@ -20,7 +16,6 @@ class State:
# ADD STATE (USING ITEM CRUD) # ADD STATE (USING ITEM CRUD)
# ---------------------------------------------------------- # ----------------------------------------------------------
def AddState(self, request): def AddState(self, request):
state_name = request.form['state_Name'].strip() state_name = request.form['state_Name'].strip()
crud = ItemCRUD(ItemCRUDType.State) crud = ItemCRUD(ItemCRUDType.State)
@@ -42,16 +37,14 @@ class State:
# GET ALL STATES (NO CHANGE - THIS IS CORRECT) # GET ALL STATES (NO CHANGE - THIS IS CORRECT)
# ---------------------------------------------------------- # ----------------------------------------------------------
def GetAllStates(self, request): def GetAllStates(self, request):
connection = config.get_db_connection() connection = config.get_db_connection()
data = [] data = []
if not connection: if not connection:
return [] return []
cursor = connection.cursor()
try: try:
cursor = connection.cursor()
cursor.callproc("GetAllStates") cursor.callproc("GetAllStates")
for res in cursor.stored_results(): for res in cursor.stored_results():
data = res.fetchall() data = res.fetchall()
@@ -77,7 +70,6 @@ class State:
# CHECK STATE (USING ITEM CRUD) # CHECK STATE (USING ITEM CRUD)
# ---------------------------------------------------------- # ----------------------------------------------------------
def CheckState(self, request): def CheckState(self, request):
state_name = request.json.get('state_Name', '').strip() state_name = request.json.get('state_Name', '').strip()
crud = ItemCRUD(ItemCRUDType.State) crud = ItemCRUD(ItemCRUDType.State)
@@ -94,7 +86,6 @@ class State:
# DELETE STATE (USING ITEM CRUD) # DELETE STATE (USING ITEM CRUD)
# ---------------------------------------------------------- # ----------------------------------------------------------
def DeleteState(self, request, id): def DeleteState(self, request, id):
crud = ItemCRUD(ItemCRUDType.State) crud = ItemCRUD(ItemCRUDType.State)
crud.DeleteItem( crud.DeleteItem(
@@ -113,7 +104,6 @@ class State:
# EDIT STATE (USING ITEM CRUD) # EDIT STATE (USING ITEM CRUD)
# ---------------------------------------------------------- # ----------------------------------------------------------
def EditState(self, request, id): def EditState(self, request, id):
state_name = request.form['state_Name'].strip() state_name = request.form['state_Name'].strip()
crud = ItemCRUD(ItemCRUDType.State) crud = ItemCRUD(ItemCRUDType.State)
@@ -136,16 +126,14 @@ class State:
# GET STATE BY ID (KEEP SAME) # GET STATE BY ID (KEEP SAME)
# ---------------------------------------------------------- # ----------------------------------------------------------
def GetStateByID(self, request, id): def GetStateByID(self, request, id):
connection = config.get_db_connection() connection = config.get_db_connection()
data = None data = None
if not connection: if not connection:
return None return None
cursor = connection.cursor()
try: try:
cursor = connection.cursor()
cursor.callproc("GetStateByID", (id,)) cursor.callproc("GetStateByID", (id,))
for res in cursor.stored_results(): for res in cursor.stored_results():
data = res.fetchone() data = res.fetchone()

View File

@@ -62,5 +62,5 @@ class HtmlHelper:
@staticmethod @staticmethod
def json_response(message_obj, status_code): def json_response(message_obj, status_code):
return jsonify(message_obj), status_code return jsonify(message_obj), status_code
#May need to refactor further

View File

@@ -1,4 +1,176 @@
# from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
# import config
# import mysql.connector
# from model.ItemCRUD import ItemCRUD
# class Village:
# isSuccess = False
# resultMessage = ""
# def __init__(self):
# self.isSuccess = False
# 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):
# block_id, village_name = self._get_form_data(request)
# if not village_name:
# self.isSuccess = False
# self.resultMessage = "Village name cannot be empty"
# return
# try:
# self.village.AddItem(
# request=request,
# parentid=block_id,
# 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):
# 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):
# block_id, village_name = self._get_form_data(request)
# if not village_name:
# self.isSuccess = False
# self.resultMessage = "Village name cannot be empty"
# return None
# 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):
# try:
# self.village.DeleteItem(
# request=request,
# itemID=village_id,
# storedprocDelete="DeleteVillage"
# )
# self._set_status(self.village)
# except Exception as e:
# self.isSuccess = False
# self.resultMessage = str(e)
# def EditVillage(self, request, village_id):
# block_id, village_name = self._get_form_data(request)
# if not village_name:
# self.isSuccess = False
# self.resultMessage = "Village name cannot be empty"
# return
# 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 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 = []
# self.isSuccess = False
# self.resultMessage = ""
# connection = config.get_db_connection()
# if not connection:
# return []
# try:
# with connection.cursor() as cursor:
# cursor.callproc('GetAllBlocks')
# for result in cursor.stored_results():
# blocks.extend(result.fetchall())
# self.isSuccess = True
# return blocks # return blocks
# except mysql.connector.Error as e:
# print(f"Error fetching blocks: {e}")
# self.isSuccess = False
# self.resultMessage = HtmlHelper.json_response(
# ResponseHandler.fetch_failure("block"), 500
# )
# return []
# finally:
# connection.close()
from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType from model.Utilities import ResponseHandler, HtmlHelper, ItemCRUDType
import config import config
import mysql.connector import mysql.connector
@@ -12,11 +184,18 @@ class Village:
def __init__(self): def __init__(self):
self.isSuccess = False self.isSuccess = False
self.resultMessage = "" self.resultMessage = ""
self.response = {} # ✅ ADDED
self.village = ItemCRUD(itemType=ItemCRUDType.Village) self.village = ItemCRUD(itemType=ItemCRUDType.Village)
# 🔹 Helper: sync status # 🔹 Helper: sync status
def _set_status(self, village): def _set_status(self, village):
self.isSuccess = village.isSuccess self.isSuccess = village.isSuccess
# ✅ UPDATED (safe handling)
if hasattr(village, "response"):
self.response = village.response
self.resultMessage = village.response.get("message", "")
else:
self.resultMessage = village.resultMessage self.resultMessage = village.resultMessage
# 🔹 Helper: get request data # 🔹 Helper: get request data
@@ -29,8 +208,9 @@ class Village:
block_id, village_name = self._get_form_data(request) block_id, village_name = self._get_form_data(request)
if not village_name: if not village_name:
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
self.resultMessage = self.response["message"]
self.isSuccess = False self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return return
try: try:
@@ -66,8 +246,9 @@ class Village:
block_id, village_name = self._get_form_data(request) block_id, village_name = self._get_form_data(request)
if not village_name: if not village_name:
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
self.resultMessage = self.response["message"]
self.isSuccess = False self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return None return None
try: try:
@@ -103,8 +284,9 @@ class Village:
block_id, village_name = self._get_form_data(request) block_id, village_name = self._get_form_data(request)
if not village_name: if not village_name:
self.response = ResponseHandler.invalid_name("village") # ✅ UPDATED
self.resultMessage = self.response["message"]
self.isSuccess = False self.isSuccess = False
self.resultMessage = "Village name cannot be empty"
return return
try: try:
@@ -164,9 +346,11 @@ class Village:
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 # ✅ FIXED (removed jsonify response)
) self.response = ResponseHandler.fetch_failure("block")
self.resultMessage = self.response["message"]
return [] return []
finally: finally:

View File

@@ -1,150 +1,246 @@
import config # from flask import request
import mysql.connector # from model.ItemCRUD import ItemCRUD
# from model.Utilities import ItemCRUDType
class GSTReleasemodel: # class GSTRelease:
# """CRUD operations for GST Release using ItemCRUD"""
@staticmethod # def __init__(self):
def get_connection(): # self.isSuccess = False
connection = config.get_db_connection() # self.resultMessage = ""
if not connection:
return None
return connection
@staticmethod # # ------------------- Add GST Release -------------------
def fetch_all_gst_releases(): # def AddGSTRelease(self, request):
connection = GSTReleasemodel.get_connection() # pmc_no = request.form.get('PMC_No', '').strip()
gst_releases = [] # invoice_no = request.form.get('invoice_No', '').strip()
if connection:
cursor = connection.cursor(dictionary=True)
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.AddItem(
# request=request,
# parentid=None,
# childname=f"{pmc_no}-{invoice_no}",
# storedprocfetch="CheckGSTReleaseExists",
# storedprocadd="AddGSTReleaseFromExcel" # your stored procedure handles extra fields
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# # ------------------- Get All GST Releases -------------------
# def GetAllGSTReleases(self):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# # Pass request=None for fetch
# rows = gst.GetAllData(request=None, storedproc="GetAllGSTReleases")
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# data = []
# for row in rows:
# data.append({
# "gst_release_id": row[0],
# "pmc_no": row[1],
# "invoice_no": row[2],
# "basic_amount": row[3],
# "final_amount": row[4],
# "total_amount": row[5],
# "utr": row[6],
# "contractor_id": row[7]
# })
# return data
# # ------------------- Get GST Release By ID -------------------
# def GetGSTReleaseByID(self, gst_release_id):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# row = gst.GetDataByID(gst_release_id, request=None, storedproc="GetGSTReleaseById")
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# if row:
# return {
# "gst_release_id": row[0],
# "pmc_no": row[1],
# "invoice_no": row[2],
# "basic_amount": row[3],
# "final_amount": row[4],
# "total_amount": row[5],
# "utr": row[6],
# "contractor_id": row[7]
# }
# return None
# # ------------------- Edit GST Release -------------------
# def EditGSTRelease(self, request, gst_release_id):
# pmc_no = request.form.get('PMC_No', '').strip()
# invoice_no = request.form.get('invoice_No', '').strip()
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.EditItem(
# request=request,
# childid=gst_release_id,
# parentid=None,
# childname=f"{pmc_no}-{invoice_no}",
# storedprocupdate="UpdateGSTRelease" # stored procedure handles extra fields
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
# # ------------------- Delete GST Release -------------------
# def DeleteGSTRelease(self, gst_release_id):
# gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# gst.DeleteItem(
# itemID=gst_release_id,
# request=None,
# storedprocDelete="DeleteGSTReleaseById"
# )
# self.isSuccess = gst.isSuccess
# self.resultMessage = str(gst.resultMessage)
from flask import request, jsonify
from model.ItemCRUD import ItemCRUD
from model.Utilities import ItemCRUDType
class GSTRelease:
def __init__(self):
self.isSuccess = False
self.resultMessage = ""
# ------------------- Add GST Release -------------------
def AddGSTRelease(self, request):
try: try:
cursor.callproc('GetAllGSTReleases') gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
gst_releases = [] data = {
for result in cursor.stored_results(): # change to procedure "PMC_No": request.form.get("PMC_No", "").strip(),
gst_releases = result.fetchall() "Invoice_No": request.form.get("Invoice_No", "").strip(),
"Basic_Amount": float(request.form.get("Basic_Amount", 0) or 0),
"Final_Amount": float(request.form.get("Final_Amount", 0) or 0),
"Total_Amount": float(request.form.get("Total_Amount", 0) or 0),
"UTR": request.form.get("UTR", "").strip(),
"Contractor_ID": int(request.form.get("Contractor_ID", 0) or 0)
}
except mysql.connector.Error as e: gst.AddItem(
print(f"Error fetching GST releases: {e}") request=request,
finally: data=data,
cursor.close() storedprocfetch="CheckGSTReleaseExists",
connection.close() storedprocadd="AddGSTReleaseFromExcel"
return gst_releases
@staticmethod
def insert_gst_release(pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr, contractor_id):
connection = GSTReleasemodel.get_connection()
if not connection:
return False
try:
cursor = connection.cursor()
# Insert into gst_release
cursor.callproc(
'InsertGSTReleaseOnly',
[pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr, contractor_id]
) )
# Insert into inpayment self.isSuccess = gst.isSuccess
cursor.callproc( self.resultMessage = str(gst.resultMessage)
'InsertInpaymentOnly',
[pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr, contractor_id] except Exception as e:
print("ERROR in AddGSTRelease:", e)
self.isSuccess = False
self.resultMessage = str(e)
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
# ------------------- Edit GST Release -------------------
def EditGSTRelease(self, request, gst_release_id):
try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
data = {
"PMC_No": request.form.get("PMC_No", "").strip(),
"Invoice_No": request.form.get("Invoice_No", "").strip(),
"Basic_Amount": float(request.form.get("Basic_Amount", 0) or 0),
"Final_Amount": float(request.form.get("Final_Amount", 0) or 0),
"Total_Amount": float(request.form.get("Total_Amount", 0) or 0),
"UTR": request.form.get("UTR", "").strip()
}
gst.EditItem(
request=request,
childid=gst_release_id,
data=data,
storedprocupdate="UpdateGSTRelease"
) )
connection.commit() self.isSuccess = gst.isSuccess
return True self.resultMessage = str(gst.resultMessage)
except mysql.connector.Error as e:
print(f"Error inserting GST release: {e}")
return False
finally:
cursor.close()
connection.close()
@staticmethod except Exception as e:
def fetch_gst_release_by_id(gst_release_id): print("ERROR in EditGSTRelease:", e)
connection = GSTReleasemodel.get_connection() self.isSuccess = False
if not connection: self.resultMessage = str(e)
return None
data = {} return jsonify({"success": self.isSuccess, "message": self.resultMessage})
# ------------------- Delete GST Release -------------------
def DeleteGSTRelease(self, gst_release_id):
try: try:
cursor = connection.cursor(dictionary=True) gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
cursor.callproc('GetGSTReleaseById', [gst_release_id]) gst.DeleteItem(
request=None,
itemID=gst_release_id,
storedprocDelete="DeleteGSTReleaseById"
)
self.isSuccess = gst.isSuccess
self.resultMessage = str(gst.resultMessage)
except Exception as e:
print("ERROR in DeleteGSTRelease:", e)
self.isSuccess = False
self.resultMessage = str(e)
return jsonify({"success": self.isSuccess, "message": self.resultMessage})
# ------------------- Get All GST Releases -------------------
def GetAllGSTReleases(self):
try:
gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
rows = gst.GetAllData(None, "GetAllGSTReleases")
data = []
for row in rows:
data.append({
"gst_release_id": row[0],
"pmc_no": row[1],
"invoice_no": row[2],
"basic_amount": row[3],
"final_amount": row[4],
"total_amount": row[5],
"utr": row[6],
"contractor_id": row[7]
})
for result in cursor.stored_results():
data = result.fetchone()
if data:
# Convert to array for template
data = [
data.get('GST_Release_Id'),
data.get('PMC_No'),
data.get('Invoice_No'),
data.get('Basic_Amount'),
data.get('Final_Amount'),
data.get('Total_Amount'),
data.get('UTR')
]
except mysql.connector.Error as e:
print(f"Error fetching GST release by id: {e}")
finally:
cursor.close()
connection.close()
return data return data
@staticmethod except Exception as e:
def update_gst_release(gst_release_id, pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr): print("ERROR in GetAllGSTReleases:", e)
connection = GSTReleasemodel.get_connection() return []
if not connection:
return False # ------------------- Get GST Release By ID -------------------
def GetGSTReleaseByID(self, gst_release_id):
try: try:
cursor = connection.cursor() gst = ItemCRUD(itemType=ItemCRUDType.GSTRelease)
# Update gst_release
cursor.callproc(
'UpdateGSTRelease',
[pmc_no, invoice_no, basic_amount, final_amount, total_amount, utr, gst_release_id]
)
# Update inpayment
cursor.callproc(
'UpdateInpaymentByUTR',
[basic_amount, final_amount, total_amount, utr]
)
connection.commit()
return True
except mysql.connector.Error as e:
print(f"Error updating GST release: {e}")
return False
finally:
cursor.close()
connection.close()
@staticmethod row = gst.GetDataByID(gst_release_id, "GetGSTReleaseById")
def delete_gst_release(gst_release_id):
connection = GSTReleasemodel.get_connection()
if not connection:
return False, None
try:
cursor = connection.cursor(dictionary=True)
cursor.callproc('GetGSTReleaseUTRById', [gst_release_id])
record = None
for result in cursor.stored_results():
record = result.fetchone()
if not record: if row:
return False, None return {
"gst_release_id": row[0],
"pmc_no": row[1],
"invoice_no": row[2],
"basic_amount": row[3],
"final_amount": row[4],
"total_amount": row[5],
"utr": row[6],
"contractor_id": row[7]
}
utr = record['UTR'] return None
# Step 1: Delete gst_release except Exception as e:
cursor.callproc('DeleteGSTReleaseById', [gst_release_id]) print("ERROR in GetGSTReleaseByID:", e)
return None
# Step 2: Reset inpayment using UTR
cursor.callproc('ResetInpaymentByUTR', [utr])
connection.commit()
return True, utr
except mysql.connector.Error as e:
print(f"Error deleting GST release: {e}")
return False, None
finally:
cursor.close()
connection.close()

View File

@@ -1,8 +1,13 @@
import config import config
import mysql.connector import mysql.connector
import config
import mysql.connector
from enum import Enum
from model.Utilities import ItemCRUDType
class Paymentmodel: class Paymentmodel:
# ---------------- Database Connection ----------------
@staticmethod @staticmethod
def get_connection(): def get_connection():
connection = config.get_db_connection() connection = config.get_db_connection()
@@ -10,6 +15,7 @@ class Paymentmodel:
return None return None
return connection return connection
# ---------------- Payment Methods ----------------
@staticmethod @staticmethod
def fetch_all_payments(): def fetch_all_payments():
connection = Paymentmodel.get_connection() connection = Paymentmodel.get_connection()
@@ -52,13 +58,7 @@ class Paymentmodel:
try: try:
cursor = connection.cursor() cursor = connection.cursor()
cursor.callproc('UpdateInpaymentRecord', [ cursor.callproc('UpdateInpaymentRecord', [
subcontractor_id, subcontractor_id, pmc_no, invoice_no, amount, tds_amount, total_amount, utr
pmc_no,
invoice_no,
amount,
tds_amount,
total_amount,
utr
]) ])
connection.commit() connection.commit()
return True return True
@@ -80,7 +80,6 @@ class Paymentmodel:
cursor.callproc("GetPaymentById", (payment_id,)) cursor.callproc("GetPaymentById", (payment_id,))
for result in cursor.stored_results(): for result in cursor.stored_results():
payment_data = result.fetchone() payment_data = result.fetchone()
# Convert to array for template
if payment_data: if payment_data:
payment_data = [ payment_data = [
payment_data.get('Payment_Id'), payment_data.get('Payment_Id'),
@@ -117,42 +116,99 @@ class Paymentmodel:
@staticmethod @staticmethod
def delete_payment(payment_id): def delete_payment(payment_id):
"""
Deletes a payment and resets the related inpayment fields in one go.
Returns (success, pmc_no, invoice_no)
"""
connection = Paymentmodel.get_connection() connection = Paymentmodel.get_connection()
if not connection: if not connection:
return False, None, None return False, None, None
try: try:
cursor = connection.cursor(dictionary=True) cursor = connection.cursor(dictionary=True)
# Fetch PMC & Invoice before deleting
cursor.callproc('GetPaymentPMCInvoiceById', [payment_id]) cursor.callproc('GetPaymentPMCInvoiceById', [payment_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:
return False, None, None return False, None, None
pmc_no = record['PMC_No'] pmc_no = record['PMC_No']
invoice_no = record['Invoice_No'] invoice_no = record['Invoice_No']
# Delete payment
# Step 2: Delete the payment using the stored procedure
cursor.callproc("DeletePayment", (payment_id,)) cursor.callproc("DeletePayment", (payment_id,))
connection.commit() connection.commit()
# Reset inpayment fields
# Step 3: Reset inpayment fields using the stored procedure
cursor.callproc("ResetInpayment", [pmc_no, invoice_no]) cursor.callproc("ResetInpayment", [pmc_no, invoice_no])
connection.commit() connection.commit()
return True, pmc_no, invoice_no return True, pmc_no, invoice_no
except mysql.connector.Error as e: except mysql.connector.Error as e:
print(f"Error deleting payment: {e}") print(f"Error deleting payment: {e}")
return False, None, None return False, None, None
finally:
cursor.close()
connection.close()
# ---------------- Item CRUD Methods ----------------
@staticmethod
def fetch_items(item_type: ItemCRUDType):
connection = Paymentmodel.get_connection()
items = []
if connection:
cursor = connection.cursor(dictionary=True)
try:
cursor.callproc('GetItemsByType', [item_type.value])
for result in cursor.stored_results():
items = result.fetchall()
except mysql.connector.Error as e:
print(f"Error fetching {item_type.name}: {e}")
finally:
cursor.close()
connection.close()
return items
@staticmethod
def insert_item(item_type: ItemCRUDType, name: str):
connection = Paymentmodel.get_connection()
if not connection:
return False
try:
cursor = connection.cursor()
cursor.callproc('InsertItem', [item_type.value, name])
connection.commit()
return True
except mysql.connector.Error as e:
print(f"Error inserting {item_type.name}: {e}")
return False
finally:
cursor.close()
connection.close()
@staticmethod
def update_item(item_type: ItemCRUDType, item_id: int, new_name: str):
connection = Paymentmodel.get_connection()
if not connection:
return False
try:
cursor = connection.cursor()
cursor.callproc('UpdateItem', [item_type.value, item_id, new_name])
connection.commit()
return True
except mysql.connector.Error as e:
print(f"Error updating {item_type.name}: {e}")
return False
finally:
cursor.close()
connection.close()
@staticmethod
def delete_item(item_type: ItemCRUDType, item_id: int):
connection = Paymentmodel.get_connection()
if not connection:
return False
try:
cursor = connection.cursor()
cursor.callproc('DeleteItem', [item_type.value, item_id])
connection.commit()
return True
except mysql.connector.Error as e:
print(f"Error deleting {item_type.name}: {e}")
return False
finally: finally:
cursor.close() cursor.close()
connection.close() connection.close()

View File

@@ -1,9 +1,237 @@
// window.onload = function () {
// document.getElementById('Village_Name').focus();
// };
// $(document).ready(function () {
// // STATE → DISTRICT
// $('#state_Id').change(function () {
// var stateId = $(this).val();
// if (stateId) {
// $.ajax({
// url: '/get_districts/' + stateId,
// type: 'GET',
// success: function (data) {
// var districtDropdown = $('#district_Id');
// districtDropdown.empty();
// districtDropdown.append('<option value="" disabled selected>Select District</option>');
// data.forEach(function (district) {
// districtDropdown.append(
// '<option value="' + district.id + '">' + district.name + '</option>'
// );
// });
// districtDropdown.prop('disabled', false);
// }
// });
// }
// });
// // DISTRICT → BLOCK
// $('#district_Id').change(function () {
// var districtId = $(this).val();
// if (districtId) {
// $.ajax({
// url: '/get_blocks/' + districtId,
// type: 'GET',
// success: function (data) {
// var blockDropdown = $('#block_Id');
// blockDropdown.empty();
// blockDropdown.append('<option value="" disabled selected>Select Block</option>');
// data.forEach(function (block) {
// blockDropdown.append(
// '<option value="' + block.id + '">' + block.name + '</option>'
// );
// });
// blockDropdown.prop('disabled', false);
// }
// });
// }
// });
// // VILLAGE NAME VALIDATION
// $('#Village_Name').on('input', function () {
// var villageName = $(this).val();
// var validPattern = /^[A-Za-z ]*$/;
// if (!validPattern.test(villageName)) {
// $('#villageMessage')
// .text('Only letters and spaces are allowed!')
// .css('color', 'red');
// $('#submitVillage').prop('disabled', true);
// } else {
// $('#villageMessage').text('');
// $('#submitVillage').prop('disabled', false);
// }
// });
// // CHECK DUPLICATE VILLAGE
// $('#Village_Name, #block_Id').on('change keyup', function () {
// var blockId = $('#block_Id').val();
// var villageName = $('#Village_Name').val().trim();
// if (blockId && villageName) {
// $.ajax({
// url: '/check_village',
// type: 'POST',
// data: {
// block_Id: blockId,
// Village_Name: villageName
// },
// success: function (response) {
// if (response.status === 'exists') {
// $('#villageMessage')
// .text(response.message)
// .css('color', 'red');
// $('#submitVillage').prop('disabled', true);
// } else {
// $('#villageMessage')
// .text(response.message)
// .css('color', 'green');
// $('#submitVillage').prop('disabled', false);
// }
// },
// error: function () {
// $('#villageMessage')
// .text('Error checking village name')
// .css('color', 'red');
// $('#submitVillage').prop('disabled', true);
// }
// });
// }
// });
// // ADD VILLAGE
// $('#villageForm').submit(function (event) {
// event.preventDefault();
// $.ajax({
// url: '/add_village',
// type: 'POST',
// data: $(this).serialize(),
// success: function (response) {
// if (response.status === 'success') {
// alert('Village added successfully!');
// location.reload();
// } else {
// alert('Error adding village. Please try again.');
// }
// },
// error: function () {
// alert('An error occurred. Please try again.');
// }
// });
// });
// });
window.onload = function () { window.onload = function () {
document.getElementById('Village_Name').focus(); document.getElementById('Village_Name').focus();
}; };
$(document).ready(function () { $(document).ready(function () {
// 🔥 RESTORE VIEW MODE AFTER RELOAD
var viewMode = localStorage.getItem("viewMode");
if (viewMode === "table") {
$('#addForm').hide();
$('#addTable').show();
} else {
$('#addForm').show();
$('#addTable').hide();
}
// 🔥 BUTTON TOGGLE LOGIC
$('#addButton').click(function () {
$('#addForm').show();
$('#addTable').hide();
localStorage.setItem("viewMode", "form");
});
$('#displayButton').click(function () {
$('#addForm').hide();
$('#addTable').show();
localStorage.setItem("viewMode", "table");
});
// STATE → DISTRICT // STATE → DISTRICT
$('#state_Id').change(function () { $('#state_Id').change(function () {
@@ -179,7 +407,7 @@ $(document).ready(function () {
} else { } else {
alert('Error adding village. Please try again.'); alert(response.message || 'Error adding village. Please try again.');
} }
@@ -196,3 +424,38 @@ $(document).ready(function () {
}); });
}); });
// 🔥 DELETE FUNCTION (UPDATED)
function deleteVillage(villageId) {
if (!confirm("Are you sure you want to delete this village?")) {
return;
}
// ✅ save that user is on table
localStorage.setItem("viewMode", "table");
$.ajax({
url: '/delete_village/' + villageId,
type: 'GET',
success: function () {
setTimeout(function () {
alert("Village deleted successfully!");
// reload but stay on table
location.reload();
}, 1000);
},
error: function () {
alert("Error deleting village. Please try again.");
}
});
}

View File

@@ -1,5 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Activity Logs</title> <title>Activity Logs</title>
@@ -9,54 +10,67 @@
background-color: #f8f9fa; background-color: #f8f9fa;
margin: 20px; margin: 20px;
} }
h2 { h2 {
text-align: center; text-align: center;
margin-bottom: 20px; margin-bottom: 20px;
} }
form { form {
display: flex; display: flex;
gap: 10px; gap: 10px;
justify-content: center; justify-content: center;
margin-bottom: 20px; margin-bottom: 20px;
flex-wrap: wrap;
} }
input, button {
input,
button {
padding: 8px; padding: 8px;
border-radius: 6px; border-radius: 6px;
border: 1px solid #ccc; border: 1px solid #ccc;
} }
button { button {
background-color: #007bff; background-color: #007bff;
color: white; color: white;
cursor: pointer; cursor: pointer;
} }
button:hover { button:hover {
background-color: #0056b3; background-color: #0056b3;
} }
table { table {
width: 90%; width: 90%;
margin: auto; margin: auto;
border-collapse: collapse; border-collapse: collapse;
background: white; background: white;
box-shadow: 0 0 8px rgba(0,0,0,0.1); box-shadow: 0 0 8px rgba(0, 0, 0, 0.1);
} }
th, td {
th,
td {
padding: 12px; padding: 12px;
border: 1px solid #ddd; border: 1px solid #ddd;
text-align: center; text-align: center;
} }
th { th {
background-color: #007bff; background-color: #007bff;
color: white; color: white;
} }
tr:nth-child(even) { tr:nth-child(even) {
background-color: #f2f2f2; background-color: #f2f2f2;
} }
</style> </style>
</head> </head>
<body> <body>
<h2>Activity Logs</h2> <h2>Activity Logs</h2>
<form method="get" action="{{ url_for('activity_log') }}" class="filter-form">
<form method="get" action="{{ url_for('log.activity_log') }}" class="filter-form">
<label for="username">Username:</label> <label for="username">Username:</label>
<input type="text" id="username" name="username" placeholder="Enter username" value="{{ username or '' }}"> <input type="text" id="username" name="username" placeholder="Enter username" value="{{ username or '' }}">
@@ -66,10 +80,9 @@
<label for="end_date">End Date:</label> <label for="end_date">End Date:</label>
<input type="date" id="end_date" name="end_date" value="{{ end_date or '' }}"> <input type="date" id="end_date" name="end_date" value="{{ end_date or '' }}">
<button type="submit" class="btn btn-primary">Filter</button> <button type="submit" class="btn btn-primary">Filter</button>
<!-- <button type="button" style="background-color: #6c757d;" onclick="resetFilter()">Reset</button> --> <button type="button" style="background-color: #6c757d;" onclick="resetFilter()">Reset</button>
</form> </form>
<table> <table>
<tr> <tr>
@@ -95,8 +108,9 @@
<script> <script>
function resetFilter() { function resetFilter() {
window.location.href = "{{ url_for('activity_log') }}"; window.location.href = "{{ url_for('log.activity_log') }}";
} }
</script> </script>
</body> </body>
</html> </html>

View File

@@ -84,11 +84,11 @@
</a> </a>
</td> </td>
<td> <td>
<a href="{{ url_for('village.delete_village', village_id=village[0]) }}" <a href="#"
onclick="return confirm('Are you sure you want to delete this village?');"> onclick="deleteVillage({{ village[0] }}); return false;">
<img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}" alt="Delete" <img src="{{ url_for('static', filename='images/icons/bin_red_icon.png') }}"
class="icon"> alt="Delete" class="icon">
</a> </a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}